[
  {
    "path": ".github/ISSUE_TEMPLATE/application-bug.yml",
    "content": "name: 🐞 Application Issue Report\ndescription: Report a issue in CloudStream\nlabels: [bug]\nbody:\n\n  - type: textarea\n    id: reproduce-steps\n    attributes:\n      label: Steps to reproduce\n      description: Provide an example of the issue.\n      placeholder: |\n        Example:\n          1. First step\n          2. Second step\n          3. Issue here\n    validations:\n      required: true\n\n  - type: textarea\n    id: expected-behavior\n    attributes:\n      label: Expected behavior\n      placeholder: |\n        Example:\n          \"This should happen...\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: actual-behavior\n    attributes:\n      label: Actual behavior\n      placeholder: |\n        Example:\n          \"This happened instead...\"\n    validations:\n      required: true\n\n  - type: input\n    id: cloudstream-version\n    attributes:\n      label: Cloudstream version and commit hash\n      description: |\n        You can find your Cloudstream version in **Settings**. Commit hash is the 7 character string next to the version.\n      placeholder: |\n        Example: \"2.8.16 a49f466\"\n    validations:\n      required: true\n\n  - type: input\n    id: android-version\n    attributes:\n      label: Android version\n      description: |\n        You can find this somewhere in your Android settings.\n      placeholder: |\n        Example: \"Android 12\"\n    validations:\n      required: true\n   \n  - type: textarea\n    id: logcat\n    attributes:\n      label: Logcat\n      placeholder: |\n        To get logcat please go to Settings > Updates and backup > Show logcat 🐈.\n        You can attach a file or link to some pastebin service if the file is too big.\n      render: java\n\n  - type: textarea\n    id: other-details\n    attributes:\n      label: Other details\n      placeholder: |\n        Additional details and attachments.\n\n  - type: checkboxes\n    id: acknowledgements\n    attributes:\n      label: Acknowledgements\n      description: Your issue will be closed if you haven't done these steps.\n      options:\n        - label: I am sure my issue is related to the app and **NOT some extension**.\n          required: true\n        - label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.\n          required: true\n        - label: I have written a short but informative title.\n          required: true\n        - label: I have updated the app to pre-release version **[Latest](https://github.com/recloudstream/cloudstream/releases)**.\n          required: true\n        - label: I will fill out all of the requested information in this form.\n          required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: Request a new provider or report bug with an existing provider\n    url: https://github.com/recloudstream\n    about: EXTREMELY IMPORTANT - Please do not report any provider bugs here or request new providers. This repository does not contain any providers. Please find the appropriate repository and report your issue there or join the discord.\n  - name: Discord\n    url: https://discord.gg/5Hus6fM\n    about: Join our discord for faster support on smaller issues.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.yml",
    "content": "name: ⭐ Feature request\ndescription: Suggest a feature to improve the app\nlabels: [enhancement]\nbody:\n\n  - type: textarea\n    id: feature-description\n    attributes:\n      label: Describe your suggested feature\n      description: How can an existing source be improved?\n      placeholder: |\n        Example:\n          \"It should work like this...\"\n    validations:\n      required: true\n\n  - type: textarea\n    id: other-details\n    attributes:\n      label: Other details\n      placeholder: |\n        Additional details and attachments.\n\n  - type: checkboxes\n    id: acknowledgements\n    attributes:\n      label: Acknowledgements\n      description: Your issue will be closed if you haven't done these steps.\n      options:\n        - label: My suggestion is **NOT** about adding a new provider\n          required: true\n        - label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open issue.\n          required: true"
  },
  {
    "path": ".github/locales.py",
    "content": "import re\nimport glob\nimport requests\nimport lxml.etree as ET  # builtin library doesn't preserve comments\n\n\nSETTINGS_PATH = \"app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt\"\nSTART_MARKER = \"/* begin language list */\"\nEND_MARKER = \"/* end language list */\"\nXML_NAME = \"app/src/main/res/values-b+\"\nISO_MAP_URL = \"https://raw.githubusercontent.com/haliaeetus/iso-639/master/data/iso_639-1.min.json\"\nINDENT = \" \"*4\n\niso_map = requests.get(ISO_MAP_URL, timeout=300).json()\n\n# Load settings file\nsrc = open(SETTINGS_PATH, \"r\", encoding='utf-8').read()\nbefore_src, rest = src.split(START_MARKER)\nrest, after_src = rest.split(END_MARKER)\n\n# Load already added langs\nlanguages = {}\nfor lang in re.finditer(r'Pair\\(\"(.*)\", \"(.*)\"\\)', rest):\n    name, iso = lang.groups()\n    languages[iso] = name\n\n# Add not yet added langs\nfor folder in glob.glob(f\"{XML_NAME}*\"):\n    iso = folder[len(XML_NAME):].replace(\"+\", \"-\")\n    if iso not in languages.keys():\n        entry = iso_map.get(iso.lower(), {'nativeName':iso}) # fallback to iso code if not found\n        languages[iso] = entry['nativeName'].split(',')[0] # first name if there are multiple\n\n# Create pairs\npairs = []\nfor iso in sorted(languages, key=lambda iso: languages[iso].lower()): # sort by language name\n    name = languages[iso]\n    pairs.append(f'{INDENT}Pair(\"{name}\", \"{iso}\"),')\n\n# Update settings file\nopen(SETTINGS_PATH, \"w+\",encoding='utf-8').write(\n    before_src +\n    START_MARKER +\n    \"\\n\" +\n    \"\\n\".join(pairs) +\n    \"\\n\" +\n    END_MARKER +\n    after_src\n)\n\n# Go through each values.xml file and fix escaped \\@string\nfor file in glob.glob(f\"{XML_NAME}*/strings.xml\"):\n    try:\n        tree = ET.parse(file)\n        for child in tree.getroot():\n            if not child.text:\n                continue\n            if child.text.startswith(\"\\\\@string/\"):\n                print(f\"[{file}] fixing {child.attrib['name']}\")\n                child.text = child.text.replace(\"\\\\@string/\", \"@string/\")\n        with open(file, 'wb') as fp:\n            fp.write(b'<?xml version=\"1.0\" encoding=\"utf-8\"?>\\n')\n            tree.write(fp, encoding=\"utf-8\", method=\"xml\", pretty_print=True, xml_declaration=False)\n    except ET.ParseError as ex:\n        print(f\"[{file}] {ex}\")\n"
  },
  {
    "path": ".github/workflows/build_to_archive.yml",
    "content": "name: Archive build\n\non:\n  push:\n    branches: [ master ]\n    paths-ignore:\n      - '*.md'\n      - '*.json'\n      - '**/wcokey.txt'\n  workflow_dispatch:\n\nconcurrency:\n  group: \"Archive-build\"\n  cancel-in-progress: true\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Generate access token\n      id: generate_token\n      uses: tibdex/github-app-token@v2\n      with:\n        app_id: ${{ secrets.GH_APP_ID }}\n        private_key: ${{ secrets.GH_APP_KEY }}\n        repository: \"recloudstream/secrets\"\n\n    - name: Generate access token (archive)\n      id: generate_archive_token\n      uses: tibdex/github-app-token@v2\n      with:\n        app_id: ${{ secrets.GH_APP_ID }}\n        private_key: ${{ secrets.GH_APP_KEY }}\n        repository: \"recloudstream/cloudstream-archive\"\n\n    - uses: actions/checkout@v6\n\n    - name: Set up JDK 17\n      uses: actions/setup-java@v5\n      with:\n        distribution: temurin\n        java-version: 17\n\n    - name: Grant execute permission for gradlew\n      run: chmod +x gradlew\n\n    - name: Fetch keystore\n      id: fetch_keystore\n      run: |\n        TMP_KEYSTORE_FILE_PATH=\"${RUNNER_TEMP}\"/keystore\n        mkdir -p \"${TMP_KEYSTORE_FILE_PATH}\"\n        curl -H \"Authorization: token ${{ steps.generate_token.outputs.token }}\" -o \"${TMP_KEYSTORE_FILE_PATH}/prerelease_keystore.keystore\" \"https://raw.githubusercontent.com/recloudstream/secrets/master/keystore.jks\"\n        curl -H \"Authorization: token ${{ steps.generate_token.outputs.token }}\" -o \"keystore_password.txt\" \"https://raw.githubusercontent.com/recloudstream/secrets/master/keystore_password.txt\"\n        KEY_PWD=\"$(cat keystore_password.txt)\"\n        echo \"::add-mask::${KEY_PWD}\"\n        echo \"key_pwd=$KEY_PWD\" >> $GITHUB_OUTPUT\n\n    - name: Setup Gradle\n      uses: gradle/actions/setup-gradle@v5\n      with:\n        cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}\n\n    - name: Run Gradle\n      run: ./gradlew assemblePrerelease\n      env:\n        SIGNING_KEY_ALIAS: \"key0\"\n        SIGNING_KEY_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}\n        SIGNING_STORE_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}\n        SIMKL_CLIENT_ID: ${{ secrets.SIMKL_CLIENT_ID }}\n        SIMKL_CLIENT_SECRET: ${{ secrets.SIMKL_CLIENT_SECRET }}\n\n    - uses: actions/checkout@v6\n      with:\n        repository: \"recloudstream/cloudstream-archive\"\n        token: ${{ steps.generate_archive_token.outputs.token }}\n        path: \"archive\"\n\n    - name: Move build\n      run: cp app/build/outputs/apk/prerelease/release/*.apk \"archive/$(git rev-parse --short HEAD).apk\"\n\n    - name: Push archive\n      run: |\n        cd $GITHUB_WORKSPACE/archive\n        git config --local user.email \"actions@github.com\"\n        git config --local user.name \"GitHub Actions\"\n        git add .\n        git commit --amend -m \"Build $GITHUB_SHA\" || exit 0   # do not error if nothing to commit\n        git push --force\n"
  },
  {
    "path": ".github/workflows/generate_dokka.yml",
    "content": "name: Dokka\n\non:\n  push:\n    branches: [ master ]\n    paths-ignore:\n      - '*.md'\n\nconcurrency:\n  group: \"dokka\"\n  cancel-in-progress: true\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Generate access token\n        id: generate_token\n        uses: tibdex/github-app-token@v2\n        with:\n          app_id: ${{ secrets.GH_APP_ID }}\n          private_key: ${{ secrets.GH_APP_KEY }}\n          repository: \"recloudstream/dokka\"\n\n      - name: Checkout\n        uses: actions/checkout@v6\n        with:\n          path: \"src\"\n\n      - name: Checkout dokka\n        uses: actions/checkout@v6\n        with:\n          repository: \"recloudstream/dokka\"\n          path: \"dokka\"\n          token: ${{ steps.generate_token.outputs.token }}\n\n      - name: Clean old builds\n        run: |\n          cd $GITHUB_WORKSPACE/dokka/\n          rm -rf \"./app\"\n          rm -rf \"./library\"\n\n      - name: Set up JDK 17\n        uses: actions/setup-java@v5\n        with:\n          distribution: temurin\n          java-version: 17\n\n      - name: Setup Gradle\n        uses: gradle/actions/setup-gradle@v5\n        with:\n          cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}\n\n      - name: Set up Android SDK\n        uses: android-actions/setup-android@v3\n\n      - name: Generate Dokka\n        run: |\n          cd $GITHUB_WORKSPACE/src/\n          chmod +x gradlew\n          ./gradlew docs:dokkaGeneratePublicationHtml\n\n      - name: Copy Dokka\n        run: cp -r $GITHUB_WORKSPACE/src/docs/build/dokka/html/* $GITHUB_WORKSPACE/dokka/\n\n      - name: Push builds\n        run: |\n          cd $GITHUB_WORKSPACE/dokka\n          touch .nojekyll\n          git config --local user.email \"111277985+recloudstream[bot]@users.noreply.github.com\"\n          git config --local user.name \"recloudstream[bot]\"\n          git add .\n          git commit --amend -m \"Generate dokka for recloudstream/cloudstream@${GITHUB_SHA}\" || exit 0   # do not error if nothing to commit\n          git push --force\n"
  },
  {
    "path": ".github/workflows/issue_action.yml",
    "content": "name: Issue automatic actions\n\non:\n  issues:\n    types: [opened]\n\njobs:\n  issue-moderator:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Generate access token\n        id: generate_token\n        uses: tibdex/github-app-token@v2\n        with:\n          app_id: ${{ secrets.GH_APP_ID }}\n          private_key: ${{ secrets.GH_APP_KEY }}\n\n      - name: Similarity analysis\n        id: similarity\n        uses: actions-cool/issues-similarity-analysis@v1\n        with:\n          token: ${{ steps.generate_token.outputs.token }}\n          filter-threshold: 0.60\n          title-excludes: ''\n          comment-title: |\n            ### Your issue looks similar to these issues:\n            Please close if duplicate.\n          comment-body: '${index}. ${similarity} #${number}'\n\n      - name: Label if possible duplicate\n        if: steps.similarity.outputs.similar-issues-found =='true'\n        uses: actions/github-script@v8\n        with:\n          github-token: ${{ steps.generate_token.outputs.token }}\n          script: |\n            github.rest.issues.addLabels({\n              issue_number: context.issue.number,\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              labels: [\"possible duplicate\"]\n            })\n\n      - uses: actions/checkout@v6\n\n      - name: Automatically close issues that dont follow the issue template\n        uses: lucasbento/auto-close-issues@v1.0.2\n        with:\n          github-token: ${{ steps.generate_token.outputs.token }}\n          issue-close-message: |\n            @${issue.user.login}: hello! :wave:\n            This issue is being automatically closed because it does not follow the issue template.\" \n          closed-issues-label: \"invalid\"\n\n      - name: Check if issue mentions a provider\n        id: provider_check\n        env:\n          GH_TEXT: \"${{ github.event.issue.title }} ${{ github.event.issue.body }}\"\n        run: |\n          wget --output-document check_issue.py \"https://raw.githubusercontent.com/recloudstream/.github/master/.github/check_issue.py\"\n          pip3 install httpx\n          RES=\"$(python3 ./check_issue.py)\"\n          echo \"name=${RES}\" >> $GITHUB_OUTPUT\n\n      - name: Comment if issue mentions a provider\n        if: steps.provider_check.outputs.name != 'none'\n        uses: actions-cool/issues-helper@v3\n        with:\n          actions: 'create-comment'\n          token: ${{ steps.generate_token.outputs.token }}\n          body: |\n            Hello ${{ github.event.issue.user.login }}. \n            Please do not report any provider bugs here. This repository does not contain any providers. Please find the appropriate repository and report your issue there or join the [discord](https://discord.gg/5Hus6fM).\n            \n            Found provider name: `${{ steps.provider_check.outputs.name }}`\n\n      - name: Label if mentions provider\n        if: steps.provider_check.outputs.name != 'none'\n        uses: actions/github-script@v8\n        with:\n          github-token: ${{ steps.generate_token.outputs.token }}\n          script: |\n            github.rest.issues.addLabels({\n              issue_number: context.issue.number,\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              labels: [\"possible provider issue\"]\n            })\n\n      - name: Add eyes reaction to all issues\n        uses: actions-cool/emoji-helper@v1.0.0\n        with:\n          type: 'issue'\n          token: ${{ steps.generate_token.outputs.token }}\n          emoji: 'eyes'\n"
  },
  {
    "path": ".github/workflows/prerelease.yml",
    "content": "name: Pre-release\n\non:\n  push:\n    branches: [ master ]\n    paths-ignore:\n      - '*.md'\n      - '*.json'\n      - '**/wcokey.txt'\n\nconcurrency:\n  group: \"pre-release\"\n  cancel-in-progress: true\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Generate access token\n      id: generate_token\n      uses: tibdex/github-app-token@v2\n      with:\n        app_id: ${{ secrets.GH_APP_ID }}\n        private_key: ${{ secrets.GH_APP_KEY }}\n        repository: \"recloudstream/secrets\"\n\n    - uses: actions/checkout@v6\n\n    - name: Set up JDK 17\n      uses: actions/setup-java@v5\n      with:\n        distribution: temurin\n        java-version: 17\n\n    - name: Grant execute permission for gradlew\n      run: chmod +x gradlew\n\n    - name: Fetch keystore\n      id: fetch_keystore\n      run: |\n        TMP_KEYSTORE_FILE_PATH=\"${RUNNER_TEMP}\"/keystore\n        mkdir -p \"${TMP_KEYSTORE_FILE_PATH}\"\n        curl -H \"Authorization: token ${{ steps.generate_token.outputs.token }}\" -o \"${TMP_KEYSTORE_FILE_PATH}/prerelease_keystore.keystore\" \"https://raw.githubusercontent.com/recloudstream/secrets/master/keystore.jks\"\n        curl -H \"Authorization: token ${{ steps.generate_token.outputs.token }}\" -o \"keystore_password.txt\" \"https://raw.githubusercontent.com/recloudstream/secrets/master/keystore_password.txt\"\n        KEY_PWD=\"$(cat keystore_password.txt)\"\n        echo \"::add-mask::${KEY_PWD}\"\n        echo \"key_pwd=$KEY_PWD\" >> $GITHUB_OUTPUT\n\n    - name: Setup Gradle\n      uses: gradle/actions/setup-gradle@v5\n      with:\n        cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}\n\n    - name: Run Gradle\n      run: ./gradlew assemblePrerelease build androidSourcesJar makeJar\n      env:\n        SIGNING_KEY_ALIAS: \"key0\"\n        SIGNING_KEY_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}\n        SIGNING_STORE_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }}\n        SIMKL_CLIENT_ID: ${{ secrets.SIMKL_CLIENT_ID }}\n        SIMKL_CLIENT_SECRET: ${{ secrets.SIMKL_CLIENT_SECRET }}\n        MDL_API_KEY: ${{ secrets.MDL_API_KEY }}\n\n    - name: Create pre-release\n      uses: marvinpinto/action-automatic-releases@latest\n      with:\n        repo_token: \"${{ secrets.GITHUB_TOKEN }}\"\n        automatic_release_tag: \"pre-release\"\n        prerelease: true\n        title: \"Pre-release Build\"\n        files: |\n          app/build/outputs/apk/prerelease/release/*.apk\n          app/build/libs/app-sources.jar\n          app/build/classes.jar\n"
  },
  {
    "path": ".github/workflows/pull_request.yml",
    "content": "name: Artifact Build\n\non: [pull_request]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v6\n\n    - name: Set up JDK 17\n      uses: actions/setup-java@v5\n      with:\n        distribution: temurin\n        java-version: 17\n\n    - name: Grant execute permission for gradlew\n      run: chmod +x gradlew\n\n    - name: Setup Gradle\n      uses: gradle/actions/setup-gradle@v5\n      with:\n        cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}\n        cache-read-only: false\n\n    - name: Run Gradle\n      run: ./gradlew assemblePrereleaseDebug lint\n\n    - name: Upload Artifact\n      uses: actions/upload-artifact@v6\n      with:\n        name: pull-request-build\n        path: \"app/build/outputs/apk/prerelease/debug/*.apk\"\n"
  },
  {
    "path": ".github/workflows/update_locales.yml",
    "content": "name: Fix locale issues\n\non:\n  push:\n    branches: [ master ]\n    paths:\n      - '**.xml'\n  workflow_dispatch:\n\nconcurrency:\n  group: \"locale\"\n  cancel-in-progress: true\n\njobs:\n  create:\n    runs-on: ubuntu-latest\n    steps:\n    - name: Generate access token\n      id: generate_token\n      uses: tibdex/github-app-token@v2\n      with:\n        app_id: ${{ secrets.GH_APP_ID }}\n        private_key: ${{ secrets.GH_APP_KEY }}\n        repository: \"recloudstream/cloudstream\"\n\n    - uses: actions/checkout@v6\n      with:\n        token: ${{ steps.generate_token.outputs.token }}\n\n    - name: Install dependencies\n      run: pip3 install lxml requests\n\n    - name: Edit files\n      run: python3 .github/locales.py\n\n    - name: Commit to the repo\n      run: |\n        git config --local user.email \"111277985+recloudstream[bot]@users.noreply.github.com\"\n        git config --local user.name \"recloudstream[bot]\"\n        git add .\n        # \"echo\" returns true so the build succeeds, even if no changed files\n        git commit -m 'chore(locales): fix locale issues' || echo\n        git push\n"
  },
  {
    "path": ".gitignore",
    "content": "/local.properties\n/.idea/caches\n/.idea/misc.xml\n/.idea/libraries\n/.idea/modules.xml\n/.idea/workspace.xml\n/.idea/navEditor.xml\n/.idea/assetWizardSettings.xml\n.DS_Store\n/build\n/captures\n.cxx\n.kotlin/*\n\n# Created by https://www.toptal.com/developers/gitignore/api/kotlin,java,android,androidstudio,visualstudiocode\n# Edit at https://www.toptal.com/developers/gitignore?templates=kotlin,java,android,androidstudio,visualstudiocode\n\n### Android ###\n# Gradle files\n.gradle/\nbuild/\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Log/OS Files\n*.log\n\n# Android Studio generated files and folders\ncaptures/\n.externalNativeBuild/\n.cxx/\n*.apk\noutput.json\n\n# IntelliJ\n*.iml\n.idea/\nmisc.xml\ndeploymentTargetDropDown.xml\nrender.experimental.xml\n\n# Keystore files\n*.jks\n*.keystore\n\n# Google Services (e.g. APIs or Firebase)\ngoogle-services.json\n\n# Android Profiling\n*.hprof\n\n### Android Patch ###\ngen-external-apklibs\n\n# Replacement of .externalNativeBuild directories introduced\n# with Android Studio 3.5.\n\n### Java ###\n# Compiled class file\n*.class\n\n# Log file\n\n# BlueJ files\n*.ctxt\n\n# Mobile Tools for Java (J2ME)\n.mtj.tmp/\n\n# Package Files #\n*.jar\n*.war\n*.nar\n*.ear\n*.zip\n*.tar.gz\n*.rar\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\nhs_err_pid*\nreplay_pid*\n\n### Kotlin ###\n# Compiled class file\n\n# Log file\n\n# BlueJ files\n\n# Mobile Tools for Java (J2ME)\n\n# Package Files #\n\n# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml\n\n### VisualStudioCode ###\n.vscode/*\n\n# Local History for Visual Studio Code\n.history/\n\n# Built Visual Studio Code Extensions\n*.vsix\n\n### VisualStudioCode Patch ###\n# Ignore all local history of files\n.history\n.ionide\n\n### AndroidStudio ###\n# Covers files to be ignored for android development using Android Studio.\n\n# Built application files\n*.ap_\n*.aab\n\n# Files for the ART/Dalvik VM\n*.dex\n\n# Java class files\n\n# Generated files\nbin/\ngen/\nout/\n\n# Gradle files\n.gradle\n\n# Signing files\n.signing/\n\n# Local configuration file (sdk path, etc)\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n\n# Android Studio\n/*/build/\n/*/local.properties\n/*/out\n/*/*/build\n/*/*/production\n.navigation/\n*.ipr\n*~\n*.swp\n\n# Keystore files\n\n# Google Services (e.g. APIs or Firebase)\n# google-services.json\n\n# Android Patch\n\n# External native build folder generated in Android Studio 2.2 and later\n.externalNativeBuild\n\n# NDK\nobj/\n\n# IntelliJ IDEA\n*.iws\n/out/\n\n# User-specific configurations\n.idea/caches/\n.idea/libraries/\n.idea/shelf/\n.idea/workspace.xml\n.idea/tasks.xml\n.idea/.name\n.idea/compiler.xml\n.idea/copyright/profiles_settings.xml\n.idea/encodings.xml\n.idea/misc.xml\n.idea/modules.xml\n.idea/scopes/scope_settings.xml\n.idea/dictionaries\n.idea/vcs.xml\n.idea/jsLibraryMappings.xml\n.idea/datasources.xml\n.idea/dataSources.ids\n.idea/sqlDataSources.xml\n.idea/dynamic.xml\n.idea/uiDesigner.xml\n.idea/assetWizardSettings.xml\n.idea/gradle.xml\n.idea/jarRepositories.xml\n.idea/navEditor.xml\n\n# Legacy Eclipse project files\n.classpath\n.project\n.cproject\n.settings/\n\n# Mobile Tools for Java (J2ME)\n\n# Package Files #\n\n# virtual machine crash logs (Reference: http://www.java.com/en/download/help/error_hotspot.xml)\n\n## Plugin-specific files:\n\n# mpeltonen/sbt-idea plugin\n.idea_modules/\n\n# JIRA plugin\natlassian-ide-plugin.xml\n\n# Mongo Explorer plugin\n.idea/mongoSettings.xml\n\n# Crashlytics plugin (for Android Studio and IntelliJ)\ncom_crashlytics_export_strings.xml\ncrashlytics.properties\ncrashlytics-build.properties\nfabric.properties\n\n### AndroidStudio Patch ###\n\n!/gradle/wrapper/gradle-wrapper.jar\n\n# End of https://www.toptal.com/developers/gitignore/api/kotlin,java,android,androidstudio,visualstudiocode\n"
  },
  {
    "path": "AI-POLICY.md",
    "content": "# AI Policy\r\n\r\nAI is a great tool. However, we want you to follow these rules regarding usage of AI in order to ensure the quality of both code and discussions.\r\n\r\n1. Always state any AI usage in pull requests and issues. \r\n\r\n2. Always test code before making a pull request. We do not want to test your AI generated code. \r\n\r\n3. Listen to humans over computers. Contributors to CloudStream know this codebase better than an AI. \r\n\r\n4. You should be able to explain and fix any code you submit. We do in-depth reviews and will reject low effort contributions.\r\n"
  },
  {
    "path": "LICENSE",
    "content": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 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 General Public License is a free, copyleft license for\nsoftware and other kinds of works.\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,\nthe GNU General Public License is 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.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\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  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\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 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. Use with the GNU Affero General Public License.\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 Affero 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 special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe 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 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 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 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 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    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 General Public License for more details.\n\n    You should have received a copy of the GNU 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 the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\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 GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>.\n"
  },
  {
    "path": "README.md",
    "content": "# CloudStream\n\n**⚠️ Warning: By default, this app doesn't provide any video sources; you have to install extensions to add functionality to the app.**\n\n[![Discord](https://invidget.switchblade.xyz/5Hus6fM)](https://discord.gg/5Hus6fM)\n\n\n## Table of Contents: \n+ [About Us:](#about_us)\n+ [Installation Steps:](#install_rules)\n+ [Contributing:](#contributing)\n+ [Issues:](#issues)\n  + [Bugs Reports:](#bug_report)\n  + [Enhancement:](#enhancment)\n+ [Extension Development:](#extensions)\n+ [Language Support:](#languages)\n+ [Further Sources](#contact_and_sources)\n\n\n<a id=\"about_us\"></a>\n\n## About us: \n\n**CloudStream is a media center that prioritizes and emphasizes complete freedom and flexibility for users and developers.** \n\nCloudStream is an extension-based multimedia player with tracking support. There are extensions to view videos from: \n\n+ [Librevox (audio-books)](https://librivox.org/) \n+ [Youtube](https://www.youtube.com/)\n+ [Twitch](https://www.twitch.tv/)\n+ [iptv-org (A collection of publicly available IPTV (Internet Protocol television) channels from all over the world.)](https://github.com/iptv-org/iptv) \n+ [nginx](https://nginx.org/)\n+ And more... \n\n\n**Please don't create illegal extensions or use any that host any copyrighted media.** For more details about our stance on the DMCA and EUCD, you can read about it on our organization: [reCloudStream](https://github.com/recloudstream)\n\n#### Important Copyright Note: \n\nOur documentation is unmaintained and open to contributions; therefore, apps and sources, extensions in recommended sources, and recommended apps are not officially moderated or endorsed by CloudStream; if you or another copyright owner identify an extension that breaches your copyright, please let us know. \n\n\n#### Features:\n+ **AdFree**, No ads whatsoever\n+ No tracking/analytics\n+ Bookmarks\n+ Phone and TV support\n+ Chromecast\n+ Extension system for personal customization\n\n\n<a id=\"install_rules\"></a>\n\n## Installation: \n\nOur documentation provides the steps to install and configure CloudStream for your streaming needs.\n\n[Getting Started With CloudStream:](https://recloudstream.github.io/csdocs/)\n\n<a id=\"contributing\"></a>\n\n## Contributing:\nWe **happily** accept any contributions to our project. To find out where you can start contributing towards the project, please look [at our issues tab](/cloudstream/issues)\n\n\n\n<a id=\"issues\"></a> \n \n### Issues: \nWhile we **actively** accept issues and pull requests, we do require you fill out an [template](https://github.com/recloudstream/cloudstream/issues/new/choose) for issues. These include the following:\n\n<a id=\"bug_report\"></a>\n\n- [Bug Report Template: ](https://github.com/recloudstream/cloudstream/issues/new?assignees=&labels=bug&projects=&template=application-bug.yml)\n  - For bug reports, we want as much info as possible, including your downloaded version of CloudeStream, device and updated version (if possible, current API),\n    expected behavior of the program, and the actual behavior that the program did, most importantly we require clear, reproducible steps of the bug. If your bug can't be       reproduced, it is unlikely we'll work on your issue.\n    \n<a id=\"enhancment\"></a>\n  \n- [Feature Request Template: ](https://github.com/recloudstream/cloudstream/issues/new?assignees=&labels=enhancement&projects=&template=feature-request.yml)\n  - Before adding a feature request, please check to see if a feature request already has been requested.  \n\n\n### Extensions:\n \n**Further details on creating extensions for CloudStream are found in our documentation.**\n\n[Guide: For Extension Developers](https://recloudstream.github.io/csdocs/devs/gettingstarted/) \n\n<a id=\"contact_and_sources\"></a>\n\n## Further Sources: \n\nAs well as providing clear install steps, our [website](https://dweb.link/ipns/cloudstream.on.fleek.co/) includes a wide variety of other tools, such as: \n- [Troubleshooting](https://recloudstream.github.io/csdocs/troubleshooting/)\n- [Further CloudStream Repositories](https://recloudstream.github.io/csdocs/repositories/) \n- Set-Up for other devices, such as:\n  - [Android TV](https://recloudstream.github.io/csdocs/other-devices/tv/)\n  - [Windows](https://recloudstream.github.io/csdocs/other-devices/windows/)\n  - [Linux](https://recloudstream.github.io/csdocs/other-devices/linux/)\n- And more...\n\n<a id=\"languages\"> </a>  \n\n### Supported languages:\n\nEven if you can't contribute to the code or documentation, we always look for those who can contribute to translation and language support. Your contribution is exceptionally appreciated; you can check our translation from the figure below. \n\n<a href=\"https://hosted.weblate.org/engage/cloudstream/\">\n  <img src=\"https://hosted.weblate.org/widgets/cloudstream/-/app/multi-auto.svg\" alt=\"Translation status\" />\n</a>\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build"
  },
  {
    "path": "app/build.gradle.kts",
    "content": "import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties\nimport org.jetbrains.dokka.gradle.engine.parameters.KotlinPlatform\nimport org.jetbrains.dokka.gradle.engine.parameters.VisibilityModifier\nimport org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode\nimport org.jetbrains.kotlin.gradle.dsl.JvmTarget\nimport org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile\n\nplugins {\n    alias(libs.plugins.android.application)\n    alias(libs.plugins.dokka)\n    alias(libs.plugins.kotlin.android)\n}\n\nval javaTarget = JvmTarget.fromTarget(libs.versions.jvmTarget.get())\nval tmpFilePath = System.getProperty(\"user.home\") + \"/work/_temp/keystore/\"\nval prereleaseStoreFile: File? = File(tmpFilePath).listFiles()?.first()\n\nfun getGitCommitHash(): String {\n    return try {\n        val headFile = file(\"${project.rootDir}/.git/HEAD\")\n\n        // Read the commit hash from .git/HEAD\n        if (headFile.exists()) {\n            val headContent = headFile.readText().trim()\n            if (headContent.startsWith(\"ref:\")) {\n                val refPath = headContent.substring(5) // e.g., refs/heads/main\n                val commitFile = file(\"${project.rootDir}/.git/$refPath\")\n                if (commitFile.exists()) commitFile.readText().trim() else \"\"\n            } else headContent // If it's a detached HEAD (commit hash directly)\n        } else {\n            \"\" // If .git/HEAD doesn't exist\n        }.take(7) // Return the short commit hash\n    } catch (_: Throwable) {\n        \"\" // Just return an empty string if any exception occurs\n    }\n}\n\nandroid {\n    @Suppress(\"UnstableApiUsage\")\n    testOptions {\n        unitTests.isReturnDefaultValues = true\n    }\n\n    viewBinding {\n        enable = true\n    }\n\n    signingConfigs {\n        if (prereleaseStoreFile != null) {\n            create(\"prerelease\") {\n                storeFile = file(prereleaseStoreFile)\n                storePassword = System.getenv(\"SIGNING_STORE_PASSWORD\")\n                keyAlias = System.getenv(\"SIGNING_KEY_ALIAS\")\n                keyPassword = System.getenv(\"SIGNING_KEY_PASSWORD\")\n            }\n        }\n    }\n\n    compileSdk = libs.versions.compileSdk.get().toInt()\n\n    defaultConfig {\n        applicationId = \"com.lagradost.cloudstream3\"\n        minSdk = libs.versions.minSdk.get().toInt()\n        targetSdk = libs.versions.targetSdk.get().toInt()\n        versionCode = 67\n        versionName = \"4.6.2\"\n\n        resValue(\"string\", \"commit_hash\", getGitCommitHash())\n\n        manifestPlaceholders[\"target_sdk_version\"] = libs.versions.targetSdk.get()\n\n        // Reads local.properties\n        val localProperties = gradleLocalProperties(rootDir, project.providers)\n\n        buildConfigField(\n            \"long\",\n            \"BUILD_DATE\",\n            \"${System.currentTimeMillis()}\"\n        )\n        buildConfigField(\n            \"String\",\n            \"SIMKL_CLIENT_ID\",\n            \"\\\"\" + (System.getenv(\"SIMKL_CLIENT_ID\") ?: localProperties[\"simkl.id\"]) + \"\\\"\"\n        )\n        buildConfigField(\n            \"String\",\n            \"SIMKL_CLIENT_SECRET\",\n            \"\\\"\" + (System.getenv(\"SIMKL_CLIENT_SECRET\") ?: localProperties[\"simkl.secret\"]) + \"\\\"\"\n        )\n        testInstrumentationRunner = \"androidx.test.runner.AndroidJUnitRunner\"\n    }\n\n    buildTypes {\n        release {\n            isDebuggable = false\n            isMinifyEnabled = false\n            isShrinkResources = false\n            proguardFiles(\n                getDefaultProguardFile(\"proguard-android-optimize.txt\"),\n                \"proguard-rules.pro\"\n            )\n        }\n        debug {\n            isDebuggable = true\n            applicationIdSuffix = \".debug\"\n            proguardFiles(\n                getDefaultProguardFile(\"proguard-android-optimize.txt\"),\n                \"proguard-rules.pro\"\n            )\n        }\n    }\n\n    flavorDimensions.add(\"state\")\n    productFlavors {\n        create(\"stable\") {\n            dimension = \"state\"\n        }\n        create(\"prerelease\") {\n            dimension = \"state\"\n            applicationIdSuffix = \".prerelease\"\n            if (signingConfigs.names.contains(\"prerelease\")) {\n                signingConfig = signingConfigs.getByName(\"prerelease\")\n            } else {\n                logger.warn(\"No prerelease signing config!\")\n            }\n            versionNameSuffix = \"-PRE\"\n            versionCode = (System.currentTimeMillis() / 60000).toInt()\n        }\n    }\n\n    compileOptions {\n        isCoreLibraryDesugaringEnabled = true\n        sourceCompatibility = JavaVersion.toVersion(javaTarget.target)\n        targetCompatibility = JavaVersion.toVersion(javaTarget.target)\n    }\n\n    java {\n\t    // Use Java 17 toolchain even if a higher JDK runs the build.\n        // We still use Java 8 for now which higher JDKs have deprecated.\n\t    toolchain {\n\t\t    languageVersion.set(JavaLanguageVersion.of(libs.versions.jdkToolchain.get()))\n    \t}\n    }\n\n    lint {\n        abortOnError = false\n        checkReleaseBuilds = false\n    }\n\n    buildFeatures {\n        buildConfig = true\n        resValues = true\n    }\n\n    packaging {\n        jniLibs {\n            // Enables legacy JNI packaging to reduce APK size (similar to builds before minSdk 23).\n            // Note: This may increase app startup time slightly.\n            useLegacyPackaging = true\n        }\n    }\n\n    namespace = \"com.lagradost.cloudstream3\"\n}\n\ndependencies {\n    // Testing\n    testImplementation(libs.junit)\n    testImplementation(libs.json)\n    androidTestImplementation(libs.core)\n    implementation(libs.junit.ktx)\n    androidTestImplementation(libs.ext.junit)\n    androidTestImplementation(libs.espresso.core)\n\n    // Android Core & Lifecycle\n    implementation(libs.core.ktx)\n    implementation(libs.activity.ktx)\n    implementation(libs.appcompat)\n    implementation(libs.fragment.ktx)\n    implementation(libs.bundles.lifecycle)\n    implementation(libs.bundles.navigation)\n\n    // Design & UI\n    implementation(libs.preference.ktx)\n    implementation(libs.material)\n    implementation(libs.constraintlayout)\n\n    // Coil Image Loading\n    implementation(libs.bundles.coil)\n\n    // Media 3 (ExoPlayer)\n    implementation(libs.bundles.media3)\n    implementation(libs.video)\n\n    // FFmpeg Decoding\n    implementation(libs.bundles.nextlib)\n\n    // PlayBack\n    implementation(libs.colorpicker) // Subtitle Color Picker\n    implementation(libs.newpipeextractor) // For Trailers\n    implementation(libs.juniversalchardet) // Subtitle Decoding\n\n    // UI Stuff\n    implementation(libs.shimmer) // Shimmering Effect (Loading Skeleton)\n    implementation(libs.palette.ktx) // Palette for Images -> Colors\n    implementation(libs.tvprovider)\n    implementation(libs.overlappingpanels) // Gestures\n    implementation(libs.biometric) // Fingerprint Authentication\n    implementation(libs.previewseekbar.media3) // SeekBar Preview\n    implementation(libs.qrcode.kotlin) // QR Code for PIN Auth on TV\n\n    // Extensions & Other Libs\n    implementation(libs.jsoup) // HTML Parser\n    implementation(libs.rhino) // Run JavaScript\n    implementation(libs.fuzzywuzzy) // Library/Ext Searching with Levenshtein Distance\n    implementation(libs.safefile) // To Prevent the URI File Fu*kery\n    coreLibraryDesugaring(libs.desugar.jdk.libs.nio) // NIO Flavor Needed for NewPipeExtractor\n    implementation(libs.conscrypt.android) // To Fix SSL Fu*kery on Android 9\n    implementation(libs.jackson.module.kotlin) // JSON Parser\n    implementation(libs.zipline)\n\n    // Torrent Support\n    implementation(libs.torrentserver)\n\n    // Downloading & Networking\n    implementation(libs.work.runtime.ktx)\n    implementation(libs.nicehttp) // HTTP Lib\n\n    implementation(project(\":library\"))\n}\n\ntasks.register<Jar>(\"androidSourcesJar\") {\n    archiveClassifier.set(\"sources\")\n    from(android.sourceSets.getByName(\"main\").java.directories) // Full Sources\n}\n\ntasks.register<Copy>(\"copyJar\") {\n    dependsOn(\"build\", \":library:jvmJar\")\n    from(\n        \"build/intermediates/compile_app_classes_jar/prereleaseDebug/bundlePrereleaseDebugClassesToCompileJar\",\n        \"../library/build/libs\"\n    )\n    into(\"build/app-classes\")\n    include(\"classes.jar\", \"library-jvm*.jar\")\n    // Remove the version\n    rename(\"library-jvm.*.jar\", \"library-jvm.jar\")\n}\n\n// Merge the app classes and the library classes into classes.jar\ntasks.register<Jar>(\"makeJar\") {\n    // Duplicates cause hard to catch errors, better to fail at compile time.\n    duplicatesStrategy = DuplicatesStrategy.FAIL\n    dependsOn(tasks.getByName(\"copyJar\"))\n    from(\n        zipTree(\"build/app-classes/classes.jar\"),\n        zipTree(\"build/app-classes/library-jvm.jar\")\n    )\n    destinationDirectory.set(layout.buildDirectory)\n    archiveBaseName = \"classes\"\n}\n\ntasks.withType<KotlinJvmCompile> {\n    compilerOptions {\n        jvmTarget.set(javaTarget)\n        jvmDefault.set(JvmDefaultMode.ENABLE)\n        freeCompilerArgs.add(\"-Xannotation-default-target=param-property\")\n        optIn.addAll(\n            \"com.lagradost.cloudstream3.InternalAPI\",\n            \"com.lagradost.cloudstream3.Prerelease\",\n        )\n    }\n}\n\ndokka {\n    moduleName = \"App\"\n    dokkaSourceSets {\n        main {\n            analysisPlatform = KotlinPlatform.JVM\n            documentedVisibilities(\n                VisibilityModifier.Public,\n                VisibilityModifier.Protected\n            )\n\n            sourceLink {\n                localDirectory = file(\"..\")\n                remoteUrl(\"https://github.com/recloudstream/cloudstream/tree/master\")\n                remoteLineSuffix = \"#L\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/lint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lint>\n    <!-- ByteOrderMark has errors in values-b+ja/strings.xml, but it's handled by weblate so we don't really care. -->\n    <issue id=\"ByteOrderMark\" severity=\"ignore\" />\n\n    <!-- We don't care about MissingTranslation since it's handled by weblate. -->\n    <issue id=\"MissingTranslation\" severity=\"ignore\" />\n</lint>\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# You can control the set of applied configuration files using the\n# proguardFiles setting in build.gradle.kts.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile"
  },
  {
    "path": "app/src/androidTest/java/com/lagradost/cloudstream3/ExampleInstrumentedTest.kt",
    "content": "package com.lagradost.cloudstream3\n\nimport android.app.Activity\nimport android.os.Bundle\nimport android.os.PersistableBundle\nimport android.view.LayoutInflater\nimport androidx.test.core.app.ActivityScenario\nimport androidx.test.ext.junit.runners.AndroidJUnit4\nimport androidx.viewbinding.ViewBinding\nimport com.lagradost.cloudstream3.databinding.BottomResultviewPreviewBinding\nimport com.lagradost.cloudstream3.databinding.FragmentHomeBinding\nimport com.lagradost.cloudstream3.databinding.FragmentHomeTvBinding\nimport com.lagradost.cloudstream3.databinding.FragmentLibraryBinding\nimport com.lagradost.cloudstream3.databinding.FragmentLibraryTvBinding\nimport com.lagradost.cloudstream3.databinding.FragmentPlayerBinding\nimport com.lagradost.cloudstream3.databinding.FragmentPlayerTvBinding\nimport com.lagradost.cloudstream3.databinding.FragmentResultBinding\nimport com.lagradost.cloudstream3.databinding.FragmentResultTvBinding\nimport com.lagradost.cloudstream3.databinding.FragmentSearchBinding\nimport com.lagradost.cloudstream3.databinding.FragmentSearchTvBinding\nimport com.lagradost.cloudstream3.databinding.HomeResultGridBinding\nimport com.lagradost.cloudstream3.databinding.HomepageParentBinding\nimport com.lagradost.cloudstream3.databinding.HomepageParentEmulatorBinding\nimport com.lagradost.cloudstream3.databinding.HomepageParentTvBinding\nimport com.lagradost.cloudstream3.databinding.PlayerCustomLayoutBinding\nimport com.lagradost.cloudstream3.databinding.PlayerCustomLayoutTvBinding\nimport com.lagradost.cloudstream3.databinding.RepositoryItemBinding\nimport com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding\nimport com.lagradost.cloudstream3.databinding.SearchResultGridBinding\nimport com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding\nimport com.lagradost.cloudstream3.databinding.TrailerCustomLayoutBinding\nimport com.lagradost.cloudstream3.utils.SubtitleHelper\nimport com.lagradost.cloudstream3.utils.TestingUtils\nimport kotlinx.coroutines.runBlocking\nimport org.junit.Assert\nimport org.junit.Test\nimport org.junit.runner.RunWith\n\n\n/**\n * Instrumented test, which will execute on an Android device.\n *\n * See [testing documentation](http://d.android.com/tools/testing).\n */\nclass TestApplication : Activity() {\n    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {\n        super.onCreate(savedInstanceState, persistentState)\n    }\n}\n\n@RunWith(AndroidJUnit4::class)\nclass ExampleInstrumentedTest {\n    private fun getAllProviders(): Array<MainAPI> {\n        println(\"Providers: ${APIHolder.allProviders.size}\")\n        return APIHolder.allProviders.toTypedArray() //.filter { !it.usesWebView }\n    }\n\n    @Test\n    fun providersExist() {\n        Assert.assertTrue(getAllProviders().isNotEmpty())\n        println(\"Done providersExist\")\n    }\n\n    @Throws\n    private inline fun <reified T : ViewBinding> testAllLayouts(\n        activity: Activity,\n       vararg layouts: Int\n    ) {\n\n        val bind = T::class.java.methods.first { it.name == \"bind\" }\n        val inflater = LayoutInflater.from(activity)\n        for (layout in layouts) {\n            val root = inflater.inflate(layout, null, false)\n            bind.invoke(null, root)\n        }\n    }\n\n    @Test\n    @Throws\n    fun layoutTest() {\n        ActivityScenario.launch(MainActivity::class.java).use { scenario ->\n            scenario.onActivity { activity: MainActivity ->\n                // FragmentHomeHeadBinding and FragmentHomeHeadTvBinding CANT be the same\n                //testAllLayouts<FragmentHomeHeadBinding>(activity, R.layout.fragment_home_head, R.layout.fragment_home_head_tv)\n                //testAllLayouts<FragmentHomeHeadTvBinding>(activity, R.layout.fragment_home_head, R.layout.fragment_home_head_tv)\n\n                // main cant be tested\n               // testAllLayouts<ActivityMainTvBinding>(activity,R.layout.activity_main, R.layout.activity_main_tv)\n               // testAllLayouts<ActivityMainBinding>(activity,R.layout.activity_main, R.layout.activity_main_tv)\n                //testAllLayouts<ActivityMainBinding>(activity, R.layout.activity_main_tv)\n\n                testAllLayouts<BottomResultviewPreviewBinding>(activity, R.layout.bottom_resultview_preview,R.layout.bottom_resultview_preview_tv)\n\n                testAllLayouts<FragmentPlayerBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)\n                testAllLayouts<FragmentPlayerTvBinding>(activity, R.layout.fragment_player,R.layout.fragment_player_tv)\n\n               // testAllLayouts<FragmentResultBinding>(activity, R.layout.fragment_result,R.layout.fragment_result_tv)\n               // testAllLayouts<FragmentResultTvBinding>(activity, R.layout.fragment_result,R.layout.fragment_result_tv)\n\n                testAllLayouts<PlayerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)\n                testAllLayouts<PlayerCustomLayoutTvBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)\n                testAllLayouts<TrailerCustomLayoutBinding>(activity, R.layout.player_custom_layout,R.layout.player_custom_layout_tv, R.layout.trailer_custom_layout)\n\n                testAllLayouts<RepositoryItemBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)\n                testAllLayouts<RepositoryItemTvBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)\n\n                testAllLayouts<RepositoryItemBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)\n                testAllLayouts<RepositoryItemTvBinding>(activity, R.layout.repository_item_tv, R.layout.repository_item)\n\n                testAllLayouts<FragmentHomeBinding>(activity, R.layout.fragment_home_tv, R.layout.fragment_home)\n                testAllLayouts<FragmentHomeTvBinding>(activity, R.layout.fragment_home_tv, R.layout.fragment_home)\n\n                testAllLayouts<FragmentSearchBinding>(activity, R.layout.fragment_search_tv, R.layout.fragment_search)\n                testAllLayouts<FragmentSearchTvBinding>(activity, R.layout.fragment_search_tv, R.layout.fragment_search)\n\n                testAllLayouts<HomeResultGridBinding>(activity, R.layout.home_result_grid_expanded, R.layout.home_result_grid)\n                //testAllLayouts<HomeResultGridExpandedBinding>(activity, R.layout.home_result_grid_expanded, R.layout.home_result_grid) ??? fails ???\n\n                testAllLayouts<SearchResultGridExpandedBinding>(activity, R.layout.search_result_grid, R.layout.search_result_grid_expanded)\n                testAllLayouts<SearchResultGridBinding>(activity, R.layout.search_result_grid, R.layout.search_result_grid_expanded)\n\n\n               // testAllLayouts<HomeScrollViewBinding>(activity, R.layout.home_scroll_view, R.layout.home_scroll_view_tv)\n               // testAllLayouts<HomeScrollViewTvBinding>(activity, R.layout.home_scroll_view, R.layout.home_scroll_view_tv)\n\n                testAllLayouts<HomepageParentTvBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent_emulator, R.layout.homepage_parent)\n                testAllLayouts<HomepageParentEmulatorBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent_emulator, R.layout.homepage_parent)\n                testAllLayouts<HomepageParentBinding>(activity, R.layout.homepage_parent_tv, R.layout.homepage_parent_emulator, R.layout.homepage_parent)\n\n                testAllLayouts<FragmentLibraryTvBinding>(activity, R.layout.fragment_library_tv, R.layout.fragment_library)\n                testAllLayouts<FragmentLibraryBinding>(activity, R.layout.fragment_library_tv, R.layout.fragment_library)\n            }\n        }\n    }\n\n    @Test\n    @Throws(AssertionError::class)\n    fun providerCorrectData() {\n        val langTagsIETF = SubtitleHelper.languages.map { it.IETF_tag }\n        Assert.assertFalse(\"IETFTagNames does not contain any languages\", langTagsIETF.isNullOrEmpty())\n        for (api in getAllProviders()) {\n            Assert.assertTrue(\"Api does not contain a mainUrl\", api.mainUrl != \"NONE\")\n            Assert.assertTrue(\"Api does not contain a name\", api.name != \"NONE\")\n            Assert.assertTrue(\n                \"Api ${api.name} does not contain a valid language code\",\n                langTagsIETF.contains(api.lang)\n            )\n            Assert.assertTrue(\n                \"Api ${api.name} does not contain any supported types\",\n                api.supportedTypes.isNotEmpty()\n            )\n        }\n        println(\"Done providerCorrectData\")\n    }\n\n    @Test\n    fun providerCorrectHomepage() {\n        runBlocking {\n            getAllProviders().toList().amap { api ->\n                TestingUtils.testHomepage(api, TestingUtils.Logger())\n            }\n        }\n        println(\"Done providerCorrectHomepage\")\n    }\n\n    @Test\n    fun testAllProvidersCorrect() {\n        runBlocking {\n            TestingUtils.getDeferredProviderTests(\n                this,\n                getAllProviders(),\n            ) { _, _ -> }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/debug/res/drawable/ic_banner_foreground.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"320dp\"\n    android:height=\"180dp\"\n    android:viewportWidth=\"320\"\n    android:viewportHeight=\"180\">\n  <group android:scaleX=\"0.6666667\"\n      android:scaleY=\"0.6666667\"\n      android:translateX=\"53.333332\"\n      android:translateY=\"30\">\n    <group android:scaleX=\"0\"\n        android:scaleY=\"0\"\n        android:translateX=\"160\"\n        android:translateY=\"90\">\n      <group android:translateY=\"155.39062\">\n        <path android:pathData=\"M81.84375,-4.53125Q70.671875,2,54,2Q32.484375,2,19.546875,-11.953125Q6.609375,-25.921875,6.609375,-48.59375Q6.609375,-72.953125,21.15625,-87.96875Q35.71875,-103,58.078125,-103Q72.421875,-103,81.84375,-98.59375L81.84375,-86Q71.015625,-92,57.9375,-92Q40.578125,-92,29.78125,-80.375Q18.984375,-68.765625,18.984375,-49.34375Q18.984375,-30.890625,29.078125,-19.9375Q39.171875,-9,55.546875,-9Q70.734375,-9,81.84375,-16L81.84375,-4.53125Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M112.203125,0L100.671875,0L100.671875,-107L112.203125,-107L112.203125,0Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M165.76562,2Q149.8125,2,140.28125,-8.171875Q130.75,-18.34375,130.75,-35.15625Q130.75,-53.4375,140.65625,-63.71875Q150.57812,-74,167.45312,-74Q183.5625,-74,192.59375,-64Q201.625,-54,201.625,-36.28125Q201.625,-18.921875,191.89062,-8.453125Q182.15625,2,165.76562,2ZM166.60938,-64Q155.5,-64,149.03125,-56.4375Q142.5625,-48.875,142.5625,-35.578125Q142.5625,-22.78125,149.09375,-15.390625Q155.64062,-8,166.60938,-8Q177.79688,-8,183.79688,-15.25Q189.8125,-22.5,189.8125,-35.859375Q189.8125,-49.359375,183.79688,-56.671875Q177.79688,-64,166.60938,-64Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M277.89062,0L266.35938,0L266.35938,-11.375L266.07812,-11.375Q258.90625,2,243.85938,2Q218.125,2,218.125,-28.78125L218.125,-72L229.59375,-72L229.59375,-30.78125Q229.59375,-8,247.03125,-8Q255.46875,-8,260.90625,-14.21875Q266.35938,-20.453125,266.35938,-30.5L266.35938,-72L277.89062,-72L277.89062,0Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M363.125,0L351.59375,0L351.59375,-12.21875L351.3125,-12.21875Q343.29688,2,326.5625,2Q313,2,304.875,-7.75Q296.75,-17.5,296.75,-34.296875Q296.75,-52.3125,305.75,-63.15625Q314.75,-74,329.73438,-74Q344.5625,-74,351.3125,-62.03125L351.59375,-62.03125L351.59375,-107L363.125,-107L363.125,0ZM351.59375,-32.546875L351.59375,-43.171875Q351.59375,-51.90625,345.82812,-57.953125Q340.0625,-64,331.20312,-64Q320.65625,-64,314.60938,-56.25Q308.5625,-48.515625,308.5625,-34.875Q308.5625,-22.421875,314.35938,-15.203125Q320.17188,-8,329.9375,-8Q339.57812,-8,345.57812,-14.953125Q351.59375,-21.921875,351.59375,-32.546875Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M383.51562,-4.078125L383.51562,-18Q385.90625,-15.90625,389.23438,-14.234375Q392.57812,-12.5625,396.26562,-11.40625Q399.96875,-10.25,403.6875,-9.625Q407.42188,-9,410.57812,-9Q421.48438,-9,426.85938,-13Q432.23438,-17,432.23438,-24.5Q432.23438,-28.609375,430.4375,-31.65625Q428.65625,-34.703125,425.48438,-37.21875Q422.32812,-39.734375,418,-42.03125Q413.67188,-44.328125,408.6875,-46.890625Q403.40625,-49.578125,398.82812,-52.34375Q394.26562,-55.109375,390.89062,-58.4375Q387.51562,-61.765625,385.57812,-65.96875Q383.65625,-70.1875,383.65625,-75.859375Q383.65625,-82.796875,386.67188,-87.9375Q389.70312,-93.078125,394.625,-96.40625Q399.54688,-99.734375,405.82812,-101.359375Q412.125,-103,418.67188,-103Q433.57812,-103,440.39062,-99.296875L440.39062,-86Q431.46875,-92,417.46875,-92Q413.60938,-92,409.73438,-91.1875Q405.875,-90.390625,402.84375,-88.578125Q399.82812,-86.765625,397.92188,-83.90625Q396.03125,-81.046875,396.03125,-76.921875Q396.03125,-73.03125,397.46875,-70.1875Q398.90625,-67.359375,401.71875,-65.015625Q404.53125,-62.6875,408.57812,-60.484375Q412.625,-58.28125,417.89062,-55.671875Q423.3125,-52.96875,428.15625,-50Q433.01562,-47.03125,436.67188,-43.40625Q440.32812,-39.796875,442.46875,-35.40625Q444.60938,-31.015625,444.60938,-25.34375Q444.60938,-17.828125,441.6875,-12.625Q438.78125,-7.421875,433.8125,-4.15625Q428.85938,-0.90625,422.39062,0.546875Q415.92188,2,408.75,2Q406.35938,2,402.84375,1.59375Q399.32812,1.1875,395.67188,0.40625Q392.01562,-0.375,388.75,-1.515625Q385.48438,-2.671875,383.51562,-4.078125Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M497.07812,-0.234375Q493,2,486.3125,2Q467.40625,2,467.40625,-19.1875L467.40625,-62L455.03125,-62L455.03125,-72L467.40625,-72L467.40625,-89.328125L478.9375,-93L478.9375,-72L497.07812,-72L497.07812,-62L478.9375,-62L478.9375,-21.4375Q478.9375,-14.1875,481.39062,-11.09375Q483.85938,-8,489.54688,-8Q493.90625,-8,497.07812,-10L497.07812,-0.234375Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M550.21875,-60Q547.2031,-62,541.5,-62Q534.125,-62,529.15625,-55.109375Q524.2031,-48.21875,524.2031,-36.328125L524.2031,0L512.6719,0L512.6719,-72L524.2031,-72L524.2031,-56.515625L524.4844,-56.515625Q526.9531,-64.296875,532.0156,-68.640625Q537.0781,-73,543.3281,-73Q547.8281,-73,550.21875,-72.015625L550.21875,-60Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M620.5469,-33L569.7031,-33Q569.9844,-21.03125,576.1719,-14.515625Q582.3594,-8,593.1875,-8Q605.3594,-8,615.5469,-16L615.5469,-5Q606.0625,2,590.4531,2Q575.1875,2,566.46875,-7.890625Q557.75,-17.78125,557.75,-35.71875Q557.75,-52.65625,567.28125,-63.328125Q576.8125,-74,590.9375,-74Q605.0781,-74,612.8125,-64.765625Q620.5469,-55.53125,620.5469,-39.109375L620.5469,-33ZM608.7344,-43Q608.65625,-52.9375,603.90625,-58.46875Q599.1719,-64,590.7344,-64Q582.5781,-64,576.875,-58.1875Q571.1875,-52.375,569.84375,-43L608.7344,-43Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M689.21875,0L677.6875,0L677.6875,-11.234375L677.40625,-11.234375Q669.875,2,655.25,2Q644.5,2,638.40625,-3.765625Q632.3281,-9.546875,632.3281,-19.109375Q632.3281,-39.578125,656.09375,-42.9375L677.6875,-46Q677.6875,-64,662.84375,-64Q649.84375,-64,639.3594,-55L639.3594,-67.09375Q649.9844,-74,663.8281,-74Q689.21875,-74,689.21875,-47.03125L689.21875,0ZM677.6875,-37L660.3125,-34.5625Q652.2969,-33.40625,648.21875,-30.5Q644.1406,-27.59375,644.1406,-20.203125Q644.1406,-14.8125,647.90625,-11.40625Q651.6719,-8,657.9219,-8Q666.5,-8,672.09375,-14.140625Q677.6875,-20.28125,677.6875,-29.671875L677.6875,-37Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M812.90625,0L801.375,0L801.375,-41.359375Q801.375,-53.3125,797.6875,-58.65625Q794,-64,785.28125,-64Q777.8906,-64,772.71875,-57.25Q767.5625,-50.5,767.5625,-41.078125L767.5625,0L756.03125,0L756.03125,-42.765625Q756.03125,-64,739.6406,-64Q732.0469,-64,727.125,-57.625Q722.2031,-51.265625,722.2031,-41.078125L722.2031,0L710.6719,0L710.6719,-72L722.2031,-72L722.2031,-60.625L722.4844,-60.625Q730.15625,-74,744.84375,-74Q752.2344,-74,757.71875,-69.796875Q763.2031,-65.609375,765.2344,-58.796875Q773.25,-74,789.1406,-74Q812.90625,-74,812.90625,-44.5625L812.90625,0Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M875.21875,0L875.21875,-101L903.0625,-101Q956.3594,-101,956.3594,-51.765625Q956.3594,-28.390625,941.5625,-14.1875Q926.7656,0,901.9375,0L875.21875,0ZM887.03125,-90L887.03125,-11L902.0781,-11Q921.90625,-11,932.9375,-21.546875Q943.9844,-32.109375,943.9844,-51.484375Q943.9844,-90,902.78125,-90L887.03125,-90Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M1032.5469,-33L981.7031,-33Q981.9844,-21.03125,988.1719,-14.515625Q994.3594,-8,1005.1875,-8Q1017.3594,-8,1027.5469,-16L1027.5469,-5Q1018.0625,2,1002.4531,2Q987.1875,2,978.46875,-7.890625Q969.75,-17.78125,969.75,-35.71875Q969.75,-52.65625,979.28125,-63.328125Q988.8125,-74,1002.9375,-74Q1017.0781,-74,1024.8125,-64.765625Q1032.5469,-55.53125,1032.5469,-39.109375L1032.5469,-33ZM1020.7344,-43Q1020.65625,-52.9375,1015.90625,-58.46875Q1011.1719,-64,1002.7344,-64Q994.5781,-64,988.875,-58.1875Q983.1875,-52.375,981.84375,-43L1020.7344,-43Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M1061.4844,-10.390625L1061.2031,-10.390625L1061.2031,0L1049.6719,0L1049.6719,-107L1061.2031,-107L1061.2031,-59.359375L1061.4844,-59.359375Q1070,-74,1086.375,-74Q1100.2344,-74,1108.0625,-64.25Q1115.9062,-54.5,1115.9062,-38.125Q1115.9062,-19.90625,1107.1094,-8.953125Q1098.3281,2,1083.0781,2Q1068.7969,2,1061.4844,-10.390625ZM1061.2031,-39.453125L1061.2031,-29.390625Q1061.2031,-20.453125,1067,-14.21875Q1072.8125,-8,1081.7344,-8Q1092.2188,-8,1098.1562,-16.015625Q1104.0938,-24.046875,1104.0938,-38.328125Q1104.0938,-50.359375,1098.5312,-57.171875Q1092.9844,-64,1083.5,-64Q1073.4375,-64,1067.3125,-57Q1061.2031,-50,1061.2031,-39.453125Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M1192.8906,0L1181.3594,0L1181.3594,-11.375L1181.0781,-11.375Q1173.9062,2,1158.8594,2Q1133.125,2,1133.125,-28.78125L1133.125,-72L1144.5938,-72L1144.5938,-30.78125Q1144.5938,-8,1162.0312,-8Q1170.4688,-8,1175.9062,-14.21875Q1181.3594,-20.453125,1181.3594,-30.5L1181.3594,-72L1192.8906,-72L1192.8906,0Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M1278.125,-5.703125Q1278.125,34,1240.1562,34Q1226.7969,34,1216.8125,28.8125L1216.8125,17Q1228.9844,24,1240.0156,24Q1266.5938,24,1266.5938,-4.21875L1266.5938,-12.078125L1266.3125,-12.078125Q1258.0938,2,1241.5625,2Q1228.1406,2,1219.9375,-7.671875Q1211.75,-17.359375,1211.75,-33.65625Q1211.75,-52.171875,1220.5781,-63.078125Q1229.4062,-74,1244.7344,-74Q1259.2812,-74,1266.3125,-62.03125L1266.5938,-62.03125L1266.5938,-72L1278.125,-72L1278.125,-5.703125ZM1266.5938,-32.546875L1266.5938,-43.171875Q1266.5938,-51.765625,1260.7969,-57.875Q1255,-64,1246.3438,-64Q1235.6562,-64,1229.6094,-56.21875Q1223.5625,-48.453125,1223.5625,-34.453125Q1223.5625,-22.421875,1229.3594,-15.203125Q1235.1719,-8,1244.7344,-8Q1254.4375,-8,1260.5156,-14.890625Q1266.5938,-21.78125,1266.5938,-32.546875Z\"\n            android:fillColor=\"#FFFFFF\"/>\n      </group>\n    </group>\n  </group>\n</vector>"
  },
  {
    "path": "app/src/debug/res/drawable-anydpi-v24/ic_stat_name.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"#FFFFFF\"\n    android:name=\"vector\">\n  <group android:scaleX=\"0.0780212\"\n      android:scaleY=\"0.0780212\"\n      android:translateX=\"0.96\"\n      android:translateY=\"0.96\">\n      <path android:name=\"path\"\n            android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n            android:fillColor=\"#2309db\" android:strokeWidth=\"1\"\n            tools:ignore=\"VectorPath\"/>\n      <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n            android:fillColor=\"#2149d8\" android:strokeWidth=\"1\"/>\n      <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n            android:fillColor=\"#5c89f7\" android:strokeWidth=\"1\"/>\n  </group>\n</vector>"
  },
  {
    "path": "app/src/debug/res/drawable-v24/ic_banner_background.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"320dp\"\n    android:height=\"180dp\"\n    android:viewportWidth=\"320\"\n    android:viewportHeight=\"180\">\n  <group android:scaleX=\"0.6666667\"\n      android:scaleY=\"0.6666667\"\n      android:translateX=\"53.333332\"\n      android:translateY=\"30\">\n    <group android:scaleX=\"0.35277516\"\n        android:scaleY=\"0.35277516\"\n        android:translateX=\"5.879586E-4\">\n      <path\n          android:strokeWidth=\"1\"\n          android:pathData=\"M-20.09,-10.91h949.79v534.26h-949.79z\"\n          android:fillColor=\"#121212\"\n          android:strokeColor=\"#fff\"/>\n      <path\n              android:pathData=\"M273.68,250.58a18.79,18.79 0,0 0,-5.64 0.86,26.56 26.56,0 0,0 -24.73,-21.51 40.83,40.83 0,0 0,-68.95 -13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H273.68a18.9,18.9 0,0 0,0 -37.8Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"245.72\"\n                  android:startX=\"113.12\"\n                  android:endY=\"245.72\"\n                  android:endX=\"292.58\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#3FAA11\"/>\n            <item android:offset=\"1\" android:color=\"#39A11D\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n              android:pathData=\"M248.76,234.41c0,-1.22 0,-2.42 -0.09,-3.63a27,27 0,0 0,-5.36 -0.85,40.83 40.83,0 0,0 -68.95,-13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H228.5A81.75,81.75 0,0 0,248.76 234.41Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"245.72\"\n                  android:startX=\"113.12\"\n                  android:endY=\"245.72\"\n                  android:endX=\"248.76\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#37DB25\"/>\n            <item android:offset=\"1\" android:color=\"#11DD6D\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n              android:pathData=\"M174.36,216.85A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.89,18.89 0,0 0,-1.18 37.74A81.53,81.53 0,0 0,210 206.83c0,-1.15 0,-2.29 -0.09,-3.43a41.33,41.33 0,0 0,-5 -0.33A40.71,40.71 0,0 0,174.36 216.85Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"245.69\"\n                  android:startX=\"113.12\"\n                  android:endY=\"245.69\"\n                  android:endX=\"210.03\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#40F15D\"/>\n            <item android:offset=\"1\" android:color=\"#42C54F\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n\n      <path\n              android:pathData=\"M358.81,285q-13.53,0 -22.64,-9.1t-9,-22.72q0,-13.62 9,-22.64 9,-9.18 22.64,-9.19 13.79,0 22.38,10l-5.62,5.44a20.82,20.82 0,0 0,-16.76 -7.91,23 23,0 0,0 -16.94,6.81q-6.72,6.72 -6.72,17.53t6.72,17.53a23,23 0,0 0,16.94 6.81q10.63,0 18.46,-8.94l5.7,5.53a29.57,29.57 0,0 1,-10.63 8A32.44,32.44 0,0 1,358.81 285Z\"\n              android:fillColor=\"#39A11D\"/>\n      <path\n              android:pathData=\"M397.78,222.69v60.93H390V222.69Z\"\n              android:fillColor=\"#39A11D\"/>\n      <path\n              android:pathData=\"M404.5,262.77q0,-9.61 6,-15.91a20.6,20.6 0,0 1,15.41 -6.3,20.31 20.31,0 0,1 15.31,6.3 21.87,21.87 0,0 1,6.13 15.91q0,9.71 -6.13,15.92A20.3,20.3 0,0 1,426 285a20.6,20.6 0,0 1,-15.41 -6.29Q404.5,272.39 404.5,262.77ZM412.33,262.77a15.31,15.31 0,0 0,3.91 10.9,13.38 13.38,0 0,0 19.41,0 17,17 0,0 0,0 -21.7,13.18 13.18,0 0,0 -19.41,0A15.18,15.18 0,0 0,412.33 262.77Z\"\n              android:fillColor=\"#39A11D\"/>\n      <path\n              android:pathData=\"M490.7,283.62h-7.48v-5.78h-0.35a13.86,13.86 0,0 1,-5.48 5.1,15.77 15.77,0 0,1 -7.7,2q-7.67,0 -11.79,-4.38t-4.13,-12.47v-26.2h7.83v25.69q0.25,10.22 10.3,10.22a9.81,9.81 0,0 0,7.83 -3.79,13.7 13.7,0 0,0 3.14,-9.06V241.93h7.83Z\"\n              android:fillColor=\"#39A11D\"/>\n      <path\n              android:pathData=\"M517.25,285a18.34,18.34 0,0 1,-14 -6.46,24.34 24.34,0 0,1 0,-31.49 18.35,18.35 0,0 1,14 -6.47,18.07 18.07,0 0,1 8.39,2 14.84,14.84 0,0 1,5.83 5.19h0.34l-0.34,-5.78L531.47,222.69h7.82v60.93h-7.48v-5.78h-0.34a14.84,14.84 0,0 1,-5.83 5.19A18.07,18.07 0,0 1,517.25 285ZM518.53,277.86a12,12 0,0 0,9.45 -4.17q3.82,-4.17 3.83,-10.9A15.54,15.54 0,0 0,528 252a12.05,12.05 0,0 0,-9.45 -4.26,12.19 12.19,0 0,0 -9.44,4.26 15.5,15.5 0,0 0,-3.83 10.8,15.32 15.32,0 0,0 3.83,10.81A12.19,12.19 0,0 0,518.53 277.84Z\"\n              android:fillColor=\"#39A11D\"/>\n      <path\n              android:pathData=\"M587.8,267.33a15.91,15.91 0,0 1,-5.87 12.88A22.43,22.43 0,0 1,567.46 285a21.39,21.39 0,0 1,-13.36 -4.42,22.65 22.65,0 0,1 -8,-12.08l7.49,-3.07a19.3,19.3 0,0 0,2.13 4.94,15.72 15.72,0 0,0 3.19,3.78 14.25,14.25 0,0 0,4 2.47,12.26 12.26,0 0,0 4.68,0.9 13.47,13.47 0,0 0,8.76 -2.77,9 9,0 0,0 3.41,-7.36 8.8,8.8 0,0 0,-2.81 -6.55q-2.64,-2.64 -9.87,-5.11 -7.32,-2.64 -9.11,-3.57 -9.69,-4.94 -9.7,-14.55a14.84,14.84 0,0 1,5.37 -11.49A19.53,19.53 0,0 1,567 221.33a20.5,20.5 0,0 1,12.09 3.58,16.67 16.67,0 0,1 6.8,8.76l-7.31,3.06a10.84,10.84 0,0 0,-4 -5.65,13.1 13.1,0 0,0 -15.11,0.28 7.41,7.41 0,0 0,-3.15 6.19,7.14 7.14,0 0,0 2.47,5.42q2.73,2.29 11.83,5.42 9.27,3.17 13.23,7.72A16.53,16.53 0,0 1,587.8 267.33Z\"\n              android:fillColor=\"#68C671\"/>\n      <path\n              android:pathData=\"M610.26,284.3a11.88,11.88 0,0 1,-8.46 -3.15c-2.25,-2.09 -3.4,-5 -3.45,-8.76V249.07H591v-7.14h7.32V229.16h7.83v12.77h10.21v7.14H606.18v20.77c0,2.78 0.54,4.66 1.61,5.66a5.27,5.27 0,0 0,3.66 1.48,7.9 7.9,0 0,0 1.83,-0.21 9,9 0,0 0,1.66 -0.55l2.47,7A21.23,21.23 0,0 1,610.26 284.3Z\"\n              android:fillColor=\"#68C671\"/>\n      <path\n              android:pathData=\"M631.71,283.62h-7.83V241.93h7.48v6.8h0.35a11.31,11.31 0,0 1,4.89 -5.66,13.66 13.66,0 0,1 7.27,-2.34 14.7,14.7 0,0 1,5.79 1l-2.38,7.57a12.93,12.93 0,0 0,-4.6 -0.6,10.11 10.11,0 0,0 -7.7,3.58 12,12 0,0 0,-3.27 8.34Z\"\n              android:fillColor=\"#68C671\"/>\n      <path\n              android:pathData=\"M670.93,285a19.93,19.93 0,0 1,-15.14 -6.29q-6,-6.3 -6,-15.92a22.65,22.65 0,0 1,5.79 -15.87,19.15 19.15,0 0,1 14.8,-6.34q9.29,0 14.77,6t5.49,16.81l-0.09,0.85L657.83,264.24a13.56,13.56 0,0 0,4.08 9.87,13.06 13.06,0 0,0 9.36,3.75q7.49,0 11.75,-7.49l7,3.4a20.69,20.69 0,0 1,-7.78 8.25A21.51,21.51 0,0 1,670.93 285ZM658.42,257.77h23.92a10.43,10.43 0,0 0,-3.53 -7.19,12.38 12.38,0 0,0 -8.56,-2.85 11.34,11.34 0,0 0,-7.61 2.72A13.09,13.09 0,0 0,658.42 257.75Z\"\n              android:fillColor=\"#68C671\"/>\n      <path\n              android:pathData=\"M714.08,240.56q8.67,0 13.7,4.64c3.34,3.1 5,7.33 5,12.72v25.7h-7.49v-5.78H725Q720.11,285 712,285a16.83,16.83 0,0 1,-11.53 -4.08,13 13,0 0,1 -4.63,-10.21 12.38,12.38 0,0 1,4.89 -10.3q4.89,-3.83 13.06,-3.83a23.16,23.16 0,0 1,11.49 2.55v-1.78a8.9,8.9 0,0 0,-3.24 -6.94,11.08 11.08,0 0,0 -7.57,-2.85 12,12 0,0 0,-10.38 5.53l-6.89,-4.34Q702.93,240.57 714.08,240.56ZM704,270.86a6.24,6.24 0,0 0,2.59 5.1,9.57 9.57,0 0,0 6.09,2.05 12.5,12.5 0,0 0,8.81 -3.66,11.47 11.47,0 0,0 3.87,-8.6q-3.66,-2.88 -10.21,-2.89a13.22,13.22 0,0 0,-8 2.3A6.81,6.81 0,0 0,704 270.86Z\"\n              android:fillColor=\"#68C671\"/>\n      <path\n              android:pathData=\"M749.47,283.62h-7.82V241.93h7.48v5.78h0.34a14,14 0,0 1,5.49 -5.1,15.06 15.06,0 0,1 7.36,-2.05 15.22,15.22 0,0 1,8.09 2.13,12.56 12.56,0 0,1 5.1,5.87q5.19,-8 14.39,-8 7.23,0 11.14,4.43T805,257.58v26h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.06,9v23.06h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.07,9Z\"\n              android:fillColor=\"#68C671\"/>\n      <path\n          android:pathData=\"M-13.76,555.76c10.3,-20.89 58.91,-113.94 157.31,-139.7C261.3,385.24 405.9,462.43 469.89,613.28\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"252.3\"\n                  android:startX=\"194.11\"\n                  android:endY=\"252.3\"\n                  android:endX=\"373.57\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#68C671\"/>\n            <item android:offset=\"0.45\" android:color=\"#11DD6D\"/>\n            <item android:offset=\"1\" android:color=\"#39A11D\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n          android:pathData=\"M318.2,592.15c52.89,-55.46 139,-131.3 263,-187.83 223.69,-102 495.29,-119.94 515.35,-62.21 13,37.39 -73.5,124.43 -496.69,339.65\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startX=\"400.11\"\n                  android:endX=\"900\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#68C671\"/>\n            <item android:offset=\"0.45\" android:color=\"#11DD6D\"/>\n            <item android:offset=\"1\" android:color=\"#39A11D\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n          android:pathData=\"M-57.58,195c206.91,86.6 494,-219.13 453.91,-347.48C353.52,-289.67 -103.15,-353.41 -203.15,-176 -265.5,-65.35 -189.57,139.73 -57.58,195Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"252.3\"\n                  android:startX=\"-100\"\n                  android:endY=\"252.3\"\n                  android:endX=\"373.57\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#68C671\"/>\n            <item android:offset=\"0.45\" android:color=\"#11DD6D\"/>\n            <item android:offset=\"1\" android:color=\"#39A11D\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n          android:pathData=\"M698.42,648.89C625.71,546 764,320.79 920.68,218.45c46.61,-30.44 110.17,-72 164.35,-50.08 102.25,41.28 158.19,303.22 28.17,446.08C996.65,742.52 762.64,739.78 698.42,648.89Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startX=\"700.11\"\n                  android:endX=\"900.57\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#68C671\"/>\n            <item android:offset=\"0.45\" android:color=\"#11DD6D\"/>\n            <item android:offset=\"1\" android:color=\"#39A11D\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n          android:pathData=\"M339.91,-42.46a246.52,141.46 0,1 0,493.04 0a246.52,141.46 0,1 0,-493.04 0z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startX=\"400.11\"\n                  android:endX=\"800.57\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#68C671\"/>\n            <item android:offset=\"0.45\" android:color=\"#11DD6D\"/>\n            <item android:offset=\"1\" android:color=\"#39A11D\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n    </group>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/debug/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\"\n    android:name=\"vector\">\n  <group android:scaleX=\"0.1755477\"\n      android:scaleY=\"0.1755477\"\n      android:translateX=\"29.16\"\n      android:translateY=\"29.16\">\n      <path android:name=\"path\"\n            android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n            android:strokeWidth=\"1\"\n            tools:ignore=\"VectorPath\">\n          <aapt:attr name=\"android:fillColor\">\n              <gradient\n                      android:startY=\"0\"\n                      android:startX=\"200\"\n                      android:endY=\"0\"\n                      android:endX=\"300\"\n                      android:type=\"linear\">\n                  <item android:offset=\"0\" android:color=\"#3FAA11\"/>\n                  <item android:offset=\"1\" android:color=\"#39A11D\"/>\n              </gradient>\n          </aapt:attr>\n      </path>\n\n      <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n            android:strokeWidth=\"1\">\n      <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"0\"\n                  android:startX=\"200\"\n                  android:endY=\"0\"\n                  android:endX=\"000\"\n                  android:type=\"linear\">\n              <item android:offset=\"0\" android:color=\"#37DB25\"/>\n              <item android:offset=\"1\" android:color=\"#11DD6D\"/>\n          </gradient>\n      </aapt:attr>\n      </path>\n\n      <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n             android:strokeWidth=\"1\">\n      <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"0\"\n                  android:startX=\"150\"\n                  android:endY=\"0\"\n                  android:endX=\"000\"\n                  android:type=\"linear\">\n              <item android:offset=\"0\" android:color=\"#40F15D\"/>\n              <item android:offset=\"1\" android:color=\"#42C54F\"/>\n          </gradient>\n      </aapt:attr>\n  </path>\n  </group>\n</vector>"
  },
  {
    "path": "app/src/debug/res/mipmap-anydpi-v26/ic_banner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_banner_background\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/debug/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_cloudstream_monochrome\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/debug/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_cloudstream_monochrome\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/debug/res/values/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_launcher_background\">#000000</color>\n</resources>"
  },
  {
    "path": "app/src/debug/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">CloudStream Debug</string>\n</resources>"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" /> <!-- I dont remember, probs has to do with downloads -->\n    <uses-permission android:name=\"android.permission.INTERNET\" /> <!-- unless you only use cs3 as a player for downloaded stuff, you need this -->\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" /> <!-- Downloads -->\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" /> <!-- Downloads on low api devices -->\n    <uses-permission android:name=\"android.permission.MANAGE_EXTERNAL_STORAGE\" tools:ignore=\"ScopedStorage\" /> <!-- Plugin API -->\n    <uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\" /> <!-- Used for player vertical slide -->\n    <uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\" /> <!-- Used for app update -->\n    <uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" /> <!-- Used for app notifications on Android 13+ -->\n    <uses-permission android:name=\"com.android.providers.tv.permission.WRITE_EPG_DATA\" /> <!-- Used for Android TV watch next -->\n    <uses-permission android:name=\"android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION\" /> <!-- Used for updates without prompt -->\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" /> <!-- Used for update service -->\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE_DATA_SYNC\" />\n    <uses-permission android:name=\"android.permission.USE_BIOMETRIC\" />\n    <uses-permission android:name=\"android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\" /> <!-- We can use this directly as CS3 is not on Play Store -->\n    <uses-permission android:name=\"com.android.providers.tv.permission.READ_EPG_DATA\" />  <!-- We can use to read the tv channel list -->\n    <!-- Required for OpenInAppAction and getting arbitrary Aniyomi packages  -->\n    <uses-permission\n        android:name=\"android.permission.QUERY_ALL_PACKAGES\"\n        tools:ignore=\"QueryAllPackagesPermission\" />\n\n    <!-- Fixes android tv fuckery -->\n    <uses-feature\n        android:name=\"android.hardware.touchscreen\"\n        android:required=\"false\" />\n    <uses-feature\n        android:name=\"android.software.leanback\"\n        android:required=\"false\" />\n\n    <!-- Without the large heap Exoplayer buffering gets reset due to OOM. -->\n    <!--TODO https://stackoverflow.com/questions/41799732/chromecast-button-not-visible-in-android-->\n    <application\n        android:name=\".CloudStreamApp\"\n        android:allowBackup=\"true\"\n        android:appCategory=\"video\"\n        android:banner=\"@mipmap/ic_banner\"\n        android:fullBackupContent=\"@xml/backup_descriptor\"\n        android:dataExtractionRules=\"@xml/data_extraction_rules\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:largeHeap=\"true\"\n        android:pageSizeCompat=\"enabled\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\"\n        android:usesCleartextTraffic=\"true\"\n        tools:targetApi=\"${target_sdk_version}\">\n\n        <meta-data\n            android:name=\"com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME\"\n            android:value=\"com.lagradost.cloudstream3.utils.CastOptionsProvider\" />\n\n        <profileable\n            android:shell=\"true\"\n            tools:targetApi=\"q\" />\n\n        <activity\n            android:name=\".ui.player.DownloadedPlayerActivity\"\n            android:configChanges=\"orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation\"\n            android:exported=\"true\"\n            android:resizeableActivity=\"true\"\n            android:screenOrientation=\"userLandscape\"\n            android:supportsPictureInPicture=\"true\"\n            android:taskAffinity=\"com.lagradost.cloudstream3.downloadedplayer\"\n            android:launchMode=\"singleTask\"\n            tools:ignore=\"DiscouragedApi\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"content\" />\n                <data android:mimeType=\"video/*\" />\n            </intent-filter>\n\n            <!-- I dont think this label can be translated, but idk -->\n            <intent-filter android:label=\"@string/play_with_app_name\">\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"*/*\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.intent.action.SEND\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"magnet\" />\n            </intent-filter>\n            <!--<intent-filter tools:ignore=\"AppLinkUrlError\">\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.intent.action.SEND\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"application/x-bittorrent\" />\n            </intent-filter>-->\n        </activity>\n        <!--\n        android:launchMode=\"singleTask\"\n        is a bit experimental, it makes loading repositories from browser still stay on the same page\n        no idea about side effects\n        -->\n        <activity\n            android:name=\".MainActivity\"\n            android:configChanges=\"orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation|uiMode\"\n            android:exported=\"true\"\n            android:launchMode=\"singleTask\"\n            android:resizeableActivity=\"true\"\n            android:supportsPictureInPicture=\"true\">\n\n            <!-- cloudstreamplayer://encodedUrl?name=Dune -->\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"cloudstreamplayer\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"cloudstreamapp\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"cloudstreamrepo\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"csshare\" />\n            </intent-filter>\n            <!-- Allow searching with intents: cloudstreamsearch://Your%20Name -->\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"cloudstreamsearch\" />\n            </intent-filter>\n\n            <!--\n            Allow opening from continue watching with intents: cloudstreamsearch://1234\n            Used on Android TV Watch Next\n             -->\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"cloudstreamcontinuewatching\" />\n            </intent-filter>\n\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data\n                    android:host=\"cs.repo\"\n                    android:pathPrefix=\"/\"\n                    android:scheme=\"https\" />\n            </intent-filter>\n        </activity>\n\n        <activity\n            android:name=\".ui.account.AccountSelectActivity\"\n            android:configChanges=\"orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden\"\n            android:exported=\"true\">\n            <intent-filter android:exported=\"true\">\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n                <category android:name=\"android.intent.category.LEANBACK_LAUNCHER\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n\n        <receiver\n            android:name=\".receivers.VideoDownloadRestartReceiver\"\n            android:enabled=\"false\"\n            android:exported=\"false\">\n            <intent-filter android:exported=\"false\">\n                <action android:name=\"restart_service\" />\n            </intent-filter>\n        </receiver>\n\n        <service\n            android:name=\".services.VideoDownloadService\"\n            android:enabled=\"true\"\n            android:foregroundServiceType=\"dataSync\"\n            android:exported=\"false\" />\n\n        <service\n            android:name=\".services.DownloadQueueService\"\n            android:enabled=\"true\"\n            android:foregroundServiceType=\"dataSync\"\n            android:exported=\"false\" />\n\n        <!-- Necessary for WorkManager services: https://stackoverflow.com/a/77186316 -->\n        <service\n            android:name=\"androidx.work.impl.foreground.SystemForegroundService\"\n            android:foregroundServiceType=\"dataSync\"\n            tools:node=\"merge\" />\n\n        <activity\n            android:name=\".ui.ControllerActivity\"\n            android:exported=\"false\" />\n\n        <service\n            android:name=\".services.PackageInstallerService\"\n            android:foregroundServiceType=\"dataSync\"\n            android:exported=\"false\" />\n\n        <provider\n            android:name=\"androidx.core.content.FileProvider\"\n            android:authorities=\"${applicationId}.provider\"\n            android:enabled=\"true\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\">\n            <meta-data\n                android:name=\"android.support.FILE_PROVIDER_PATHS\"\n                android:resource=\"@xml/provider_paths\" />\n        </provider>\n    </application>\n    \n</manifest>\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt",
    "content": "package com.lagradost.cloudstream3\n\nimport android.content.Context\nimport com.lagradost.api.setContext\nimport com.lagradost.cloudstream3.utils.DataStore.getKey\nimport com.lagradost.cloudstream3.utils.DataStore.removeKeys\nimport com.lagradost.cloudstream3.utils.DataStore.setKey\nimport java.lang.ref.WeakReference\n\n/**\n * Deprecated alias for CloudStreamApp for backwards compatibility with plugins.\n * Use CloudStreamApp instead.\n */\n// Deprecate after next stable\n/*@Deprecated(\n    message = \"AcraApplication is deprecated, use CloudStreamApp instead\",\n    replaceWith = ReplaceWith(\"com.lagradost.cloudstream3.CloudStreamApp\"),\n    level = DeprecationLevel.WARNING\n)*/\nclass AcraApplication {\n\t// All methods here can be changed to be a wrapper around CloudStream app\n\t// without a seperate deprecation after next stable. All methods should\n\t// also be deprecated at that time.\n\tcompanion object {\n\n\t\t// This can be removed without deprecation after next stable\n\t\tprivate var _context: WeakReference<Context>? = null\n\t\t/*@Deprecated(\n\t\t    message = \"AcraApplication is deprecated, use CloudStreamApp instead\",\n\t\t    replaceWith = ReplaceWith(\"com.lagradost.cloudstream3.CloudStreamApp.context\"),\n\t\t    level = DeprecationLevel.WARNING\n\t\t)*/\n\t\tvar context\n\t\tget() = _context?.get()\n\t\tinternal set(value) {\n\t\t\t_context = WeakReference(value)\n\t\t\tsetContext(WeakReference(value))\n\t\t}\n\n\t\t/*@Deprecated(\n\t\t    message = \"AcraApplication is deprecated, use CloudStreamApp instead\",\n\t\t    replaceWith = ReplaceWith(\"com.lagradost.cloudstream3.CloudStreamApp.removeKeys(folder)\"),\n\t\t    level = DeprecationLevel.WARNING\n\t\t)*/\n\t\tfun removeKeys(folder: String): Int? {\n            return context?.removeKeys(folder)\n        }\n\n\t\t/*@Deprecated(\n\t\t    message = \"AcraApplication is deprecated, use CloudStreamApp instead\",\n\t\t    replaceWith = ReplaceWith(\"com.lagradost.cloudstream3.CloudStreamApp.setKey(path, value)\"),\n\t\t    level = DeprecationLevel.WARNING\n\t\t)*/\n\t\tfun <T> setKey(path: String, value: T) {\n\t\t\tcontext?.setKey(path, value)\n\t\t}\n\n\t\t/*@Deprecated(\n\t\t    message = \"AcraApplication is deprecated, use CloudStreamApp instead\",\n\t\t    replaceWith = ReplaceWith(\"com.lagradost.cloudstream3.CloudStreamApp.setKey(folder, path, value)\"),\n\t\t    level = DeprecationLevel.WARNING\n\t\t)*/\n\t\tfun <T> setKey(folder: String, path: String, value: T) {\n\t\t\tcontext?.setKey(folder, path, value)\n\t\t}\n\n\t\t/*@Deprecated(\n\t\t    message = \"AcraApplication is deprecated, use CloudStreamApp instead\",\n\t\t    replaceWith = ReplaceWith(\"com.lagradost.cloudstream3.CloudStreamApp.getKey(path, defVal)\"),\n\t\t    level = DeprecationLevel.WARNING\n\t\t)*/\n\t\tinline fun <reified T : Any> getKey(path: String, defVal: T?): T? {\n\t\t\treturn context?.getKey(path, defVal)\n\t\t}\n\n\t\t/*@Deprecated(\n\t\t    message = \"AcraApplication is deprecated, use CloudStreamApp instead\",\n\t\t    replaceWith = ReplaceWith(\"com.lagradost.cloudstream3.CloudStreamApp.getKey(path)\"),\n\t\t    level = DeprecationLevel.WARNING\n\t\t)*/\n\t\tinline fun <reified T : Any> getKey(path: String): T? {\n\t\t\treturn context?.getKey(path)\n\t\t}\n\n\t\t/*@Deprecated(\n\t\t    message = \"AcraApplication is deprecated, use CloudStreamApp instead\",\n\t\t    replaceWith = ReplaceWith(\"com.lagradost.cloudstream3.CloudStreamApp.getKey(folder, path)\"),\n\t\t    level = DeprecationLevel.WARNING\n\t\t)*/\n\t\tinline fun <reified T : Any> getKey(folder: String, path: String): T? {\n\t\t\treturn context?.getKey(folder, path)\n\t\t}\n\n\t\t/*@Deprecated(\n\t\t    message = \"AcraApplication is deprecated, use CloudStreamApp instead\",\n\t\t    replaceWith = ReplaceWith(\"com.lagradost.cloudstream3.CloudStreamApp.getKey(folder, path, defVal)\"),\n\t\t    level = DeprecationLevel.WARNING\n\t\t)*/\n\t\tinline fun <reified T : Any> getKey(folder: String, path: String, defVal: T?): T? {\n\t\t\treturn context?.getKey(folder, path, defVal)\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/CloudStreamApp.kt",
    "content": "package com.lagradost.cloudstream3\n\nimport android.app.Activity\nimport android.app.Application\nimport android.content.Context\nimport android.content.ContextWrapper\nimport android.content.Intent\nimport android.os.Build\nimport android.widget.Toast\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.FragmentActivity\nimport coil3.ImageLoader\nimport coil3.PlatformContext\nimport coil3.SingletonImageLoader\nimport com.lagradost.api.setContext\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.mvvm.safeAsync\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.openBrowser\nimport com.lagradost.cloudstream3.utils.AppDebug\nimport com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread\nimport com.lagradost.cloudstream3.utils.DataStore.getKey\nimport com.lagradost.cloudstream3.utils.DataStore.getKeys\nimport com.lagradost.cloudstream3.utils.DataStore.removeKey\nimport com.lagradost.cloudstream3.utils.DataStore.removeKeys\nimport com.lagradost.cloudstream3.utils.DataStore.setKey\nimport com.lagradost.cloudstream3.utils.ImageLoader.buildImageLoader\nimport kotlinx.coroutines.runBlocking\nimport java.io.File\nimport java.io.FileNotFoundException\nimport java.io.PrintStream\nimport java.lang.ref.WeakReference\nimport java.util.Locale\nimport kotlin.concurrent.thread\nimport kotlin.system.exitProcess\n\nclass ExceptionHandler(\n    val errorFile: File,\n    val onError: (() -> Unit)\n) : Thread.UncaughtExceptionHandler {\n\n    override fun uncaughtException(thread: Thread, error: Throwable) {\n        try {\n            val threadId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) {\n                thread.threadId()\n            } else {\n                @Suppress(\"DEPRECATION\")\n                thread.id\n            }\n\n            PrintStream(errorFile).use { ps ->\n                ps.println(\"Currently loading extension: ${PluginManager.currentlyLoading ?: \"none\"}\")\n                ps.println(\"Fatal exception on thread ${thread.name} ($threadId)\")\n                error.printStackTrace(ps)\n            }\n        } catch (_: FileNotFoundException) {\n        }\n        try {\n            onError()\n        } catch (_: Exception) {\n        }\n        exitProcess(1)\n    }\n}\n\n@Prerelease\nclass CloudStreamApp : Application(), SingletonImageLoader.Factory {\n\n    override fun onCreate() {\n        super.onCreate()\n        // If we want to initialize Coil as early as possible, maybe when\n        // loading an image or GIF in a splash screen activity.\n        // buildImageLoader(applicationContext)\n\n        ExceptionHandler(filesDir.resolve(\"last_error\")) {\n            val intent = context!!.packageManager.getLaunchIntentForPackage(context!!.packageName)\n            startActivity(Intent.makeRestartActivityTask(intent!!.component))\n        }.also {\n            exceptionHandler = it\n            Thread.setDefaultUncaughtExceptionHandler(it)\n        }\n\n        AppDebug.isDebug = BuildConfig.DEBUG\n    }\n\n    override fun attachBaseContext(base: Context?) {\n        super.attachBaseContext(base)\n        context = base\n        // This can be removed without deprecation after next stable\n        AcraApplication.context = context\n    }\n\n    override fun newImageLoader(context: PlatformContext): ImageLoader {\n        // Coil module will be initialized globally when first loadImage() is invoked.\n        return buildImageLoader(applicationContext)\n    }\n\n    companion object {\n        var exceptionHandler: ExceptionHandler? = null\n\n        /** Use to get Activity from Context. */\n        tailrec fun Context.getActivity(): Activity? {\n            return when (this) {\n                is Activity -> this\n                is ContextWrapper -> baseContext.getActivity()\n                else -> null\n            }\n        }\n\n        private var _context: WeakReference<Context>? = null\n        var context\n            get() = _context?.get()\n            private set(value) {\n                _context = WeakReference(value)\n                setContext(WeakReference(value))\n            }\n\n        fun <T : Any> getKeyClass(path: String, valueType: Class<T>): T? {\n            return context?.getKey(path, valueType)\n        }\n\n        fun <T : Any> setKeyClass(path: String, value: T) {\n            context?.setKey(path, value)\n        }\n\n        fun removeKeys(folder: String): Int? {\n            return context?.removeKeys(folder)\n        }\n\n        fun <T> setKey(path: String, value: T) {\n            context?.setKey(path, value)\n        }\n\n        fun <T> setKey(folder: String, path: String, value: T) {\n            context?.setKey(folder, path, value)\n        }\n\n        inline fun <reified T : Any> getKey(path: String, defVal: T?): T? {\n            return context?.getKey(path, defVal)\n        }\n\n        inline fun <reified T : Any> getKey(path: String): T? {\n            return context?.getKey(path)\n        }\n\n        inline fun <reified T : Any> getKey(folder: String, path: String): T? {\n            return context?.getKey(folder, path)\n        }\n\n        inline fun <reified T : Any> getKey(folder: String, path: String, defVal: T?): T? {\n            return context?.getKey(folder, path, defVal)\n        }\n\n        fun getKeys(folder: String): List<String>? {\n            return context?.getKeys(folder)\n        }\n\n        fun removeKey(folder: String, path: String) {\n            context?.removeKey(folder, path)\n        }\n\n        fun removeKey(path: String) {\n            context?.removeKey(path)\n        }\n\n        /** If fallbackWebView is true and a fragment is supplied then it will open a WebView with the URL if the browser fails. */\n        fun openBrowser(url: String, fallbackWebView: Boolean = false, fragment: Fragment? = null) {\n            context?.openBrowser(url, fallbackWebView, fragment)\n        }\n\n        /** Will fall back to WebView if in TV or emulator layout. */\n        fun openBrowser(url: String, activity: FragmentActivity?) {\n            openBrowser(\n                url,\n                isLayout(TV or EMULATOR),\n                activity?.supportFragmentManager?.fragments?.lastOrNull()\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt",
    "content": "package com.lagradost.cloudstream3\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.app.PictureInPictureParams\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.content.res.Configuration\nimport android.content.res.Resources\nimport android.Manifest\nimport android.os.Build\nimport android.util.DisplayMetrics\nimport android.util.Log\nimport android.view.Gravity\nimport android.view.KeyEvent\nimport android.view.View\nimport android.view.View.NO_ID\nimport android.view.ViewGroup\nimport android.widget.Toast\nimport androidx.activity.ComponentActivity\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.annotation.MainThread\nimport androidx.annotation.StringRes\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.appcompat.widget.SearchView\nimport androidx.core.content.ContextCompat\nimport androidx.core.view.children\nimport androidx.core.view.isNotEmpty\nimport androidx.preference.PreferenceManager\nimport com.google.android.gms.cast.framework.CastSession\nimport com.google.android.material.chip.ChipGroup\nimport com.google.android.material.navigationrail.NavigationRailView\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\nimport com.lagradost.cloudstream3.actions.VideoClickActionHolder\nimport com.lagradost.cloudstream3.databinding.ToastBinding\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.syncproviders.AccountManager\nimport com.lagradost.cloudstream3.ui.home.HomeChildItemAdapter\nimport com.lagradost.cloudstream3.ui.home.ParentItemAdapter\nimport com.lagradost.cloudstream3.ui.player.PlayerEventType\nimport com.lagradost.cloudstream3.ui.player.PlayerPipHelper.isPIPPossible\nimport com.lagradost.cloudstream3.ui.player.Torrent\nimport com.lagradost.cloudstream3.ui.result.ActorAdaptor\nimport com.lagradost.cloudstream3.ui.result.EpisodeAdapter\nimport com.lagradost.cloudstream3.ui.result.ImageAdapter\nimport com.lagradost.cloudstream3.ui.search.SearchAdapter\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.updateTv\nimport com.lagradost.cloudstream3.ui.settings.extensions.PluginAdapter\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isRtl\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Event\nimport com.lagradost.cloudstream3.utils.UIHelper.showInputMethod\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\nimport com.lagradost.cloudstream3.utils.UiText\nimport java.lang.ref.WeakReference\nimport java.util.Locale\nimport kotlin.math.max\nimport kotlin.math.min\nimport org.schabi.newpipe.extractor.NewPipe\n\nenum class FocusDirection {\n    Start,\n    End,\n    Up,\n    Down,\n}\n\nobject CommonActivity {\n\n    private var _activity: WeakReference<Activity>? = null\n    var activity\n        get() = _activity?.get()\n        private set(value) {\n            _activity = WeakReference(value)\n        }\n\n    @MainThread\n    fun setActivityInstance(newActivity: Activity?) {\n        activity = newActivity\n    }\n\n    @MainThread\n    fun Activity?.getCastSession(): CastSession? {\n        return (this as MainActivity?)?.mSessionManager?.currentCastSession\n    }\n\n    val displayMetrics: DisplayMetrics = Resources.getSystem().displayMetrics\n\n    // screenWidth and screenHeight does always\n    // refer to the screen while in landscape mode\n    val screenWidth: Int\n        get() {\n            return max(displayMetrics.widthPixels, displayMetrics.heightPixels)\n        }\n    val screenHeight: Int\n        get() {\n            return min(displayMetrics.widthPixels, displayMetrics.heightPixels)\n        }\n    val screenWidthWithOrientation: Int\n        get() {\n            return displayMetrics.widthPixels\n        }\n    val screenHeightWithOrientation: Int\n        get() {\n            return displayMetrics.heightPixels\n        }\n\n    var isPipDesired: Boolean = false\n    var isInPIPMode: Boolean = false\n\n    val onColorSelectedEvent = Event<Pair<Int, Int>>()\n    val onDialogDismissedEvent = Event<Int>()\n\n    var playerEventListener: ((PlayerEventType) -> Unit)? = null\n    var keyEventListener: ((Pair<KeyEvent?, Boolean>) -> Boolean)? = null\n    var appliedTheme: Int = 0\n    var appliedColor: Int = 0\n\n    private var currentToast: Toast? = null\n\n    fun showToast(@StringRes message: Int, duration: Int? = null) {\n        val act = activity ?: return\n        act.runOnUiThread {\n            showToast(act, act.getString(message), duration)\n        }\n    }\n\n    fun showToast(message: String?, duration: Int? = null) {\n        val act = activity ?: return\n        act.runOnUiThread {\n            showToast(act, message, duration)\n        }\n    }\n\n    fun showToast(message: UiText?, duration: Int? = null) {\n        val act = activity ?: return\n        if (message == null) return\n        act.runOnUiThread {\n            showToast(act, message.asString(act), duration)\n        }\n    }\n\n\n    @MainThread\n    fun showToast(act: Activity?, text: UiText, duration: Int) {\n        if (act == null) return\n        text.asStringNull(act)?.let {\n            showToast(act, it, duration)\n        }\n    }\n\n    /** duration is Toast.LENGTH_SHORT if null*/\n    @MainThread\n    fun showToast(act: Activity?, @StringRes message: Int, duration: Int? = null) {\n        if (act == null) return\n        showToast(act, act.getString(message), duration)\n    }\n\n    const val TAG = \"COMPACT\"\n\n    /** duration is Toast.LENGTH_SHORT if null*/\n    @MainThread\n    fun showToast(act: Activity?, message: String?, duration: Int? = null) {\n        if (act == null || message == null) {\n            Log.w(TAG, \"invalid showToast act = $act message = $message\")\n            return\n        }\n        Log.i(TAG, \"showToast = $message\")\n\n        try {\n            currentToast?.cancel()\n        } catch (e: Exception) {\n            logError(e)\n        }\n\n        try {\n            val binding = ToastBinding.inflate(act.layoutInflater)\n            binding.text.text = message.trim()\n\n            // custom toasts are deprecated and won't appear when cs3 sets minSDK to api30 (A11)\n            val toast = Toast(act)\n            toast.duration = duration ?: Toast.LENGTH_SHORT\n            toast.setGravity(Gravity.CENTER_HORIZONTAL or Gravity.BOTTOM, 0, 5.toPx)\n            @Suppress(\"DEPRECATION\")\n            toast.view =\n                binding.root // FIXME Find an alternative using default Toasts since custom toasts are deprecated and won't appear with api30 set as minSDK version.\n            currentToast = toast\n            toast.show()\n\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    /**\n     * Set locale\n     * @param languageTag shall a IETF BCP 47 conformant tag.\n     * Check [com.lagradost.cloudstream3.utils.SubtitleHelper].\n     *\n     * See locales on:\n     * https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/availableLocales.json\n     * https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry\n     * https://android.googlesource.com/platform/frameworks/base/+/android-16.0.0_r2/core/res/res/values/locale_config.xml\n     * https://iso639-3.sil.org/code_tables/639/data/all\n     */\n    fun setLocale(context: Context?, languageTag: String?) {\n        if (context == null || languageTag == null) return\n        val locale = Locale.forLanguageTag(languageTag)\n        val resources: Resources = context.resources\n        val config = resources.configuration\n        Locale.setDefault(locale)\n        config.setLocale(locale)\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)\n            context.createConfigurationContext(config)\n\n        @Suppress(\"DEPRECATION\")\n        resources.updateConfiguration(\n            config,\n            resources.displayMetrics\n        ) // FIXME this should be replaced\n    }\n\n    fun Context.updateLocale() {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        val localeCode = settingsManager.getString(getString(R.string.locale_key), null)\n        setLocale(this, localeCode)\n    }\n\n    fun init(act: Activity) {\n        setActivityInstance(act)\n        ioSafe { Torrent.deleteAllFiles() }\n        val componentActivity = activity as? ComponentActivity ?: return\n\n        componentActivity.updateLocale()\n        componentActivity.updateTv()\n        AccountManager.initMainAPI()\n        NewPipe.init(DownloaderTestImpl.getInstance())\n\n        MainActivity.activityResultLauncher =\n            componentActivity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->\n                if (result.resultCode == AppCompatActivity.RESULT_OK) {\n                    val actionUid =\n                        getKey<String>(\"last_click_action\") ?: return@registerForActivityResult\n                    Log.d(TAG, \"Loading action $actionUid result handler\")\n                    val action = VideoClickActionHolder.getByUniqueId(actionUid) as? OpenInAppAction\n                        ?: return@registerForActivityResult\n                    action.onResultSafe(act, result.data)\n                    removeKey(\"last_click_action\")\n                    removeKey(\"last_opened\")\n                }\n            }\n\n        // Ask for notification permissions on Android 13\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&\n            ContextCompat.checkSelfPermission(\n                componentActivity,\n                Manifest.permission.POST_NOTIFICATIONS\n            ) != PackageManager.PERMISSION_GRANTED\n        ) {\n            val requestPermissionLauncher = componentActivity.registerForActivityResult(\n                ActivityResultContracts.RequestPermission()\n            ) { isGranted: Boolean ->\n                Log.d(TAG, \"Notification permission: $isGranted\")\n            }\n            requestPermissionLauncher.launch(\n                Manifest.permission.POST_NOTIFICATIONS\n            )\n        }\n    }\n\n    /** Enters pip mode if it is both possible and desired to do so*/\n    private fun Activity.enterPIPMode() {\n        if (!isPipDesired || !this.isPIPPossible()) return\n\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                try {\n                    enterPictureInPictureMode(PictureInPictureParams.Builder().build())\n                } catch (_: Exception) {\n                    // Use fallback just in case\n                    @Suppress(\"DEPRECATION\")\n                    enterPictureInPictureMode()\n                }\n            } else {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    @Suppress(\"DEPRECATION\")\n                    enterPictureInPictureMode()\n                }\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    fun onUserLeaveHint(act: Activity) {\n        // On Android 12 and later we use setAutoEnterEnabled() instead.\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) return\n        act.enterPIPMode()\n    }\n\n    fun updateTheme(act: Activity) {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(act)\n        if (settingsManager\n                .getString(act.getString(R.string.app_theme_key), \"AmoledLight\") == \"System\"\n            && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q\n        ) {\n            loadThemes(act)\n        }\n    }\n\n    private fun mapSystemTheme(act: Activity): Int {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            val currentNightMode =\n                act.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK\n            return when (currentNightMode) {\n                Configuration.UI_MODE_NIGHT_NO -> R.style.LightMode // Night mode is not active, we're using the light theme\n                else -> R.style.AppTheme // Night mode is active, we're using dark theme\n            }\n        } else {\n            return R.style.AppTheme\n        }\n    }\n\n    fun loadThemes(act: Activity?) {\n        if (act == null) return\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(act)\n\n        val currentTheme =\n            when (settingsManager.getString(act.getString(R.string.app_theme_key), \"AmoledLight\")) {\n                \"System\" -> mapSystemTheme(act)\n                \"Black\" -> R.style.AppTheme\n                \"Light\" -> R.style.LightMode\n                \"Amoled\" -> R.style.AmoledMode\n                \"AmoledLight\" -> R.style.AmoledModeLight\n                \"Monet\" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)\n                    R.style.MonetMode else R.style.AppTheme\n\n                \"Dracula\" -> R.style.DraculaMode\n                \"Lavender\" -> R.style.LavenderMode\n                \"SilentBlue\" -> R.style.SilentBlueMode\n\n                else -> R.style.AppTheme\n            }\n\n        val currentOverlayTheme =\n            when (settingsManager.getString(act.getString(R.string.primary_color_key), \"Normal\")) {\n                \"Normal\" -> R.style.OverlayPrimaryColorNormal\n                \"DandelionYellow\" -> R.style.OverlayPrimaryColorDandelionYellow\n                \"CarnationPink\" -> R.style.OverlayPrimaryColorCarnationPink\n                \"Orange\" -> R.style.OverlayPrimaryColorOrange\n                \"DarkGreen\" -> R.style.OverlayPrimaryColorDarkGreen\n                \"Maroon\" -> R.style.OverlayPrimaryColorMaroon\n                \"NavyBlue\" -> R.style.OverlayPrimaryColorNavyBlue\n                \"Grey\" -> R.style.OverlayPrimaryColorGrey\n                \"White\" -> R.style.OverlayPrimaryColorWhite\n                \"CoolBlue\" -> R.style.OverlayPrimaryColorCoolBlue\n                \"Brown\" -> R.style.OverlayPrimaryColorBrown\n                \"Purple\" -> R.style.OverlayPrimaryColorPurple\n                \"Green\" -> R.style.OverlayPrimaryColorGreen\n                \"GreenApple\" -> R.style.OverlayPrimaryColorGreenApple\n                \"Red\" -> R.style.OverlayPrimaryColorRed\n                \"Banana\" -> R.style.OverlayPrimaryColorBanana\n                \"Party\" -> R.style.OverlayPrimaryColorParty\n                \"Pink\" -> R.style.OverlayPrimaryColorPink\n                \"Lavender\" -> R.style.OverlayPrimaryColorLavender\n                \"Monet\" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)\n                    R.style.OverlayPrimaryColorMonet else R.style.OverlayPrimaryColorNormal\n\n                \"Monet2\" -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)\n                    R.style.OverlayPrimaryColorMonetTwo else R.style.OverlayPrimaryColorNormal\n\n                else -> R.style.OverlayPrimaryColorNormal\n            }\n\n        act.theme.applyStyle(currentTheme, true)\n        act.theme.applyStyle(currentOverlayTheme, true)\n        appliedTheme = currentTheme\n        appliedColor = currentOverlayTheme\n        act.updateTv()\n        if (isLayout(TV)) act.theme.applyStyle(R.style.AppThemeTvOverlay, true)\n        act.theme.applyStyle(\n            R.style.LoadedStyle,\n            true\n        ) // THEME IS SET BEFORE VIEW IS CREATED TO APPLY THE THEME TO THE MAIN VIEW\n    }\n\n    /** because we want closes find, aka when multiple have the same id, we go to parent\n    until the correct one is found */\n    private fun localLook(from: View, id: Int): View? {\n        if (id == NO_ID) return null\n        var currentLook: View = from\n        // limit to 15 look depth\n        for (i in 0..15) {\n            currentLook.findViewById<View?>(id)?.let { return it }\n            currentLook = (currentLook.parent as? View) ?: break\n        }\n        return null\n    }\n    /*var currentLook: View = view\n    while (true) {\n        val tmpNext = currentLook.findViewById<View?>(nextId)\n        if (tmpNext != null) {\n            next = tmpNext\n            break\n        }\n        currentLook = currentLook.parent as? View ?: break\n    }*/\n\n    private fun View.hasContent(): Boolean {\n        return isShown && when (this) {\n            is ViewGroup -> this.isNotEmpty()\n            else -> true\n        }\n    }\n\n    /** skips the initial stage of searching for an id using the view, see getNextFocus for specification */\n    fun continueGetNextFocus(\n        root: Any?,\n        view: View,\n        direction: FocusDirection,\n        nextId: Int,\n        depth: Int = 0\n    ): View? {\n        if (nextId == NO_ID) return null\n\n        // do an initial search for the view, in case the localLook is too deep we can use this as\n        // an early break and backup view\n        var next =\n            when (root) {\n                is Activity -> root.findViewById(nextId)\n                is View -> root.rootView.findViewById<View?>(nextId)\n                else -> null\n            } ?: return null\n\n        next = localLook(view, nextId) ?: next\n        val shown = next.hasContent()\n\n        // if cant focus but visible then break and let android decide\n        // the exception if is the view is a parent and has children that wants focus\n        val hasChildrenThatWantsFocus = (next as? ViewGroup)?.let { parent ->\n            parent.descendantFocusability == ViewGroup.FOCUS_AFTER_DESCENDANTS && parent.isNotEmpty()\n        } ?: false\n        if (!next.isFocusable && shown && !hasChildrenThatWantsFocus) return null\n\n        // if not shown then continue because we will \"skip\" over views to get to a replacement\n        if (!shown) {\n            // we don't want a while true loop, so we let android decide if we find a recursive view\n            if (next == view) return null\n            return getNextFocus(root, next, direction, depth + 1)\n        }\n\n        (when (next) {\n            is ChipGroup -> {\n                next.children.firstOrNull { it.isFocusable && it.isShown }\n            }\n\n            is NavigationRailView -> {\n                next.findViewById(next.selectedItemId) ?: next.findViewById(R.id.navigation_home)\n            }\n\n            else -> null\n        })?.let {\n            return it\n        }\n\n        // nothing wrong with the view found, return it\n        return next\n    }\n\n    /** recursively looks for a next focus up to a depth of 10,\n     * this is used to override the normal shit focus system\n     * because this application has a lot of invisible views that messes with some tv devices*/\n    fun getNextFocus(\n        root: Any?,\n        view: View?,\n        direction: FocusDirection,\n        depth: Int = 0\n    ): View? {\n        // if input is invalid let android decide + depth test to not crash if loop is found\n        if (view == null || depth >= 10 || root == null) {\n            return null\n        }\n\n        var nextId = when (direction) {\n            FocusDirection.Start -> {\n                if (view.isRtl())\n                    view.nextFocusRightId\n                else\n                    view.nextFocusLeftId\n            }\n\n            FocusDirection.Up -> {\n                view.nextFocusUpId\n            }\n\n            FocusDirection.End -> {\n                if (view.isRtl())\n                    view.nextFocusLeftId\n                else\n                    view.nextFocusRightId\n            }\n\n            FocusDirection.Down -> {\n                view.nextFocusDownId\n            }\n        }\n\n        if (nextId == NO_ID) {\n            // if not specified then use forward id\n            nextId = view.nextFocusForwardId\n            // if view is still not found to next focus then return and let android decide\n            if (nextId == NO_ID)\n                return null\n        }\n        return continueGetNextFocus(root, view, direction, nextId, depth)\n    }\n\n\n    fun onKeyDown(act: Activity?, keyCode: Int, event: KeyEvent?): Boolean? {\n\n        // 149 keycode_numpad 5\n        val playerEvent = when (keyCode) {\n            KeyEvent.KEYCODE_FORWARD, KeyEvent.KEYCODE_D, KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD, KeyEvent.KEYCODE_MEDIA_FAST_FORWARD -> {\n                PlayerEventType.SeekForward\n            }\n\n            KeyEvent.KEYCODE_A, KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD, KeyEvent.KEYCODE_MEDIA_REWIND -> {\n                PlayerEventType.SeekBack\n            }\n\n            KeyEvent.KEYCODE_MEDIA_NEXT, KeyEvent.KEYCODE_BUTTON_R1, KeyEvent.KEYCODE_N, KeyEvent.KEYCODE_NUMPAD_2, KeyEvent.KEYCODE_CHANNEL_UP -> {\n                PlayerEventType.NextEpisode\n            }\n\n            KeyEvent.KEYCODE_MEDIA_PREVIOUS, KeyEvent.KEYCODE_BUTTON_L1, KeyEvent.KEYCODE_B, KeyEvent.KEYCODE_NUMPAD_1, KeyEvent.KEYCODE_CHANNEL_DOWN -> {\n                PlayerEventType.PrevEpisode\n            }\n\n            KeyEvent.KEYCODE_MEDIA_PAUSE -> {\n                PlayerEventType.Pause\n            }\n\n            KeyEvent.KEYCODE_MEDIA_PLAY, KeyEvent.KEYCODE_BUTTON_START -> {\n                PlayerEventType.Play\n            }\n\n            KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_NUMPAD_7, KeyEvent.KEYCODE_7 -> {\n                PlayerEventType.Lock\n            }\n\n            KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_MENU -> {\n                PlayerEventType.ToggleHide\n            }\n\n            KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_VOLUME_MUTE -> {\n                PlayerEventType.ToggleMute\n            }\n\n            KeyEvent.KEYCODE_S, KeyEvent.KEYCODE_NUMPAD_9, KeyEvent.KEYCODE_9 -> {\n                PlayerEventType.ShowMirrors\n            }\n            // OpenSubtitles shortcut\n            KeyEvent.KEYCODE_O, KeyEvent.KEYCODE_NUMPAD_8, KeyEvent.KEYCODE_8 -> {\n                PlayerEventType.SearchSubtitlesOnline\n            }\n\n            KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_NUMPAD_3, KeyEvent.KEYCODE_3 -> {\n                PlayerEventType.ShowSpeed\n            }\n\n            KeyEvent.KEYCODE_R, KeyEvent.KEYCODE_NUMPAD_0, KeyEvent.KEYCODE_0 -> {\n                PlayerEventType.Resize\n            }\n\n            KeyEvent.KEYCODE_C, KeyEvent.KEYCODE_NUMPAD_4, KeyEvent.KEYCODE_4 -> {\n                PlayerEventType.SkipOp\n            }\n\n            KeyEvent.KEYCODE_V, KeyEvent.KEYCODE_NUMPAD_5, KeyEvent.KEYCODE_5 -> {\n                PlayerEventType.SkipCurrentChapter\n            }\n\n            KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, KeyEvent.KEYCODE_P, KeyEvent.KEYCODE_SPACE, KeyEvent.KEYCODE_NUMPAD_ENTER, KeyEvent.KEYCODE_ENTER -> { // space is not captured due to navigation\n                PlayerEventType.PlayPauseToggle\n            }\n\n            else -> return null\n        }\n        val listener = playerEventListener\n        if (listener != null) {\n            listener.invoke(playerEvent)\n            return true\n        }\n        return null\n\n        //when (keyCode) {\n        //    KeyEvent.KEYCODE_DPAD_CENTER -> {\n        //        println(\"DPAD PRESSED\")\n        //    }\n        //}\n    }\n\n    /** overrides focus and custom key events */\n    fun dispatchKeyEvent(act: Activity?, event: KeyEvent?): Boolean? {\n        if (act == null) return null\n        val currentFocus = act.currentFocus\n\n        event?.keyCode?.let { keyCode ->\n            if (currentFocus == null || event.action != KeyEvent.ACTION_DOWN) return@let\n            val nextView = when (keyCode) {\n                KeyEvent.KEYCODE_DPAD_LEFT -> getNextFocus(\n                    act,\n                    currentFocus,\n                    FocusDirection.Start\n                )\n\n                KeyEvent.KEYCODE_DPAD_RIGHT -> getNextFocus(\n                    act,\n                    currentFocus,\n                    FocusDirection.End\n                )\n\n                KeyEvent.KEYCODE_DPAD_UP -> getNextFocus(\n                    act,\n                    currentFocus,\n                    FocusDirection.Up\n                )\n\n                KeyEvent.KEYCODE_DPAD_DOWN -> getNextFocus(\n                    act,\n                    currentFocus,\n                    FocusDirection.Down\n                )\n\n                else -> null\n            }\n\n            // println(\"NEXT FOCUS : $nextView\")\n            if (nextView != null) {\n                nextView.requestFocus()\n                keyEventListener?.invoke(Pair(event, true))\n                return true\n            }\n\n            // TODO: Figure out why removing the check for SearchAutoComplete seems\n            // to break focus on TV as it shouldn't need to be used.\n            @SuppressLint(\"RestrictedApi\")\n            if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER &&\n                (act.currentFocus is SearchView || act.currentFocus is SearchView.SearchAutoComplete)\n            ) {\n                showInputMethod(act.currentFocus?.findFocus())\n            }\n\n            //println(\"Keycode: $keyCode\")\n            //showToast(\n            //    this,\n            //    \"Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \\n ${event?.action}\",\n            //    Toast.LENGTH_LONG\n            //)\n        }\n\n        // if someone else want to override the focus then don't handle the event as it is already\n        // consumed. used in video player\n        if (keyEventListener?.invoke(Pair(event, false)) == true) {\n            return true\n        }\n        return null\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/DownloaderTestImpl.kt",
    "content": "package com.lagradost.cloudstream3\n\nimport okhttp3.OkHttpClient\nimport okhttp3.RequestBody\nimport okhttp3.RequestBody.Companion.toRequestBody\nimport org.schabi.newpipe.extractor.downloader.Downloader\nimport org.schabi.newpipe.extractor.downloader.Request\nimport org.schabi.newpipe.extractor.downloader.Response\nimport org.schabi.newpipe.extractor.exceptions.ReCaptchaException\nimport java.util.concurrent.TimeUnit\n\n\nclass DownloaderTestImpl private constructor(builder: OkHttpClient.Builder) : Downloader() {\n    private val client: OkHttpClient = builder.readTimeout(30, TimeUnit.SECONDS).build()\n    override fun execute(request: Request): Response {\n        val httpMethod: String = request.httpMethod()\n        val url: String = request.url()\n        val headers: Map<String, List<String>> = request.headers()\n        val dataToSend: ByteArray? = request.dataToSend()\n        var requestBody: RequestBody? = null\n        if (dataToSend != null) {\n            requestBody = dataToSend.toRequestBody(null, 0, dataToSend.size)\n        }\n        val requestBuilder: okhttp3.Request.Builder = okhttp3.Request.Builder()\n            .method(httpMethod, requestBody).url(url)\n            .addHeader(\"User-Agent\", USER_AGENT)\n\n        for ((headerName, headerValueList) in headers) {\n            if (headerValueList.size > 1) {\n                requestBuilder.removeHeader(headerName)\n                for (headerValue in headerValueList) {\n                    requestBuilder.addHeader(headerName, headerValue)\n                }\n            } else if (headerValueList.size == 1) {\n                requestBuilder.header(headerName, headerValueList[0])\n            }\n        }\n        val response = client.newCall(requestBuilder.build()).execute()\n        if (response.code == 429) {\n            response.close()\n            throw ReCaptchaException(\"reCaptcha Challenge requested\", url)\n        }\n        val body = response.body\n        val responseBodyToReturn: String = body.string()\n        val latestUrl = response.request.url.toString()\n        return Response(\n            response.code, response.message, response.headers.toMultimap(),\n            responseBodyToReturn, latestUrl\n        )\n    }\n\n    companion object {\n        private const val USER_AGENT =\n            \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\"\n        private var instance: DownloaderTestImpl? = null\n\n        /**\n         * It's recommended to call exactly once in the entire lifetime of the application.\n         *\n         * @param builder if null, default builder will be used\n         * @return a new instance of [DownloaderTestImpl]\n         */\n        fun init(builder: OkHttpClient.Builder?): DownloaderTestImpl? {\n            instance = DownloaderTestImpl(\n                builder ?: OkHttpClient.Builder()\n            )\n            return instance\n        }\n\n        fun getInstance(): DownloaderTestImpl? {\n            if (instance == null) {\n                init(null)\n            }\n            return instance\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt",
    "content": "package com.lagradost.cloudstream3\n\nimport android.animation.ValueAnimator\nimport android.annotation.SuppressLint\nimport android.app.Dialog\nimport android.content.Context\nimport android.content.Intent\nimport android.content.SharedPreferences\nimport android.content.res.ColorStateList\nimport android.content.res.Configuration\nimport android.graphics.Rect\nimport android.os.Bundle\nimport android.util.AttributeSet\nimport android.util.Log\nimport android.view.Gravity\nimport android.view.KeyEvent\nimport android.view.Menu\nimport android.view.MenuItem\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.WindowManager\nimport android.widget.CheckBox\nimport android.widget.ImageView\nimport android.widget.LinearLayout\nimport android.widget.Toast\nimport androidx.activity.result.ActivityResultLauncher\nimport androidx.annotation.IdRes\nimport androidx.annotation.MainThread\nimport androidx.appcompat.app.AlertDialog\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.cardview.widget.CardView\nimport androidx.core.content.edit\nimport androidx.core.net.toUri\nimport androidx.core.view.children\nimport androidx.core.view.get\nimport androidx.core.view.isGone\nimport androidx.core.view.isInvisible\nimport androidx.core.view.isVisible\nimport androidx.core.view.marginStart\nimport androidx.fragment.app.FragmentActivity\nimport androidx.lifecycle.ViewModelProvider\nimport androidx.navigation.NavController\nimport androidx.navigation.NavDestination\nimport androidx.navigation.NavDestination.Companion.hierarchy\nimport androidx.navigation.NavGraph.Companion.findStartDestination\nimport androidx.navigation.NavOptions\nimport androidx.navigation.fragment.NavHostFragment\nimport androidx.navigation.ui.setupWithNavController\nimport androidx.preference.PreferenceManager\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.LinearSnapHelper\nimport androidx.recyclerview.widget.RecyclerView\nimport androidx.viewpager2.widget.ViewPager2\nimport com.google.android.gms.cast.framework.CastContext\nimport com.google.android.gms.cast.framework.Session\nimport com.google.android.gms.cast.framework.SessionManager\nimport com.google.android.gms.cast.framework.SessionManagerListener\nimport com.google.android.material.bottomnavigation.BottomNavigationView\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.google.android.material.navigationrail.NavigationRailView\nimport com.google.android.material.snackbar.Snackbar\nimport com.google.common.collect.Comparators.min\nimport com.jaredrummler.android.colorpicker.ColorPickerDialogListener\nimport com.lagradost.cloudstream3.APIHolder.allProviders\nimport com.lagradost.cloudstream3.APIHolder.apis\nimport com.lagradost.cloudstream3.APIHolder.initAll\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity.loadThemes\nimport com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent\nimport com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent\nimport com.lagradost.cloudstream3.CommonActivity.onUserLeaveHint\nimport com.lagradost.cloudstream3.CommonActivity.screenHeight\nimport com.lagradost.cloudstream3.CommonActivity.setActivityInstance\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.CommonActivity.updateLocale\nimport com.lagradost.cloudstream3.CommonActivity.updateTheme\nimport com.lagradost.cloudstream3.actions.temp.fcast.FcastManager\nimport com.lagradost.cloudstream3.databinding.ActivityMainBinding\nimport com.lagradost.cloudstream3.databinding.ActivityMainTvBinding\nimport com.lagradost.cloudstream3.databinding.BottomResultviewPreviewBinding\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.mvvm.observeNullable\nimport com.lagradost.cloudstream3.network.initClient\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.plugins.PluginManager.___DO_NOT_CALL_FROM_A_PLUGIN_loadAllOnlinePlugins\nimport com.lagradost.cloudstream3.plugins.PluginManager.loadSinglePlugin\nimport com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver\nimport com.lagradost.cloudstream3.services.SubscriptionWorkManager\nimport com.lagradost.cloudstream3.syncproviders.AccountManager\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING_PLAYER\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING_REPO\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING_RESUME_WATCHING\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING_SEARCH\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING_SHARE\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.localListApi\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.ui.APIRepository\nimport com.lagradost.cloudstream3.ui.SyncWatchType\nimport com.lagradost.cloudstream3.ui.WatchType\nimport com.lagradost.cloudstream3.ui.account.AccountHelper.showAccountSelectLinear\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO\nimport com.lagradost.cloudstream3.ui.home.HomeViewModel\nimport com.lagradost.cloudstream3.ui.library.LibraryViewModel\nimport com.lagradost.cloudstream3.ui.player.BasicLink\nimport com.lagradost.cloudstream3.ui.player.GeneratorPlayer\nimport com.lagradost.cloudstream3.ui.player.LinkGenerator\nimport com.lagradost.cloudstream3.ui.result.LinearListLayout\nimport com.lagradost.cloudstream3.ui.result.ResultViewModel2\nimport com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST\nimport com.lagradost.cloudstream3.ui.result.SyncViewModel\nimport com.lagradost.cloudstream3.ui.search.SearchFragment\nimport com.lagradost.cloudstream3.ui.search.SearchResultBuilder\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.ui.settings.Globals.updateTv\nimport com.lagradost.cloudstream3.ui.settings.SettingsGeneral\nimport com.lagradost.cloudstream3.ui.setup.HAS_DONE_SETUP_KEY\nimport com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions\nimport com.lagradost.cloudstream3.utils.ApkInstaller\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiDubstatusSettings\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isCastApiAvailable\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isLtr\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isNetworkAvailable\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isRtl\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadCache\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadRepository\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadResult\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadSearchResult\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.AppContextUtils.updateHasTrailers\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackupUtils.backup\nimport com.lagradost.cloudstream3.utils.BackupUtils.setUpBackup\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.BiometricCallback\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.biometricPrompt\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.promptInfo\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.DataStore.getKey\nimport com.lagradost.cloudstream3.utils.DataStore.setKey\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.accounts\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching\nimport com.lagradost.cloudstream3.utils.Event\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.InAppUpdater.runAutoUpdate\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\nimport com.lagradost.cloudstream3.utils.SnackbarHelper.showSnackbar\nimport com.lagradost.cloudstream3.utils.TvChannelUtils\nimport com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState\nimport com.lagradost.cloudstream3.utils.UIHelper.checkWrite\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.enableEdgeToEdgeCompat\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.getResourceColor\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UIHelper.requestRW\nimport com.lagradost.cloudstream3.utils.UIHelper.setNavigationBarColorCompat\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\nimport com.lagradost.cloudstream3.utils.USER_PROVIDER_API\nimport com.lagradost.cloudstream3.utils.USER_SELECTED_HOMEPAGE_API\nimport com.lagradost.cloudstream3.utils.setText\nimport com.lagradost.cloudstream3.utils.setTextHtml\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.safefile.SafeFile\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport java.io.File\nimport java.lang.ref.WeakReference\nimport java.net.URI\nimport java.net.URLDecoder\nimport java.nio.charset.Charset\nimport kotlin.math.abs\nimport kotlin.math.absoluteValue\nimport kotlin.system.exitProcess\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager\n\nclass MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCallback {\n    companion object {\n        var activityResultLauncher: ActivityResultLauncher<Intent>? = null\n\n        const val TAG = \"MAINACT\"\n        const val ANIMATED_OUTLINE: Boolean = false\n        var lastError: String? = null\n\n        /** Update lastError variable based on error file, to check if app crashed.\n         * Can be called multiple times without changing the lastError variable changing.\n         **/\n        fun setLastError(context: Context) {\n            if (lastError != null) return\n\n            val errorFile = context.filesDir.resolve(\"last_error\")\n            if (errorFile.exists() && errorFile.isFile) {\n                lastError = errorFile.readText(Charset.defaultCharset())\n                errorFile.delete()\n            } else {\n                lastError = null\n            }\n        }\n\n        private const val FILE_DELETE_KEY = \"FILES_TO_DELETE_KEY\"\n        const val API_NAME_EXTRA_KEY = \"API_NAME_EXTRA_KEY\"\n\n        /**\n         * Transient files to delete on application exit.\n         * Deletes files on onDestroy().\n         */\n        private var filesToDelete: Set<String>\n            // This needs to be persistent because the application may exit without calling onDestroy.\n            get() = getKey<Set<String>>(FILE_DELETE_KEY) ?: setOf()\n            private set(value) = setKey(FILE_DELETE_KEY, value)\n\n        /**\n         * Add file to delete on Exit.\n         */\n        fun deleteFileOnExit(file: File) {\n            filesToDelete = filesToDelete + file.path\n        }\n\n        /**\n         * Setting this will automatically enter the query in the search\n         * next time the search fragment is opened.\n         * This variable will clear itself after one use. Null does nothing.\n         *\n         * This is a very bad solution but I was unable to find a better one.\n         **/\n        var nextSearchQuery: String? = null\n\n        /**\n         * Fires every time a new batch of plugins have been loaded, no guarantee about how often this is run and on which thread\n         * Boolean signifies if stuff should be force reloaded (true if force reload, false if reload when necessary).\n         *\n         * The force reloading are used for plugin development to instantly reload the page on deployWithAdb\n         * */\n        val afterPluginsLoadedEvent = Event<Boolean>()\n        val mainPluginsLoadedEvent =\n            Event<Boolean>() // homepage api, used to speed up time to load for homepage\n        val afterRepositoryLoadedEvent = Event<Boolean>()\n\n        // kinda shitty solution, but cant com main->home otherwise for popups\n        val bookmarksUpdatedEvent = Event<Boolean>()\n\n        /**\n         * Used by DataStoreHelper to fully reload home when switching accounts\n         */\n        val reloadHomeEvent = Event<Boolean>()\n\n        /**\n         * Used by DataStoreHelper to fully reload library when switching accounts\n         */\n        val reloadLibraryEvent = Event<Boolean>()\n\n        /**\n         * Used by DataStoreHelper to fully reload Navigation Rail header picture\n         */\n        val reloadAccountEvent = Event<Boolean>()\n\n        /**\n         * @return true if the str has launched an app task (be it successful or not)\n         * @param isWebview does not handle providers and opening download page if true. Can still add repos and login.\n         * */\n        @Suppress(\"DEPRECATION_ERROR\")\n        fun handleAppIntentUrl(\n            activity: FragmentActivity?,\n            str: String?,\n            isWebview: Boolean,\n            extraArgs: Bundle? = null\n        ): Boolean =\n            with(activity) {\n                // TODO MUCH BETTER HANDLING\n\n                // Invalid URIs can crash\n                fun safeURI(uri: String) = safe { URI(uri) }\n\n                if (str != null && this != null) {\n                    if (str.startsWith(\"https://cs.repo\")) {\n                        val realUrl = \"https://\" + str.substringAfter(\"?\")\n                        println(\"Repository url: $realUrl\")\n                        loadRepository(realUrl)\n                        return true\n                    } else if (str.contains(APP_STRING)) {\n                        for (api in AccountManager.allApis) {\n                            if (api.isValidRedirectUrl(str)) {\n                                ioSafe {\n                                    Log.i(TAG, \"handleAppIntent $str\")\n                                    try {\n                                        val isSuccessful = api.login(str)\n                                        if (isSuccessful) {\n                                            Log.i(TAG, \"authenticated ${api.name}\")\n                                        } else {\n                                            Log.i(TAG, \"failed to authenticate ${api.name}\")\n                                        }\n                                        showToast(\n                                            if (isSuccessful) {\n                                                txt(R.string.authenticated_user, api.name)\n                                            } else {\n                                                txt(R.string.authenticated_user_fail, api.name)\n                                            }\n                                        )\n                                    } catch (t: Throwable) {\n                                        logError(t)\n                                        showToast(\n                                            txt(R.string.authenticated_user_fail, api.name)\n                                        )\n                                    }\n                                }\n                                return true\n                            }\n                        }\n                        // This specific intent is used for the gradle deployWithAdb\n                        // https://github.com/recloudstream/gradle/blob/master/src/main/kotlin/com/lagradost/cloudstream3/gradle/tasks/DeployWithAdbTask.kt#L46\n                        if (str == \"$APP_STRING:\") {\n                            ioSafe {\n                                PluginManager.___DO_NOT_CALL_FROM_A_PLUGIN_hotReloadAllLocalPlugins(\n                                    activity\n                                )\n                            }\n                        }\n                    } else if (safeURI(str)?.scheme == APP_STRING_REPO) {\n                        val url = str.replaceFirst(APP_STRING_REPO, \"https\")\n                        loadRepository(url)\n                        return true\n                    } else if (safeURI(str)?.scheme == APP_STRING_SEARCH) {\n                        val query = str.substringAfter(\"$APP_STRING_SEARCH://\")\n                        nextSearchQuery =\n                            try {\n                                URLDecoder.decode(query, \"UTF-8\")\n                            } catch (t: Throwable) {\n                                logError(t)\n                                query\n                            }\n                        // Use both navigation views to support both layouts.\n                        // It might be better to use the QuickSearch.\n                        activity?.findViewById<BottomNavigationView>(R.id.nav_view)?.selectedItemId =\n                            R.id.navigation_search\n                        activity?.findViewById<NavigationRailView>(R.id.nav_rail_view)?.selectedItemId =\n                            R.id.navigation_search\n                    } else if (safeURI(str)?.scheme == APP_STRING_PLAYER) {\n                        val uri = str.toUri()\n                        val name = uri.getQueryParameter(\"name\")\n                        val url = URLDecoder.decode(uri.authority, \"UTF-8\")\n\n                        navigate(\n                            R.id.global_to_navigation_player,\n                            GeneratorPlayer.newInstance(\n                                LinkGenerator(\n                                    listOf(BasicLink(url, name)),\n                                    extract = true,\n                                )\n                            )\n                        )\n                    } else if (safeURI(str)?.scheme == APP_STRING_RESUME_WATCHING) {\n                        val id =\n                            str.substringAfter(\"$APP_STRING_RESUME_WATCHING://\").toIntOrNull()\n                                ?: return false\n                        ioSafe {\n                            val resumeWatchingCard =\n                                HomeViewModel.getResumeWatching()?.firstOrNull { it.id == id }\n                                    ?: return@ioSafe\n                            activity.loadSearchResult(\n                                resumeWatchingCard,\n                                START_ACTION_RESUME_LATEST\n                            )\n                        }\n                    } else if (str.startsWith(APP_STRING_SHARE)) {\n                        try {\n                            val data = str.substringAfter(\"$APP_STRING_SHARE:\")\n                            val parts = data.split(\"?\", limit = 2)\n                            loadResult(\n                                String(base64DecodeArray(parts[1]), Charsets.UTF_8),\n                                String(base64DecodeArray(parts[0]), Charsets.UTF_8),\n                                \"\"\n                            )\n                            return true\n                        } catch (e: Exception) {\n                            showToast(\"Invalid Uri\", Toast.LENGTH_SHORT)\n                            return false\n                        }\n                    } else if (!isWebview) {\n                        if (str.startsWith(DOWNLOAD_NAVIGATE_TO)) {\n                            this.navigate(R.id.navigation_downloads)\n                            return true\n                        } else {\n                            val apiName = extraArgs?.getString(API_NAME_EXTRA_KEY)\n                                ?.takeIf { it.isNotBlank() }\n                            // if provided, try to match the api name instead of the api url\n                            // this is in order to also support providers that use JSON dataUrls\n                            // for example\n                            if (apiName != null) {\n                                loadResult(str, apiName, \"\")\n                                return true\n                            }\n\n                            synchronized(apis) {\n                                for (api in apis) {\n                                    if (str.startsWith(api.mainUrl)) {\n                                        loadResult(str, api.name, \"\")\n                                        return true\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n                return false\n            }\n\n\n        fun centerView(view: View?) {\n            if (view == null) return\n            try {\n                Log.v(TAG, \"centerView: $view\")\n                val r = Rect(0, 0, 0, 0)\n                view.getDrawingRect(r)\n                val x = r.centerX()\n                val y = r.centerY()\n                val dx = r.width() / 2 //screenWidth / 2\n                val dy = screenHeight / 2\n                val r2 = Rect(x - dx, y - dy, x + dx, y + dy)\n                view.requestRectangleOnScreen(r2, false)\n                // TvFocus.current =TvFocus.current.copy(y=y.toFloat())\n            } catch (_: Throwable) {\n            }\n        }\n    }\n\n\n    var lastPopup: SearchResponse? = null\n    fun loadPopup(result: SearchResponse, load: Boolean = true) {\n        lastPopup = result\n        val syncName = syncViewModel.syncName(result.apiName)\n\n        // based on apiName we decide on if it is a local list or not, this is because\n        // we want to show a bit of extra UI to sync apis\n        if (result is SyncAPI.LibraryItem && syncName != null) {\n            isLocalList = false\n            syncViewModel.setSync(syncName, result.syncId)\n            syncViewModel.updateMetaAndUser()\n        } else {\n            isLocalList = true\n            syncViewModel.clear()\n        }\n\n        if (load) {\n            viewModel.load(\n                this, result.url, result.apiName, false, if (getApiDubstatusSettings()\n                        .contains(DubStatus.Dubbed)\n                ) DubStatus.Dubbed else DubStatus.Subbed, null\n            )\n        } else {\n            viewModel.loadSmall(result)\n        }\n    }\n\n    override fun onColorSelected(dialogId: Int, color: Int) {\n        onColorSelectedEvent.invoke(Pair(dialogId, color))\n    }\n\n    override fun onDialogDismissed(dialogId: Int) {\n        onDialogDismissedEvent.invoke(dialogId)\n    }\n\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n        updateLocale() // android fucks me by chaining lang when rotating the phone\n        updateTheme(this) // Update if system theme\n\n        val navHostFragment =\n            supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment\n        navHostFragment.navController.currentDestination?.let { updateNavBar(it) }\n    }\n\n    private fun updateNavBar(destination: NavDestination) {\n        this.hideKeyboard()\n\n        // Fucks up anime info layout since that has its own layout\n        binding?.castMiniControllerHolder?.isVisible =\n            !listOf(\n                R.id.navigation_results_phone,\n                R.id.navigation_results_tv,\n                R.id.navigation_player\n            ).contains(destination.id)\n\n        val isNavVisible = listOf(\n            R.id.navigation_home,\n            R.id.navigation_search,\n            R.id.navigation_library,\n            R.id.navigation_downloads,\n            R.id.navigation_settings,\n            R.id.navigation_download_child,\n            R.id.navigation_download_queue,\n            R.id.navigation_subtitles,\n            R.id.navigation_chrome_subtitles,\n            R.id.navigation_settings_player,\n            R.id.navigation_settings_updates,\n            R.id.navigation_settings_ui,\n            R.id.navigation_settings_account,\n            R.id.navigation_settings_providers,\n            R.id.navigation_settings_general,\n            R.id.navigation_settings_extensions,\n            R.id.navigation_settings_plugins,\n            R.id.navigation_test_providers,\n        ).contains(destination.id)\n\n\n        /*val dontPush = listOf(\n            R.id.navigation_home,\n            R.id.navigation_search,\n            R.id.navigation_results_phone,\n            R.id.navigation_results_tv,\n            R.id.navigation_player,\n            R.id.navigation_quick_search,\n        ).contains(destination.id)\n\n        binding?.navHostFragment?.apply {\n            val params = layoutParams as ConstraintLayout.LayoutParams\n            val push =\n                if (!dontPush && isLayout(TV or EMULATOR)) resources.getDimensionPixelSize(R.dimen.navbar_width) else 0\n\n            if (!this.isLtr()) {\n                params.setMargins(\n                    params.leftMargin,\n                    params.topMargin,\n                    push,\n                    params.bottomMargin\n                )\n            } else {\n                params.setMargins(\n                    push,\n                    params.topMargin,\n                    params.rightMargin,\n                    params.bottomMargin\n                )\n            }\n\n            layoutParams = params\n        }*/\n\n        binding?.apply {\n            navRailView.isVisible = isNavVisible && isLandscape()\n            navView.isVisible = isNavVisible && !isLandscape()\n            navHostFragment.apply {\n                val marginPx = resources.getDimensionPixelSize(R.dimen.nav_rail_view_width)\n                layoutParams = (navHostFragment.layoutParams as ViewGroup.MarginLayoutParams).apply {\n                    marginStart = if (isNavVisible && isLandscape() && isLayout(TV or EMULATOR)) marginPx else 0\n                }\n            }\n\n            /**\n             * We need to make sure if we return to a sub-fragment,\n             * the correct navigation item is selected so that it does not\n             * highlight the wrong one in UI.\n             */\n            when (destination.id) {\n                in listOf(R.id.navigation_downloads, R.id.navigation_download_child, R.id.navigation_download_queue) -> {\n                    navRailView.menu.findItem(R.id.navigation_downloads).isChecked = true\n                    navView.menu.findItem(R.id.navigation_downloads).isChecked = true\n                }\n\n                in listOf(\n                    R.id.navigation_settings,\n                    R.id.navigation_subtitles,\n                    R.id.navigation_chrome_subtitles,\n                    R.id.navigation_settings_player,\n                    R.id.navigation_settings_updates,\n                    R.id.navigation_settings_ui,\n                    R.id.navigation_settings_account,\n                    R.id.navigation_settings_providers,\n                    R.id.navigation_settings_general,\n                    R.id.navigation_settings_extensions,\n                    R.id.navigation_settings_plugins,\n                    R.id.navigation_test_providers\n                ) -> {\n                    navRailView.menu.findItem(R.id.navigation_settings).isChecked = true\n                    navView.menu.findItem(R.id.navigation_settings).isChecked = true\n                }\n            }\n        }\n    }\n\n    //private var mCastSession: CastSession? = null\n    var mSessionManager: SessionManager? = null\n    private val mSessionManagerListener: SessionManagerListener<Session> by lazy { SessionManagerListenerImpl() }\n\n    private inner class SessionManagerListenerImpl : SessionManagerListener<Session> {\n        override fun onSessionStarting(session: Session) {\n        }\n\n        override fun onSessionStarted(session: Session, sessionId: String) {\n            invalidateOptionsMenu()\n        }\n\n        override fun onSessionStartFailed(session: Session, i: Int) {\n        }\n\n        override fun onSessionEnding(session: Session) {\n        }\n\n        override fun onSessionResumed(session: Session, wasSuspended: Boolean) {\n            invalidateOptionsMenu()\n        }\n\n        override fun onSessionResumeFailed(session: Session, i: Int) {\n        }\n\n        override fun onSessionSuspended(session: Session, i: Int) {\n        }\n\n        override fun onSessionEnded(session: Session, error: Int) {\n        }\n\n        override fun onSessionResuming(session: Session, s: String) {\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        afterPluginsLoadedEvent += ::onAllPluginsLoaded\n        setActivityInstance(this)\n        try {\n            if (isCastApiAvailable()) {\n                mSessionManager?.addSessionManagerListener(mSessionManagerListener)\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    override fun onPause() {\n        super.onPause()\n\n        // Start any delayed updates\n        if (ApkInstaller.delayedInstaller?.startInstallation() == true) {\n            Toast.makeText(this, R.string.update_started, Toast.LENGTH_LONG).show()\n        }\n        try {\n            if (isCastApiAvailable()) {\n                mSessionManager?.removeSessionManagerListener(mSessionManagerListener)\n                //mCastSession = null\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    override fun dispatchKeyEvent(event: KeyEvent): Boolean =\n        CommonActivity.dispatchKeyEvent(this, event) ?: super.dispatchKeyEvent(event)\n\n    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean =\n        CommonActivity.onKeyDown(this, keyCode, event) ?: super.onKeyDown(keyCode, event)\n\n\n    override fun onUserLeaveHint() {\n        super.onUserLeaveHint()\n        onUserLeaveHint(this)\n    }\n\n    @SuppressLint(\"ApplySharedPref\") // commit since the op needs to be synchronous\n    private fun showConfirmExitDialog(settingsManager: SharedPreferences) {\n        val confirmBeforeExit = settingsManager.getInt(getString(R.string.confirm_exit_key), -1)\n\n        if (confirmBeforeExit == 1 || (confirmBeforeExit == -1 && isLayout(PHONE))) {\n            // finish() causes a bug on some TVs where player\n            // may keep playing after closing the app.\n            if (isLayout(TV)) exitProcess(0) else finish()\n            return\n        }\n\n        val dialogView = layoutInflater.inflate(R.layout.confirm_exit_dialog, null)\n        val dontShowAgainCheck: CheckBox = dialogView.findViewById(R.id.checkboxDontShowAgain)\n        val builder: AlertDialog.Builder = AlertDialog.Builder(this)\n        builder.setView(dialogView)\n            .setTitle(R.string.confirm_exit_dialog)\n            .setNegativeButton(R.string.no) { _, _ -> /*NO-OP*/ }\n            .setPositiveButton(R.string.yes) { _, _ ->\n                if (dontShowAgainCheck.isChecked) {\n                    settingsManager.edit(commit = true) {\n                        putInt(getString(R.string.confirm_exit_key), 1)\n                    }\n                }\n                // finish() causes a bug on some TVs where player\n                // may keep playing after closing the app.\n                if (isLayout(TV)) exitProcess(0) else finish()\n            }\n\n        builder.show().setDefaultFocus()\n    }\n\n    override fun onDestroy() {\n        filesToDelete.forEach { path ->\n            val result = File(path).deleteRecursively()\n            if (result) {\n                Log.d(TAG, \"Deleted temporary file: $path\")\n            } else {\n                Log.d(TAG, \"Failed to delete temporary file: $path\")\n            }\n        }\n        filesToDelete = setOf()\n        val broadcastIntent = Intent()\n        broadcastIntent.action = \"restart_service\"\n        broadcastIntent.setClass(this, VideoDownloadRestartReceiver::class.java)\n        this.sendBroadcast(broadcastIntent)\n        afterPluginsLoadedEvent -= ::onAllPluginsLoaded\n        detachBackPressedCallback(\"MainActivityDefault\")\n        super.onDestroy()\n    }\n\n    override fun onNewIntent(intent: Intent) {\n        handleAppIntent(intent)\n        super.onNewIntent(intent)\n    }\n\n    private fun handleAppIntent(intent: Intent?) {\n        if (intent == null) return\n        val str = intent.dataString\n        loadCache()\n\n        handleAppIntentUrl(this, str, false, intent.extras)\n    }\n\n    private fun NavDestination.matchDestination(@IdRes destId: Int): Boolean =\n        hierarchy.any { it.id == destId }\n\n    private var lastNavTime = 0L\n    private fun onNavDestinationSelected(item: MenuItem, navController: NavController): Boolean {\n        val currentTime = System.currentTimeMillis()\n        // safeDebounce: Check if a previous tap happened within the last 400ms\n        if (currentTime - lastNavTime < 400) return false\n        lastNavTime = currentTime\n\n        val destinationId = item.itemId\n\n        // Check if we are already at the selected destination\n        if (navController.currentDestination?.id == destinationId) return false\n\n        // Make all nav buttons focus on this specific view when nextFocusRightId\n        val targetView = when (destinationId) {\n            // Please note that if R.id.navigation_home is readded, then it will only take affect when\n            // navigation to home for the second time as onNavDestinationSelected will not get called\n            // when first loading up the app\n\n            // R.id.navigation_home -> R.id.home_preview_change_api\n            R.id.navigation_search -> R.id.main_search\n            R.id.navigation_library -> R.id.main_search\n            R.id.navigation_downloads -> R.id.download_appbar\n            else -> null\n        }\n        if (targetView != null && isLayout(TV or EMULATOR)) {\n            val fromView = binding?.navRailView\n            if (fromView != null) {\n                fromView.nextFocusRightId = targetView\n\n                for (focusView in arrayOf(\n                    R.id.navigation_downloads,\n                    R.id.navigation_home,\n                    R.id.navigation_search,\n                    R.id.navigation_library,\n                    R.id.navigation_settings,\n                )) {\n                    fromView.findViewById<View?>(focusView)?.nextFocusRightId = targetView\n                }\n            }\n        }\n\n\n        val builder = NavOptions.Builder().setLaunchSingleTop(true).setRestoreState(true)\n            .setEnterAnim(R.anim.enter_anim)\n            .setExitAnim(R.anim.exit_anim)\n            .setPopEnterAnim(R.anim.pop_enter)\n            .setPopExitAnim(R.anim.pop_exit)\n        if (item.order and Menu.CATEGORY_SECONDARY == 0) {\n            builder.setPopUpTo(\n                navController.graph.findStartDestination().id,\n                inclusive = false,\n                saveState = true\n            )\n        }\n        return try {\n            navController.navigate(destinationId, null, builder.build())\n            navController.currentDestination?.matchDestination(destinationId) == true\n        } catch (e: IllegalArgumentException) {\n            Log.e(\"NavigationError\", \"Failed to navigate: ${e.message}\")\n            false\n        }\n    }\n\n\n    private val pluginsLock = Mutex()\n    private fun onAllPluginsLoaded(success: Boolean = false) {\n        ioSafe {\n            pluginsLock.withLock {\n                synchronized(allProviders) {\n                    // Load cloned sites after plugins have been loaded since clones depend on plugins.\n                    try {\n                        getKey<Array<SettingsGeneral.CustomSite>>(USER_PROVIDER_API)?.let { list ->\n                            list.forEach { custom ->\n                                allProviders.firstOrNull { it.javaClass.simpleName == custom.parentJavaClass }\n                                    ?.let {\n                                        allProviders.add(\n                                            it.javaClass.getDeclaredConstructor().newInstance()\n                                                .apply {\n                                                    name = custom.name\n                                                    lang = custom.lang\n                                                    mainUrl = custom.url.trimEnd('/')\n                                                    canBeOverridden = false\n                                                })\n                                    }\n                            }\n                        }\n                        // it.hashCode() is not enough to make sure they are distinct\n                        apis =\n                            allProviders.distinctBy { it.lang + it.name + it.mainUrl + it.javaClass.name }\n                        APIHolder.apiMap = null\n                    } catch (e: Exception) {\n                        logError(e)\n                    }\n                }\n            }\n        }\n    }\n\n    lateinit var viewModel: ResultViewModel2\n    lateinit var syncViewModel: SyncViewModel\n    private var libraryViewModel: LibraryViewModel? = null\n\n    /** kinda dirty, however it signals that we should use the watch status as sync or not*/\n    var isLocalList: Boolean = false\n    override fun onCreateView(name: String, context: Context, attrs: AttributeSet): View? {\n\n        viewModel = ViewModelProvider(this)[ResultViewModel2::class.java]\n        syncViewModel = ViewModelProvider(this)[SyncViewModel::class.java]\n\n        return super.onCreateView(name, context, attrs)\n    }\n\n    private fun hidePreviewPopupDialog() {\n        bottomPreviewPopup.dismissSafe(this)\n        bottomPreviewPopup = null\n        bottomPreviewBinding = null\n    }\n\n    private var bottomPreviewPopup: Dialog? = null\n    private var bottomPreviewBinding: BottomResultviewPreviewBinding? = null\n    private fun showPreviewPopupDialog(): BottomResultviewPreviewBinding {\n        val ret = (bottomPreviewBinding ?: run {\n\n            val builder: Dialog\n            val layout: Int\n\n            if (isLayout(PHONE)) {\n                builder =\n                    BottomSheetDialog(this)\n                layout = R.layout.bottom_resultview_preview\n            } else {\n                builder =\n                    Dialog(this, R.style.DialogHalfFullscreen)\n                layout = R.layout.bottom_resultview_preview_tv\n                // No way to do this in styles :(\n                builder.window?.setGravity(Gravity.CENTER_VERTICAL or Gravity.END)\n            }\n\n            val root = layoutInflater.inflate(layout, null, false)\n            val binding = BottomResultviewPreviewBinding.bind(root)\n\n            bottomPreviewBinding = binding\n            builder.setContentView(root)\n            builder.setOnDismissListener {\n                bottomPreviewPopup = null\n                bottomPreviewBinding = null\n                viewModel.clear()\n            }\n            builder.setCanceledOnTouchOutside(true)\n            builder.show()\n            bottomPreviewPopup = builder\n            binding\n        })\n\n        return ret\n    }\n\n    var binding: ActivityMainBinding? = null\n\n    object TvFocus {\n        data class FocusTarget(\n            val width: Int,\n            val height: Int,\n            val x: Float,\n            val y: Float,\n        ) {\n            companion object {\n                fun lerp(a: FocusTarget, b: FocusTarget, lerp: Float): FocusTarget {\n                    val ilerp = 1 - lerp\n                    return FocusTarget(\n                        width = (a.width * ilerp + b.width * lerp).toInt(),\n                        height = (a.height * ilerp + b.height * lerp).toInt(),\n                        x = a.x * ilerp + b.x * lerp,\n                        y = a.y * ilerp + b.y * lerp\n                    )\n                }\n            }\n        }\n\n        var last: FocusTarget = FocusTarget(0, 0, 0.0f, 0.0f)\n        var current: FocusTarget = FocusTarget(0, 0, 0.0f, 0.0f)\n\n        var focusOutline: WeakReference<View> = WeakReference(null)\n        var lastFocus: WeakReference<View> = WeakReference(null)\n        private val layoutListener: View.OnLayoutChangeListener =\n            View.OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->\n                // shitty fix for layouts\n                lastFocus.get()?.apply {\n                    updateFocusView(\n                        this, same = true\n                    )\n                    postDelayed({\n                        updateFocusView(\n                            lastFocus.get(), same = false\n                        )\n                    }, 300)\n                }\n            }\n        private val attachListener: View.OnAttachStateChangeListener =\n            object : View.OnAttachStateChangeListener {\n                override fun onViewAttachedToWindow(v: View) {\n                    updateFocusView(v)\n                }\n\n                override fun onViewDetachedFromWindow(v: View) {\n                    // removes the focus view but not the listener as updateFocusView(null) will remove the listener\n                    focusOutline.get()?.isVisible = false\n                }\n            }\n        /*private val scrollListener = object : RecyclerView.OnScrollListener() {\n            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {\n                super.onScrolled(recyclerView, dx, dy)\n                current = current.copy(x = current.x + dx, y = current.y + dy)\n                setTargetPosition(current)\n            }\n        }*/\n\n        private fun setTargetPosition(target: FocusTarget) {\n            focusOutline.get()?.apply {\n                layoutParams = layoutParams?.apply {\n                    width = target.width\n                    height = target.height\n                }\n\n                translationX = target.x\n                translationY = target.y\n                bringToFront()\n            }\n        }\n\n        private var animator: ValueAnimator? = null\n\n        /** if this is enabled it will keep the focus unmoving\n         *  during listview move */\n        private const val NO_MOVE_LIST: Boolean = false\n\n        /** If this is enabled then it will try to move the\n         * listview focus to the left instead of center */\n        private const val LEFTMOST_MOVE_LIST: Boolean = true\n\n        private val reflectedScroll by lazy {\n            try {\n                RecyclerView::class.java.declaredMethods.firstOrNull {\n                    it.name == \"scrollStep\"\n                }?.also { it.isAccessible = true }\n            } catch (t: Throwable) {\n                null\n            }\n        }\n\n        @MainThread\n        fun updateFocusView(newFocus: View?, same: Boolean = false) {\n            val focusOutline = focusOutline.get() ?: return\n            val lastView = lastFocus.get()\n            val exactlyTheSame = lastView == newFocus && newFocus != null\n            if (!exactlyTheSame) {\n                lastView?.removeOnLayoutChangeListener(layoutListener)\n                lastView?.removeOnAttachStateChangeListener(attachListener)\n                (lastView?.parent as? RecyclerView)?.apply {\n                    removeOnLayoutChangeListener(layoutListener)\n                    //removeOnScrollListener(scrollListener)\n                }\n            }\n\n            val wasGone = focusOutline.isGone\n\n            val visible =\n                newFocus != null && newFocus.measuredHeight > 0 && newFocus.measuredWidth > 0 && newFocus.isShown && newFocus.tag != \"tv_no_focus_tag\"\n            focusOutline.isVisible = visible\n\n            if (newFocus != null) {\n                lastFocus = WeakReference(newFocus)\n                val parent = newFocus.parent\n                var targetDx = 0\n                if (parent is RecyclerView) {\n                    val layoutManager = parent.layoutManager\n                    if (layoutManager is LinearListLayout && layoutManager.orientation == LinearLayoutManager.HORIZONTAL) {\n                        val dx =\n                            LinearSnapHelper().calculateDistanceToFinalSnap(layoutManager, newFocus)\n                                ?.get(0)\n\n                        if (dx != null) {\n                            val rdx = if (LEFTMOST_MOVE_LIST) {\n                                // this makes the item the leftmost in ltr, instead of center\n                                val diff =\n                                    ((layoutManager.width - layoutManager.paddingStart - newFocus.measuredWidth) / 2) - newFocus.marginStart\n                                dx + if (parent.isRtl()) {\n                                    -diff\n                                } else {\n                                    diff\n                                }\n                            } else {\n                                if (dx > 0) dx else 0\n                            }\n\n                            if (!NO_MOVE_LIST) {\n                                parent.smoothScrollBy(rdx, 0)\n                            } else {\n                                val smoothScroll = reflectedScroll\n                                if (smoothScroll == null) {\n                                    parent.smoothScrollBy(rdx, 0)\n                                } else {\n                                    try {\n                                        // this is very fucked but because it is a protected method to\n                                        // be able to compute the scroll I use reflection, scroll, then\n                                        // scroll back, then smooth scroll and set the no move\n                                        val out = IntArray(2)\n                                        smoothScroll.invoke(parent, rdx, 0, out)\n                                        val scrolledX = out[0]\n                                        if (abs(scrolledX) <= 0) { // newFocus.measuredWidth*2\n                                            smoothScroll.invoke(parent, -rdx, 0, out)\n                                            parent.smoothScrollBy(scrolledX, 0)\n                                            if (NO_MOVE_LIST) targetDx = scrolledX\n                                        }\n                                    } catch (t: Throwable) {\n                                        parent.smoothScrollBy(rdx, 0)\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n\n                val out = IntArray(2)\n                newFocus.getLocationInWindow(out)\n                val (screenX, screenY) = out\n                var (x, y) = screenX.toFloat() to screenY.toFloat()\n                val (currentX, currentY) = focusOutline.translationX to focusOutline.translationY\n\n                if (!newFocus.isLtr()) {\n                    x = x - focusOutline.rootView.width + newFocus.measuredWidth\n                }\n                x -= targetDx\n\n                // out of bounds = 0,0\n                if (screenX == 0 && screenY == 0) {\n                    focusOutline.isVisible = false\n                }\n                if (!exactlyTheSame) {\n                    (newFocus.parent as? RecyclerView)?.apply {\n                        addOnLayoutChangeListener(layoutListener)\n                        //addOnScrollListener(scrollListener)\n                    }\n                    newFocus.addOnLayoutChangeListener(layoutListener)\n                    newFocus.addOnAttachStateChangeListener(attachListener)\n                }\n                val start = FocusTarget(\n                    x = currentX,\n                    y = currentY,\n                    width = focusOutline.measuredWidth,\n                    height = focusOutline.measuredHeight\n                )\n                val end = FocusTarget(\n                    x = x,\n                    y = y,\n                    width = newFocus.measuredWidth,\n                    height = newFocus.measuredHeight\n                )\n\n                // if they are the same within then snap, aka scrolling\n                val deltaMinX = min(end.width / 2, 60.toPx)\n                val deltaMinY = min(end.height / 2, 60.toPx)\n                if (start.width == end.width && start.height == end.height && (start.x - end.x).absoluteValue < deltaMinX && (start.y - end.y).absoluteValue < deltaMinY) {\n                    animator?.cancel()\n                    last = start\n                    current = end\n                    setTargetPosition(end)\n                    return\n                }\n\n                // if running then \"reuse\"\n                if (animator?.isRunning == true) {\n                    current = end\n                    return\n                } else {\n                    animator?.cancel()\n                }\n\n\n                last = start\n                current = end\n\n                // if previously gone, then tp\n                if (wasGone) {\n                    setTargetPosition(current)\n                    return\n                }\n\n                // animate between a and b\n                animator = ValueAnimator.ofFloat(0.0f, 1.0f).apply {\n                    startDelay = 0\n                    duration = 200\n                    addUpdateListener { animation ->\n                        val animatedValue = animation.animatedValue as Float\n                        val target = FocusTarget.lerp(last, current, minOf(animatedValue, 1.0f))\n                        setTargetPosition(target)\n                    }\n                    start()\n                }\n\n                // post check\n                if (!same) {\n                    newFocus.postDelayed({\n                        updateFocusView(lastFocus.get(), same = true)\n                    }, 200)\n                }\n\n                /*\n\n                the following is working, but somewhat bad code code\n\n                if (!wasGone) {\n                    (focusOutline.parent as? ViewGroup)?.let {\n                        TransitionManager.endTransitions(it)\n                        TransitionManager.beginDelayedTransition(\n                            it,\n                            TransitionSet().addTransition(ChangeBounds())\n                                .addTransition(ChangeTransform())\n                                .setDuration(100)\n                        )\n                    }\n                }\n\n                focusOutline.layoutParams = focusOutline.layoutParams?.apply {\n                    width = newFocus.measuredWidth\n                    height = newFocus.measuredHeight\n                }\n                focusOutline.translationX = x.toFloat()\n                focusOutline.translationY = y.toFloat()*/\n            }\n        }\n    }\n\n    @Suppress(\"DEPRECATION_ERROR\")\n    override fun onCreate(savedInstanceState: Bundle?) {\n        app.initClient(this)\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n\n        setLastError(this)\n\n        val settingsForProvider = SettingsJson()\n        settingsForProvider.enableAdult =\n            settingsManager.getBoolean(getString(R.string.enable_nsfw_on_providers_key), false)\n\n        MainAPI.settingsForProvider = settingsForProvider\n\n        loadThemes(this)\n        enableEdgeToEdgeCompat()\n        setNavigationBarColorCompat(R.attr.primaryGrayBackground)\n        updateLocale()\n        super.onCreate(savedInstanceState)\n        try {\n            if (isCastApiAvailable()) {\n                CastContext.getSharedInstance(this) { it.run() }\n                    .addOnSuccessListener { mSessionManager = it.sessionManager }\n            }\n        } catch (t: Throwable) {\n            logError(t)\n        }\n\n        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)\n        updateTv()\n\n        // backup when we update the app, I don't trust myself to not boot lock users, might want to make this a setting?\n        safe {\n            val appVer = BuildConfig.VERSION_NAME\n            val lastAppAutoBackup: String = getKey(\"VERSION_NAME\") ?: \"\"\n            if (appVer != lastAppAutoBackup) {\n                setKey(\"VERSION_NAME\", BuildConfig.VERSION_NAME)\n                if (lastAppAutoBackup.isEmpty()) return@safe\n\n                safe {\n                    backup(this)\n                }\n                safe {\n                    // Recompile oat on new version\n                    PluginManager.deleteAllOatFiles(this)\n                }\n            }\n        }\n\n        // just in case, MAIN SHOULD *NEVER* BOOT LOOP CRASH\n        binding = try {\n            if (isLayout(TV or EMULATOR)) {\n                val newLocalBinding = ActivityMainTvBinding.inflate(layoutInflater, null, false)\n                setContentView(newLocalBinding.root)\n\n                if (isLayout(TV) && ANIMATED_OUTLINE) {\n                    TvFocus.focusOutline = WeakReference(newLocalBinding.focusOutline)\n                    newLocalBinding.root.viewTreeObserver.addOnScrollChangedListener {\n                        TvFocus.updateFocusView(TvFocus.lastFocus.get(), same = true)\n                    }\n                    newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->\n                        TvFocus.updateFocusView(newFocus)\n                    }\n                } else {\n                    newLocalBinding.focusOutline.isVisible = false\n                }\n\n                if (isLayout(TV)) {\n                    // Put here any button you don't want focusing it to center the view\n                    val exceptionButtons = listOf(\n                        //R.id.home_preview_play_btt,\n                        R.id.home_preview_info_btt,\n                        R.id.home_preview_hidden_next_focus,\n                        R.id.home_preview_hidden_prev_focus,\n                        R.id.result_play_movie_button,\n                        R.id.result_play_series_button,\n                        R.id.result_resume_series_button,\n                        R.id.result_play_trailer_button,\n                        R.id.result_bookmark_Button,\n                        R.id.result_favorite_Button,\n                        R.id.result_subscribe_Button,\n                        R.id.result_search_Button,\n                        R.id.result_episodes_show_button,\n                    )\n\n                    newLocalBinding.root.viewTreeObserver.addOnGlobalFocusChangeListener { _, newFocus ->\n                        if (exceptionButtons.contains(newFocus?.id)) return@addOnGlobalFocusChangeListener\n                        centerView(newFocus)\n                    }\n                }\n\n                ActivityMainBinding.bind(newLocalBinding.root) // this may crash\n            } else {\n                val newLocalBinding = ActivityMainBinding.inflate(layoutInflater, null, false)\n                setContentView(newLocalBinding.root)\n                newLocalBinding\n            }\n        } catch (t: Throwable) {\n            showToast(txt(R.string.unable_to_inflate, t.message ?: \"\"), Toast.LENGTH_LONG)\n            null\n        }\n\n        binding?.apply {\n            fixSystemBarsPadding(\n                navView,\n                heightResId = R.dimen.nav_view_height,\n                padTop = false,\n                overlayCutout = false\n            )\n\n            fixSystemBarsPadding(\n                navRailView,\n                widthResId = R.dimen.nav_rail_view_width,\n                padRight = false,\n                padTop = false\n            )\n        }\n\n        // overscan\n        val padding = settingsManager.getInt(getString(R.string.overscan_key), 0).toPx\n        binding?.homeRoot?.setPadding(padding, padding, padding, padding)\n\n        changeStatusBarState(isLayout(EMULATOR))\n\n        /** Biometric stuff for users without accounts **/\n        val noAccounts = settingsManager.getBoolean(\n            getString(R.string.skip_startup_account_select_key),\n            false\n        ) || accounts.count() <= 1\n\n        if (isLayout(PHONE) && isAuthEnabled(this) && noAccounts) {\n            if (deviceHasPasswordPinLock(this)) {\n                startBiometricAuthentication(this, R.string.biometric_authentication_title, false)\n\n                promptInfo?.let { prompt ->\n                    biometricPrompt?.authenticate(prompt)\n                }\n\n                // hide background while authenticating, Sorry moms & dads 🙏\n                binding?.navHostFragment?.isInvisible = true\n            }\n        }\n\n        // Automatically enable jsdelivr if cant connect to raw.githubusercontent.com\n        if (this.getKey<Boolean>(getString(R.string.jsdelivr_proxy_key)) == null && isNetworkAvailable()) {\n            main {\n                if (checkGithubConnectivity()) {\n                    this.setKey(getString(R.string.jsdelivr_proxy_key), false)\n                } else {\n                    this.setKey(getString(R.string.jsdelivr_proxy_key), true)\n                    showSnackbar(\n                        this@MainActivity,\n                        R.string.jsdelivr_enabled,\n                        Snackbar.LENGTH_LONG,\n                        R.string.revert\n                    ) { setKey(getString(R.string.jsdelivr_proxy_key), false) }\n                }\n            }\n        }\n\n        ioSafe { SafeFile.check(this@MainActivity) }\n\n        if (PluginManager.checkSafeModeFile()) {\n            safe {\n                showToast(R.string.safe_mode_file, Toast.LENGTH_LONG)\n            }\n        } else if (lastError == null) {\n            ioSafe {\n                DataStoreHelper.currentHomePage?.let { homeApi ->\n                    mainPluginsLoadedEvent.invoke(loadSinglePlugin(this@MainActivity, homeApi))\n                } ?: run {\n                    mainPluginsLoadedEvent.invoke(false)\n                }\n\n                ioSafe {\n                    if (settingsManager.getBoolean(\n                            getString(R.string.auto_update_plugins_key),\n                            true\n                        )\n                    ) {\n                        PluginManager.___DO_NOT_CALL_FROM_A_PLUGIN_updateAllOnlinePluginsAndLoadThem(\n                            this@MainActivity\n                        )\n                    } else {\n                        ___DO_NOT_CALL_FROM_A_PLUGIN_loadAllOnlinePlugins(this@MainActivity)\n                    }\n\n                    //Automatically download not existing plugins, using mode specified.\n                    val autoDownloadPlugin = AutoDownloadMode.getEnum(\n                        settingsManager.getInt(\n                            getString(R.string.auto_download_plugins_key),\n                            0\n                        )\n                    ) ?: AutoDownloadMode.Disable\n                    if (autoDownloadPlugin != AutoDownloadMode.Disable) {\n                        PluginManager.___DO_NOT_CALL_FROM_A_PLUGIN_downloadNotExistingPluginsAndLoad(\n                            this@MainActivity,\n                            autoDownloadPlugin\n                        )\n                    }\n                }\n\n                ioSafe {\n                    PluginManager.___DO_NOT_CALL_FROM_A_PLUGIN_loadAllLocalPlugins(\n                        this@MainActivity,\n                        false\n                    )\n                }\n\n// Add your channel creation here\n\n            }\n        } else {\n            val builder: AlertDialog.Builder = AlertDialog.Builder(this)\n            builder.setTitle(R.string.safe_mode_title)\n            builder.setMessage(R.string.safe_mode_description)\n            builder.apply {\n                setPositiveButton(R.string.safe_mode_crash_info) { _, _ ->\n                    val tbBuilder: AlertDialog.Builder = AlertDialog.Builder(context)\n                    tbBuilder.setTitle(R.string.safe_mode_title)\n                    tbBuilder.setMessage(lastError)\n                    tbBuilder.show()\n                }\n\n                setNegativeButton(\"Ok\") { _, _ -> }\n            }\n            builder.show().setDefaultFocus()\n        }\n\n\n        fun setUserData(status: Resource<SyncAPI.AbstractSyncStatus>?) {\n            if (isLocalList) return\n            bottomPreviewBinding?.apply {\n                when (status) {\n                    is Resource.Success -> {\n                        resultviewPreviewBookmark.isEnabled = true\n                        resultviewPreviewBookmark.setText(status.value.status.stringRes)\n                        resultviewPreviewBookmark.setIconResource(status.value.status.iconRes)\n                    }\n\n                    is Resource.Failure -> {\n                        resultviewPreviewBookmark.isEnabled = false\n                        resultviewPreviewBookmark.setIconResource(R.drawable.ic_baseline_bookmark_border_24)\n                        resultviewPreviewBookmark.text = status.errorString\n                    }\n\n                    else -> {\n                        resultviewPreviewBookmark.isEnabled = false\n                        resultviewPreviewBookmark.setIconResource(R.drawable.ic_baseline_bookmark_border_24)\n                        resultviewPreviewBookmark.setText(R.string.loading)\n                    }\n                }\n            }\n        }\n\n        fun setWatchStatus(state: WatchType?) {\n            if (!isLocalList || state == null) return\n\n            bottomPreviewBinding?.resultviewPreviewBookmark?.apply {\n                setIconResource(state.iconRes)\n                setText(state.stringRes)\n            }\n        }\n\n        fun setSubscribeStatus(state: Boolean?) {\n            bottomPreviewBinding?.resultviewPreviewSubscribe?.apply {\n                if (state != null) {\n                    val drawable = if (state) {\n                        R.drawable.ic_baseline_notifications_active_24\n                    } else {\n                        R.drawable.baseline_notifications_none_24\n                    }\n                    setImageResource(drawable)\n                }\n                isVisible = state != null\n\n                setOnClickListener {\n                    viewModel.toggleSubscriptionStatus(context) { newStatus: Boolean? ->\n                        if (newStatus == null) return@toggleSubscriptionStatus\n\n                        val message = if (newStatus) {\n                            // Kinda icky to have this here, but it works.\n                            SubscriptionWorkManager.enqueuePeriodicWork(context)\n                            R.string.subscription_new\n                        } else {\n                            R.string.subscription_deleted\n                        }\n\n                        val name = (viewModel.page.value as? Resource.Success)?.value?.title\n                            ?: txt(R.string.no_data).asStringNull(context) ?: \"\"\n                        showToast(txt(message, name), Toast.LENGTH_SHORT)\n                    }\n                }\n            }\n        }\n\n        observe(viewModel.watchStatus, ::setWatchStatus)\n        observe(syncViewModel.userData, ::setUserData)\n        observeNullable(viewModel.subscribeStatus, ::setSubscribeStatus)\n\n        observeNullable(viewModel.page) { resource ->\n            if (resource == null) {\n                hidePreviewPopupDialog()\n                return@observeNullable\n            }\n            when (resource) {\n                is Resource.Failure -> {\n                    showToast(R.string.error)\n                    viewModel.clear()\n                    hidePreviewPopupDialog()\n                }\n\n                is Resource.Loading -> {\n                    showPreviewPopupDialog().apply {\n                        resultviewPreviewLoading.isVisible = true\n                        resultviewPreviewResult.isVisible = false\n                        resultviewPreviewLoadingShimmer.startShimmer()\n                    }\n                }\n\n                is Resource.Success -> {\n                    val d = resource.value\n                    showPreviewPopupDialog().apply {\n                        resultviewPreviewLoading.isVisible = false\n                        resultviewPreviewResult.isVisible = true\n                        resultviewPreviewLoadingShimmer.stopShimmer()\n\n                        resultviewPreviewTitle.text = d.title\n\n                        resultviewPreviewMetaType.setText(d.typeText)\n                        resultviewPreviewMetaYear.setText(d.yearText)\n                        resultviewPreviewMetaDuration.setText(d.durationText)\n                        resultviewPreviewMetaRating.setText(d.ratingText)\n\n                        resultviewPreviewDescription.setTextHtml(d.plotText)\n                        if (isLayout(PHONE)) {\n                            resultviewPreviewPoster.loadImage(\n                                d.posterImage ?: d.posterBackgroundImage,\n                                headers = d.posterHeaders\n                            )\n                        } else {\n                            resultviewPreviewPoster.loadImage(\n                                d.posterBackgroundImage ?: d.posterImage,\n                                headers = d.posterHeaders\n                            )\n                        }\n\n                        setUserData(syncViewModel.userData.value)\n                        setWatchStatus(viewModel.watchStatus.value)\n                        setSubscribeStatus(viewModel.subscribeStatus.value)\n\n                        resultviewPreviewBookmark.setOnClickListener {\n                            //viewModel.updateWatchStatus(WatchType.PLANTOWATCH)\n                            if (isLocalList) {\n                                val value = viewModel.watchStatus.value ?: WatchType.NONE\n\n                                this@MainActivity.showBottomDialog(\n                                    WatchType.entries.map { getString(it.stringRes) }.toList(),\n                                    value.ordinal,\n                                    this@MainActivity.getString(R.string.action_add_to_bookmarks),\n                                    showApply = false,\n                                    {}) {\n                                    viewModel.updateWatchStatus(\n                                        WatchType.entries[it],\n                                        this@MainActivity\n                                    )\n                                }\n                            } else {\n                                val value =\n                                    (syncViewModel.userData.value as? Resource.Success)?.value?.status\n                                        ?: SyncWatchType.NONE\n\n                                this@MainActivity.showBottomDialog(\n                                    SyncWatchType.entries.map { getString(it.stringRes) }.toList(),\n                                    value.ordinal,\n                                    this@MainActivity.getString(R.string.action_add_to_bookmarks),\n                                    showApply = false,\n                                    {}) {\n                                    syncViewModel.setStatus(SyncWatchType.entries[it].internalId)\n                                    syncViewModel.publishUserData()\n                                }\n                            }\n                        }\n\n                        observeNullable(viewModel.favoriteStatus) observeFavoriteStatus@{ isFavorite ->\n                            resultviewPreviewFavorite.isVisible = isFavorite != null\n                            if (isFavorite == null) return@observeFavoriteStatus\n\n                            val drawable = if (isFavorite) {\n                                R.drawable.ic_baseline_favorite_24\n                            } else {\n                                R.drawable.ic_baseline_favorite_border_24\n                            }\n\n                            resultviewPreviewFavorite.setImageResource(drawable)\n                        }\n\n                        resultviewPreviewFavorite.setOnClickListener {\n                            viewModel.toggleFavoriteStatus(this@MainActivity) { newStatus: Boolean? ->\n                                if (newStatus == null) return@toggleFavoriteStatus\n\n                                val message = if (newStatus) {\n                                    R.string.favorite_added\n                                } else {\n                                    R.string.favorite_removed\n                                }\n\n                                val name = (viewModel.page.value as? Resource.Success)?.value?.title\n                                    ?: txt(R.string.no_data).asStringNull(this@MainActivity) ?: \"\"\n                                showToast(txt(message, name), Toast.LENGTH_SHORT)\n                            }\n                        }\n\n                        if (isLayout(PHONE)) // dont want this clickable on tv layout\n                            resultviewPreviewDescription.setOnClickListener { view ->\n                                view.context?.let { ctx ->\n                                    val builder: AlertDialog.Builder =\n                                        AlertDialog.Builder(ctx, R.style.AlertDialogCustom)\n                                    builder.setMessage(d.plotText.asString(ctx).html())\n                                        .setTitle(d.plotHeaderText.asString(ctx))\n                                        .show()\n                                }\n                            }\n\n                        resultviewPreviewMoreInfo.setOnClickListener {\n                            viewModel.clear()\n                            hidePreviewPopupDialog()\n                            lastPopup?.let {\n                                loadSearchResult(it)\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n//        ioSafe {\n//            val plugins =\n//                RepositoryParser.getRepoPlugins(\"https://raw.githubusercontent.com/recloudstream/TestPlugin/master/repo.json\")\n//                    ?: emptyList()\n//            plugins.map {\n//                println(\"Load plugin: ${it.name} ${it.url}\")\n//                RepositoryParser.loadSiteTemp(applicationContext, it.url, it.name)\n//            }\n//        }\n\n        // init accounts\n        ioSafe {\n            // we need to run this after we init all apis, otherwise currentSyncApi will fuck itself\n            this@MainActivity.runOnUiThread {\n                // Change library icon with logo of current api in sync\n                libraryViewModel =\n                    ViewModelProvider(this@MainActivity)[LibraryViewModel::class.java]\n                libraryViewModel?.currentApiName?.observe(this@MainActivity) {\n                    val syncAPI = libraryViewModel?.currentSyncApi\n                    Log.i(\"SYNC_API\", \"${syncAPI?.name}, ${syncAPI?.idPrefix}\")\n                    val icon = if (syncAPI?.idPrefix == localListApi.idPrefix) {\n                        R.drawable.library_icon_selector\n                    } else {\n                        syncAPI?.icon ?: R.drawable.library_icon_selector\n                    }\n\n                    binding?.apply {\n                        navRailView.menu.findItem(R.id.navigation_library)?.setIcon(icon)\n                        navView.menu.findItem(R.id.navigation_library)?.setIcon(icon)\n                    }\n                }\n            }\n        }\n\n        SearchResultBuilder.updateCache(this)\n\n        ioSafe {\n            initAll()\n            // No duplicates (which can happen by registerMainAPI)\n            apis = synchronized(allProviders) {\n                allProviders.distinctBy { it }\n            }\n        }\n\n        //  val navView: BottomNavigationView = findViewById(R.id.nav_view)\n        setUpBackup()\n\n        CommonActivity.init(this)\n        val navHostFragment =\n            supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment\n        val navController = navHostFragment.navController\n\n        navController.addOnDestinationChangedListener { _: NavController, navDestination: NavDestination, bundle: Bundle? ->\n            // Intercept search and add a query\n            updateNavBar(navDestination)\n            if (navDestination.matchDestination(R.id.navigation_search) && !nextSearchQuery.isNullOrBlank()) {\n                bundle?.apply {\n                    this.putString(SearchFragment.SEARCH_QUERY, nextSearchQuery)\n                }\n            }\n\n            if (navDestination.matchDestination(R.id.navigation_home)) {\n                attachBackPressedCallback(\"MainActivity\") {\n                    showConfirmExitDialog(settingsManager)\n                }\n            } else detachBackPressedCallback(\"MainActivity\")\n        }\n\n        //val navController = findNavController(R.id.nav_host_fragment)\n\n        /*navOptions = NavOptions.Builder()\n            .setLaunchSingleTop(true)\n            .setEnterAnim(R.anim.nav_enter_anim)\n            .setExitAnim(R.anim.nav_exit_anim)\n            .setPopEnterAnim(R.anim.nav_pop_enter)\n            .setPopExitAnim(R.anim.nav_pop_exit)\n            .setPopUpTo(navController.graph.startDestination, false)\n            .build()*/\n\n        val rippleColor = ColorStateList.valueOf(getResourceColor(R.attr.colorPrimary, 0.1f))\n\n        binding?.navView?.apply {\n            itemRippleColor = rippleColor\n            itemActiveIndicatorColor = rippleColor\n            setupWithNavController(navController)\n            setOnItemSelectedListener { item ->\n                onNavDestinationSelected(\n                    item,\n                    navController\n                )\n            }\n\n        }\n\n        binding?.navRailView?.apply {\n            if (isLayout(PHONE)) {\n                itemRippleColor = rippleColor\n                itemActiveIndicatorColor = rippleColor\n            } else {\n                val rippleColor = ColorStateList.valueOf(getResourceColor(R.attr.textColor, 1.0f))\n                val rippleColorTransparent =\n                    ColorStateList.valueOf(getResourceColor(R.attr.textColor, 0.2f))\n                itemSpacing = 12.toPx // expandedItemSpacing does not have an attr\n                itemRippleColor = rippleColorTransparent\n                itemActiveIndicatorColor = rippleColor\n            }\n            setupWithNavController(navController)\n            /*if (isLayout(TV or EMULATOR)) {\n                background?.alpha = 200\n            } else {\n                background?.alpha = 255\n            }*/\n\n            setOnItemSelectedListener { item ->\n                onNavDestinationSelected(\n                    item,\n                    navController\n                )\n            }\n\n\n            fun noFocus(view: View) {\n                view.tag = view.context.getString(R.string.tv_no_focus_tag)\n                (view as? ViewGroup)?.let {\n                    for (child in it.children) {\n                        noFocus(child)\n                    }\n                }\n            }\n            //noFocus(this)\n\n            val navProfileRoot = findViewById<LinearLayout>(R.id.nav_footer_root)\n\n            if (isLayout(TV or EMULATOR)) {\n                val navProfilePic = findViewById<ImageView>(R.id.nav_footer_profile_pic)\n                val navProfileCard = findViewById<CardView>(R.id.nav_footer_profile_card)\n\n                navProfileCard?.setOnClickListener {\n                    showAccountSelectLinear()\n                }\n\n                val homeViewModel =\n                    ViewModelProvider(this@MainActivity)[HomeViewModel::class.java]\n\n                observe(homeViewModel.currentAccount) { currentAccount ->\n                    if (currentAccount != null) {\n                        navProfilePic?.loadImage(\n                            currentAccount.image\n                        )\n                        navProfileRoot.isVisible = true\n                    } else {\n                        navProfileRoot.isGone = true\n                    }\n                }\n            } else {\n                navProfileRoot.isGone = true\n            }\n        }\n\n        val rail = binding?.navRailView\n        if (rail != null) {\n            binding?.navRailView?.labelVisibilityMode =\n                NavigationRailView.LABEL_VISIBILITY_UNLABELED\n            //val focus = mutableSetOf<Int>()\n\n            var prevId: Int? = null\n            var prevView: View? = null\n\n            // The genius engineers at google did not actually \n            // write a nextFocus for the navrail\n            rail.findViewById<View?>(R.id.navigation_settings)?.nextFocusDownId =\n                R.id.nav_footer_profile_card\n            for (id in arrayOf(\n                R.id.navigation_home,\n                R.id.navigation_search,\n                R.id.navigation_library,\n                R.id.navigation_downloads,\n                R.id.navigation_settings\n            )) {\n                val view = rail.findViewById<View?>(id) ?: continue\n                prevId?.let { view.nextFocusUpId = it }\n                prevView?.nextFocusDownId = id\n\n                prevView = view\n                prevId = id\n                // Uncomment for focus expand\n                /*if (!isLayout(TV)) {\n                    view.onFocusChangeListener = null\n                } else {\n                    view.onFocusChangeListener =\n                        View.OnFocusChangeListener { v, hasFocus ->\n                            if (hasFocus) {\n                                focus += id\n                                binding?.navRailView?.labelVisibilityMode =\n                                    NavigationRailView.LABEL_VISIBILITY_LABELED\n                                binding?.navRailView?.expand()\n                            } else {\n                                focus -= id\n                                v.post {\n                                    if (focus.isEmpty()) {\n                                        binding?.navRailView?.labelVisibilityMode =\n                                            NavigationRailView.LABEL_VISIBILITY_UNLABELED\n                                        binding?.navRailView?.collapse()\n                                    }\n                                }\n                            }\n                        }\n                }*/\n            }\n        }\n\n        // Navigation button long click functionality to scroll to top\n        for (view in listOf(binding?.navView, binding?.navRailView)) {\n            view?.findViewById<View?>(R.id.navigation_home)?.setOnLongClickListener {\n                val recycler = binding?.root?.findViewById<RecyclerView?>(R.id.home_master_recycler)\n                recycler?.smoothScrollToPosition(0)\n                return@setOnLongClickListener recycler != null\n            }\n\n            view?.findViewById<View?>(R.id.navigation_library)?.setOnLongClickListener {\n                val viewPager = binding?.root?.findViewById<ViewPager2?>(R.id.viewpager)\n                    ?: return@setOnLongClickListener false\n                try {\n                    val children = (viewPager[0] as? RecyclerView)?.children\n                        ?: return@setOnLongClickListener false\n                    for (child in children) {\n                        child.findViewById<RecyclerView?>(R.id.page_recyclerview)\n                            ?.smoothScrollToPosition(0)\n                    }\n                } catch (_: IndexOutOfBoundsException) {\n                } catch (t: Throwable) {\n                    logError(t)\n                }\n                return@setOnLongClickListener true\n            }\n\n            view?.findViewById<View?>(R.id.navigation_search)?.setOnLongClickListener {\n                for (recyclerId in arrayOf(\n                    R.id.search_master_recycler,\n                    R.id.search_autofit_results,\n                    R.id.search_history_recycler\n                )) {\n                    val recycler = binding?.root?.findViewById<RecyclerView?>(recyclerId)\n                        ?: return@setOnLongClickListener false\n                    recycler.smoothScrollToPosition(0)\n                }\n                return@setOnLongClickListener true\n            }\n\n            view?.findViewById<View?>(R.id.navigation_downloads)?.setOnLongClickListener {\n                val recycler: RecyclerView? = binding?.root?.findViewById(R.id.download_list)\n                    ?: binding?.root?.findViewById(R.id.download_child_list)\n                recycler?.smoothScrollToPosition(0)\n                return@setOnLongClickListener recycler != null\n            }\n        }\n\n        loadCache()\n        updateHasTrailers()\n        /*nav_view.setOnNavigationItemSelectedListener { item ->\n            when (item.itemId) {\n                R.id.navigation_home -> {\n                    navController.navigate(R.id.navigation_home, null, navOptions)\n                }\n                R.id.navigation_search -> {\n                    navController.navigate(R.id.navigation_search, null, navOptions)\n                }\n                R.id.navigation_downloads -> {\n                    navController.navigate(R.id.navigation_downloads, null, navOptions)\n                }\n                R.id.navigation_settings -> {\n                    navController.navigate(R.id.navigation_settings, null, navOptions)\n                }\n            }\n            true\n        }*/\n\n\n        if (!checkWrite()) {\n            requestRW()\n            if (checkWrite()) return\n        }\n        //CastButtonFactory.setUpMediaRouteButton(this, media_route_button)\n\n        // THIS IS CURRENTLY REMOVED BECAUSE HIGHER VERS OF ANDROID NEEDS A NOTIFICATION\n        //if (!VideoDownloadManager.isMyServiceRunning(this, VideoDownloadKeepAliveService::class.java)) {\n        //    val mYourService = VideoDownloadKeepAliveService()\n        //    val mServiceIntent = Intent(this, mYourService::class.java).putExtra(START_VALUE_KEY, RESTART_ALL_DOWNLOADS_AND_QUEUE)\n        //    this.startService(mServiceIntent)\n        //}\n//settingsManager.getBoolean(\"disable_automatic_data_downloads\", true) &&\n\n        // TODO RETURN TO TRUE\n        /*\n        if (isUsingMobileData()) {\n            Toast.makeText(this, \"Downloads not resumed on mobile data\", Toast.LENGTH_LONG).show()\n        } else {\n            val keys = getKeys(VideoDownloadManager.KEY_RESUME_PACKAGES)\n            val resumePkg = keys.mapNotNull { k -> getKey<VideoDownloadManager.DownloadResumePackage>(k) }\n\n            // To remove a bug where this is permanent\n            removeKeys(VideoDownloadManager.KEY_RESUME_PACKAGES)\n\n            for (pkg in resumePkg) { // ADD ALL CURRENT DOWNLOADS\n                VideoDownloadManager.downloadFromResume(this, pkg, false)\n            }\n\n            // ADD QUEUE\n            // array needed because List gets cast exception to linkedList for some unknown reason\n            val resumeQueue =\n                getKey<Array<VideoDownloadManager.DownloadQueueResumePackage>>(VideoDownloadManager.KEY_RESUME_QUEUE_PACKAGES)\n\n            resumeQueue?.sortedBy { it.index }?.forEach {\n                VideoDownloadManager.downloadFromResume(this, it.pkg)\n            }\n        }*/\n\n\n        /*\n        val castContext = CastContext.getSharedInstance(applicationContext)\n         fun buildMediaQueueItem(video: String): MediaQueueItem {\n           // val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_PHOTO)\n            //movieMetadata.putString(MediaMetadata.KEY_TITLE, \"CloudStream\")\n            val mediaInfo = MediaInfo.Builder(video.toUri().toString())\n                .setStreamType(MediaInfo.STREAM_TYPE_NONE)\n                .setContentType(MimeTypes.IMAGE_JPEG)\n               // .setMetadata(movieMetadata).build()\n                .build()\n            return MediaQueueItem.Builder(mediaInfo).build()\n        }*/\n        /*\n        castContext.addCastStateListener { state ->\n            if (state == CastState.CONNECTED) {\n                println(\"TESTING\")\n                val isCasting = castContext?.sessionManager?.currentCastSession?.remoteMediaClient?.currentItem != null\n                if(!isCasting) {\n                    val castPlayer = CastPlayer(castContext)\n                    println(\"LOAD ITEM\")\n\n                    castPlayer.loadItem(buildMediaQueueItem(\"https://cdn.discordapp.com/attachments/551382684560261121/730169809408622702/ChromecastLogo6.png\"),0)\n                }\n            }\n        }*/\n        /*thread {\n            createISO()\n        }*/\n\n        if (BuildConfig.DEBUG) {\n            var providersAndroidManifestString = \"Current androidmanifest should be:\\n\"\n            synchronized(allProviders) {\n                for (api in allProviders) {\n                    providersAndroidManifestString += \"<data android:scheme=\\\"https\\\" android:host=\\\"${\n                        api.mainUrl.removePrefix(\n                            \"https://\"\n                        )\n                    }\\\" android:pathPrefix=\\\"/\\\"/>\\n\"\n                }\n            }\n            println(providersAndroidManifestString)\n        }\n\n        handleAppIntent(intent)\n\n        ioSafe {\n            runAutoUpdate()\n        }\n\n        FcastManager().init(this, false)\n\n        APIRepository.dubStatusActive = getApiDubstatusSettings()\n\n        try {\n            // this ensures that no unnecessary space is taken\n            loadCache()\n            File(filesDir, \"exoplayer\").deleteRecursively() // old cache\n            deleteFileOnExit(File(cacheDir, \"exoplayer\"))   // current cache\n        } catch (e: Exception) {\n            logError(e)\n        }\n        println(\"Loaded everything\")\n\n        ioSafe {\n            migrateResumeWatching()\n        }\n\n        main {\n            val channelId =\n                TvChannelUtils.getChannelId(this@MainActivity, getString(R.string.app_name))\n            if (channelId == null) {\n                Log.d(\"TvChannel\", \"Channel not found, creating\")\n                TvChannelUtils.createTvChannel(this@MainActivity)\n            } else {\n                Log.d(\"TvChannel\", \"Channel ID: $channelId\")\n            }\n        }\n\n        getKey<String>(USER_SELECTED_HOMEPAGE_API)?.let { homepage ->\n            DataStoreHelper.currentHomePage = homepage\n            removeKey(USER_SELECTED_HOMEPAGE_API)\n        }\n\n        try {\n            if (getKey(HAS_DONE_SETUP_KEY, false) != true) {\n                navController.navigate(R.id.navigation_setup_language)\n                // If no plugins bring up extensions screen\n            } else if (PluginManager.getPluginsOnline().isEmpty()\n                && PluginManager.getPluginsLocal().isEmpty()\n//                && PREBUILT_REPOSITORIES.isNotEmpty()\n            ) {\n                navController.navigate(\n                    R.id.navigation_setup_extensions,\n                    SetupFragmentExtensions.newInstance(false)\n                )\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n\n//        Used to check current focus for TV\n//        main {\n//            while (true) {\n//                delay(5000)\n//                println(\"Current focus: $currentFocus\")\n//                showToast(this, currentFocus.toString(), Toast.LENGTH_LONG)\n//            }\n//        }\n\n        attachBackPressedCallback(\"MainActivityDefault\") {\n            setNavigationBarColorCompat(R.attr.primaryGrayBackground)\n            updateLocale()\n            runDefault()\n        }\n        \n        // Start the download queue\n        DownloadQueueManager.init(this)\n    }\n\n    /** Biometric stuff **/\n    override fun onAuthenticationSuccess() {\n        // make background (nav host fragment) visible again\n        binding?.navHostFragment?.isInvisible = false\n    }\n\n    override fun onAuthenticationError() {\n        finish()\n    }\n\n    suspend fun checkGithubConnectivity(): Boolean {\n        return try {\n            app.get(\n                \"https://raw.githubusercontent.com/recloudstream/.github/master/connectivitycheck\",\n                timeout = 5\n            ).text.trim() == \"ok\"\n        } catch (t: Throwable) {\n            false\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/AlwaysAskAction.kt",
    "content": "package com.lagradost.cloudstream3.actions\n\nimport android.content.Context\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.txt\n\nclass AlwaysAskAction : VideoClickAction() {\n    override val name = txt(R.string.player_settings_always_ask)\n    override val isPlayer = true\n\n    // Only show in settings, not on a video\n    override fun shouldShow(context: Context?, video: ResultEpisode?): Boolean = video == null\n    \n    override suspend fun runAction(\n        context: Context?,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        // This is handled specially in ResultViewModel2.kt by detecting the AlwaysAskAction\n        // and showing the player selection dialog instead of executing the action directly\n        throw NotImplementedError(\"AlwaysAskAction is handled specially by the calling code\")\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/OpenInAppAction.kt",
    "content": "package com.lagradost.cloudstream3.actions\n\nimport android.app.Activity\nimport android.content.ComponentName\nimport android.content.Context\nimport android.content.Intent\nimport androidx.core.content.FileProvider\nimport androidx.core.net.toUri\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.ui.result.ResultFragment\nimport com.lagradost.cloudstream3.utils.UiText\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isAppInstalled\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport java.io.File\n\nfun updateDurationAndPosition(position: Long, duration: Long) {\n    if (position <= 0 || duration <= 0) return\n    val episode = getKey<ResultEpisode>(\"last_opened\") ?: return\n    DataStoreHelper.setViewPosAndResume(episode.id, position, duration, episode, null)\n    ResultFragment.updateUI()\n}\n\n/**\n * Util method that may be helpful for creating intents for apps that support m3u8 files.\n * All sources are written to a temporary m3u8 file, which is then sent to the app.\n */\nfun makeTempM3U8Intent(\n    context: Context,\n    intent: Intent,\n    result: LinkLoadingResult\n) {\n    if (result.links.size == 1) {\n        intent.setDataAndType(result.links.first().url.toUri(), \"video/*\")\n        return\n    }\n\n    intent.apply {\n        addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)\n        addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)\n        addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)\n        addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)\n    }\n\n    val outputFile = File.createTempFile(\"mirrorlist\", \".m3u8\", context.cacheDir)\n    var text = \"#EXTM3U\\n#EXT-X-VERSION:3\"\n\n    result.links.forEach { link ->\n        text += \"\\n#EXTINF:0,${link.name}\\n${link.url}\"\n    }\n\n    //With subtitles it doesn't work for no reason :(\n    /*for (sub in result.subs) {\n        val normalizedName = sub.name.replace(\"[^a-zA-Z0-9 ]\".toRegex(), \"\")\n        text += \"\\n#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=\\\"subs\\\",NAME=\\\"${normalizedName}\\\",DEFAULT=NO,AUTOSELECT=NO,FORCED=NO,LANGUAGE=\\\"${sub.languageCode}\\\",URI=\\\"${sub.url}\\\"\"\n    }*/\n\n    text += \"\\n#EXT-X-ENDLIST\"\n    outputFile.writeText(text)\n\n    intent.setDataAndType(\n        FileProvider.getUriForFile(\n            context,\n            context.applicationContext.packageName + \".provider\",\n            outputFile\n        ), \"application/x-mpegURL\"\n    )\n}\n\nabstract class OpenInAppAction(\n    open val appName: UiText,\n    open val packageName: String,\n    private val intentClass: String? = null,\n    private val action: String = Intent.ACTION_VIEW\n) : VideoClickAction() {\n    override val name: UiText\n        get() = txt(R.string.episode_action_play_in_format, appName)\n\n    override val isPlayer = true\n\n    override fun shouldShow(context: Context?, video: ResultEpisode?) =\n        context?.isAppInstalled(packageName) != false\n\n    override suspend fun runAction(\n        context: Context?,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        if (context == null) return\n        val intent = Intent(action)\n        intent.setPackage(packageName)\n        if (intentClass != null) {\n            intent.component = ComponentName(packageName, intentClass)\n        }\n        putExtra(context, intent, video, result, index)\n        setKey(\"last_opened\", video)\n        launchResult(intent)\n    }\n\n    /**\n     * Before intent is sent, this function is called to put extra data into the intent.\n     * @see VideoClickAction.runAction\n     * */\n    @Throws\n    abstract suspend fun putExtra(\n        context: Context,\n        intent: Intent,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    )\n\n    /**\n     * This function is called when the app is opened again after the intent was sent.\n     * You can use it to for example update duration and position.\n     * @see updateDurationAndPosition\n     */\n    @Throws\n    abstract fun onResult(activity: Activity, intent: Intent?)\n\n    /** Safe version of onResult, we don't trust extension devs to not crash the app */\n    fun onResultSafe(activity: Activity, intent: Intent?) {\n        try {\n            onResult(activity, intent)\n        } catch (t: Throwable) {\n            logError(t)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt",
    "content": "package com.lagradost.cloudstream3.actions\n\nimport android.app.Activity\nimport android.content.ActivityNotFoundException\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport android.widget.Toast\nimport androidx.core.app.ActivityOptionsCompat\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.actions.temp.BiglyBTPackage\nimport com.lagradost.cloudstream3.actions.temp.CopyClipboardAction\nimport com.lagradost.cloudstream3.actions.temp.JustPlayerPackage\nimport com.lagradost.cloudstream3.actions.temp.LibreTorrentPackage\nimport com.lagradost.cloudstream3.actions.temp.MpvExPackage\nimport com.lagradost.cloudstream3.actions.temp.MpvKtPackage\nimport com.lagradost.cloudstream3.actions.temp.MpvKtPreviewPackage\nimport com.lagradost.cloudstream3.actions.temp.MpvPackage\nimport com.lagradost.cloudstream3.actions.temp.MpvYTDLPackage\nimport com.lagradost.cloudstream3.actions.temp.NextPlayerPackage\nimport com.lagradost.cloudstream3.actions.temp.PlayInBrowserAction\nimport com.lagradost.cloudstream3.actions.temp.PlayMirrorAction\nimport com.lagradost.cloudstream3.actions.temp.ViewM3U8Action\nimport com.lagradost.cloudstream3.actions.temp.VlcNightlyPackage\nimport com.lagradost.cloudstream3.actions.temp.VlcPackage\nimport com.lagradost.cloudstream3.actions.temp.WebVideoCastPackage\nimport com.lagradost.cloudstream3.actions.temp.fcast.FcastAction\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.UiText\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport java.util.concurrent.Callable\nimport java.util.concurrent.FutureTask\nimport kotlin.reflect.jvm.jvmName\n\nobject VideoClickActionHolder {\n    val allVideoClickActions = threadSafeListOf(\n        // Default\n        PlayInBrowserAction(),\n        CopyClipboardAction(),\n        ViewM3U8Action(),\n        PlayMirrorAction(),\n        // main support external apps\n        VlcPackage(),\n        MpvPackage(),\n        MpvExPackage(),\n        NextPlayerPackage(),\n        JustPlayerPackage(),\n        FcastAction(),\n        LibreTorrentPackage(),\n        BiglyBTPackage(),\n        // forks/backup apps\n        VlcNightlyPackage(),\n        WebVideoCastPackage(),\n        MpvYTDLPackage(),\n        MpvKtPackage(),\n        MpvKtPreviewPackage(),\n        // Always Ask option\n        AlwaysAskAction(),\n        // added by plugins\n        // ...\n    )\n\n    init {\n        Log.d(\"VideoClickActionHolder\", \"allVideoClickActions: ${allVideoClickActions.map { it.uniqueId() }}\")\n    }\n\n    private const val ACTION_ID_OFFSET = 1000\n\n    fun makeOptionMap(activity: Activity?, video: ResultEpisode) = allVideoClickActions\n        // We need to have index before filtering\n        .mapIndexed { id, it -> it to id + ACTION_ID_OFFSET }\n        .filter { it.first.shouldShowSafe(activity, video) }\n        .map { it.first.name to it.second }\n\n\n    fun getActionById(id: Int): VideoClickAction? = allVideoClickActions.getOrNull(id - ACTION_ID_OFFSET)\n\n    fun getByUniqueId(uniqueId: String): VideoClickAction? = allVideoClickActions.firstOrNull { it.uniqueId() == uniqueId }\n\n    fun uniqueIdToId(uniqueId: String?): Int? {\n        if (uniqueId == null) return null\n        return allVideoClickActions\n            .mapIndexed { id, it -> it to id + ACTION_ID_OFFSET }\n            .firstOrNull { it.first.uniqueId() == uniqueId }\n            ?.second\n    }\n\n    fun getPlayers(activity: Activity? = null) = allVideoClickActions.filter { it.isPlayer && it.shouldShowSafe(activity, null) }\n}\n\nabstract class VideoClickAction {\n    abstract val name: UiText\n\n    /** if true, the app will show dialog to select source - result.links[index] */\n    open val oneSource : Boolean = false\n\n    /** if true, this action could be selected as default player (one press action) in settings */\n    open val isPlayer: Boolean = false\n\n    /** Which type of sources this action can handle. */\n    open val sourceTypes: Set<ExtractorLinkType> = ExtractorLinkType.entries.toSet()\n\n    /** Determines which plugin a given provider is from. This is the full path to the plugin. */\n    var sourcePlugin: String? = null\n\n    /** Even if VideoClickAction should not run any UI code, startActivity requires it,\n     * this is a wrapper for runOnUiThread in a suspended safe context that bubble up exceptions  */\n    @Throws\n    suspend fun <T> uiThread(callable : Callable<T>) : T? {\n        val future = FutureTask{\n            try {\n                Result.success(callable.call())\n            } catch (t : Throwable) {\n                Result.failure(t)\n            }\n        }\n        CommonActivity.activity?.runOnUiThread(future) ?: throw ErrorLoadingException(\"No UI Activity, this should never happened\")\n        val result = withContext(Dispatchers.IO) {\n            return@withContext future.get()\n        }\n        return result.getOrThrow()\n    }\n\n    /** Internally uses activityResultLauncher,\n     * use this when the activity has a result like watched position */\n    @Throws\n    suspend fun launchResult(intent : Intent?, options : ActivityOptionsCompat? = null) {\n        if (intent == null) {\n            return\n        }\n\n        uiThread {\n            MainActivity.activityResultLauncher?.launch(intent,options)\n        }\n    }\n\n    /** Internally uses startActivity, use this when you don't\n     * have any result that needs to be stored when exiting the activity  */\n    @Throws\n    suspend fun launch(intent : Intent?, bundle : Bundle? = null) {\n        if (intent == null) {\n            return\n        }\n\n        uiThread {\n            CommonActivity.activity?.startActivity(intent, bundle)\n        }\n    }\n\n    fun uniqueId() = \"$sourcePlugin:${this::class.jvmName}\"\n\n    @Throws\n    abstract fun shouldShow(context: Context?, video: ResultEpisode?): Boolean\n\n    /** Safe version of shouldShow, as we don't trust extension devs to handle exceptions,\n     * however no dev *should* throw in shouldShow */\n    fun shouldShowSafe(context: Context?, video: ResultEpisode?): Boolean {\n        return try {\n            shouldShow(context,video)\n        } catch (t : Throwable) {\n            logError(t)\n            false\n        }\n    }\n\n    /**\n     *  This function is called when the action is clicked.\n     *  @param context The current activity\n     *  @param video The episode/movie that was clicked\n     *  @param result The result of the link loading, contains video & subtitle links\n     *  @param index if oneSource is true, this is the index of the selected source\n     */\n    @Throws\n    abstract suspend fun runAction(context: Context?, video: ResultEpisode, result: LinkLoadingResult, index: Int?)\n\n    /** Safe version of runAction, as we don't trust extension devs to handle exceptions */\n    fun runActionSafe(context: Context?, video: ResultEpisode, result: LinkLoadingResult, index: Int?) = ioSafe {\n        try {\n            runAction(context, video, result, index)\n        }  catch (_ : NotImplementedError) {\n            CommonActivity.showToast(\"runAction has not been implemented for ${name.asStringNull(context)}, please contact the extension developer of $sourcePlugin\", Toast.LENGTH_LONG)\n        } catch (error : ErrorLoadingException) {\n            CommonActivity.showToast(error.message, Toast.LENGTH_LONG)\n        } catch (_: ActivityNotFoundException) {\n            CommonActivity.showToast(R.string.app_not_found_error, Toast.LENGTH_LONG)\n        } catch (t : Throwable) {\n            logError(t)\n            CommonActivity.showToast(t.toString(), Toast.LENGTH_LONG)\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/Aria2Package.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\r\n\r\nimport android.app.Activity\r\nimport android.content.Context\r\nimport android.content.Intent\r\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\r\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\r\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\r\nimport com.lagradost.cloudstream3.utils.txt\r\n\r\n/** https://github.com/devgianlu/Aria2Android */\r\n@Suppress(\"unused\")\r\nclass Aria2Package : OpenInAppAction(\r\n    appName = txt(\"Aria2\"),\r\n    packageName = \"com.gianlu.aria2android\",\r\n    intentClass = \"com.gianlu.aria2android.MainActivity\"\r\n) {\r\n    override val oneSource: Boolean = true\r\n    override suspend fun putExtra(\r\n        context: Context,\r\n        intent: Intent,\r\n        video: ResultEpisode,\r\n        result: LinkLoadingResult,\r\n        index: Int?\r\n    ) {\r\n        throw NotImplementedError(\"Aria2Android is missing getIntent, and onNewIntent, meaning it cant handle intents\")\r\n    }\r\n\r\n    override fun onResult(activity: Activity, intent: Intent?) = Unit\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/BiglyBTPackage.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\r\n\r\nimport android.app.Activity\r\nimport android.content.Context\r\nimport android.content.Intent\r\nimport androidx.core.net.toUri\r\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\r\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\r\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\r\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\r\nimport com.lagradost.cloudstream3.utils.txt\r\n\r\n/** https://github.com/BiglySoftware/BiglyBT-Android */\r\nclass BiglyBTPackage : OpenInAppAction(\r\n    appName = txt(\"BiglyBT\"),\r\n    packageName = \"com.biglybt.android.client\",\r\n    intentClass = \"com.biglybt.android.client.activity.IntentHandler\"\r\n) {\r\n    // Only torrents are supported by the app\r\n    override val sourceTypes: Set<ExtractorLinkType> =\r\n        setOf(ExtractorLinkType.MAGNET, ExtractorLinkType.TORRENT)\r\n\r\n    override val oneSource: Boolean = true\r\n\r\n    override suspend fun putExtra(\r\n        context: Context,\r\n        intent: Intent,\r\n        video: ResultEpisode,\r\n        result: LinkLoadingResult,\r\n        index: Int?\r\n    ) {\r\n        intent.data = result.links[index!!].url.toUri()\r\n    }\r\n\r\n    override fun onResult(activity: Activity, intent: Intent?) = Unit\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\r\n\r\nimport android.app.Activity\r\nimport android.content.Context\r\nimport android.content.Intent\r\nimport android.net.Uri\r\nimport com.fasterxml.jackson.annotation.JsonProperty\r\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\r\nimport com.lagradost.cloudstream3.BuildConfig\r\nimport com.lagradost.cloudstream3.ui.player.ExtractorUri\r\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\r\nimport com.lagradost.cloudstream3.ui.player.SubtitleOrigin\r\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\r\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\r\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\r\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\r\nimport com.lagradost.cloudstream3.utils.DrmExtractorLink\r\nimport com.lagradost.cloudstream3.utils.ExtractorLink\r\nimport com.lagradost.cloudstream3.utils.ExtractorLinkPlayList\r\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\r\nimport com.lagradost.cloudstream3.utils.newExtractorLink\r\nimport com.lagradost.cloudstream3.utils.Qualities\r\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromCodeToLangTagIETF\r\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromLanguageToTagIETF\r\nimport com.lagradost.cloudstream3.utils.txt\r\n\r\n/**\r\n * If you want to support CloudStream 3 as an external player, then this shows how to play any video link\r\n * For basic interactions, just `intent.data = uri` works\r\n *\r\n * However for more advanced use, CloudStream 3 also supports playlists of MinimalVideoLink and MinimalSubtitleLink with a `String[]` of JSON\r\n * These are passed as LINKS_EXTRA and SUBTITLE_EXTRA respectively\r\n */\r\n@Suppress(\"Unused\")\r\nclass CloudStreamPackage : OpenInAppAction(\r\n    appName = txt(\"CloudStream\"),\r\n    packageName = BuildConfig.APPLICATION_ID, //\"com.lagradost.cloudstream3\" or \"com.lagradost.cloudstream3.prerelease\"\r\n    intentClass = \"com.lagradost.cloudstream3.ui.player.DownloadedPlayerActivity\"\r\n) {\r\n    override val oneSource: Boolean = false\r\n\r\n    companion object {\r\n        const val SUBTITLE_EXTRA: String = \"subs\" // Json of an array of MinimalVideoLink\r\n        const val LINKS_EXTRA: String = \"links\" // Json of an array of MinimalSubtitleLink\r\n        const val TITLE_EXTRA: String = \"title\" // Unused (String)\r\n        const val ID_EXTRA: String =\r\n            \"id\" // Identification number for the video(s), used to store start time (Int)\r\n        const val POSITION_EXTRA: String = \"pos\" // Start time in MS (Long)\r\n        const val DURATION_EXTRA: String = \"dur\" // Duration time in MS (Long)\r\n    }\r\n\r\n    data class MinimalVideoLink(\r\n        @JsonProperty(\"uri\")\r\n        val uri: Uri?,\r\n        @JsonProperty(\"url\")\r\n        val url: String?,\r\n        @JsonProperty(\"mimeType\")\r\n        val mimeType: String = \"video/mp4\",\r\n        @JsonProperty(\"name\")\r\n        val name: String?,\r\n        @JsonProperty(\"headers\")\r\n        var headers: Map<String, String> = mapOf(),\r\n        @JsonProperty(\"quality\")\r\n        val quality: Int?,\r\n    ) {\r\n        companion object {\r\n            fun fromExtractor(link: ExtractorLink): MinimalVideoLink = MinimalVideoLink(\r\n                uri = null,\r\n                url = link.url,\r\n                name = link.name,\r\n                mimeType = link.type.getMimeType(),\r\n                headers = if (link.referer.isBlank()) emptyMap() else mapOf(\"referer\" to link.referer) + link.headers,\r\n                quality = link.quality\r\n            )\r\n        }\r\n\r\n        suspend fun toExtractorLink(): Pair<ExtractorLink?, ExtractorUri?> =\r\n            url?.let { url ->\r\n                newExtractorLink(\r\n                    source = \"NONE\",\r\n                    name = name ?: \"Unknown\",\r\n                    url = url,\r\n                    type = ExtractorLinkType.entries.firstOrNull { ty -> ty.getMimeType() == mimeType }\r\n                        ?: ExtractorLinkType.VIDEO) {\r\n\r\n                    this@newExtractorLink.headers =\r\n                        this@MinimalVideoLink.headers\r\n\r\n                    this@newExtractorLink.quality =\r\n                        this@MinimalVideoLink.quality ?: Qualities.Unknown.value\r\n                }\r\n            } to uri?.let { uri ->\r\n                ExtractorUri(\r\n                    uri = uri,\r\n                    name = name ?: \"Unknown\",\r\n                )\r\n            }\r\n    }\r\n\r\n\r\n    data class MinimalSubtitleLink(\r\n        @JsonProperty(\"url\")\r\n        val url: String,\r\n        @JsonProperty(\"mimeType\")\r\n        val mimeType: String = \"text/vtt\",\r\n        @JsonProperty(\"name\")\r\n        val name: String?,\r\n        @JsonProperty(\"headers\")\r\n        var headers: Map<String, String> = mapOf(),\r\n    ) {\r\n        companion object {\r\n            fun fromSubtitle(sub: SubtitleData): MinimalSubtitleLink = MinimalSubtitleLink(\r\n                url = sub.url,\r\n                mimeType = sub.mimeType,\r\n                name = sub.originalName,\r\n                headers = sub.headers,\r\n            )\r\n        }\r\n\r\n        fun toSubtitleData(): SubtitleData = SubtitleData(\r\n            url = url,\r\n            nameSuffix = \"\",\r\n            mimeType = mimeType,\r\n            originalName = name ?: \"Unknown\",\r\n            headers = headers,\r\n            origin = SubtitleOrigin.URL,\r\n            languageCode = fromCodeToLangTagIETF(name) ?:\r\n                           fromLanguageToTagIETF(name, true) ?:\r\n                           name,\r\n        )\r\n    }\r\n\r\n    override suspend fun putExtra(\r\n        context: Context,\r\n        intent: Intent,\r\n        video: ResultEpisode,\r\n        result: LinkLoadingResult,\r\n        index: Int?\r\n    ) {\r\n        intent.apply {\r\n            val position = getViewPos(video.id)?.position\r\n            if (position != null)\r\n                putExtra(POSITION_EXTRA, position)\r\n\r\n            putExtra(ID_EXTRA, video.id)\r\n            putExtra(TITLE_EXTRA, video.name)\r\n            putExtra(\r\n                SUBTITLE_EXTRA,\r\n                result.subs.map { MinimalSubtitleLink.fromSubtitle(it).toJson() }.toTypedArray()\r\n            )\r\n            putExtra(\r\n                LINKS_EXTRA,\r\n                result.links.filter { it !is ExtractorLinkPlayList && it !is DrmExtractorLink }\r\n                    .map { MinimalVideoLink.fromExtractor(it).toJson() }.toTypedArray()\r\n            )\r\n        }\r\n    }\r\n\r\n    override fun onResult(activity: Activity, intent: Intent?) {\r\n        // No results yet\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/CopyClipboardAction.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\n\nimport android.content.Context\nimport com.lagradost.cloudstream3.actions.VideoClickAction\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper\n\nclass CopyClipboardAction: VideoClickAction() {\n    override val name = txt(\"Copy to clipboard\")\n\n    override val oneSource = true\n\n    override fun shouldShow(context: Context?, video: ResultEpisode?) = true\n\n    override suspend fun runAction(\n        context: Context?,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        if (index == null) return\n        val link = result.links.getOrNull(index) ?: return\n        clipboardHelper(txt(link.name), link.url)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/JustPlayerPackage.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\r\n\r\nimport android.app.Activity\r\nimport android.content.Context\r\nimport android.content.Intent\r\nimport androidx.core.net.toUri\r\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\r\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\r\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\r\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\r\nimport com.lagradost.cloudstream3.utils.txt\r\n\r\n/** https://github.com/moneytoo/Player/ */\r\nclass JustPlayerPackage : OpenInAppAction(\r\n    appName = txt(\"JustPlayer\"),\r\n    packageName = \"com.brouken.player\",\r\n    intentClass = \"com.brouken.player.PlayerActivity\"\r\n) {\r\n    override val sourceTypes: Set<ExtractorLinkType> =\r\n        setOf(ExtractorLinkType.VIDEO, ExtractorLinkType.M3U8, ExtractorLinkType.DASH)\r\n\r\n    override val oneSource: Boolean = true\r\n\r\n    override suspend fun putExtra(\r\n        context: Context,\r\n        intent: Intent,\r\n        video: ResultEpisode,\r\n        result: LinkLoadingResult,\r\n        index: Int?\r\n    ) {\r\n        // While JustPlayer has support for subs, it cant add both subs and links at the same time\r\n        // See https://github.com/moneytoo/Player/blob/49d80eb8de7a7bfc662393fdf114788fed1ebb2e/app/src/main/java/com/brouken/player/PlayerActivity.java#L794\r\n        intent.data = result.links[index!!].url.toUri()\r\n    }\r\n\r\n    override fun onResult(activity: Activity, intent: Intent?) = Unit\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/LibreTorrentPackage.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\r\n\r\nimport android.app.Activity\r\nimport android.content.Context\r\nimport android.content.Intent\r\nimport androidx.core.net.toUri\r\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\r\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\r\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\r\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\r\nimport com.lagradost.cloudstream3.utils.txt\r\n\r\n/** https://github.com/proninyaroslav/libretorrent */\r\nclass LibreTorrentPackage : OpenInAppAction(\r\n    appName = txt(\"LibreTorrent\"),\r\n    packageName = \"org.proninyaroslav.libretorrent\",\r\n    intentClass = \"org.proninyaroslav.libretorrent.ui.addtorrent.AddTorrentActivity\"\r\n) {\r\n    // Only torrents are supported by the app\r\n    override val sourceTypes: Set<ExtractorLinkType> =\r\n        setOf(ExtractorLinkType.MAGNET, ExtractorLinkType.TORRENT)\r\n\r\n    override val oneSource: Boolean = true\r\n\r\n    override suspend fun putExtra(\r\n        context: Context,\r\n        intent: Intent,\r\n        video: ResultEpisode,\r\n        result: LinkLoadingResult,\r\n        index: Int?\r\n    ) {\r\n        intent.data = result.links[index!!].url.toUri()\r\n    }\r\n\r\n    override fun onResult(activity: Activity, intent: Intent?) = Unit\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvKtPackage.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.Intent\nimport androidx.core.net.toUri\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\nimport com.lagradost.cloudstream3.actions.updateDurationAndPosition\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\n\nclass MpvKtPreviewPackage: MpvKtPackage(\n    appName = \"mpvKt Preview\",\n    packageName = \"live.mehiz.mpvkt.preview\",\n)\n\nopen class MpvKtPackage(\n    appName: String = \"mpvKt\",\n    packageName: String = \"live.mehiz.mpvkt\",\n): OpenInAppAction(\n    appName = txt(appName),\n    packageName = packageName,\n    intentClass = \"live.mehiz.mpvkt.ui.player.PlayerActivity\"\n) {\n    override val oneSource = true\n\n    override val sourceTypes = setOf(\n        ExtractorLinkType.VIDEO,\n        ExtractorLinkType.DASH,\n        ExtractorLinkType.M3U8\n    )\n\n    override suspend fun putExtra(\n        context: Context,\n        intent: Intent,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        val link = result.links.getOrNull(index ?: 0) ?: return\n\n        intent.apply {\n            putExtra(\"subs\", result.subs.map { it.url.toUri() }.toTypedArray())\n            setDataAndType(link.url.toUri(), \"video/*\")\n\n            // m3u8 plays, but changing sources feature is not available\n            // makeTempM3U8Intent(activity, this, result)\n\n            //putExtra(\"headers\", link.headers.flatMap { listOf(it.key, it.value) }.toTypedArray())\n\n            val position = getViewPos(video.id)?.position\n            if (position != null)\n                putExtra(\"position\", position.toInt())\n\n            putExtra(\"secure_uri\", true)\n        }\n    }\n\n    override fun onResult(activity: Activity, intent: Intent?) {\n        val position = intent?.getIntExtra(\"position\", -1)?.toLong() ?: -1\n        val duration = intent?.getIntExtra(\"duration\", -1)?.toLong() ?: -1\n        updateDurationAndPosition(position, duration)\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.Intent\nimport androidx.core.net.toUri\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\nimport com.lagradost.cloudstream3.actions.makeTempM3U8Intent\nimport com.lagradost.cloudstream3.actions.updateDurationAndPosition\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\n\n// https://github.com/mpv-android/mpv-android/blob/0eb3cdc6f1632636b9c30d52ec50e4b017661980/app/src/main/java/is/xyz/mpv/MPVActivity.kt#L904\n// https://mpv-android.github.io/mpv-android/intent.html\n\n//https://github.com/marlboro-advance/mpvEx\nclass MpvExPackage: MpvPackage(\"mpvEx\",\"app.marlboroadvance.mpvex\",\"app.marlboroadvance.mpvex.ui.player.PlayerActivity\")\n\nclass MpvYTDLPackage : MpvPackage(\"MPV YTDL\", \"is.xyz.mpv.ytdl\") {\n    override val sourceTypes = setOf(\n        ExtractorLinkType.VIDEO,\n        ExtractorLinkType.DASH,\n        ExtractorLinkType.M3U8\n    )\n}\n\nopen class MpvPackage(appName: String = \"MPV\", packageName: String = \"is.xyz.mpv\",intentClass:String = \"is.xyz.mpv.MPVActivity\"): OpenInAppAction(\n    txt(appName),\n    packageName,\n    intentClass\n) {\n    override val oneSource = true // mpv has poor playlist support on TV\n    override suspend fun putExtra(\n        context: Context,\n        intent: Intent,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        intent.apply {\n            putExtra(\"subs\", result.subs.map { it.url.toUri() }.toTypedArray())\n            putExtra(\"title\", video.name)\n\n            if (index != null) {\n                setDataAndType((result.links.getOrNull(index)?.url ?: return).toUri(), \"video/*\")\n            } else {\n                makeTempM3U8Intent(context, this, result)\n            }\n\n            val position = getViewPos(video.id)?.position\n            if (position != null)\n                putExtra(\"position\", position.toInt())\n\n            putExtra(\"secure_uri\", true)\n        }\n    }\n\n    override fun onResult(activity: Activity, intent: Intent?) {\n        val position = intent?.getIntExtra(\"position\", -1) ?: -1\n        val duration = intent?.getIntExtra(\"duration\", -1) ?: -1\n        Log.d(\"MPV\", \"Position: $position, Duration: $duration\")\n        updateDurationAndPosition(position.toLong(), duration.toLong())\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/NextPlayerPackage.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\r\n\r\nimport android.app.Activity\r\nimport android.content.Context\r\nimport android.content.Intent\r\nimport androidx.core.net.toUri\r\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\r\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\r\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\r\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\r\nimport com.lagradost.cloudstream3.utils.txt\r\n\r\n/** https://github.com/anilbeesetti/nextplayer */\r\nclass NextPlayerPackage : OpenInAppAction(\r\n    appName = txt(\"NextPlayer\"),\r\n    packageName = \"dev.anilbeesetti.nextplayer\",\r\n    intentClass = \"dev.anilbeesetti.nextplayer.feature.player.PlayerActivity\"\r\n) {\r\n    override val sourceTypes: Set<ExtractorLinkType> =\r\n        setOf(ExtractorLinkType.VIDEO, ExtractorLinkType.M3U8, ExtractorLinkType.DASH)\r\n\r\n    override val oneSource: Boolean = true\r\n\r\n    override suspend fun putExtra(\r\n        context: Context,\r\n        intent: Intent,\r\n        video: ResultEpisode,\r\n        result: LinkLoadingResult,\r\n        index: Int?\r\n    ) {\r\n        intent.data = result.links[index!!].url.toUri()\r\n    }\r\n\r\n    override fun onResult(activity: Activity, intent: Intent?) = Unit\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/PlayInBrowserAction.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\n\nimport android.content.Context\nimport android.content.Intent\nimport androidx.core.net.toUri\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.actions.VideoClickAction\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\n\nclass PlayInBrowserAction: VideoClickAction() {\n    override val name = txt(R.string.episode_action_play_in_format, \"Browser\")\n\n    override val oneSource = true\n\n    override val isPlayer = true\n\n    override val sourceTypes: Set<ExtractorLinkType> = setOf(\n        ExtractorLinkType.VIDEO,\n        ExtractorLinkType.DASH,\n        ExtractorLinkType.M3U8\n    )\n\n    override fun shouldShow(context: Context?, video: ResultEpisode?) = true\n\n    override suspend fun runAction(\n        context: Context?,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        val link = result.links.getOrNull(index ?: 0) ?: return\n        val i = Intent(Intent.ACTION_VIEW)\n        i.data = link.url.toUri()\n        launch(i)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/PlayMirrorAction.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\n\nimport android.app.Activity\nimport android.content.Context\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.actions.VideoClickAction\nimport com.lagradost.cloudstream3.ui.player.ExtractorUri\nimport com.lagradost.cloudstream3.ui.player.GeneratorPlayer\nimport com.lagradost.cloudstream3.ui.player.LOADTYPE_INAPP\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.ui.player.VideoGenerator\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.txt\n\nclass PlayMirrorAction : VideoClickAction() {\n    override val name = txt(R.string.episode_action_play_mirror)\n\n    override val oneSource = true\n\n    override val isPlayer = true\n\n    override val sourceTypes: Set<ExtractorLinkType> = LOADTYPE_INAPP\n\n    override fun shouldShow(context: Context?, video: ResultEpisode?) = true\n\n    override suspend fun runAction(\n        context: Context?,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        //Implemented a generator to handle the single\n        val activity = context as? Activity ?: return\n        val generatorMirror = object : VideoGenerator<ResultEpisode>(listOf(video)) {\n            override val hasCache: Boolean = false\n            override val canSkipLoading: Boolean = false\n\n            override suspend fun generateLinks(\n                clearCache: Boolean,\n                sourceTypes: Set<ExtractorLinkType>,\n                callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,\n                subtitleCallback: (SubtitleData) -> Unit,\n                offset: Int,\n                isCasting: Boolean\n            ): Boolean {\n                index?.let { callback(result.links[it] to null) }\n                result.subs.forEach { subtitle -> subtitleCallback(subtitle) }\n                return true\n            }\n        }\n\n        activity.navigate(\n            R.id.global_to_navigation_player,\n            GeneratorPlayer.newInstance(\n                generatorMirror, result.syncData\n            )\n        )\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/ViewM3U8Action.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\n\nimport android.content.Context\nimport android.content.Intent\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.actions.VideoClickAction\nimport com.lagradost.cloudstream3.actions.makeTempM3U8Intent\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.txt\n\nclass ViewM3U8Action: VideoClickAction() {\n    override val name = txt(R.string.episode_action_play_in_format, \"m3u8 player\")\n\n    override val isPlayer = true\n\n    override fun shouldShow(context: Context?, video: ResultEpisode?) = true\n\n    override suspend fun runAction(\n        context: Context?,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        if (context == null) return\n        val i = Intent(Intent.ACTION_VIEW)\n        makeTempM3U8Intent(context, i, result)\n        launch(i)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/VlcPackage.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build\nimport androidx.core.net.toUri\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\nimport com.lagradost.cloudstream3.actions.makeTempM3U8Intent\nimport com.lagradost.cloudstream3.actions.updateDurationAndPosition\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.ui.subtitles.SUBTITLE_AUTO_SELECT_KEY\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\n\n// https://github.com/videolan/vlc-android/blob/3706c4be2da6800b3d26344fc04fab03ffa4b860/application/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.kt#L1898\n// https://wiki.videolan.org/Android_Player_Intents/\n\nclass VlcNightlyPackage : VlcPackage() {\n    override val packageName = \"org.videolan.vlc.debug\"\n    override val appName = txt(\"VLC Nightly\")\n}\n\nopen class VlcPackage: OpenInAppAction(\n    appName = txt(\"VLC\"),\n    packageName = \"org.videolan.vlc\",\n    intentClass = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {\n        \"org.videolan.vlc.gui.video.VideoPlayerActivity\"\n    } else {\n        null\n    },\n    action = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {\n        \"org.videolan.vlc.player.result\"\n    } else {\n        Intent.ACTION_VIEW\n    }\n) {\n    // while VLC supports multi links, it has poor support, so we disable it for now\n    override val oneSource = true\n\n    override suspend fun putExtra(\n        context: Context,\n        intent: Intent,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        if (index != null) {\n            intent.setDataAndType(result.links[index].url.toUri(), \"video/*\")\n        } else {\n            makeTempM3U8Intent(context, intent, result)\n        }\n        val position = getViewPos(video.id)?.position ?: 0L\n\n        intent.putExtra(\"from_start\", false)\n        intent.putExtra(\"position\", position)\n        intent.putExtra(\"secure_uri\", true)\n        intent.putExtra(\"title\", video.name)\n\n        val subsLang = getKey(SUBTITLE_AUTO_SELECT_KEY) ?: \"en\"\n        result.subs.firstOrNull {\n            subsLang == it.languageCode\n        }?.let {\n            intent.putExtra(\"subtitles_location\", it.url)\n        }\n    }\n\n    override fun onResult(activity: Activity, intent: Intent?) {\n        val position = intent?.getLongExtra(\"extra_position\", -1) ?: -1\n        val duration = intent?.getLongExtra(\"extra_duration\", -1) ?: -1\n        Log.d(\"VLC\", \"Position: $position, Duration: $duration\")\n        updateDurationAndPosition(position, duration)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/WebVideoCastPackage.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Bundle\nimport androidx.core.net.toUri\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.actions.OpenInAppAction\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\n\n// https://www.webvideocaster.com/integrations\n\nclass WebVideoCastPackage: OpenInAppAction(\n    txt(\"Web Video Cast\"),\n    \"com.instantbits.cast.webvideo\"\n) {\n\n    override val oneSource = true\n\n    override val sourceTypes = setOf(\n        ExtractorLinkType.VIDEO,\n        ExtractorLinkType.DASH,\n        ExtractorLinkType.M3U8\n    )\n\n    override suspend fun putExtra(\n        context: Context,\n        intent: Intent,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        val link = result.links[index ?: 0]\n\n        intent.apply {\n            setDataAndType(link.url.toUri(), \"video/*\")\n\n            val title = video.name ?: video.headerName\n\n            putExtra(\"subs\", result.subs.map { it.url.toUri() }.toTypedArray())\n            putExtra(\"title\", title)\n            video.poster?.let { putExtra(\"poster\", it) }\n            val headers = Bundle().apply {\n                if (link.referer.isNotBlank())\n                    putString(\"Referer\", link.referer)\n                putString(\"User-Agent\", USER_AGENT)\n                for ((key, value) in link.headers) {\n                    putString(key, value)\n                }\n            }\n            putExtra(\"android.media.intent.extra.HTTP_HEADERS\", headers)\n            putExtra(\"secure_uri\", true)\n        }\n    }\n\n    override fun onResult(activity: Activity, intent: Intent?) = Unit\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastAction.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp.fcast\n\nimport android.content.Context\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.actions.VideoClickAction\nimport com.lagradost.cloudstream3.ui.result.LinkLoadingResult\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\n\nclass FcastAction: VideoClickAction() {\n    override val name = txt(\"Fcast to device\")\n\n    override val oneSource = true\n\n    override val sourceTypes = setOf(\n        ExtractorLinkType.VIDEO,\n        ExtractorLinkType.DASH,\n        ExtractorLinkType.M3U8\n    )\n\n    override fun shouldShow(context: Context?, video: ResultEpisode?) = FcastManager.currentDevices.isNotEmpty()\n\n    override suspend fun runAction(\n        context: Context?,\n        video: ResultEpisode,\n        result: LinkLoadingResult,\n        index: Int?\n    ) {\n        val link = result.links.getOrNull(index ?: 0) ?: return\n        val devices = FcastManager.currentDevices.toList()\n        uiThread {\n            context?.getActivity()?.showBottomDialog(\n                devices.map { it.name },\n                -1,\n                txt(R.string.player_settings_select_cast_device).asString(context),\n                false,\n                {}) {\n                val position = getViewPos(video.id)?.position\n                castTo(devices.getOrNull(it), link, position)\n            }\n        }\n    }\n\n\n    private fun castTo(device: PublicDeviceInfo?, link: ExtractorLink, position: Long?) {\n        val host = device?.host ?: return\n\n        FcastSession(host).use { session ->\n            session.sendMessage(\n                Opcode.Play,\n                PlayMessage(\n                    link.type.getMimeType(),\n                    link.url,\n                    time = position?.let { it / 1000.0 },\n                    headers = mapOf(\n                        \"referer\" to link.referer,\n                        \"user-agent\" to USER_AGENT\n                    ) + link.headers\n                )\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastManager.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp.fcast\n\nimport android.content.Context\nimport android.net.nsd.NsdManager\nimport android.net.nsd.NsdManager.ResolveListener\nimport android.net.nsd.NsdServiceInfo\nimport android.os.Build\nimport android.os.ext.SdkExtensions\nimport android.util.Log\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\n\nclass FcastManager {\n    private var nsdManager: NsdManager? = null\n\n    // Used for receiver\n    private val registrationListenerTcp = DefaultRegistrationListener()\n    private fun getDeviceName(): String {\n        return \"${Build.MANUFACTURER}-${Build.MODEL}\"\n    }\n\n    /**\n     * Start the fcast service\n     * @param registerReceiver If true will register the app as a compatible fcast receiver for discovery in other app\n     */\n    fun init(context: Context, registerReceiver: Boolean) = ioSafe {\n        nsdManager = context.getSystemService(Context.NSD_SERVICE) as NsdManager\n        val serviceType = \"_fcast._tcp\"\n\n        if (registerReceiver) {\n            val serviceName = \"$APP_PREFIX-${getDeviceName()}\"\n\n            val serviceInfo = NsdServiceInfo().apply {\n                this.serviceName = serviceName\n                this.serviceType = serviceType\n                this.port = TCP_PORT\n            }\n\n            nsdManager?.registerService(\n                serviceInfo,\n                NsdManager.PROTOCOL_DNS_SD,\n                registrationListenerTcp\n            )\n        }\n\n        nsdManager?.discoverServices(\n            serviceType,\n            NsdManager.PROTOCOL_DNS_SD,\n            DefaultDiscoveryListener()\n        )\n    }\n\n    fun stop() {\n        nsdManager?.unregisterService(registrationListenerTcp)\n    }\n\n    inner class DefaultDiscoveryListener : NsdManager.DiscoveryListener {\n        val tag = \"DiscoveryListener\"\n        override fun onStartDiscoveryFailed(serviceType: String?, errorCode: Int) {\n            Log.d(tag, \"Discovery failed: $serviceType, error code: $errorCode\")\n        }\n\n        override fun onStopDiscoveryFailed(serviceType: String?, errorCode: Int) {\n            Log.d(tag, \"Stop discovery failed: $serviceType, error code: $errorCode\")\n        }\n\n        override fun onDiscoveryStarted(serviceType: String?) {\n            Log.d(tag, \"Discovery started: $serviceType\")\n        }\n\n        override fun onDiscoveryStopped(serviceType: String?) {\n            Log.d(tag, \"Discovery stopped: $serviceType\")\n        }\n\n        override fun onServiceFound(serviceInfo: NsdServiceInfo?) {\n            // Safe here as, java.lang.NoClassDefFoundError: Failed resolution of: Landroid/net/nsd/NsdManager$ServiceInfoCallback\n            safe {\n                if (serviceInfo == null) return@safe\n\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && SdkExtensions.getExtensionVersion(\n                        Build.VERSION_CODES.TIRAMISU\n                    ) >= 7\n                ) {\n                    nsdManager?.registerServiceInfoCallback(\n                        serviceInfo,\n                        Runnable::run,\n                        object : NsdManager.ServiceInfoCallback {\n                            override fun onServiceInfoCallbackRegistrationFailed(errorCode: Int) {\n                                Log.e(tag, \"Service registration failed: $errorCode\")\n                            }\n\n                            override fun onServiceUpdated(serviceInfo: NsdServiceInfo) {\n                                Log.d(\n                                    tag,\n                                    \"Service updated: ${serviceInfo.serviceName},\" +\n                                            \"Net: ${serviceInfo.hostAddresses.firstOrNull()?.hostAddress}\"\n                                )\n                                synchronized(_currentDevices) {\n                                    _currentDevices.removeIf { it.rawName == serviceInfo.serviceName }\n                                    _currentDevices.add(PublicDeviceInfo(serviceInfo))\n                                }\n                            }\n\n                            override fun onServiceLost() {\n                                Log.d(tag, \"Service lost: ${serviceInfo.serviceName},\")\n                                synchronized(_currentDevices) {\n                                    _currentDevices.removeIf { it.rawName == serviceInfo.serviceName }\n                                }\n                            }\n\n                            override fun onServiceInfoCallbackUnregistered() {}\n                        })\n                } else {\n                    @Suppress(\"DEPRECATION\")\n                    nsdManager?.resolveService(serviceInfo, object : ResolveListener {\n                        override fun onResolveFailed(\n                            serviceInfo: NsdServiceInfo?,\n                            errorCode: Int\n                        ) {\n                        }\n\n                        override fun onServiceResolved(serviceInfo: NsdServiceInfo?) {\n                            if (serviceInfo == null) return\n\n                            synchronized(_currentDevices) {\n                                _currentDevices.add(PublicDeviceInfo(serviceInfo))\n                            }\n\n                            Log.d(\n                                tag,\n                                \"Service found: ${serviceInfo.serviceName}, Net: ${serviceInfo.host.hostAddress}\"\n                            )\n                        }\n                    })\n                }\n            }\n        }\n\n        override fun onServiceLost(serviceInfo: NsdServiceInfo?) {\n            if (serviceInfo == null) return\n\n            // May remove duplicates, but net and port is null here, preventing device specific identification\n            synchronized(_currentDevices) {\n                _currentDevices.removeAll {\n                    it.rawName == serviceInfo.serviceName\n                }\n            }\n\n            Log.d(tag, \"Service lost: ${serviceInfo.serviceName}\")\n        }\n    }\n\n    companion object {\n        const val APP_PREFIX = \"CloudStream\"\n        private val _currentDevices: MutableList<PublicDeviceInfo> = mutableListOf()\n        val currentDevices: List<PublicDeviceInfo> = _currentDevices\n\n        class DefaultRegistrationListener : NsdManager.RegistrationListener {\n            val tag = \"DiscoveryService\"\n            override fun onServiceRegistered(serviceInfo: NsdServiceInfo) {\n                Log.d(tag, \"Service registered: ${serviceInfo.serviceName}\")\n            }\n\n            override fun onRegistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {\n                Log.e(tag, \"Service registration failed: errorCode=$errorCode\")\n            }\n\n            override fun onServiceUnregistered(serviceInfo: NsdServiceInfo) {\n                Log.d(tag, \"Service unregistered: ${serviceInfo.serviceName}\")\n            }\n\n            override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) {\n                Log.e(tag, \"Service unregistration failed: errorCode=$errorCode\")\n            }\n        }\n\n        const val TCP_PORT = 46899\n    }\n}\n\nclass PublicDeviceInfo(serviceInfo: NsdServiceInfo) {\n    val rawName: String = serviceInfo.serviceName\n    val host: String? = if (\n        Build.VERSION.SDK_INT >= Build.VERSION_CODES.R &&\n        SdkExtensions.getExtensionVersion(\n            Build.VERSION_CODES.TIRAMISU\n        ) >= 7\n    ) {\n        serviceInfo.hostAddresses.firstOrNull()?.hostAddress\n    } else {\n        @Suppress(\"DEPRECATION\")\n        serviceInfo.host.hostAddress\n    }\n    val name = rawName.replace(\"-\", \" \") + host?.let { \" $it\" }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastSession.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp.fcast\n\nimport android.util.Log\nimport androidx.annotation.WorkerThread\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.safefile.closeQuietly\nimport java.io.DataOutputStream\nimport java.net.Socket\nimport kotlin.jvm.Throws\n\nclass FcastSession(private val hostAddress: String): AutoCloseable {\n    val tag = \"FcastSession\"\n\n    private var socket: Socket? = null\n    @Throws\n    @WorkerThread\n    fun open(): Socket {\n        val socket = Socket(hostAddress, FcastManager.TCP_PORT)\n        this.socket = socket\n        return socket\n    }\n\n    override fun close() {\n        socket?.closeQuietly()\n        socket = null\n    }\n\n    @Throws\n    private fun acquireSocket(): Socket {\n        return socket ?: open()\n    }\n\n    fun ping() {\n        sendMessage(Opcode.Ping, null)\n    }\n\n    fun <T> sendMessage(opcode: Opcode, message: T) {\n        ioSafe {\n            val socket = acquireSocket()\n            val outputStream = DataOutputStream(socket.getOutputStream())\n\n            val json = message?.toJson()\n            val content = json?.toByteArray() ?: ByteArray(0)\n\n            // Little endian starting from 1\n            // https://gitlab.com/futo-org/fcast/-/wikis/Protocol-version-1\n            val size = content.size + 1\n\n            val sizeArray = ByteArray(4) { num ->\n                (size shr 8 * num and 0xff).toByte()\n            }\n\n            Log.d(tag, \"Sending message with size: $size, opcode: $opcode\")\n            outputStream.write(sizeArray)\n            outputStream.write(ByteArray(1) { opcode.value })\n            outputStream.write(content)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/Packets.kt",
    "content": "package com.lagradost.cloudstream3.actions.temp.fcast\n\n// See https://gitlab.com/futo-org/fcast/-/wikis/Protocol-version-1\nenum class Opcode(val value: Byte) {\n    None(0),\n    Play(1),\n    Pause(2),\n    Resume(3),\n    Stop(4),\n    Seek(5),\n    PlaybackUpdate(6),\n    VolumeUpdate(7),\n    SetVolume(8),\n    PlaybackError(9),\n    SetSpeed(10),\n    Version(11),\n    Ping(12),\n    Pong(13);\n}\n\n\ndata class PlayMessage(\n    val container: String,\n    val url: String? = null,\n    val content: String? = null,\n    val time: Double? = null,\n    val speed: Double? = null,\n    val headers: Map<String, String>? = null\n)\n\ndata class SeekMessage(\n    val time: Double\n)\n\ndata class PlaybackUpdateMessage(\n    val generationTime: Long,\n    val time: Double,\n    val duration: Double,\n    val state: Int,\n    val speed: Double\n)\n\ndata class VolumeUpdateMessage(\n    val generationTime: Long,\n    val volume: Double\n)\n\ndata class PlaybackErrorMessage(\n    val message: String\n)\n\ndata class SetSpeedMessage(\n    val speed: Double\n)\n\ndata class SetVolumeMessage(\n    val volume: Double\n)\n\ndata class VersionMessage(\n    val version: Long\n)\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/mvvm/Lifecycle.kt",
    "content": "package com.lagradost.cloudstream3.mvvm\n\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.LiveData\n\n/** NOTE: Only one observer at a time per value */\nfun <T> LifecycleOwner.observe(liveData: LiveData<T>, action: (t: T) -> Unit) {\n    liveData.removeObservers(this)\n    liveData.observe(this) { it?.let { t -> action(t) } }\n}\n\n/** NOTE: Only one observer at a time per value */\nfun <T> LifecycleOwner.observeNullable(liveData: LiveData<T>, action: (t: T) -> Unit) {\n    liveData.removeObservers(this)\n    liveData.observe(this) { action(it) }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/network/CloudflareKiller.kt",
    "content": "package com.lagradost.cloudstream3.network\n\nimport android.util.Log\nimport android.webkit.CookieManager\nimport androidx.annotation.AnyThread\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.debugWarning\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.nicehttp.Requests.Companion.await\nimport com.lagradost.nicehttp.cookies\nimport kotlinx.coroutines.runBlocking\nimport okhttp3.Headers\nimport okhttp3.Interceptor\nimport okhttp3.Request\nimport okhttp3.Response\nimport java.net.URI\n\n\n@AnyThread\nclass CloudflareKiller : Interceptor {\n    companion object {\n        const val TAG = \"CloudflareKiller\"\n        private val ERROR_CODES = listOf(403, 503)\n        private val CLOUDFLARE_SERVERS = listOf(\"cloudflare-nginx\", \"cloudflare\")\n        fun parseCookieMap(cookie: String): Map<String, String> {\n            return cookie.split(\";\").associate {\n                val split = it.split(\"=\")\n                (split.getOrNull(0)?.trim() ?: \"\") to (split.getOrNull(1)?.trim() ?: \"\")\n            }.filter { it.key.isNotBlank() && it.value.isNotBlank() }\n        }\n    }\n\n    init {\n        // Needs to clear cookies between sessions to generate new cookies.\n        safe {\n            // This can throw an exception on unsupported devices :(\n            CookieManager.getInstance().removeAllCookies(null)\n        }\n    }\n\n    val savedCookies: MutableMap<String, Map<String, String>> = mutableMapOf()\n\n    /**\n     * Gets the headers with cookies, webview user agent included!\n     * */\n    fun getCookieHeaders(url: String): Headers {\n        val userAgentHeaders = WebViewResolver.webViewUserAgent?.let {\n            mapOf(\"user-agent\" to it)\n        } ?: emptyMap()\n\n        return getHeaders(userAgentHeaders, savedCookies[URI(url).host] ?: emptyMap())\n    }\n\n    override fun intercept(chain: Interceptor.Chain): Response = runBlocking {\n        val request = chain.request()\n\n        when (val cookies = savedCookies[request.url.host]) {\n            null -> {\n                val response = chain.proceed(request)\n                if(!(response.header(\"Server\") in CLOUDFLARE_SERVERS && response.code in ERROR_CODES)) {\n                    return@runBlocking response\n                } else {\n                    response.close()\n                    bypassCloudflare(request)?.let {\n                        Log.d(TAG, \"Succeeded bypassing cloudflare: ${request.url}\")\n                        return@runBlocking it\n                    }\n                }\n            }\n            else -> {\n                return@runBlocking proceed(request, cookies)\n            }\n        }\n\n        debugWarning({ true }) { \"Failed cloudflare at: ${request.url}\" }\n        return@runBlocking chain.proceed(request)\n    }\n\n    private fun getWebViewCookie(url: String): String? {\n        return safe {\n            CookieManager.getInstance()?.getCookie(url)\n        }\n    }\n\n    /**\n     * Returns true if the cf cookies were successfully fetched from the CookieManager\n     * Also saves the cookies.\n     * */\n    private fun trySolveWithSavedCookies(request: Request): Boolean {\n        // Not sure if this takes expiration into account\n        return getWebViewCookie(request.url.toString())?.let { cookie ->\n            cookie.contains(\"cf_clearance\").also { solved ->\n                if (solved) savedCookies[request.url.host] = parseCookieMap(cookie)\n            }\n        } ?: false\n    }\n\n    private suspend fun proceed(request: Request, cookies: Map<String, String>): Response {\n        val userAgentMap = WebViewResolver.getWebViewUserAgent()?.let {\n            mapOf(\"user-agent\" to it)\n        } ?: emptyMap()\n\n        val headers =\n            getHeaders(request.headers.toMap() + userAgentMap, cookies + request.cookies)\n        return app.baseClient.newCall(\n            request.newBuilder()\n                .headers(headers)\n                .build()\n        ).await()\n    }\n\n    private suspend fun bypassCloudflare(request: Request): Response? {\n        val url = request.url.toString()\n\n        // If no cookies then try to get them\n        // Remove this if statement if cookies expire\n        if (!trySolveWithSavedCookies(request)) {\n            Log.d(TAG, \"Loading webview to solve cloudflare for ${request.url}\")\n            WebViewResolver(\n                // Never exit based on url\n                Regex(\".^\"),\n                // Cloudflare needs default user agent\n                userAgent = null,\n                // Cannot use okhttp (i think intercepting cookies fails which causes the issues)\n                useOkhttp = false,\n                // Match every url for the requestCallBack\n                additionalUrls = listOf(Regex(\".\"))\n            ).resolveUsingWebView(\n                url\n            ) {\n                trySolveWithSavedCookies(request)\n            }\n        }\n\n        val cookies = savedCookies[request.url.host] ?: return null\n        return proceed(request, cookies)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/network/DdosGuardKiller.kt",
    "content": "package com.lagradost.cloudstream3.network\n\nimport androidx.annotation.AnyThread\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.nicehttp.Requests\nimport com.lagradost.nicehttp.cookies\nimport kotlinx.coroutines.runBlocking\nimport okhttp3.Interceptor\nimport okhttp3.Request\nimport okhttp3.Response\n\n/**\n * @param alwaysBypass will pre-emptively fetch ddos guard cookies if true.\n * If false it will only try to get cookies when a request returns 403\n * */\n// As seen in https://github.com/anime-dl/anime-downloader/blob/master/anime_downloader/sites/erairaws.py\n@AnyThread\nclass DdosGuardKiller(private val alwaysBypass: Boolean) : Interceptor {\n    val savedCookiesMap = mutableMapOf<String, Map<String, String>>()\n\n    private var ddosBypassPath: String? = null\n\n    override fun intercept(chain: Interceptor.Chain): Response = runBlocking {\n        val request = chain.request()\n        if (alwaysBypass) return@runBlocking bypassDdosGuard(request)\n\n        val response = chain.proceed(request)\n        return@runBlocking if (response.code == 403) {\n            bypassDdosGuard(request)\n        } else response\n    }\n\n    private suspend fun bypassDdosGuard(request: Request): Response {\n        ddosBypassPath = ddosBypassPath ?: Regex(\"'(.*?)'\").find(\n            app.get(\n                \"https://check.ddos-guard.net/check.js\"\n            ).text\n        )?.groupValues?.get(1)\n\n        val cookies =\n            savedCookiesMap[request.url.host]\n            // If no cookies are found fetch and save em.\n                ?: (request.url.scheme + \"://\" + request.url.host + (ddosBypassPath ?: \"\")).let {\n                    // Somehow app.get fails\n                    Requests().get(it).cookies.also { cookies ->\n                        savedCookiesMap[request.url.host] = cookies\n                    }\n                }\n\n        val headers = getHeaders(request.headers.toMap(), cookies + request.cookies)\n        return app.baseClient.newCall(\n            request.newBuilder()\n                .headers(headers)\n                .build()\n        ).execute()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/network/DohProviders.kt",
    "content": "package com.lagradost.cloudstream3.network\n\nimport okhttp3.HttpUrl.Companion.toHttpUrl\nimport okhttp3.OkHttpClient\nimport okhttp3.dnsoverhttps.DnsOverHttps\nimport java.net.InetAddress\n\n/**\n * Based on https://github.com/tachiyomiorg/tachiyomi/blob/master/app/src/main/java/eu/kanade/tachiyomi/network/DohProviders.kt\n */\n\nfun OkHttpClient.Builder.addGenericDns(url: String, ips: List<String>) = dns(\n    DnsOverHttps\n        .Builder()\n        .client(build())\n        .url(url.toHttpUrl())\n        .bootstrapDnsHosts(\n            ips.map { InetAddress.getByName(it) }\n        )\n        .build()\n)\n\nfun OkHttpClient.Builder.addGoogleDns() = (\n        addGenericDns(\n            \"https://dns.google/dns-query\",\n            listOf(\n                \"8.8.4.4\",\n                \"8.8.8.8\"\n            )\n        ))\n\nfun OkHttpClient.Builder.addCloudFlareDns() = (\n        addGenericDns(\n            \"https://cloudflare-dns.com/dns-query\",\n            // https://www.cloudflare.com/ips/\n            listOf(\n                \"1.1.1.1\",\n                \"1.0.0.1\",\n                \"2606:4700:4700::1111\",\n                \"2606:4700:4700::1001\"\n            )\n        ))\n\n// Commented out as it doesn't work\n//fun OkHttpClient.Builder.addOpenDns() = (\n//        addGenericDns(\n//            \"https://doh.opendns.com/dns-query\",\n//            // https://support.opendns.com/hc/en-us/articles/360038086532-Using-DNS-over-HTTPS-DoH-with-OpenDNS\n//            listOf(\n//                \"208.67.222.222\",\n//                \"208.67.220.220\",\n//                \"2620:119:35::35\",\n//                \"2620:119:53::53\",\n//            )\n//        ))\n\n\nfun OkHttpClient.Builder.addAdGuardDns() = (\n        addGenericDns(\n            \"https://dns.adguard.com/dns-query\",\n            // https://github.com/AdguardTeam/AdGuardDNS\n            listOf(\n                // \"Non-filtering\"\n                \"94.140.14.140\",\n                \"94.140.14.141\",\n            )\n        ))\n\nfun OkHttpClient.Builder.addDNSWatchDns() = (\n    addGenericDns(\n        \"https://resolver2.dns.watch/dns-query\",\n        // https://dns.watch/\n        listOf(\n            \"84.200.69.80\",\n            \"84.200.70.40\",\n        )\n    ))\n\nfun OkHttpClient.Builder.addQuad9Dns() = (\n    addGenericDns(\n        \"https://dns.quad9.net/dns-query\",\n        // https://www.quad9.net/service/service-addresses-and-features\n        listOf(\n            \"9.9.9.9\",\n            \"149.112.112.112\",\n        )\n    ))\n\nfun OkHttpClient.Builder.addDnsSbDns() = (\n        addGenericDns(\n            \"https://doh.dns.sb/dns-query\",\n            //https://dns.sb/guide/\n            listOf(\n                \"185.222.222.222\",\n                \"45.11.45.11\",\n            )\n        ))\n\nfun OkHttpClient.Builder.addCanadianShieldDns() = (\n        addGenericDns(\n            \"https://private.canadianshield.cira.ca/dns-query\",\n            //https://www.cira.ca/en/canadian-shield/configure/summary-cira-canadian-shield-dns-resolver-addresses/\n            listOf(\n                \"149.112.121.10\",\n                \"149.112.122.10\",\n            )\n        ))\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/network/RequestsHelper.kt",
    "content": "package com.lagradost.cloudstream3.network\n\nimport android.content.Context\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.nicehttp.Requests\nimport com.lagradost.nicehttp.ignoreAllSSLErrors\nimport okhttp3.Cache\nimport okhttp3.Headers\nimport okhttp3.Headers.Companion.toHeaders\nimport okhttp3.OkHttpClient\nimport org.conscrypt.Conscrypt\nimport java.io.File\nimport java.security.Security\n\nfun Requests.initClient(context: Context) {\n    this.baseClient = buildDefaultClient(context)\n}\n\nfun buildDefaultClient(context: Context): OkHttpClient {\n    safe { Security.insertProviderAt(Conscrypt.newProvider(), 1) }\n    \n    val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)\n    val dns = settingsManager.getInt(context.getString(R.string.dns_pref), 0)\n    val baseClient = OkHttpClient.Builder()\n        .followRedirects(true)\n        .followSslRedirects(true)\n        .ignoreAllSSLErrors()\n        .cache(\n            // Note that you need to add a ResponseInterceptor to make this 100% active.\n            // The server response dictates if and when stuff should be cached.\n            Cache(\n                directory = File(context.cacheDir, \"http_cache\"),\n                maxSize = 50L * 1024L * 1024L // 50 MiB\n            )\n        ).apply {\n            when (dns) {\n                1 -> addGoogleDns()\n                2 -> addCloudFlareDns()\n//                3 -> addOpenDns()\n                4 -> addAdGuardDns()\n                5 -> addDNSWatchDns()\n                6 -> addQuad9Dns()\n                7 -> addDnsSbDns()\n                8 -> addCanadianShieldDns()\n            }\n        }\n        // Needs to be build as otherwise the other builders will change this object\n        .build()\n    return baseClient\n}\n\n//val Request.cookies: Map<String, String>\n//    get() {\n//        return this.headers.getCookies(\"Cookie\")\n//    }\n\nprivate val DEFAULT_HEADERS = mapOf(\"user-agent\" to USER_AGENT)\n\n/**\n * Set headers > Set cookies > Default headers > Default Cookies\n * TODO REMOVE AND REPLACE WITH NICEHTTP\n */\nfun getHeaders(\n    headers: Map<String, String>,\n    cookie: Map<String, String>\n): Headers {\n    val cookieMap =\n        if (cookie.isNotEmpty()) mapOf(\n            \"Cookie\" to cookie.entries.joinToString(\" \") {\n                \"${it.key}=${it.value};\"\n            }) else mapOf()\n    val tempHeaders = (DEFAULT_HEADERS + headers + cookieMap)\n    return tempHeaders.toHeaders()\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/plugins/Plugin.kt",
    "content": "package com.lagradost.cloudstream3.plugins\n\nimport android.content.Context\nimport android.content.res.Resources\nimport android.util.Log\nimport com.lagradost.cloudstream3.actions.VideoClickAction\nimport com.lagradost.cloudstream3.actions.VideoClickActionHolder\nimport kotlin.Throws\n\n\nabstract class Plugin : BasePlugin() {\n    /**\n     * Called when your Plugin is loaded\n     * @param context Context\n     */\n    @Throws(Throwable::class)\n    open fun load(context: Context) {\n        // If not overridden by an extension then try the cross-platform load()\n        load()\n    }\n\n    /**\n     * Used to register VideoClickAction instances\n     * @param element VideoClickAction you want to register\n     */\n    fun registerVideoClickAction(element: VideoClickAction) {\n        Log.i(PLUGIN_TAG, \"Adding ${element.name} VideoClickAction\")\n        element.sourcePlugin = this.filename\n        synchronized(VideoClickActionHolder.allVideoClickActions) {\n            VideoClickActionHolder.allVideoClickActions.add(element)\n        }\n    }\n\n    /**\n     * This will contain your resources if you specified requiresResources in gradle\n     */\n    var resources: Resources? = null\n\n    /**\n     * This will add a button in the settings allowing you to add custom settings\n     */\n    var openSettings: ((context: Context) -> Unit)? = null\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt",
    "content": "package com.lagradost.cloudstream3.plugins\n\nimport android.Manifest\nimport android.app.Activity\nimport android.app.Notification\nimport android.app.NotificationChannel\nimport android.app.NotificationManager\nimport android.content.Context\nimport android.content.pm.PackageManager\nimport android.content.res.AssetManager\nimport android.content.res.Resources\nimport android.os.Build\nimport android.os.Environment\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.core.app.ActivityCompat\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.fragment.app.FragmentActivity\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder\nimport com.lagradost.cloudstream3.APIHolder.removePluginMapping\nimport com.lagradost.cloudstream3.AllLanguagesName\nimport com.lagradost.cloudstream3.AutoDownloadMode\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.MainAPI.Companion.settingsForProvider\nimport com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent\nimport com.lagradost.cloudstream3.MainActivity.Companion.lastError\nimport com.lagradost.cloudstream3.PROVIDER_STATUS_DOWN\nimport com.lagradost.cloudstream3.PROVIDER_STATUS_OK\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.actions.VideoClickAction\nimport com.lagradost.cloudstream3.actions.VideoClickActionHolder\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.mvvm.debugPrint\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.plugins.RepositoryManager.ONLINE_PLUGINS_FOLDER\nimport com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES\nimport com.lagradost.cloudstream3.plugins.RepositoryManager.downloadPluginToFile\nimport com.lagradost.cloudstream3.plugins.RepositoryManager.getRepoPlugins\nimport com.lagradost.cloudstream3.ui.settings.extensions.REPOSITORIES_KEY\nimport com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiProviderLangSettings\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.UiText\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.sanitizeFilename\nimport com.lagradost.cloudstream3.utils.extractorApis\nimport com.lagradost.cloudstream3.utils.txt\nimport dalvik.system.PathClassLoader\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport java.io.File\nimport java.io.InputStreamReader\n\n// Different keys for local and not since local can be removed at any time without app knowing, hence the local are getting rebuilt on every app start\nconst val PLUGINS_KEY = \"PLUGINS_KEY\"\nconst val PLUGINS_KEY_LOCAL = \"PLUGINS_KEY_LOCAL\"\n\nconst val EXTENSIONS_CHANNEL_ID = \"cloudstream3.extensions\"\nconst val EXTENSIONS_CHANNEL_NAME = \"Extensions\"\nconst val EXTENSIONS_CHANNEL_DESCRIPT = \"Extension notification channel\"\n\n// Data class for internal storage\ndata class PluginData(\n    @JsonProperty(\"internalName\") val internalName: String,\n    @JsonProperty(\"url\") val url: String?,\n    @JsonProperty(\"isOnline\") val isOnline: Boolean,\n    @JsonProperty(\"filePath\") val filePath: String,\n    @JsonProperty(\"version\") val version: Int,\n) {\n    fun toSitePlugin(): SitePlugin {\n        return SitePlugin(\n            this.filePath,\n            PROVIDER_STATUS_OK,\n            maxOf(1, version),\n            1,\n            internalName,\n            internalName,\n            emptyList(),\n            File(this.filePath).name,\n            null,\n            null,\n            null,\n            null,\n            File(this.filePath).length()\n        )\n    }\n}\n\n// This is used as a placeholder / not set version\nconst val PLUGIN_VERSION_NOT_SET = Int.MIN_VALUE\n\n// This always updates\nconst val PLUGIN_VERSION_ALWAYS_UPDATE = -1\n\nobject PluginManager {\n    // Prevent multiple writes at once\n    val lock = Mutex()\n\n    const val TAG = \"PluginManager\"\n\n    private var hasCreatedNotChanel = false\n\n    /**\n     * Store data about the plugin for fetching later\n     * */\n    private suspend fun setPluginData(data: PluginData) {\n        lock.withLock {\n            if (data.isOnline) {\n                val plugins = getPluginsOnline()\n                val newPlugins = plugins.filter { it.filePath != data.filePath } + data\n                setKey(PLUGINS_KEY, newPlugins)\n            } else {\n                val plugins = getPluginsLocal()\n                setKey(PLUGINS_KEY_LOCAL, plugins.filter { it.filePath != data.filePath } + data)\n            }\n        }\n    }\n\n    private suspend fun deletePluginData(data: PluginData?) {\n        if (data == null) return\n        lock.withLock {\n            if (data.isOnline) {\n                val plugins = getPluginsOnline().filter { it.url != data.url }\n                setKey(PLUGINS_KEY, plugins)\n            } else {\n                val plugins = getPluginsLocal().filter { it.filePath != data.filePath }\n                setKey(PLUGINS_KEY_LOCAL, plugins)\n            }\n        }\n    }\n\n    suspend fun deleteRepositoryData(repositoryPath: String) {\n        lock.withLock {\n            val plugins = getPluginsOnline().filter {\n                !it.filePath.contains(repositoryPath)\n            }\n            val file = File(repositoryPath)\n            safe {\n                if (file.exists()) file.deleteRecursively()\n            }\n            setKey(PLUGINS_KEY, plugins)\n        }\n    }\n\n    /**\n     * Deletes all generated oat files which will force Android to recompile the dex extensions.\n     * This might fix unrecoverable SIGSEGV exceptions when old oat files are loaded in a new app update.\n     */\n    fun deleteAllOatFiles(context: Context) {\n        File(\"${context.filesDir}/${ONLINE_PLUGINS_FOLDER}\").listFiles()?.forEach { repo ->\n            repo.listFiles { file -> file.name == \"oat\" && file.isDirectory }?.forEach { file ->\n                val success = file.deleteRecursively()\n                Log.i(TAG, \"Deleted oat directory: ${file.absolutePath} Success=$success\")\n            }\n        }\n    }\n\n\n    fun getPluginsOnline(): Array<PluginData> {\n        return getKey(PLUGINS_KEY) ?: emptyArray()\n    }\n\n    fun getPluginsLocal(): Array<PluginData> {\n        return getKey(PLUGINS_KEY_LOCAL) ?: emptyArray()\n    }\n\n    private val CLOUD_STREAM_FOLDER =\n        Environment.getExternalStorageDirectory().absolutePath + \"/Cloudstream3/\"\n\n    private val LOCAL_PLUGINS_PATH = CLOUD_STREAM_FOLDER + \"plugins\"\n\n    var currentlyLoading: String? = null\n\n    // Maps filepath to plugin\n    val plugins: MutableMap<String, BasePlugin> =\n        LinkedHashMap<String, BasePlugin>()\n\n    // Maps urls to plugin\n    val urlPlugins: MutableMap<String, BasePlugin> =\n        LinkedHashMap<String, BasePlugin>()\n\n    private val classLoaders: MutableMap<PathClassLoader, BasePlugin> =\n        HashMap<PathClassLoader, BasePlugin>()\n\n    var loadedLocalPlugins = false\n        private set\n\n    var loadedOnlinePlugins = false\n        private set\n\n    private suspend fun maybeLoadPlugin(context: Context, file: File) {\n        val name = file.name\n        if (file.extension == \"zip\" || file.extension == \"cs3\") {\n            loadPlugin(\n                context,\n                file,\n                PluginData(name, null, false, file.absolutePath, PLUGIN_VERSION_NOT_SET)\n            )\n        } else {\n            Log.i(TAG, \"Skipping invalid plugin file: $file\")\n        }\n    }\n\n\n    // Helper class for updateAllOnlinePluginsAndLoadThem\n    data class OnlinePluginData(\n        val savedData: PluginData,\n        val onlineData: Pair<String, SitePlugin>,\n    ) {\n        val isOutdated =\n            onlineData.second.version > savedData.version || onlineData.second.version == PLUGIN_VERSION_ALWAYS_UPDATE\n        val isDisabled = onlineData.second.status == PROVIDER_STATUS_DOWN\n\n        fun validOnlineData(context: Context): Boolean {\n            return getPluginPath(\n                context,\n                savedData.internalName,\n                onlineData.first\n            ).absolutePath == savedData.filePath\n        }\n    }\n\n    // var allCurrentOutDatedPlugins: Set<OnlinePluginData> = emptySet()\n\n    suspend fun loadSinglePlugin(context: Context, apiName: String): Boolean {\n        return (getPluginsOnline().firstOrNull {\n            // Most of the time the provider ends with Provider which isn't part of the api name\n            it.internalName.replace(\"provider\", \"\", ignoreCase = true) == apiName\n        }\n            ?: getPluginsLocal().firstOrNull {\n                it.internalName.replace(\"provider\", \"\", ignoreCase = true) == apiName\n            })?.let { savedData ->\n            // OnlinePluginData(savedData, onlineData)\n            loadPlugin(\n                context,\n                File(savedData.filePath),\n                savedData\n            )\n        } ?: false\n    }\n\n    /**\n     * Needs to be run before other plugin loading because plugin loading can not be overwritten\n     * 1. Gets all online data about the downloaded plugins\n     * 2. If disabled do nothing\n     * 3. If outdated download and load the plugin\n     * 4. Else load the plugin normally\n     *\n     * DO NOT USE THIS IN A PLUGIN! It may case an infinite recursive loop lagging or crashing everyone's devices.\n     * If you use it from a plugin, do not expect a stable jvmName, SO DO NOT USE IT!\n     */\n    @Suppress(\"FunctionName\", \"DEPRECATION_ERROR\")\n    @Deprecated(\n        \"Calling this function from a plugin will lead to crashes, use loadPlugin and unloadPlugin\",\n        replaceWith = ReplaceWith(\"loadPlugin\"),\n        level = DeprecationLevel.ERROR\n    )\n    @Throws\n    suspend fun ___DO_NOT_CALL_FROM_A_PLUGIN_updateAllOnlinePluginsAndLoadThem(activity: Activity) {\n        assertNonRecursiveCallstack()\n\n        // Load all plugins as fast as possible!\n        ___DO_NOT_CALL_FROM_A_PLUGIN_loadAllOnlinePlugins(activity)\n        afterPluginsLoadedEvent.invoke(false)\n\n        val urls = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY)\n            ?: emptyArray()) + PREBUILT_REPOSITORIES\n\n        val onlinePlugins = urls.toList().amap {\n            getRepoPlugins(it.url)?.toList() ?: emptyList()\n        }.flatten().distinctBy { it.second.url }\n\n        // Iterates over all offline plugins, compares to remote repo and returns the plugins which are outdated\n        val outdatedPlugins = getPluginsOnline().map { savedData ->\n            onlinePlugins\n                .filter { onlineData -> savedData.internalName == onlineData.second.internalName }\n                .map { onlineData ->\n                    OnlinePluginData(savedData, onlineData)\n                }.filter {\n                    it.validOnlineData(activity)\n                }\n        }.flatten().distinctBy { it.onlineData.second.url }\n\n        debugPrint {\n            \"Outdated plugins: ${outdatedPlugins.filter { it.isOutdated }}\"\n        }\n\n        val updatedPlugins = mutableListOf<String>()\n\n        outdatedPlugins.amap { pluginData ->\n            if (pluginData.isDisabled) {\n                //updatedPlugins.add(activity.getString(R.string.single_plugin_disabled, pluginData.onlineData.second.name))\n                unloadPlugin(pluginData.savedData.filePath)\n            } else if (pluginData.isOutdated) {\n                downloadPlugin(\n                    activity,\n                    pluginData.onlineData.second.url,\n                    pluginData.savedData.internalName,\n                    File(pluginData.savedData.filePath),\n                    true\n                ).let { success ->\n                    if (success)\n                        updatedPlugins.add(pluginData.onlineData.second.name)\n                }\n            }\n        }\n\n        main {\n            val uitext = txt(R.string.plugins_updated, updatedPlugins.size)\n            createNotification(activity, uitext, updatedPlugins)\n            /*val navBadge = (activity as MainActivity).binding?.navRailView?.getOrCreateBadge(R.id.navigation_settings)\n            navBadge?.isVisible = true\n            navBadge?.number = 5*/\n        }\n\n        // ioSafe {\n        loadedOnlinePlugins = true\n        afterPluginsLoadedEvent.invoke(false)\n        // }\n\n        Log.i(TAG, \"Plugin update done!\")\n    }\n\n    /**\n     * Automatically download plugins not yet existing on local\n     * 1. Gets all online data from online plugins repo\n     * 2. Fetch all not downloaded plugins\n     * 3. Download them and reload plugins\n     *\n     * DO NOT USE THIS IN A PLUGIN! It may case an infinite recursive loop lagging or crashing everyone's devices.\n     * If you use it from a plugin, do not expect a stable jvmName, SO DO NOT USE IT!\n     */\n    @Suppress(\"FunctionName\", \"DEPRECATION_ERROR\")\n    @Deprecated(\n        \"Calling this function from a plugin will lead to crashes, use loadPlugin and unloadPlugin\",\n        replaceWith = ReplaceWith(\"loadPlugin\"),\n        level = DeprecationLevel.ERROR\n    )\n    @Throws\n    suspend fun ___DO_NOT_CALL_FROM_A_PLUGIN_downloadNotExistingPluginsAndLoad(\n        activity: Activity,\n        mode: AutoDownloadMode\n    ) {\n        assertNonRecursiveCallstack()\n\n        val newDownloadPlugins = mutableListOf<String>()\n        val urls = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY)\n            ?: emptyArray()) + PREBUILT_REPOSITORIES\n        val onlinePlugins = urls.toList().amap {\n            getRepoPlugins(it.url)?.toList() ?: emptyList()\n        }.flatten().distinctBy { it.second.url }\n\n        val providerLang = activity.getApiProviderLangSettings()\n        //Log.i(TAG, \"providerLang => ${providerLang.toJson()}\")\n\n        // Iterate online repos and returns not downloaded plugins\n        val notDownloadedPlugins = onlinePlugins.mapNotNull { onlineData ->\n            val sitePlugin = onlineData.second\n            val tvtypes = sitePlugin.tvTypes ?: listOf()\n\n            //Don't include empty urls\n            if (sitePlugin.url.isBlank()) {\n                return@mapNotNull null\n            }\n            if (sitePlugin.repositoryUrl.isNullOrBlank()) {\n                return@mapNotNull null\n            }\n\n            //Omit already existing plugins\n            if (getPluginPath(activity, sitePlugin.internalName, onlineData.first).exists()) {\n                Log.i(TAG, \"Skip > ${sitePlugin.internalName}\")\n                return@mapNotNull null\n            }\n\n            //Omit non-NSFW if mode is set to NSFW only\n            if (mode == AutoDownloadMode.NsfwOnly) {\n                if (!tvtypes.contains(TvType.NSFW.name)) {\n                    return@mapNotNull null\n                }\n            }\n            //Omit NSFW, if disabled\n            if (!settingsForProvider.enableAdult) {\n                if (tvtypes.contains(TvType.NSFW.name)) {\n                    return@mapNotNull null\n                }\n            }\n\n            //Omit lang not selected on language setting\n            if (mode == AutoDownloadMode.FilterByLang) {\n                val lang = sitePlugin.language ?: return@mapNotNull null\n                //If set to 'universal', don't skip any language\n                if (!providerLang.contains(AllLanguagesName) && !providerLang.contains(lang)) {\n                    return@mapNotNull null\n                }\n                //Log.i(TAG, \"sitePlugin lang => $lang\")\n            }\n\n            val savedData = PluginData(\n                url = sitePlugin.url,\n                internalName = sitePlugin.internalName,\n                isOnline = true,\n                filePath = \"\",\n                version = sitePlugin.version\n            )\n            OnlinePluginData(savedData, onlineData)\n        }\n        //Log.i(TAG, \"notDownloadedPlugins => ${notDownloadedPlugins.toJson()}\")\n\n        notDownloadedPlugins.amap { pluginData ->\n            downloadPlugin(\n                activity,\n                pluginData.onlineData.second.url,\n                pluginData.savedData.internalName,\n                pluginData.onlineData.first,\n                !pluginData.isDisabled\n            ).let { success ->\n                if (success)\n                    newDownloadPlugins.add(pluginData.onlineData.second.name)\n            }\n        }\n\n        main {\n            val uitext = txt(R.string.plugins_downloaded, newDownloadPlugins.size)\n            createNotification(activity, uitext, newDownloadPlugins)\n        }\n\n        // ioSafe {\n        afterPluginsLoadedEvent.invoke(false)\n        // }\n\n        Log.i(TAG, \"Plugin download done!\")\n    }\n\n    @Throws\n    private fun assertNonRecursiveCallstack() {\n        if (Thread.currentThread().stackTrace.any { it.methodName == \"loadPlugin\" }) {\n            throw Error(\"You tried to call a function that will recursively call loadPlugin, this will cause crashes or memory leaks. Do not do this, there is better ways to implement the feature than reloading plugins. Are you sure you read the compile error or docs?\")\n        }\n    }\n\n    /**\n     * Use updateAllOnlinePluginsAndLoadThem\n     *\n     * DO NOT USE THIS IN A PLUGIN! It may case an infinite recursive loop lagging or crashing everyone's devices.\n     * If you use it from a plugin, do not expect a stable jvmName, SO DO NOT USE IT!\n     */\n    @Suppress(\"FunctionName\", \"DEPRECATION_ERROR\")\n    @Deprecated(\n        \"Calling this function from a plugin will lead to crashes, use loadPlugin and unloadPlugin\",\n        replaceWith = ReplaceWith(\"loadPlugin\"),\n        level = DeprecationLevel.ERROR\n    )\n    @Throws\n    suspend fun ___DO_NOT_CALL_FROM_A_PLUGIN_loadAllOnlinePlugins(context: Context) {\n        assertNonRecursiveCallstack()\n\n        // Load all plugins as fast as possible!\n        (getPluginsOnline()).toList().amap { pluginData ->\n            loadPlugin(\n                context,\n                File(pluginData.filePath),\n                pluginData\n            )\n        }\n    }\n\n    /**\n     * Reloads all local plugins and forces a page update, used for hot reloading with deployWithAdb\n     *\n     * DO NOT USE THIS IN A PLUGIN! It may case an infinite recursive loop lagging or crashing everyone's devices.\n     * If you use it from a plugin, do not expect a stable jvmName, SO DO NOT USE IT!\n     */\n    @Suppress(\"FunctionName\", \"DEPRECATION_ERROR\")\n    @Throws\n    @Deprecated(\n        \"Calling this function from a plugin will lead to crashes, use loadPlugin and unloadPlugin\",\n        replaceWith = ReplaceWith(\"loadPlugin\"),\n        level = DeprecationLevel.ERROR\n    )\n    suspend fun ___DO_NOT_CALL_FROM_A_PLUGIN_hotReloadAllLocalPlugins(activity: FragmentActivity?) {\n        assertNonRecursiveCallstack()\n\n        Log.d(TAG, \"Reloading all local plugins!\")\n        if (activity == null) return\n        getPluginsLocal().forEach {\n            unloadPlugin(it.filePath)\n        }\n        ___DO_NOT_CALL_FROM_A_PLUGIN_loadAllLocalPlugins(activity, true)\n    }\n\n    /**\n     * @param forceReload see afterPluginsLoadedEvent, basically a way to load all local plugins\n     * and reload all pages even if they are previously valid\n     *\n     * DO NOT USE THIS IN A PLUGIN! It may case an infinite recursive loop lagging or crashing everyone's devices.\n     * If you use it from a plugin, do not expect a stable jvmName, SO DO NOT USE IT!\n     */\n    @Suppress(\"FunctionName\", \"DEPRECATION_ERROR\")\n    @Deprecated(\n        \"Calling this function from a plugin will lead to crashes, use loadPlugin and unloadPlugin\",\n        replaceWith = ReplaceWith(\"loadPlugin\"),\n        level = DeprecationLevel.ERROR\n    )\n    @Throws\n    suspend fun ___DO_NOT_CALL_FROM_A_PLUGIN_loadAllLocalPlugins(context: Context, forceReload: Boolean) {\n        assertNonRecursiveCallstack()\n\n        val dir = File(LOCAL_PLUGINS_PATH)\n\n        if (!dir.exists()) {\n            val res = dir.mkdirs()\n            if (!res) {\n                Log.w(TAG, \"Failed to create local directories\")\n                return\n            }\n        }\n\n        val sortedPlugins = dir.listFiles()\n        // Always sort plugins alphabetically for reproducible results\n\n        Log.d(TAG, \"Files in '${LOCAL_PLUGINS_PATH}' folder: ${sortedPlugins?.size}\")\n\n        // Use app-specific external files directory and copy the file there.\n        // We have to do this because on Android 14+, it otherwise gives SecurityException\n        // due to dex files and setReadOnly seems to have no effect unless it it here.\n        val pluginDirectory = File(context.getExternalFilesDir(null), \"plugins\")\n        if (!pluginDirectory.exists()) {\n            pluginDirectory.mkdirs() // Ensure the plugins directory exists\n        }\n\n        // Make sure all local plugins are fully refreshed.\n        removeKey(PLUGINS_KEY_LOCAL)\n\n        sortedPlugins?.sortedBy { it.name }?.amap { file ->\n            try {\n                val destinationFile = File(pluginDirectory, file.name)\n\n                // Only copy the file if the destination file doesn't exist or if it\n                // has been modified (check file length and modification time).\n                if (!destinationFile.exists() ||\n                    destinationFile.length() != file.length() ||\n                    destinationFile.lastModified() != file.lastModified()\n                ) {\n\n                    // Copy the file to the app-specific plugin directory\n                    file.copyTo(destinationFile, overwrite = true)\n\n                    // After copying, set the destination file's modification time\n                    // to match the source file. We do this for performance so that we\n                    // can check the modification time and not make redundant writes.\n                    destinationFile.setLastModified(file.lastModified())\n                }\n\n                // Load the plugin after it has been copied\n                maybeLoadPlugin(context, destinationFile)\n            } catch (t: Throwable) {\n                Log.e(TAG, \"Failed to copy the file\")\n                logError(t)\n            }\n        }\n\n        loadedLocalPlugins = true\n        afterPluginsLoadedEvent.invoke(forceReload)\n    }\n\n    /** @return true if safe mode is enabled in any possible way. */\n    fun isSafeMode(): Boolean {\n        return checkSafeModeFile() || lastError != null\n    }\n\n    /**\n     * This can be used to override any extension loading to fix crashes!\n     * @return true if safe mode file is present\n     **/\n    fun checkSafeModeFile(): Boolean {\n        return safe {\n            val folder = File(CLOUD_STREAM_FOLDER)\n            if (!folder.exists()) return@safe false\n            val files = folder.listFiles { _, name ->\n                name.equals(\"safe\", ignoreCase = true)\n            }\n            files?.any()\n        } ?: false\n    }\n\n    /**\n     * @return True if successful, false if not\n     * */\n    private suspend fun loadPlugin(context: Context, file: File, data: PluginData): Boolean {\n        val fileName = file.nameWithoutExtension\n        val filePath = file.absolutePath\n        currentlyLoading = fileName\n        Log.i(TAG, \"Loading plugin: $data\")\n\n        return try {\n            // In case of Android 14+ then\n            try {\n                // Set the file as read-only and log if it fails\n                if (!file.setReadOnly()) {\n                    Log.e(TAG, \"Failed to set read-only on plugin file: ${file.name}\")\n                }\n            } catch (t: Throwable) {\n                Log.e(TAG, \"Failed to set dex as read-only\")\n                logError(t)\n            }\n\n            val loader = PathClassLoader(filePath, context.classLoader)\n            var manifest: BasePlugin.Manifest\n            loader.getResourceAsStream(\"manifest.json\").use { stream ->\n                if (stream == null) {\n                    Log.e(TAG, \"Failed to load plugin  $fileName: No manifest found\")\n                    return false\n                }\n                InputStreamReader(stream).use { reader ->\n                    manifest = parseJson(reader, BasePlugin.Manifest::class.java)\n                }\n            }\n\n            val name: String = manifest.name ?: \"NO NAME\".also {\n                Log.d(TAG, \"No manifest name for ${data.internalName}\")\n            }\n            val version: Int = manifest.version ?: PLUGIN_VERSION_NOT_SET.also {\n                Log.d(TAG, \"No manifest version for ${data.internalName}\")\n            }\n\n            @Suppress(\"UNCHECKED_CAST\")\n            val pluginClass: Class<*> =\n                loader.loadClass(manifest.pluginClassName) as Class<out BasePlugin?>\n            val pluginInstance: BasePlugin =\n                pluginClass.getDeclaredConstructor().newInstance() as BasePlugin\n\n            // Sets with the proper version\n            setPluginData(data.copy(version = version))\n\n            if (plugins.containsKey(filePath)) {\n                Log.i(TAG, \"Plugin with name $name already exists\")\n                return true\n            }\n\n            pluginInstance.filename = file.absolutePath\n            if (manifest.requiresResources) {\n                Log.d(TAG, \"Loading resources for ${data.internalName}\")\n                // based on https://stackoverflow.com/questions/7483568/dynamic-resource-loading-from-other-apk\n                val assets = AssetManager::class.java.getDeclaredConstructor().newInstance()\n                val addAssetPath =\n                    AssetManager::class.java.getMethod(\"addAssetPath\", String::class.java)\n                addAssetPath.invoke(assets, file.absolutePath)\n\n                @Suppress(\"DEPRECATION\")\n                (pluginInstance as? Plugin)?.resources = Resources(\n                    assets,\n                    context.resources.displayMetrics,\n                    context.resources.configuration\n                )\n            }\n            plugins[filePath] = pluginInstance\n            classLoaders[loader] = pluginInstance\n            urlPlugins[data.url ?: filePath] = pluginInstance\n            if (pluginInstance is Plugin) {\n                pluginInstance.load(context)\n            } else {\n                pluginInstance.load()\n            }\n            Log.i(TAG, \"Loaded plugin ${data.internalName} successfully\")\n            currentlyLoading = null\n            true\n        } catch (e: Throwable) {\n            Log.e(TAG, \"Failed to load $file: ${Log.getStackTraceString(e)}\")\n            showToast(\n                // context.getActivity(), // we are not always on the main thread\n                context.getString(R.string.plugin_load_fail).format(fileName),\n                Toast.LENGTH_LONG\n            )\n            currentlyLoading = null\n            false\n        }\n    }\n\n    fun unloadPlugin(absolutePath: String) {\n        Log.i(TAG, \"Unloading plugin: $absolutePath\")\n        val plugin = plugins[absolutePath]\n        if (plugin == null) {\n            Log.w(TAG, \"Couldn't find plugin $absolutePath\")\n            return\n        }\n\n        try {\n            plugin.beforeUnload()\n        } catch (e: Throwable) {\n            Log.e(TAG, \"Failed to run beforeUnload $absolutePath: ${Log.getStackTraceString(e)}\")\n        }\n\n        // remove all registered apis\n        synchronized(APIHolder.apis) {\n            APIHolder.apis.filter { api -> api.sourcePlugin == plugin.filename }.forEach {\n                removePluginMapping(it)\n            }\n        }\n        synchronized(APIHolder.allProviders) {\n            APIHolder.allProviders.removeIf { provider: MainAPI -> provider.sourcePlugin == plugin.filename }\n        }\n\n        extractorApis.removeIf { provider: ExtractorApi -> provider.sourcePlugin == plugin.filename }\n\n        synchronized(VideoClickActionHolder.allVideoClickActions) {\n            VideoClickActionHolder.allVideoClickActions.removeIf { action: VideoClickAction -> action.sourcePlugin == plugin.filename }\n        }\n\n        classLoaders.values.removeIf { v -> v == plugin }\n\n        plugins.remove(absolutePath)\n        urlPlugins.values.removeIf { v -> v == plugin }\n    }\n\n    /**\n     * Spits out a unique and safe filename based on name.\n     * Used for repo folders (using repo url) and plugin file names (using internalName)\n     * */\n    fun getPluginSanitizedFileName(name: String): String {\n        return sanitizeFilename(\n            name,\n            true\n        ) + \".\" + name.hashCode()\n    }\n\n    /**\n     * This should not be changed as it is used to also detect if a plugin is installed!\n     **/\n    fun getPluginPath(\n        context: Context,\n        internalName: String,\n        repositoryUrl: String\n    ): File {\n        val folderName = getPluginSanitizedFileName(repositoryUrl) // Guaranteed unique\n        val fileName = getPluginSanitizedFileName(internalName)\n        return File(\"${context.filesDir}/${ONLINE_PLUGINS_FOLDER}/${folderName}/$fileName.cs3\")\n    }\n\n    suspend fun downloadPlugin(\n        activity: Activity,\n        pluginUrl: String,\n        internalName: String,\n        repositoryUrl: String,\n        loadPlugin: Boolean\n    ): Boolean {\n        val file = getPluginPath(activity, internalName, repositoryUrl)\n        return downloadPlugin(activity, pluginUrl, internalName, file, loadPlugin)\n    }\n\n    suspend fun downloadPlugin(\n        activity: Activity,\n        pluginUrl: String,\n        internalName: String,\n        file: File,\n        loadPlugin: Boolean\n    ): Boolean {\n        try {\n            Log.d(TAG, \"Downloading plugin: $pluginUrl to ${file.absolutePath}\")\n            // The plugin file needs to be salted with the repository url hash as to allow multiple repositories with the same internal plugin names\n            val newFile = downloadPluginToFile(pluginUrl, file) ?: return false\n\n            val data = PluginData(\n                internalName,\n                pluginUrl,\n                true,\n                newFile.absolutePath,\n                PLUGIN_VERSION_NOT_SET\n            )\n\n            return if (loadPlugin) {\n                unloadPlugin(file.absolutePath)\n                loadPlugin(\n                    activity,\n                    newFile,\n                    data\n                )\n            } else {\n                setPluginData(data)\n                true\n            }\n        } catch (e: Exception) {\n            logError(e)\n            return false\n        }\n    }\n\n    suspend fun deletePlugin(file: File): Boolean {\n        val list =\n            (getPluginsLocal() + getPluginsOnline()).filter { it.filePath == file.absolutePath }\n\n        return try {\n            if (File(file.absolutePath).delete()) {\n                unloadPlugin(file.absolutePath)\n                list.forEach { deletePluginData(it) }\n                return true\n            }\n            false\n        } catch (e: Exception) {\n            false\n        }\n    }\n\n    /**\n     * DO NOT USE THIS IN A PLUGIN! It may case an infinite recursive loop lagging or crashing everyone's devices.\n     * If you use it from a plugin, do not expect a stable jvmName, SO DO NOT USE IT!\n     */\n    @Suppress(\"FunctionName\", \"DEPRECATION_ERROR\")\n    @Throws\n    @Deprecated(\n        \"Calling this function from a plugin will lead to crashes, use loadPlugin and unloadPlugin\",\n        replaceWith = ReplaceWith(\"loadPlugin\"),\n        level = DeprecationLevel.ERROR\n    )\n    suspend fun ___DO_NOT_CALL_FROM_A_PLUGIN_manuallyReloadAndUpdatePlugins(activity: Activity) {\n        assertNonRecursiveCallstack()\n\n        showToast(activity.getString(R.string.starting_plugin_update_manually), Toast.LENGTH_LONG)\n\n        ___DO_NOT_CALL_FROM_A_PLUGIN_loadAllOnlinePlugins(activity)\n        afterPluginsLoadedEvent.invoke(false)\n\n        val urls = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY)\n            ?: emptyArray()) + PREBUILT_REPOSITORIES\n        val onlinePlugins = urls.toList().amap {\n            getRepoPlugins(it.url)?.toList() ?: emptyList()\n        }.flatten().distinctBy { it.second.url }\n\n        val allPlugins = getPluginsOnline().flatMap { savedData ->\n            onlinePlugins\n                .filter { it.second.internalName == savedData.internalName }\n                .mapNotNull { onlineData ->\n                    OnlinePluginData(savedData, onlineData).takeIf { it.validOnlineData(activity) }\n                }\n        }.distinctBy { it.onlineData.second.url }\n\n        val updatedPlugins = mutableListOf<String>()\n\n        allPlugins.amap { pluginData ->\n            if (pluginData.isDisabled) {\n                Log.e(\n                    \"PluginManager\",\n                    \"Unloading disabled plugin: ${pluginData.onlineData.second.name}\"\n                )\n                unloadPlugin(pluginData.savedData.filePath)\n            } else {\n                val existingFile = File(pluginData.savedData.filePath)\n                if (existingFile.exists()) existingFile.delete()\n\n                if (downloadPlugin(\n                        activity,\n                        pluginData.onlineData.second.url,\n                        pluginData.savedData.internalName,\n                        existingFile,\n                        true\n                    )\n                ) {\n                    updatedPlugins.add(pluginData.onlineData.second.name)\n                }\n            }\n        }.also {\n            main {\n                val message = if (updatedPlugins.isNotEmpty()) {\n                    activity.getString(R.string.plugins_updated_manually, updatedPlugins.size)\n                } else {\n                    activity.getString(R.string.no_plugins_updated_manually)\n                }\n                showToast(message, Toast.LENGTH_LONG)\n\n                val notificationText = UiText.StringResource(\n                    R.string.plugins_updated_manually,\n                    listOf(updatedPlugins.size)\n                )\n                createNotification(activity, notificationText, updatedPlugins)\n\n            }\n        }\n\n        loadedOnlinePlugins = true\n        afterPluginsLoadedEvent.invoke(false)\n\n        Log.i(\"PluginManager\", \"Plugin update done!\")\n    }\n\n    private fun Context.createNotificationChannel() {\n        hasCreatedNotChanel = true\n        // Create the NotificationChannel, but only on API 26+ because\n        // the NotificationChannel class is new and not in the support library\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            val name = EXTENSIONS_CHANNEL_NAME //getString(R.string.channel_name)\n            val descriptionText =\n                EXTENSIONS_CHANNEL_DESCRIPT//getString(R.string.channel_description)\n            val importance = NotificationManager.IMPORTANCE_LOW\n            val channel = NotificationChannel(EXTENSIONS_CHANNEL_ID, name, importance).apply {\n                description = descriptionText\n            }\n            // Register the channel with the system\n            val notificationManager: NotificationManager =\n                this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n            notificationManager.createNotificationChannel(channel)\n        }\n    }\n\n    private fun createNotification(\n        context: Context,\n        uitext: UiText,\n        extensions: List<String>\n    ): Notification? {\n        try {\n\n            if (extensions.isEmpty()) return null\n\n            val content = extensions.joinToString(\", \")\n//        main { // DON'T WANT TO SLOW IT DOWN\n            val builder = NotificationCompat.Builder(context, EXTENSIONS_CHANNEL_ID)\n                .setAutoCancel(false)\n                .setColorized(true)\n                .setOnlyAlertOnce(true)\n                .setSilent(true)\n                .setPriority(NotificationCompat.PRIORITY_LOW)\n                .setColor(context.colorFromAttribute(R.attr.colorPrimary))\n                .setContentTitle(uitext.asString(context))\n                //.setContentTitle(context.getString(title, extensionNames.size))\n                .setSmallIcon(R.drawable.ic_baseline_extension_24)\n                .setStyle(\n                    NotificationCompat.BigTextStyle()\n                        .bigText(content)\n                )\n                .setContentText(content)\n\n            if (!hasCreatedNotChanel) {\n                context.createNotificationChannel()\n            }\n\n            val notification = builder.build()\n            // notificationId is a unique int for each notification that you must define\n            if (ActivityCompat.checkSelfPermission(\n                    context,\n                    Manifest.permission.POST_NOTIFICATIONS\n                ) == PackageManager.PERMISSION_GRANTED\n            ) {\n                NotificationManagerCompat.from(context)\n                    .notify((System.currentTimeMillis() / 1000).toInt(), notification)\n            }\n            return notification\n        } catch (e: Exception) {\n            logError(e)\n            return null\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt",
    "content": "package com.lagradost.cloudstream3.plugins\n\nimport android.content.Context\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.context\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.mvvm.safeAsync\nimport com.lagradost.cloudstream3.plugins.PluginManager.getPluginSanitizedFileName\nimport com.lagradost.cloudstream3.plugins.PluginManager.unloadPlugin\nimport com.lagradost.cloudstream3.ui.settings.extensions.REPOSITORIES_KEY\nimport com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport java.io.BufferedInputStream\nimport java.io.File\nimport java.io.InputStream\nimport java.io.OutputStream\n\n/**\n * Comes with the app, always available in the app, non removable.\n * */\n\ndata class Repository(\n    @JsonProperty(\"iconUrl\") val iconUrl: String?,\n    @JsonProperty(\"name\") val name: String,\n    @JsonProperty(\"description\") val description: String?,\n    @JsonProperty(\"manifestVersion\") val manifestVersion: Int,\n    @JsonProperty(\"pluginLists\") val pluginLists: List<String>\n)\n\n/**\n * Status int as the following:\n * 0: Down\n * 1: Ok\n * 2: Slow\n * 3: Beta only\n * */\ndata class SitePlugin(\n    // Url to the .cs3 file\n    @JsonProperty(\"url\") val url: String,\n    // Status to remotely disable the provider\n    @JsonProperty(\"status\") val status: Int,\n    // Integer over 0, any change of this will trigger an auto update\n    @JsonProperty(\"version\") val version: Int,\n    // Unused currently, used to make the api backwards compatible?\n    // Set to 1\n    @JsonProperty(\"apiVersion\") val apiVersion: Int,\n    // Name to be shown in app\n    @JsonProperty(\"name\") val name: String,\n    // Name to be referenced internally. Separate to make name and url changes possible\n    @JsonProperty(\"internalName\") val internalName: String,\n    @JsonProperty(\"authors\") val authors: List<String>,\n    @JsonProperty(\"description\") val description: String?,\n    // Might be used to go directly to the plugin repo in the future\n    @JsonProperty(\"repositoryUrl\") val repositoryUrl: String?,\n    // These types are yet to be mapped and used, ignore for now\n    @JsonProperty(\"tvTypes\") val tvTypes: List<String>?,\n    // Most often a language tag like \"en\" or \"zh-TW\"\n    @JsonProperty(\"language\") val language: String?,\n    @JsonProperty(\"iconUrl\") val iconUrl: String?,\n    // Automatically generated by the gradle plugin\n    @JsonProperty(\"fileSize\") val fileSize: Long?,\n)\n\n\nobject RepositoryManager {\n    const val ONLINE_PLUGINS_FOLDER = \"Extensions\"\n    val PREBUILT_REPOSITORIES: Array<RepositoryData> by lazy {\n        getKey(\"PREBUILT_REPOSITORIES\") ?: emptyArray()\n    }\n    private val GH_REGEX = Regex(\"^https://raw.githubusercontent.com/([A-Za-z0-9-]+)/([A-Za-z0-9_.-]+)/(.*)$\")\n\n    /* Convert raw.githubusercontent.com urls to cdn.jsdelivr.net if enabled in settings */\n    fun convertRawGitUrl(url: String): String {\n        if (getKey<Boolean>(context!!.getString(R.string.jsdelivr_proxy_key)) != true) return url\n        val match = GH_REGEX.find(url) ?: return url\n        val (user, repo, rest) = match.destructured\n        return \"https://cdn.jsdelivr.net/gh/$user/$repo@$rest\"\n    }\n\n    suspend fun parseRepoUrl(url: String): String? {\n        val fixedUrl = url.trim()\n        return if (fixedUrl.contains(\"^https?://\".toRegex())) {\n            fixedUrl\n        } else if (fixedUrl.contains(\"^(cloudstreamrepo://)|(https://cs\\\\.repo/\\\\??)\".toRegex())) {\n            fixedUrl.replace(\"^(cloudstreamrepo://)|(https://cs\\\\.repo/\\\\??)\".toRegex(), \"\").let {\n                return@let if (!it.contains(\"^https?://\".toRegex()))\n                    \"https://${it}\"\n                else fixedUrl\n            }\n        } else if (fixedUrl.matches(\"^[a-zA-Z0-9!_-]+$\".toRegex())) {\n            safeAsync {\n                app.get(\"https://cutt.ly/${fixedUrl}\", allowRedirects = false).let { it2 ->\n                    it2.headers[\"Location\"]?.let { url ->\n                        if (url.startsWith(\"https://cutt.ly/404\")) return@safeAsync null\n                        if (url.removeSuffix(\"/\") == \"https://cutt.ly\") return@safeAsync null\n                        return@safeAsync url\n                    }\n                }\n            }\n        } else null\n    }\n\n    suspend fun parseRepository(url: String): Repository? {\n        return safeAsync {\n            // Take manifestVersion and such into account later\n            app.get(convertRawGitUrl(url)).parsedSafe()\n        }\n    }\n\n    private suspend fun parsePlugins(pluginUrls: String): List<SitePlugin> {\n        // Take manifestVersion and such into account later\n        return try {\n            val response = app.get(convertRawGitUrl(pluginUrls))\n            // Normal parsed function not working?\n            // return response.parsedSafe()\n            tryParseJson<Array<SitePlugin>>(response.text)?.toList() ?: emptyList()\n        } catch (t: Throwable) {\n            logError(t)\n            emptyList()\n        }\n    }\n\n    /**\n     * Gets all plugins from repositories and pairs them with the repository url\n     * */\n    suspend fun getRepoPlugins(repositoryUrl: String): List<Pair<String, SitePlugin>>? {\n        val repo = parseRepository(repositoryUrl) ?: return null\n        return repo.pluginLists.amap { url ->\n            parsePlugins(url).map {\n                repositoryUrl to it\n            }\n        }.flatten()\n    }\n\n    suspend fun downloadPluginToFile(\n        pluginUrl: String,\n        file: File\n    ): File? {\n        return safeAsync {\n            file.mkdirs()\n\n            // Overwrite if exists\n            if (file.exists()) {\n                file.delete()\n            }\n            file.createNewFile()\n\n            val body = app.get(convertRawGitUrl(pluginUrl)).okhttpResponse.body\n            write(body.byteStream(), file.outputStream())\n            file\n        }\n    }\n\n    fun getRepositories(): Array<RepositoryData> {\n        return getKey(REPOSITORIES_KEY) ?: emptyArray()\n    }\n\n    // Don't want to read before we write in another thread\n    private val repoLock = Mutex()\n    suspend fun addRepository(repository: RepositoryData) {\n        repoLock.withLock {\n            val currentRepos = getRepositories()\n            // No duplicates\n            setKey(REPOSITORIES_KEY, (currentRepos + repository).distinctBy { it.url })\n        }\n    }\n\n    /**\n     * Also deletes downloaded repository plugins\n     * */\n    suspend fun removeRepository(context: Context, repository: RepositoryData) {\n        val extensionsDir = File(context.filesDir, ONLINE_PLUGINS_FOLDER)\n\n        repoLock.withLock {\n            val currentRepos = getKey<Array<RepositoryData>>(REPOSITORIES_KEY) ?: emptyArray()\n            // No duplicates\n            val newRepos = currentRepos.filter { it.url != repository.url }\n            setKey(REPOSITORIES_KEY, newRepos)\n        }\n\n        val file = File(\n            extensionsDir,\n            getPluginSanitizedFileName(repository.url)\n        )\n\n        // Unload all plugins, not using deletePlugin since we\n        // delete all data and files in deleteRepositoryData\n        safe {\n            file.listFiles { plugin: File ->\n                unloadPlugin(plugin.absolutePath)\n                false\n            }\n        }\n\n        PluginManager.deleteRepositoryData(file.absolutePath)\n    }\n\n    private fun write(stream: InputStream, output: OutputStream) {\n        val input = BufferedInputStream(stream)\n        val dataBuffer = ByteArray(512)\n        var readBytes: Int\n        while (input.read(dataBuffer).also { readBytes = it } != -1) {\n            output.write(dataBuffer, 0, readBytes)\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/plugins/VotingApi.kt",
    "content": "package com.lagradost.cloudstream3.plugins\n\nimport android.util.Log\nimport android.widget.Toast\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.context\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.R\nimport java.security.MessageDigest\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\n\nobject VotingApi {\n\n    private const val LOGKEY = \"VotingApi\"\n    private const val API_DOMAIN = \"https://api.countify.xyz\"\n\n    private fun transformUrl(url: String): String =\n        MessageDigest\n            .getInstance(\"SHA-256\")\n            .digest(\"${url}#funny-salt\".toByteArray())\n            .fold(\"\") { str, it -> str + \"%02x\".format(it) }\n\n    suspend fun SitePlugin.getVotes(): Int = getVotes(url)\n    fun SitePlugin.hasVoted(): Boolean = hasVoted(url)\n    suspend fun SitePlugin.vote(): Int = vote(url)\n    fun SitePlugin.canVote(): Boolean = canVote(this.url)\n\n    private val votesCache = mutableMapOf<String, Int>()\n\n    private suspend fun readVote(pluginUrl: String): Int {\n        val id = transformUrl(pluginUrl)\n        val url = \"$API_DOMAIN/get-total/$id\"\n        Log.d(LOGKEY, \"Requesting GET: $url\")\n        return app.get(url).parsedSafe<CountifyResult>()?.count ?: 0\n    }\n\n    private suspend fun writeVote(pluginUrl: String): Boolean {\n        val id = transformUrl(pluginUrl)\n        val url = \"$API_DOMAIN/increment/$id\"\n        Log.d(LOGKEY, \"Requesting POST: $url\")\n        return app.post(url, emptyMap<String, String>())\n            .parsedSafe<CountifyResult>()?.count != null\n    }\n\n    suspend fun getVotes(pluginUrl: String): Int =\n        votesCache[pluginUrl] ?: readVote(pluginUrl).also {\n            votesCache[pluginUrl] = it\n        }\n\n    fun hasVoted(pluginUrl: String) =\n        getKey(\"cs3-votes/${transformUrl(pluginUrl)}\") ?: false\n\n    fun canVote(pluginUrl: String): Boolean =\n        PluginManager.urlPlugins.contains(pluginUrl)\n\n    private val voteLock = Mutex()\n\n    suspend fun vote(pluginUrl: String): Int {\n        voteLock.withLock {\n            if (!canVote(pluginUrl)) {\n                main {\n                    Toast.makeText(\n                        context,\n                        R.string.extension_install_first,\n                        Toast.LENGTH_SHORT\n                    ).show()\n                }\n                return getVotes(pluginUrl)\n            }\n\n            if (hasVoted(pluginUrl)) {\n                main {\n                    Toast.makeText(\n                        context,\n                        R.string.already_voted,\n                        Toast.LENGTH_SHORT\n                    ).show()\n                }\n                return getVotes(pluginUrl)\n            }\n\n            if (writeVote(pluginUrl)) {\n                setKey(\"cs3-votes/${transformUrl(pluginUrl)}\", true)\n                votesCache[pluginUrl] = votesCache[pluginUrl]?.plus(1) ?: 1\n            }\n\n            return getVotes(pluginUrl)\n        }\n    }\n\n    private data class CountifyResult(\n        val id: String? = null,\n        val count: Int? = null\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/receivers/VideoDownloadRestartReceiver.kt",
    "content": "package com.lagradost.cloudstream3.receivers\n\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.util.Log\n\nclass VideoDownloadRestartReceiver : BroadcastReceiver() {\n    override fun onReceive(context: Context?, intent: Intent?) {\n        Log.i(\"Broadcast Listened\", \"Service tried to stop\")\n\n//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n//            context?.startForegroundService(Intent(context, VideoDownloadKeepAliveService::class.java).putExtra(START_VALUE_KEY, RESTART_ALL_DOWNLOADS_AND_QUEUE))\n//        } else {\n//            context?.startService(Intent(context, VideoDownloadKeepAliveService::class.java).putExtra(START_VALUE_KEY, RESTART_ALL_DOWNLOADS_AND_QUEUE))\n//        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/services/BackupWorkManager.kt",
    "content": "package com.lagradost.cloudstream3.services\n\nimport android.content.Context\nimport android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC\nimport android.os.Build.VERSION.SDK_INT\nimport androidx.core.app.NotificationCompat\nimport androidx.work.Constraints\nimport androidx.work.CoroutineWorker\nimport androidx.work.ExistingPeriodicWorkPolicy\nimport androidx.work.ForegroundInfo\nimport androidx.work.PeriodicWorkRequest\nimport androidx.work.WorkManager\nimport androidx.work.WorkerParameters\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.utils.AppContextUtils.createNotificationChannel\nimport com.lagradost.cloudstream3.utils.BackupUtils\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport java.util.concurrent.TimeUnit\n\nconst val BACKUP_CHANNEL_ID = \"cloudstream3.backups\"\nconst val BACKUP_WORK_NAME = \"work_backup\"\nconst val BACKUP_CHANNEL_NAME = \"Backups\"\nconst val BACKUP_CHANNEL_DESCRIPTION = \"Notifications for background backups\"\nconst val BACKUP_NOTIFICATION_ID = 938712898 // Random unique\n\nclass BackupWorkManager(val context: Context, workerParams: WorkerParameters) :\n    CoroutineWorker(context, workerParams) {\n    companion object {\n        fun enqueuePeriodicWork(context: Context?, intervalHours: Long) {\n            if (context == null) return\n\n            if (intervalHours == 0L) {\n                WorkManager.getInstance(context).cancelUniqueWork(BACKUP_WORK_NAME)\n                return\n            }\n\n            val constraints = Constraints.Builder()\n                .setRequiresStorageNotLow(true)\n                .build()\n\n            val periodicSyncDataWork =\n                PeriodicWorkRequest.Builder(\n                    BackupWorkManager::class.java,\n                    intervalHours,\n                    TimeUnit.HOURS\n                )\n                    .addTag(BACKUP_WORK_NAME)\n                    .setConstraints(constraints)\n                    .build()\n\n            WorkManager.getInstance(context).enqueueUniquePeriodicWork(\n                BACKUP_WORK_NAME,\n                ExistingPeriodicWorkPolicy.UPDATE,\n                periodicSyncDataWork\n            )\n\n            // Uncomment below for testing\n\n//            val oneTimeBackupWork =\n//                OneTimeWorkRequest.Builder(BackupWorkManager::class.java)\n//                    .addTag(BACKUP_WORK_NAME)\n//                    .setConstraints(constraints)\n//                    .build()\n//\n//            WorkManager.getInstance(context).enqueue(oneTimeBackupWork)\n        }\n    }\n\n    private val backupNotificationBuilder =\n        NotificationCompat.Builder(context, BACKUP_CHANNEL_ID)\n            .setColorized(true)\n            .setOnlyAlertOnce(true)\n            .setSilent(true)\n            .setAutoCancel(true)\n            .setContentTitle(context.getString(R.string.pref_category_backup))\n            .setPriority(NotificationCompat.PRIORITY_DEFAULT)\n            .setColor(context.colorFromAttribute(R.attr.colorPrimary))\n            .setSmallIcon(R.drawable.ic_cloudstream_monochrome_big)\n\n    override suspend fun doWork(): Result {\n        context.createNotificationChannel(\n            BACKUP_CHANNEL_ID,\n            BACKUP_CHANNEL_NAME,\n            BACKUP_CHANNEL_DESCRIPTION\n        )\n\n        val foregroundInfo = if (SDK_INT >= 29)\n            ForegroundInfo(\n                BACKUP_NOTIFICATION_ID, backupNotificationBuilder.build(), FOREGROUND_SERVICE_TYPE_DATA_SYNC\n            ) else  ForegroundInfo(BACKUP_NOTIFICATION_ID, backupNotificationBuilder.build())\n        setForeground(foregroundInfo)\n\n        BackupUtils.backup(context)\n\n        return Result.success()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/services/DownloadQueueService.kt",
    "content": "package com.lagradost.cloudstream3.services\n\nimport android.app.Service\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.IBinder\nimport android.util.Log\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.app.PendingIntentCompat\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.MainActivity.Companion.lastError\nimport com.lagradost.cloudstream3.MainActivity.Companion.setLastError\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.debugAssert\nimport com.lagradost.cloudstream3.mvvm.debugWarning\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.utils.AppContextUtils.createNotificationChannel\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_RESUME_IN_QUEUE\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_RESUME_PACKAGES\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.downloadEvent\nimport kotlinx.coroutines.ExperimentalCoroutinesApi\nimport kotlinx.coroutines.FlowPreview\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.flow.MutableStateFlow\nimport kotlinx.coroutines.flow.StateFlow\nimport kotlinx.coroutines.flow.combine\nimport kotlinx.coroutines.flow.takeWhile\nimport kotlinx.coroutines.flow.update\nimport kotlinx.coroutines.flow.updateAndGet\nimport kotlinx.coroutines.withTimeoutOrNull\nimport kotlin.system.measureTimeMillis\nimport kotlin.time.Duration.Companion.milliseconds\nimport kotlin.time.Duration.Companion.seconds\n\nclass DownloadQueueService : Service() {\n    companion object {\n        const val TAG = \"DownloadQueueService\"\n        const val DOWNLOAD_QUEUE_CHANNEL_ID = \"cloudstream3.download.queue\"\n        const val DOWNLOAD_QUEUE_CHANNEL_NAME = \"Download queue service\"\n        const val DOWNLOAD_QUEUE_CHANNEL_DESCRIPTION = \"App download queue notification.\"\n        const val DOWNLOAD_QUEUE_NOTIFICATION_ID = 917194232 // Random unique\n        @Volatile\n        var isRunning = false\n\n        fun getIntent(\n            context: Context,\n        ): Intent {\n            return Intent(context, DownloadQueueService::class.java)\n        }\n\n        private val _downloadInstances: MutableStateFlow<List<VideoDownloadManager.EpisodeDownloadInstance>> =\n            MutableStateFlow(emptyList())\n\n        /** Flow of all active downloads, not queued. May temporarily contain completed or failed EpisodeDownloadInstances.\n         * Completed or failed instances are automatically removed by the download queue service.\n         *\n         */\n        val downloadInstances: StateFlow<List<VideoDownloadManager.EpisodeDownloadInstance>> =\n            _downloadInstances\n\n        private val totalDownloadFlow =\n            downloadInstances.combine(DownloadQueueManager.queue) { instances, queue ->\n                instances to queue\n            }\n                .combine(VideoDownloadManager.currentDownloads) { (instances, queue), currentDownloads ->\n                    Triple(instances, queue, currentDownloads)\n                }\n    }\n\n\n    private val baseNotification by lazy {\n        val intent = Intent(this, MainActivity::class.java)\n        val pendingIntent =\n            PendingIntentCompat.getActivity(this, 0, intent, 0, false)\n\n        val activeDownloads = resources.getQuantityString(R.plurals.downloads_active, 0).format(0)\n        val activeQueue = resources.getQuantityString(R.plurals.downloads_queued, 0).format(0)\n\n        NotificationCompat.Builder(this, DOWNLOAD_QUEUE_CHANNEL_ID)\n            .setOngoing(true) // Make it persistent\n            .setAutoCancel(false)\n            .setColorized(false)\n            .setOnlyAlertOnce(true)\n            .setSilent(true)\n            .setShowWhen(false)\n            // If low priority then the notification might not show :(\n            .setPriority(NotificationCompat.PRIORITY_DEFAULT)\n            .setColor(this.colorFromAttribute(R.attr.colorPrimary))\n            .setContentText(activeDownloads)\n            .setSubText(activeQueue)\n            .setContentIntent(pendingIntent)\n            .setSmallIcon(R.drawable.download_icon_load)\n    }\n\n\n    private fun updateNotification(context: Context, downloads: Int, queued: Int) {\n        val activeDownloads =\n            resources.getQuantityString(R.plurals.downloads_active, downloads).format(downloads)\n        val activeQueue =\n            resources.getQuantityString(R.plurals.downloads_queued, queued).format(queued)\n\n        val newNotification = baseNotification\n            .setContentText(activeDownloads)\n            .setSubText(activeQueue)\n            .build()\n\n        safe {\n            NotificationManagerCompat.from(context)\n                .notify(DOWNLOAD_QUEUE_NOTIFICATION_ID, newNotification)\n        }\n    }\n\n    // We always need to listen to events, even before the download is launched.\n    // Stopping link loading is an event which can trigger before downloading.\n    val downloadEventListener = { event: Pair<Int, VideoDownloadManager.DownloadActionType> ->\n        when (event.second) {\n            VideoDownloadManager.DownloadActionType.Stop -> {\n                removeKey(KEY_RESUME_PACKAGES, event.first.toString())\n                removeKey(KEY_RESUME_IN_QUEUE, event.first.toString())\n                DownloadQueueManager.cancelDownload(event.first)\n            }\n\n            else -> {}\n        }\n    }\n\n    @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class)\n    override fun onCreate() {\n        isRunning = true\n        val context: Context = this // To make code more readable\n\n        Log.d(TAG, \"Download queue service started.\")\n        this.createNotificationChannel(\n            DOWNLOAD_QUEUE_CHANNEL_ID,\n            DOWNLOAD_QUEUE_CHANNEL_NAME,\n            DOWNLOAD_QUEUE_CHANNEL_DESCRIPTION\n        )\n        if (SDK_INT >= 29) {\n            startForeground(\n                DOWNLOAD_QUEUE_NOTIFICATION_ID,\n                baseNotification.build(),\n                FOREGROUND_SERVICE_TYPE_DATA_SYNC\n            )\n        } else {\n            startForeground(DOWNLOAD_QUEUE_NOTIFICATION_ID, baseNotification.build())\n        }\n\n        downloadEvent += downloadEventListener\n\n        val queueJob = ioSafe {\n            // Ensure this is up to date to prevent race conditions with MainActivity launches\n            setLastError(context)\n            // Early return, to prevent waiting for plugins in safe mode\n            if (lastError != null) return@ioSafe\n\n            // Try to ensure all plugins are loaded before starting the downloader.\n            // To prevent infinite stalls we use a timeout of 15 seconds, it is judged as long enough\n            val timeout = 15.seconds\n            val timeTaken = withTimeoutOrNull(timeout) {\n                measureTimeMillis {\n                    while (!(PluginManager.loadedOnlinePlugins && PluginManager.loadedLocalPlugins)) {\n                        delay(100.milliseconds)\n                    }\n                }\n            }\n\n            debugWarning({ timeTaken == null || timeTaken > 3_000 }, {\n                \"Abnormally long downloader startup time of: ${timeTaken ?: timeout.inWholeMilliseconds}ms\"\n            })\n            debugAssert({ timeTaken == null }, { \"Downloader startup should not time out\" })\n\n            totalDownloadFlow\n                .takeWhile { (instances, queue) ->\n                    // Stop if destroyed\n                    isRunning\n                            // Run as long as there is a queue to process\n                            && (instances.isNotEmpty() || queue.isNotEmpty())\n                            // Run as long as there are no app crashes\n                            && lastError == null\n                }\n                .collect { (_, queue, currentDownloads) ->\n                    // Remove completed or failed\n                    val newInstances = _downloadInstances.updateAndGet { currentInstances ->\n                        currentInstances.filterNot { it.isCompleted || it.isFailed || it.isCancelled }\n                    }\n\n                    val maxDownloads = VideoDownloadManager.maxConcurrentDownloads(context)\n                    val currentInstanceCount = newInstances.size\n\n                    val newDownloads = minOf(\n                        // Cannot exceed the max downloads\n                        maxOf(0, maxDownloads - currentInstanceCount),\n                        // Cannot start more downloads than the queue size\n                        queue.size\n                    )\n\n                    // Cant start multiple downloads at once. If this is rerun it may start too many downloads.\n                    if (newDownloads > 0) {\n                        _downloadInstances.update { instances ->\n                            val downloadInstance = DownloadQueueManager.popQueue(context)\n                            if (downloadInstance != null) {\n                                downloadInstance.startDownload()\n                                instances + downloadInstance\n                            } else {\n                                instances\n                            }\n                        }\n                    }\n\n                    // The downloads actually displayed to the user with a notification\n                    val currentVisualDownloads =\n                        currentDownloads.size + newInstances.count {\n                            currentDownloads.contains(it.downloadQueueWrapper.id)\n                                .not()\n                        }\n                    // Just the queue\n                    val currentVisualQueue = queue.size\n\n                    updateNotification(context, currentVisualDownloads, currentVisualQueue)\n                }\n        }\n\n        // Stop self regardless of job outcome\n        queueJob.invokeOnCompletion { throwable ->\n            if (throwable != null) {\n                logError(throwable)\n            }\n            safe {\n                stopSelf()\n            }\n        }\n    }\n\n    override fun onDestroy() {\n        Log.d(TAG, \"Download queue service stopped.\")\n        downloadEvent -= downloadEventListener\n        isRunning = false\n        super.onDestroy()\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        return START_STICKY // We want the service restarted if its killed\n    }\n\n    override fun onBind(intent: Intent?): IBinder? = null\n\n    override fun onTimeout(reason: Int) {\n        stopSelf()\n        Log.e(TAG, \"Service stopped due to timeout: $reason\")\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/services/PackageInstallerService.kt",
    "content": "package com.lagradost.cloudstream3.services\n\nimport android.app.NotificationManager\nimport android.app.Service\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.IBinder\nimport android.util.Log\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.PendingIntentCompat\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.MainActivity.Companion.deleteFileOnExit\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.utils.ApkInstaller\nimport com.lagradost.cloudstream3.utils.AppContextUtils.createNotificationChannel\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport kotlin.math.roundToInt\n\nclass PackageInstallerService : Service() {\n    private var installer: ApkInstaller? = null\n\n    private val baseNotification by lazy {\n        val intent = Intent(this, MainActivity::class.java)\n        val pendingIntent =\n            PendingIntentCompat.getActivity(this, 0, intent, 0, false)\n\n        NotificationCompat.Builder(this, UPDATE_CHANNEL_ID)\n            .setAutoCancel(false)\n            .setColorized(true)\n            .setOnlyAlertOnce(true)\n            .setSilent(true)\n            // If low priority then the notification might not show :(\n            .setPriority(NotificationCompat.PRIORITY_DEFAULT)\n            .setColor(this.colorFromAttribute(R.attr.colorPrimary))\n            .setContentTitle(getString(R.string.update_notification_downloading))\n            .setContentIntent(pendingIntent)\n            .setSmallIcon(R.drawable.rdload)\n    }\n\n    override fun onCreate() {\n        this.createNotificationChannel(\n            UPDATE_CHANNEL_ID,\n            UPDATE_CHANNEL_NAME,\n            UPDATE_CHANNEL_DESCRIPTION\n        )\n        if (SDK_INT >= 29)\n        startForeground(UPDATE_NOTIFICATION_ID, baseNotification.build(), FOREGROUND_SERVICE_TYPE_DATA_SYNC)\n        else startForeground(UPDATE_NOTIFICATION_ID, baseNotification.build())\n    }\n\n    private val updateLock = Mutex()\n\n    private suspend fun downloadUpdate(url: String): Boolean {\n        try {\n            Log.d(\"PackageInstallerService\", \"Downloading update: $url\")\n\n            // Delete all old updates\n            ioSafe {\n                val appUpdateName = \"CloudStream\"\n                val appUpdateSuffix = \"apk\"\n\n                this@PackageInstallerService.cacheDir.listFiles()?.filter {\n                    it.name.startsWith(appUpdateName) && it.extension == appUpdateSuffix\n                }?.forEach {\n                    deleteFileOnExit(it)\n                }\n            }\n\n            updateLock.withLock {\n                updateNotificationProgress(\n                    0f,\n                    ApkInstaller.InstallProgressStatus.Downloading\n                )\n\n                val body = app.get(url).body\n                val inputStream = body.byteStream()\n                installer = ApkInstaller(this)\n                val totalSize = body.contentLength()\n                var currentSize = 0\n\n                installer?.installApk(this, inputStream, totalSize, {\n                    currentSize += it\n                    // Prevent div 0\n                    if (totalSize == 0L) return@installApk\n\n                    val percentage = currentSize / totalSize.toFloat()\n                    updateNotificationProgress(\n                        percentage,\n                        ApkInstaller.InstallProgressStatus.Downloading\n                    )\n                }) { status ->\n                    updateNotificationProgress(0f, status)\n                }\n            }\n            return true\n        } catch (e: Exception) {\n            logError(e)\n            updateNotificationProgress(0f, ApkInstaller.InstallProgressStatus.Failed)\n            return false\n        }\n    }\n\n    private fun updateNotificationProgress(\n        percentage: Float,\n        state: ApkInstaller.InstallProgressStatus\n    ) {\n//        Log.d(LOG_TAG, \"Downloading app update progress $percentage | $state\")\n        val text = when (state) {\n            ApkInstaller.InstallProgressStatus.Installing -> R.string.update_notification_installing\n            ApkInstaller.InstallProgressStatus.Preparing, ApkInstaller.InstallProgressStatus.Downloading -> R.string.update_notification_downloading\n            ApkInstaller.InstallProgressStatus.Failed -> R.string.update_notification_failed\n        }\n\n        val newNotification = baseNotification\n            .setContentTitle(getString(text))\n            .apply {\n                if (state == ApkInstaller.InstallProgressStatus.Failed) {\n                    setSmallIcon(R.drawable.rderror)\n                    setAutoCancel(true)\n                } else {\n                    setProgress(\n                        10000, (10000 * percentage).roundToInt(),\n                        state != ApkInstaller.InstallProgressStatus.Downloading\n                    )\n                }\n            }\n            .build()\n\n        val notificationManager =\n            getSystemService(NOTIFICATION_SERVICE) as NotificationManager\n\n        // Persistent notification on failure\n        val id =\n            if (state == ApkInstaller.InstallProgressStatus.Failed) UPDATE_NOTIFICATION_ID + 1 else UPDATE_NOTIFICATION_ID\n        notificationManager.notify(id, newNotification)\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        val url = intent?.getStringExtra(EXTRA_URL) ?: return START_NOT_STICKY\n        ioSafe {\n            downloadUpdate(url)\n            // Close the service after the update is done\n            // If no sleep then the install prompt may not appear and the notification\n            // will disappear instantly\n            delay(10_000)\n            this@PackageInstallerService.stopSelf()\n        }\n        return START_NOT_STICKY\n    }\n\n    override fun onDestroy() {\n        installer?.unregisterInstallActionReceiver()\n        installer = null\n        this.stopSelf()\n        super.onDestroy()\n    }\n\n    override fun onBind(i: Intent?): IBinder? = null\n\n    override fun onTimeout(reason: Int) {\n        stopSelf()\n        Log.e(\"PackageInstallerService\", \"Service stopped due to timeout: $reason\")\n    }\n\n    companion object {\n        private const val EXTRA_URL = \"EXTRA_URL\"\n\n        const val UPDATE_CHANNEL_ID = \"cloudstream3.updates\"\n        const val UPDATE_CHANNEL_NAME = \"App Updates\"\n        const val UPDATE_CHANNEL_DESCRIPTION = \"App updates notification channel\"\n        const val UPDATE_NOTIFICATION_ID = -68454136 // Random unique\n\n        fun getIntent(\n            context: Context,\n            url: String,\n        ): Intent {\n            return Intent(context, PackageInstallerService::class.java)\n                .putExtra(EXTRA_URL, url)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/services/SubscriptionWorkManager.kt",
    "content": "package com.lagradost.cloudstream3.services\n\nimport android.app.NotificationManager\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC\nimport android.os.Build.VERSION.SDK_INT\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.net.toUri\nimport androidx.work.*\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.AppContextUtils.createNotificationChannel\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiDubstatusSettings\nimport com.lagradost.cloudstream3.utils.Coroutines.ioWork\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllSubscriptions\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getDub\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.downloader.DownloadUtils.getImageBitmapFromUrl\nimport kotlinx.coroutines.withTimeoutOrNull\nimport java.util.concurrent.TimeUnit\n\nconst val SUBSCRIPTION_CHANNEL_ID = \"cloudstream3.subscriptions\"\nconst val SUBSCRIPTION_WORK_NAME = \"work_subscription\"\nconst val SUBSCRIPTION_CHANNEL_NAME = \"Subscriptions\"\nconst val SUBSCRIPTION_CHANNEL_DESCRIPTION = \"Notifications for new episodes on subscribed shows\"\nconst val SUBSCRIPTION_NOTIFICATION_ID = 938712897 // Random unique\n\nclass SubscriptionWorkManager(val context: Context, workerParams: WorkerParameters) :\n    CoroutineWorker(context, workerParams) {\n    companion object {\n        fun enqueuePeriodicWork(context: Context?) {\n            if (context == null) return\n\n            val constraints = Constraints.Builder()\n                .setRequiredNetworkType(NetworkType.CONNECTED)\n                .build()\n\n            val periodicSyncDataWork =\n                PeriodicWorkRequest.Builder(SubscriptionWorkManager::class.java, 6, TimeUnit.HOURS)\n                    .addTag(SUBSCRIPTION_WORK_NAME)\n                    .setConstraints(constraints)\n                    .build()\n\n            WorkManager.getInstance(context).enqueueUniquePeriodicWork(\n                SUBSCRIPTION_WORK_NAME,\n                ExistingPeriodicWorkPolicy.KEEP,\n                periodicSyncDataWork\n            )\n\n            // Uncomment below for testing\n\n//            val oneTimeSyncDataWork =\n//                OneTimeWorkRequest.Builder(SubscriptionWorkManager::class.java)\n//                    .addTag(SUBSCRIPTION_WORK_NAME)\n//                    .setConstraints(constraints)\n//                    .build()\n//\n//            WorkManager.getInstance(context).enqueue(oneTimeSyncDataWork)\n        }\n    }\n\n    private val progressNotificationBuilder =\n        NotificationCompat.Builder(context, SUBSCRIPTION_CHANNEL_ID)\n            .setAutoCancel(false)\n            .setColorized(true)\n            .setOnlyAlertOnce(true)\n            .setSilent(true)\n            .setPriority(NotificationCompat.PRIORITY_DEFAULT)\n            .setColor(context.colorFromAttribute(R.attr.colorPrimary))\n            .setContentTitle(context.getString(R.string.subscription_in_progress_notification))\n            .setSmallIcon(com.google.android.gms.cast.framework.R.drawable.quantum_ic_refresh_white_24)\n            .setProgress(0, 0, true)\n\n    private val updateNotificationBuilder =\n        NotificationCompat.Builder(context, SUBSCRIPTION_CHANNEL_ID)\n            .setColorized(true)\n            .setOnlyAlertOnce(true)\n            .setAutoCancel(true)\n            .setPriority(NotificationCompat.PRIORITY_DEFAULT)\n            .setColor(context.colorFromAttribute(R.attr.colorPrimary))\n            .setSmallIcon(R.drawable.ic_cloudstream_monochrome_big)\n\n    private val notificationManager: NotificationManager =\n        context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n\n    private fun updateProgress(max: Int, progress: Int, indeterminate: Boolean) {\n        notificationManager.notify(\n            SUBSCRIPTION_NOTIFICATION_ID, progressNotificationBuilder\n                .setProgress(max, progress, indeterminate)\n                .build()\n        )\n    }\n    @Suppress(\"DEPRECATION_ERROR\")\n    override suspend fun doWork(): Result {\n        try {\n//        println(\"Update subscriptions!\")\n            context.createNotificationChannel(\n                SUBSCRIPTION_CHANNEL_ID,\n                SUBSCRIPTION_CHANNEL_NAME,\n                SUBSCRIPTION_CHANNEL_DESCRIPTION\n            )\n\n            val foregroundInfo = if (SDK_INT >= 29)\n                ForegroundInfo(\n                    SUBSCRIPTION_NOTIFICATION_ID,\n                    progressNotificationBuilder.build(),\n                    FOREGROUND_SERVICE_TYPE_DATA_SYNC\n                ) else ForegroundInfo(SUBSCRIPTION_NOTIFICATION_ID, progressNotificationBuilder.build(),)\n            setForeground(foregroundInfo)\n\n            val subscriptions = getAllSubscriptions()\n\n            if (subscriptions.isEmpty()) {\n                WorkManager.getInstance(context).cancelWorkById(this.id)\n                return Result.success()\n            }\n\n            val max = subscriptions.size\n            var progress = 0\n\n            updateProgress(max, progress, true)\n\n            // We need all plugins loaded.\n            PluginManager.___DO_NOT_CALL_FROM_A_PLUGIN_loadAllOnlinePlugins(context)\n            PluginManager.___DO_NOT_CALL_FROM_A_PLUGIN_loadAllLocalPlugins(context, false)\n\n            subscriptions.amap { savedData ->\n                try {\n                    val id = savedData.id ?: return@amap null\n                    val api = getApiFromNameNull(savedData.apiName) ?: return@amap null\n\n                    // Reasonable timeout to prevent having this worker run forever.\n                    val response = withTimeoutOrNull(60_000) {\n                        api.load(savedData.url) as? EpisodeResponse\n                    } ?: return@amap null\n\n                    val dubPreference =\n                        getDub(id) ?: if (\n                            context.getApiDubstatusSettings().contains(DubStatus.Dubbed)\n                        ) {\n                            DubStatus.Dubbed\n                        } else {\n                            DubStatus.Subbed\n                        }\n\n                    val latestEpisodes = response.getLatestEpisodes()\n                    val latestPreferredEpisode = latestEpisodes[dubPreference]\n\n                    val (shouldUpdate, latestEpisode) = if (latestPreferredEpisode != null) {\n                        val latestSeenEpisode =\n                            savedData.lastSeenEpisodeCount[dubPreference] ?: Int.MIN_VALUE\n                        val shouldUpdate = latestPreferredEpisode > latestSeenEpisode\n                        shouldUpdate to latestPreferredEpisode\n                    } else {\n                        val latestEpisode = latestEpisodes[DubStatus.None] ?: Int.MIN_VALUE\n                        val latestSeenEpisode =\n                            savedData.lastSeenEpisodeCount[DubStatus.None] ?: Int.MIN_VALUE\n                        val shouldUpdate = latestEpisode > latestSeenEpisode\n                        shouldUpdate to latestEpisode\n                    }\n\n                    DataStoreHelper.updateSubscribedData(\n                        id,\n                        savedData,\n                        response\n                    )\n\n                    if (shouldUpdate) {\n                        val updateHeader = savedData.name\n                        val updateDescription = txt(\n                            R.string.subscription_episode_released,\n                            latestEpisode,\n                            savedData.name\n                        ).asString(context)\n\n                        val intent = Intent(context, MainActivity::class.java).apply {\n                            data = savedData.url.toUri()\n                            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK\n                        }.putExtra(MainActivity.API_NAME_EXTRA_KEY, api.name)\n\n                        val pendingIntent =\n                            PendingIntentCompat.getActivity(context, 0, intent, 0, false)\n\n                        val poster = ioWork {\n                            savedData.posterUrl?.let { url ->\n                                context.getImageBitmapFromUrl(\n                                    url,\n                                    savedData.posterHeaders\n                                )\n                            }\n                        }\n\n                        val updateNotification =\n                            updateNotificationBuilder.setContentTitle(updateHeader)\n                                .setContentText(updateDescription)\n                                .setContentIntent(pendingIntent)\n                                .setLargeIcon(poster)\n                                .build()\n\n                        notificationManager.notify(id, updateNotification)\n                    }\n\n                    // You can probably get some issues here since this is async but it does not matter much.\n                    updateProgress(max, ++progress, false)\n                } catch (t: Throwable) {\n                    logError(t)\n                }\n            }\n\n            return Result.success()\n        } catch (t: Throwable) {\n            logError(t)\n            // ye, while this is not correct, but because gods know why android just crashes\n            // and this causes major battery usage as it retries it inf times. This is better, just\n            // in case android decides to be android and fuck us\n            return Result.success()\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/services/VideoDownloadService.kt",
    "content": "package com.lagradost.cloudstream3.services\nimport android.app.Service\nimport android.content.Intent\nimport android.os.IBinder\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.cancel\nimport kotlinx.coroutines.launch\n\n/** Handle notification actions such as pause/resume downloads */\nclass VideoDownloadService : Service() {\n\n    private val downloadScope = CoroutineScope(Dispatchers.Default)\n\n    override fun onBind(intent: Intent?): IBinder? {\n        return null\n    }\n\n    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {\n        if (intent != null) {\n            val id = intent.getIntExtra(\"id\", -1)\n            val type = intent.getStringExtra(\"type\")\n            if (id != -1 && type != null) {\n                val state = when (type) {\n                    \"resume\" -> VideoDownloadManager.DownloadActionType.Resume\n                    \"pause\" -> VideoDownloadManager.DownloadActionType.Pause\n                    \"stop\" -> VideoDownloadManager.DownloadActionType.Stop\n                    else -> return START_NOT_STICKY\n                }\n\n                downloadScope.launch {\n                    VideoDownloadManager.downloadEvent.invoke(Pair(id, state))\n                }\n            }\n        }\n\n        return START_NOT_STICKY\n    }\n\n    override fun onDestroy() {\n        downloadScope.coroutineContext.cancel()\n        super.onDestroy()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/subtitles/AbstractSubProvider.kt",
    "content": "package com.lagradost.cloudstream3.subtitles\n\nimport androidx.core.net.toUri\nimport com.lagradost.cloudstream3.MainActivity.Companion.deleteFileOnExit\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.ui.player.SubtitleOrigin\nimport okio.BufferedSource\nimport okio.buffer\nimport okio.sink\nimport okio.source\nimport java.io.File\nimport java.util.zip.ZipInputStream\n\n/**\n * A builder for subtitle files.\n * @see addUrl\n * @see addFile\n */\nclass SubtitleResource {\n    fun downloadFile(source: BufferedSource): File {\n        val file = File.createTempFile(\"temp-subtitle\", \".tmp\").apply {\n            deleteFileOnExit(this)\n        }\n        val sink = file.sink().buffer()\n        sink.writeAll(source)\n        sink.close()\n        source.close()\n\n        return file\n    }\n\n    private fun unzip(file: File): List<Pair<String, File>> {\n        val entries = mutableListOf<Pair<String, File>>()\n\n        ZipInputStream(file.inputStream()).use { zipInputStream ->\n            var zipEntry = zipInputStream.nextEntry\n\n            while (zipEntry != null) {\n                val tempFile = File.createTempFile(\"unzipped-subtitle\", \".tmp\").apply {\n                    deleteFileOnExit(this)\n                }\n                entries.add(zipEntry.name to tempFile)\n\n                tempFile.sink().buffer().use { buffer ->\n                    buffer.writeAll(zipInputStream.source())\n                }\n\n                zipEntry = zipInputStream.nextEntry\n            }\n        }\n        return entries\n    }\n\n    data class SingleSubtitleResource(\n        val name: String?,\n        val url: String,\n        val origin: SubtitleOrigin\n    )\n\n    private var resources: MutableList<SingleSubtitleResource> = mutableListOf()\n\n    fun getSubtitles(): List<SingleSubtitleResource> {\n        return resources.toList()\n    }\n\n    fun addUrl(url: String?, name: String? = null) {\n        if (url == null) return\n        this.resources.add(\n            SingleSubtitleResource(name, url, SubtitleOrigin.URL)\n        )\n    }\n\n    fun addFile(file: File, name: String? = null) {\n        this.resources.add(\n            SingleSubtitleResource(name, file.toUri().toString(), SubtitleOrigin.DOWNLOADED_FILE)\n        )\n        deleteFileOnExit(file)\n    }\n\n    suspend fun addZipUrl(\n        url: String,\n        nameGenerator: (String, File) -> String? = { _, _ -> null }\n    ) {\n        val source = app.get(url).okhttpResponse.body.source()\n        val zip = downloadFile(source)\n        val realFiles = unzip(zip)\n        zip.deleteRecursively()\n        realFiles.forEach { (name, subtitleFile) ->\n            addFile(subtitleFile, nameGenerator(name, subtitleFile))\n        }\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/subtitles/AbstractSubtitleEntities.kt",
    "content": "package com.lagradost.cloudstream3.subtitles\n\nimport com.lagradost.cloudstream3.TvType\n\nclass AbstractSubtitleEntities {\n    data class SubtitleEntity(\n        var idPrefix : String,\n        var name: String = \"\", //Title of movie/series. This is the one to be displayed when choosing.\n        var lang: String = \"en\",\n        var data: String = \"\", //Id or link, depends on provider how to process\n        var type: TvType = TvType.Movie, //Movie, TV series, etc..\n        var source: String,\n        var epNumber: Int? = null,\n        var seasonNumber: Int? = null,\n        var year: Int? = null,\n        var isHearingImpaired: Boolean = false,\n        var headers: Map<String, String> = emptyMap()\n    )\n\n    data class SubtitleSearch(\n        var query: String = \"\",\n        var lang: String? = null,\n        var imdbId: String? = null,\n        var tmdbId: Int? = null,\n        var malId: Int? = null,\n        var aniListId: Int? = null,\n        var epNumber: Int? = null,\n        var seasonNumber: Int? = null,\n        var year: Int? = null\n    )\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders\r\n\r\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\r\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\r\nimport com.lagradost.cloudstream3.LoadResponse\r\nimport com.lagradost.cloudstream3.syncproviders.providers.Addic7ed\r\nimport com.lagradost.cloudstream3.syncproviders.providers.AniListApi\r\nimport com.lagradost.cloudstream3.syncproviders.providers.KitsuApi\r\nimport com.lagradost.cloudstream3.syncproviders.providers.LocalList\r\nimport com.lagradost.cloudstream3.syncproviders.providers.MALApi\r\nimport com.lagradost.cloudstream3.syncproviders.providers.OpenSubtitlesApi\r\nimport com.lagradost.cloudstream3.syncproviders.providers.SimklApi\r\nimport com.lagradost.cloudstream3.syncproviders.providers.SubDlApi\r\nimport com.lagradost.cloudstream3.syncproviders.providers.SubSourceApi\r\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\r\nimport java.util.concurrent.TimeUnit\r\n\r\nabstract class AccountManager {\r\n    companion object {\r\n        const val NONE_ID: Int = -1\r\n        val malApi = MALApi()\r\n        val kitsuApi = KitsuApi()\r\n        val aniListApi = AniListApi()\r\n        val simklApi = SimklApi()\r\n        val localListApi = LocalList()\r\n\r\n        val openSubtitlesApi = OpenSubtitlesApi()\r\n        val addic7ed = Addic7ed()\r\n        val subDlApi = SubDlApi()\r\n        val subSourceApi = SubSourceApi()\r\n\r\n        var cachedAccounts: MutableMap<String, Array<AuthData>>\r\n        var cachedAccountIds: MutableMap<String, Int>\r\n\r\n        const val ACCOUNT_TOKEN = \"auth_tokens\"\r\n        const val ACCOUNT_IDS = \"auth_ids\"\r\n\r\n        fun accounts(prefix: String): Array<AuthData> {\r\n            require(prefix != \"NONE\")\r\n            return getKey<Array<AuthData>>(\r\n                ACCOUNT_TOKEN,\r\n                \"${prefix}/${DataStoreHelper.currentAccount}\"\r\n            ) ?: arrayOf()\r\n        }\r\n\r\n        fun updateAccounts(prefix: String, array: Array<AuthData>) {\r\n            require(prefix != \"NONE\")\r\n            setKey(ACCOUNT_TOKEN, \"${prefix}/${DataStoreHelper.currentAccount}\", array)\r\n            synchronized(cachedAccounts) {\r\n                cachedAccounts[prefix] = array\r\n            }\r\n        }\r\n\r\n        fun updateAccountsId(prefix: String, id: Int) {\r\n            require(prefix != \"NONE\")\r\n            setKey(ACCOUNT_IDS, \"${prefix}/${DataStoreHelper.currentAccount}\", id)\r\n            synchronized(cachedAccountIds) {\r\n                cachedAccountIds[prefix] = id\r\n            }\r\n        }\r\n\r\n        val allApis = arrayOf(\r\n            SyncRepo(malApi),\r\n            SyncRepo(kitsuApi),\r\n            SyncRepo(aniListApi),\r\n            SyncRepo(simklApi),\r\n            SyncRepo(localListApi),\r\n            SubtitleRepo(openSubtitlesApi),\r\n            SubtitleRepo(addic7ed),\r\n            SubtitleRepo(subDlApi)\r\n        )\r\n\r\n        fun updateAccountIds() {\r\n            val ids = mutableMapOf<String, Int>()\r\n            for (api in allApis) {\r\n                ids.put(\r\n                    api.idPrefix,\r\n                    getKey<Int>(\r\n                        ACCOUNT_IDS,\r\n                        \"${api.idPrefix}/${DataStoreHelper.currentAccount}\",\r\n                        NONE_ID\r\n                    ) ?: NONE_ID\r\n                )\r\n            }\r\n            synchronized(cachedAccountIds) {\r\n                cachedAccountIds = ids\r\n            }\r\n        }\r\n\r\n        init {\r\n            val data = mutableMapOf<String, Array<AuthData>>()\r\n            val ids = mutableMapOf<String, Int>()\r\n            for (api in allApis) {\r\n                data.put(api.idPrefix, accounts(api.idPrefix))\r\n                ids.put(\r\n                    api.idPrefix,\r\n                    getKey<Int>(\r\n                        ACCOUNT_IDS,\r\n                        \"${api.idPrefix}/${DataStoreHelper.currentAccount}\",\r\n                        NONE_ID\r\n                    ) ?: NONE_ID\r\n                )\r\n            }\r\n            cachedAccounts = data\r\n            cachedAccountIds = ids\r\n        }\r\n\r\n        // I do not want to place this in the init block as JVM initialization order is weird, and it may cause exceptions\r\n        // accessing other classes\r\n        fun initMainAPI() {\r\n            LoadResponse.malIdPrefix = malApi.idPrefix\r\n            LoadResponse.kitsuIdPrefix = kitsuApi.idPrefix\r\n            LoadResponse.aniListIdPrefix = aniListApi.idPrefix\r\n            LoadResponse.simklIdPrefix = simklApi.idPrefix\r\n        }\r\n\r\n        val subtitleProviders = arrayOf(\r\n            SubtitleRepo(openSubtitlesApi),\r\n            SubtitleRepo(addic7ed),\r\n            SubtitleRepo(subDlApi)\r\n        )\r\n        val syncApis = arrayOf(\r\n            SyncRepo(malApi),\r\n            SyncRepo(kitsuApi),\r\n            SyncRepo(aniListApi),\r\n            SyncRepo(simklApi),\r\n            SyncRepo(localListApi)\r\n        )\r\n\r\n        const val APP_STRING = \"cloudstreamapp\"\r\n        const val APP_STRING_REPO = \"cloudstreamrepo\"\r\n        const val APP_STRING_PLAYER = \"cloudstreamplayer\"\r\n\r\n        // Instantly start the search given a query\r\n        const val APP_STRING_SEARCH = \"cloudstreamsearch\"\r\n\r\n        // Instantly resume watching a show\r\n        const val APP_STRING_RESUME_WATCHING = \"cloudstreamcontinuewatching\"\r\n\r\n        const val APP_STRING_SHARE = \"csshare\"\r\n\r\n        fun secondsToReadable(seconds: Int, completedValue: String): String {\r\n            var secondsLong = seconds.toLong()\r\n            val days = TimeUnit.SECONDS\r\n                .toDays(secondsLong)\r\n            secondsLong -= TimeUnit.DAYS.toSeconds(days)\r\n\r\n            val hours = TimeUnit.SECONDS\r\n                .toHours(secondsLong)\r\n            secondsLong -= TimeUnit.HOURS.toSeconds(hours)\r\n\r\n            val minutes = TimeUnit.SECONDS\r\n                .toMinutes(secondsLong)\r\n            secondsLong -= TimeUnit.MINUTES.toSeconds(minutes)\r\n            if (minutes < 0) {\r\n                return completedValue\r\n            }\r\n            //println(\"$days $hours $minutes\")\r\n            return \"${if (days != 0L) \"$days\" + \"d \" else \"\"}${if (hours != 0L) \"$hours\" + \"h \" else \"\"}${minutes}m\"\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders\n\nimport android.util.Base64\nimport androidx.annotation.WorkerThread\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder.unixTime\nimport com.lagradost.cloudstream3.ActorData\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.NextAiring\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.SearchQuality\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.ShowStatus\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.mvvm.safeApiCall\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.NONE_ID\nimport com.lagradost.cloudstream3.syncproviders.providers.Addic7ed\nimport com.lagradost.cloudstream3.syncproviders.providers.AniListApi\nimport com.lagradost.cloudstream3.syncproviders.providers.LocalList\nimport com.lagradost.cloudstream3.syncproviders.providers.MALApi\nimport com.lagradost.cloudstream3.syncproviders.providers.KitsuApi\nimport com.lagradost.cloudstream3.syncproviders.providers.OpenSubtitlesApi\nimport com.lagradost.cloudstream3.syncproviders.providers.SimklApi\nimport com.lagradost.cloudstream3.syncproviders.providers.SubDlApi\nimport com.lagradost.cloudstream3.syncproviders.providers.SubSourceApi\nimport com.lagradost.cloudstream3.ui.SyncWatchType\nimport com.lagradost.cloudstream3.ui.library.ListSorting\nimport com.lagradost.cloudstream3.utils.AppContextUtils.splitQuery\nimport com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.UiText\nimport com.lagradost.cloudstream3.utils.txt\nimport me.xdrop.fuzzywuzzy.FuzzySearch\nimport java.net.URL\nimport java.security.SecureRandom\nimport java.util.Date\nimport java.util.concurrent.TimeUnit\n\ndata class AuthLoginPage(\n    /** The website to open to authenticate */\n    val url: String,\n    /**\n     * State/control code to verify against the redirectUrl to make sure the request is valid.\n     * This parameter will be saved, and then used in AuthAPI::login.\n     * */\n    val payload: String? = null,\n)\n\ndata class AuthToken(\n    /**\n     * This is the general access tokens/api token representing a logged in user.\n     *\n     * `Access tokens are the thing that applications use to make API requests on behalf of a user.`\n     * */\n    @JsonProperty(\"accessToken\")\n    val accessToken: String? = null,\n    /**\n     * For OAuth a special refresh token is issues to refresh the access token.\n     * */\n    @JsonProperty(\"refreshToken\")\n    val refreshToken: String? = null,\n    /** In UnixTime (sec) when it expires */\n    @JsonProperty(\"accessTokenLifetime\")\n    val accessTokenLifetime: Long? = null,\n    /** In UnixTime (sec) when it expires */\n    @JsonProperty(\"refreshTokenLifetime\")\n    val refreshTokenLifetime: Long? = null,\n    /** Sometimes AuthToken needs to be customized to store e.g. username/password,\n     * this acts as a catch all to store text or JSON data. */\n    @JsonProperty(\"payload\")\n    val payload: String? = null,\n) {\n    fun isAccessTokenExpired(marginSec: Long = 10L) =\n        accessTokenLifetime != null && (System.currentTimeMillis() / 1000) + marginSec >= accessTokenLifetime\n\n    fun isRefreshTokenExpired(marginSec: Long = 10L) =\n        refreshTokenLifetime != null && (System.currentTimeMillis() / 1000) + marginSec >= refreshTokenLifetime\n}\n\ndata class AuthUser(\n    /** Account display-name, can also be email if name does not exist */\n    @JsonProperty(\"name\")\n    val name: String?,\n    /** Unique account identifier,\n     * if a subsequent login is done then it will be refused if another account with the same id exists*/\n    @JsonProperty(\"id\")\n    val id: Int,\n    /** Profile picture URL */\n    @JsonProperty(\"profilePicture\")\n    val profilePicture: String? = null,\n    /** Profile picture Headers of the URL */\n    @JsonProperty(\"profilePictureHeader\")\n    val profilePictureHeaders: Map<String, String>? = null\n)\n\n/**\n * Stores all information that should be used to authorize access.\n * Be aware that token and user may change independently when a refresh is needed,\n * and as such there should be no strong pairing between the two.\n *\n * Any local set/get key should use user.id.toString(),\n * as token.accessToken (even hashed) is unsecure, and will rotate.\n * */\ndata class AuthData(\n    @JsonProperty(\"user\")\n    val user: AuthUser,\n    @JsonProperty(\"token\")\n    val token: AuthToken,\n)\n\ndata class AuthPinData(\n    val deviceCode: String,\n    val userCode: String,\n    /** QR Code url */\n    val verificationUrl: String,\n    /** In seconds */\n    val expiresIn: Int,\n    /** Check if the code has been verified interval */\n    val interval: Int,\n)\n\n/** The login field requirements to display to the user */\ndata class AuthLoginRequirement(\n    val password: Boolean = false,\n    val username: Boolean = false,\n    val email: Boolean = false,\n    val server: Boolean = false,\n)\n\n/** What the user responds to the AuthLoginRequirement */\ndata class AuthLoginResponse(\n    @JsonProperty(\"password\")\n    val password: String?,\n    @JsonProperty(\"username\")\n    val username: String?,\n    @JsonProperty(\"email\")\n    val email: String?,\n    @JsonProperty(\"server\")\n    val server: String?,\n)\n\n/** Stateless Authentication class used for all personalized content */\nabstract class AuthAPI {\n    open val name: String = \"NONE\"\n    open val idPrefix: String = \"NONE\"\n\n    /** Drawable icon of the service */\n    open val icon: Int? = null\n\n    /** If this service requires an account to use */\n    open val requiresLogin: Boolean = true\n\n    /** Link to a website for creating a new account */\n    open val createAccountUrl: String? = null\n\n    /** The sensitive redirect URL from OAuth should contain \"/redirectUrlIdentifier\" to trigger the login */\n    open val redirectUrlIdentifier: String? = null\n\n    /** Has OAuth2 login support, including login, loginRequest and refreshToken */\n    open val hasOAuth2: Boolean = false\n\n    /** Has on device pin support, aka login with a QR code */\n    open val hasPin: Boolean = false\n\n    /** Has in app login support, aka login with a dialog */\n    open val hasInApp: Boolean = false\n\n    /** The requirements to login in app */\n    open val inAppLoginRequirement: AuthLoginRequirement? = null\n\n    companion object {\n        val unixTime: Long\n            get() = System.currentTimeMillis() / 1000L\n        val unixTimeMs: Long\n            get() = System.currentTimeMillis()\n\n        fun splitRedirectUrl(redirectUrl: String): Map<String, String> {\n            return splitQuery(\n                URL(\n                    redirectUrl.replace(APP_STRING, \"https\").replace(\"/#\", \"?\")\n                )\n            )\n        }\n\n        fun generateCodeVerifier(): String {\n            // It is recommended to use a URL-safe string as code_verifier.\n            // See section 4 of RFC 7636 for more details.\n            val secureRandom = SecureRandom()\n            val codeVerifierBytes = ByteArray(96) // base64 has 6bit per char; (8/6)*96 = 128\n            secureRandom.nextBytes(codeVerifierBytes)\n            return Base64.encodeToString(codeVerifierBytes, Base64.DEFAULT).trimEnd('=')\n                .replace(\"+\", \"-\")\n                .replace(\"/\", \"_\").replace(\"\\n\", \"\")\n        }\n    }\n\n    /** Is this url a valid redirect url for this service? */\n    @Throws\n    open fun isValidRedirectUrl(url: String): Boolean =\n        redirectUrlIdentifier != null && url.contains(\"/$redirectUrlIdentifier\")\n\n    /** OAuth2 login from a valid redirectUrl, and payload given in loginRequest */\n    @Throws\n    open suspend fun login(redirectUrl: String, payload: String?): AuthToken? =\n        throw NotImplementedError()\n\n    /** OAuth2 login request, asking the service to provide a url to open in the browser */\n    @Throws\n    open fun loginRequest(): AuthLoginPage? = throw NotImplementedError()\n\n    /** Pin login request, asking the service to provide an verificationUrl to display with a QR code */\n    @Throws\n    open suspend fun pinRequest(): AuthPinData? = throw NotImplementedError()\n\n    /** OAuth2 token refresh, this ensures that all token passed to other functions will be valid */\n    @Throws\n    open suspend fun refreshToken(token: AuthToken): AuthToken? = throw NotImplementedError()\n\n    /** Pin login, this will be called periodically while logging in to check if the pin has been verified by the user */\n    @Throws\n    open suspend fun login(payload: AuthPinData): AuthToken? = throw NotImplementedError()\n\n    /** In app login */\n    @Throws\n    open suspend fun login(form: AuthLoginResponse): AuthToken? = throw NotImplementedError()\n\n    /** Get the visible user account */\n    @Throws\n    open suspend fun user(token: AuthToken?): AuthUser? = throw NotImplementedError()\n\n    /**\n     * An optional security measure to make sure that even if an attacker gets ahold of the token, it will be invalid.\n     *\n     * Note that this will currently only be called *once* on logout,\n     * and as such any network issues it will fail silently, and the token will not be revoked.\n     **/\n    @Throws\n    open suspend fun invalidateToken(token: AuthToken): Nothing = throw NotImplementedError()\n\n    @Throws\n    @Deprecated(\"Please use the new API for AuthAPI\", level = DeprecationLevel.ERROR)\n    fun toRepo(): AuthRepo = when (this) {\n        is SubtitleAPI -> SubtitleRepo(this)\n        is SyncAPI -> SyncRepo(this)\n        else -> throw NotImplementedError(\"Unknown inheritance from AuthAPI\")\n    }\n\n    @Suppress(\"DEPRECATION_ERROR\")\n    @Deprecated(\"Please use the new API for AuthAPI\", level = DeprecationLevel.ERROR)\n    fun loginInfo(): LoginInfo? {\n        return this.toRepo().authUser()?.let { user ->\n            LoginInfo(\n                profilePicture = user.profilePicture,\n                name = user.name,\n                accountIndex = -1,\n            )\n        }\n    }\n\n    @Deprecated(\"Please use the new API for AuthAPI\", level = DeprecationLevel.ERROR)\n    suspend fun getPersonalLibrary(): SyncAPI.LibraryMetadata? {\n        @Suppress(\"DEPRECATION_ERROR\")\n        return (this.toRepo() as? SyncRepo)?.library()?.getOrThrow()\n    }\n\n    @Deprecated(\"Please use the new API for AuthAPI\", level = DeprecationLevel.ERROR)\n    class LoginInfo(\n        val profilePicture: String? = null,\n        val name: String?,\n        val accountIndex: Int,\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthRepo.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders\r\n\r\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser\r\nimport com.lagradost.cloudstream3.CommonActivity.showToast\r\nimport com.lagradost.cloudstream3.ErrorLoadingException\r\nimport com.lagradost.cloudstream3.R\r\nimport com.lagradost.cloudstream3.mvvm.logError\r\nimport com.lagradost.cloudstream3.mvvm.safe\r\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.NONE_ID\r\nimport com.lagradost.cloudstream3.utils.txt\r\n\r\n/** Safe abstraction for AuthAPI that provides both a catching interface, and automatic token management. */\r\nabstract class AuthRepo(open val api: AuthAPI) {\r\n    fun isValidRedirectUrl(url: String) = safe { api.isValidRedirectUrl(url) } ?: false\r\n    val idPrefix get() = api.idPrefix\r\n    val name get() = api.name\r\n    val icon get() = api.icon\r\n    val requiresLogin get() = api.requiresLogin\r\n    val createAccountUrl get() = api.createAccountUrl\r\n    val hasOAuth2 get() = api.hasOAuth2\r\n    val hasPin get() = api.hasPin\r\n    val hasInApp get() = api.hasInApp\r\n    val inAppLoginRequirement get() = api.inAppLoginRequirement\r\n    val isAvailable get() = !api.requiresLogin || authUser() != null\r\n\r\n    companion object {\r\n        private val oauthPayload: MutableMap<String, String?> = mutableMapOf()\r\n    }\r\n\r\n    @Throws\r\n    protected suspend fun freshAuth(): AuthData? {\r\n        val data = authData() ?: return null\r\n        if (data.token.isAccessTokenExpired()) {\r\n            val newToken = api.refreshToken(data.token) ?: return null\r\n            val newAuth = AuthData(user = data.user, token = newToken)\r\n            refreshUser(newAuth)\r\n            return newAuth\r\n        }\r\n        return data\r\n    }\r\n\r\n    @Throws\r\n    fun openOAuth2Page(): Boolean {\r\n        val page = api.loginRequest() ?: return false\r\n        synchronized(oauthPayload) {\r\n            oauthPayload.put(idPrefix, page.payload)\r\n        }\r\n        openBrowser(page.url)\r\n        return true\r\n    }\r\n\r\n    fun openOAuth2PageWithToast() {\r\n        try {\r\n            if (!openOAuth2Page()) {\r\n                showToast(txt(R.string.authenticated_user_fail, api.name))\r\n            }\r\n        } catch (t: Throwable) {\r\n            logError(t)\r\n            if (t is ErrorLoadingException && t.message != null) {\r\n                showToast(t.message)\r\n                return\r\n            }\r\n            showToast(txt(R.string.authenticated_user_fail, api.name))\r\n        }\r\n    }\r\n\r\n    suspend fun logout(from: AuthUser) {\r\n        val currentAccounts = AccountManager.accounts(idPrefix)\r\n        val (newAccounts, oldAccounts) = currentAccounts.partition { it.user.id != from.id }\r\n        if (newAccounts.size < currentAccounts.size) {\r\n            AccountManager.updateAccounts(idPrefix, newAccounts.toTypedArray())\r\n            AccountManager.updateAccountsId(idPrefix, 0)\r\n        }\r\n\r\n        for (oldAccount in oldAccounts) {\r\n            try {\r\n                api.invalidateToken(oldAccount.token)\r\n            } catch (_: NotImplementedError) {\r\n                // no-op\r\n            } catch (t: Throwable) {\r\n                logError(t)\r\n            }\r\n        }\r\n    }\r\n\r\n    fun refreshUser(newAuth: AuthData) {\r\n        val currentAccounts = AccountManager.accounts(idPrefix)\r\n        val newAccounts = currentAccounts.map {\r\n            if (it.user.id == newAuth.user.id) {\r\n                newAuth\r\n            } else {\r\n                it\r\n            }\r\n        }.toTypedArray()\r\n        AccountManager.updateAccounts(idPrefix, newAccounts)\r\n    }\r\n\r\n    fun authData(): AuthData? = synchronized(AccountManager.cachedAccountIds) {\r\n        AccountManager.cachedAccountIds[idPrefix]?.let { id ->\r\n            AccountManager.cachedAccounts[idPrefix]?.firstOrNull { data -> data.user.id == id }\r\n        }\r\n    }\r\n\r\n    fun authToken(): AuthToken? = authData()?.token\r\n\r\n    fun authUser(): AuthUser? = authData()?.user\r\n\r\n    val accounts\r\n        get() = synchronized(AccountManager.cachedAccounts) {\r\n            AccountManager.cachedAccounts[idPrefix] ?: emptyArray()\r\n        }\r\n    var accountId\r\n        get() = synchronized(AccountManager.cachedAccountIds) {\r\n            AccountManager.cachedAccountIds[idPrefix] ?: NONE_ID\r\n        }\r\n        set(value) {\r\n            AccountManager.updateAccountsId(idPrefix, value)\r\n        }\r\n\r\n    @Throws\r\n    suspend fun pinRequest() =\r\n        api.pinRequest()\r\n\r\n    @Throws\r\n    private suspend fun setupLogin(token: AuthToken): Boolean {\r\n        val user = api.user(token) ?: return false\r\n\r\n        val newAccount = AuthData(\r\n            token = token,\r\n            user = user,\r\n        )\r\n\r\n        val currentAccounts = AccountManager.accounts(idPrefix)\r\n        if (currentAccounts.any { it.user.id == newAccount.user.id }) {\r\n            throw ErrorLoadingException(\"Already logged into this account\")\r\n        }\r\n\r\n        val newAccounts = currentAccounts + newAccount\r\n        AccountManager.updateAccounts(idPrefix, newAccounts)\r\n        AccountManager.updateAccountsId(idPrefix, user.id)\r\n        if (this is SyncRepo) {\r\n            requireLibraryRefresh = true\r\n        }\r\n        return true\r\n    }\r\n\r\n    @Throws\r\n    suspend fun login(form: AuthLoginResponse): Boolean {\r\n        return setupLogin(api.login(form) ?: return false)\r\n    }\r\n\r\n    @Throws\r\n    suspend fun login(payload: AuthPinData): Boolean {\r\n        return setupLogin(api.login(payload) ?: return false)\r\n    }\r\n\r\n    @Throws\r\n    suspend fun login(redirectUrl: String): Boolean {\r\n        return setupLogin(\r\n            api.login(\r\n                redirectUrl,\r\n                synchronized(oauthPayload) { oauthPayload[api.idPrefix] }) ?: return false\r\n        )\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/BackupAPI.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders\r\n\r\n/** Work in progress */\r\nabstract class BackupAPI : AuthAPI() {\r\n    open val filename : String = \"cloudstream-backup.json\"\r\n\r\n    /** Get the backup file as a JSON string from the remote storage. Return null if not found/empty */\r\n    @Throws\r\n    open suspend fun downloadFile(auth: AuthData?) : String? = throw NotImplementedError()\r\n\r\n    /** Get the backup file as a JSON string from the remote storage. */\r\n    @Throws\r\n    open suspend fun uploadFile(auth: AuthData?, data : String) : String? = throw NotImplementedError()\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/SubtitleAPI.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders\r\n\r\nimport androidx.annotation.WorkerThread\r\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities.SubtitleEntity\r\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities.SubtitleSearch\r\nimport com.lagradost.cloudstream3.subtitles.SubtitleResource\r\n\r\n/**\r\n * Stateless subtitle class for external subtitles.\r\n *\r\n * All non-null `AuthToken` will be non-expired when each function is called.\r\n */\r\nabstract class SubtitleAPI : AuthAPI() {\r\n    @WorkerThread\r\n    @Throws\r\n    open suspend fun search(auth: AuthData?, query: SubtitleSearch): List<SubtitleEntity>? =\r\n        throw NotImplementedError()\r\n\r\n    @WorkerThread\r\n    @Throws\r\n    open suspend fun load(auth: AuthData?, subtitle: SubtitleEntity): String? =\r\n        throw NotImplementedError()\r\n\r\n    @WorkerThread\r\n    @Throws\r\n    open suspend fun SubtitleResource.getResources(auth: AuthData?, subtitle: SubtitleEntity) {\r\n        this.addUrl(load(auth, subtitle))\r\n    }\r\n\r\n    @WorkerThread\r\n    @Throws\r\n    suspend fun resource(auth: AuthData?, subtitle: SubtitleEntity): SubtitleResource {\r\n        return SubtitleResource().apply {\r\n            this.getResources(auth, subtitle)\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/SubtitleRepo.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders\r\n\r\nimport androidx.annotation.WorkerThread\r\nimport com.lagradost.cloudstream3.APIHolder.unixTime\r\nimport com.lagradost.cloudstream3.ErrorLoadingException\r\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities.SubtitleEntity\r\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities.SubtitleSearch\r\nimport com.lagradost.cloudstream3.subtitles.SubtitleResource\r\nimport com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf\r\n\r\n/** Stateless safe abstraction of SubtitleAPI */\r\nclass SubtitleRepo(override val api: SubtitleAPI) : AuthRepo(api) {\r\n    companion object {\r\n        data class SavedSearchResponse(\r\n            val unixTime: Long,\r\n            val response: List<SubtitleEntity>,\r\n            val query: SubtitleSearch\r\n        )\r\n\r\n        data class SavedResourceResponse(\r\n            val unixTime: Long,\r\n            val response: SubtitleResource,\r\n            val query: SubtitleEntity\r\n        )\r\n\r\n        // maybe make this a generic struct? right now there is a lot of boilerplate\r\n        private val searchCache = threadSafeListOf<SavedSearchResponse>()\r\n        private var searchCacheIndex: Int = 0\r\n        private val resourceCache = threadSafeListOf<SavedResourceResponse>()\r\n        private var resourceCacheIndex: Int = 0\r\n        const val CACHE_SIZE = 20\r\n    }\r\n\r\n    @WorkerThread\r\n    suspend fun resource(data: SubtitleEntity): Result<SubtitleResource> = runCatching {\r\n        synchronized(resourceCache) {\r\n            for (item in resourceCache) {\r\n                // 20 min save\r\n                if (item.query == data && (unixTime - item.unixTime) < 60 * 20) {\r\n                    return@runCatching item.response\r\n                }\r\n            }\r\n        }\r\n\r\n        val returnValue = api.resource(freshAuth(), data)\r\n        synchronized(resourceCache) {\r\n            val add = SavedResourceResponse(unixTime, returnValue, data)\r\n            if (resourceCache.size > CACHE_SIZE) {\r\n                resourceCache[resourceCacheIndex] = add // rolling cache\r\n                resourceCacheIndex = (resourceCacheIndex + 1) % CACHE_SIZE\r\n            } else {\r\n                resourceCache.add(add)\r\n            }\r\n        }\r\n        returnValue\r\n    }\r\n\r\n    @WorkerThread\r\n    suspend fun search(query: SubtitleSearch): Result<List<SubtitleEntity>> {\r\n        return runCatching {\r\n            synchronized(searchCache) {\r\n                for (item in searchCache) {\r\n                    // 120 min save\r\n                    if (item.query == query && (unixTime - item.unixTime) < 60 * 120) {\r\n                        return@runCatching item.response\r\n                    }\r\n                }\r\n            }\r\n\r\n            val returnValue =\r\n                api.search(freshAuth(), query) ?: emptyList()\r\n\r\n            // only cache valid return values\r\n            if (returnValue.isNotEmpty()) {\r\n                val add = SavedSearchResponse(unixTime, returnValue, query)\r\n                synchronized(searchCache) {\r\n                    if (searchCache.size > CACHE_SIZE) {\r\n                        searchCache[searchCacheIndex] = add // rolling cache\r\n                        searchCacheIndex = (searchCacheIndex + 1) % CACHE_SIZE\r\n                    } else {\r\n                        searchCache.add(add)\r\n                    }\r\n                }\r\n            }\r\n            returnValue\r\n        }\r\n    }\r\n}\r\n\r\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/SyncAPI.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders\r\n\r\nimport androidx.annotation.WorkerThread\r\nimport com.lagradost.cloudstream3.ActorData\r\nimport com.lagradost.cloudstream3.NextAiring\r\nimport com.lagradost.cloudstream3.Score\r\nimport com.lagradost.cloudstream3.SearchQuality\r\nimport com.lagradost.cloudstream3.SearchResponse\r\nimport com.lagradost.cloudstream3.ShowStatus\r\nimport com.lagradost.cloudstream3.TvType\r\nimport com.lagradost.cloudstream3.ui.SyncWatchType\r\nimport com.lagradost.cloudstream3.ui.library.ListSorting\r\nimport com.lagradost.cloudstream3.utils.UiText\r\nimport me.xdrop.fuzzywuzzy.FuzzySearch\r\nimport java.util.Date\r\n\r\n/**\r\n * Stateless synchronization class, used for syncing status about a specific movie/show.\r\n *\r\n * All non-null `AuthToken` will be non-expired when each function is called.\r\n */\r\nabstract class SyncAPI : AuthAPI() {\r\n    /**\r\n     * Set this to true if the user updates something on the list like watch status or score\r\n     **/\r\n    open var requireLibraryRefresh: Boolean = true\r\n    open val mainUrl: String = \"NONE\"\r\n\r\n    /** Currently unused, but will be used to correctly render the UI.\r\n     * This should specify what sync watch types can be used with this service. */\r\n    open val supportedWatchTypes: Set<SyncWatchType> = SyncWatchType.entries.toSet()\r\n    /**\r\n     * Allows certain providers to open pages from\r\n     * library links.\r\n     **/\r\n    open val syncIdName: SyncIdName? = null\r\n\r\n    /** Modify the current status of an item */\r\n    @Throws\r\n    @WorkerThread\r\n    open suspend fun updateStatus(\r\n        auth: AuthData?,\r\n        id: String,\r\n        newStatus: AbstractSyncStatus\r\n    ): Boolean = throw NotImplementedError()\r\n\r\n    /** Get the current status of an item */\r\n    @Throws\r\n    @WorkerThread\r\n    open suspend fun status(auth: AuthData?, id: String): AbstractSyncStatus? =\r\n        throw NotImplementedError()\r\n\r\n    /** Get metadata about an item */\r\n    @Throws\r\n    @WorkerThread\r\n    open suspend fun load(auth: AuthData?, id: String): SyncResult? = throw NotImplementedError()\r\n\r\n    /** Search this service for any results for a given query */\r\n    @Throws\r\n    @WorkerThread\r\n    open suspend fun search(auth: AuthData?, query: String): List<SyncSearchResult>? =\r\n        throw NotImplementedError()\r\n\r\n    /** Get the current library/bookmarks of this service */\r\n    @Throws\r\n    @WorkerThread\r\n    open suspend fun library(auth: AuthData?): LibraryMetadata? = throw NotImplementedError()\r\n\r\n    /** Helper function, may be used in the future */\r\n    @Throws\r\n    open fun urlToId(url: String): String? = null\r\n\r\n    data class SyncSearchResult(\r\n        override val name: String,\r\n        override val apiName: String,\r\n        var syncId: String,\r\n        override val url: String,\r\n        override var posterUrl: String?,\r\n        override var type: TvType? = null,\r\n        override var quality: SearchQuality? = null,\r\n        override var posterHeaders: Map<String, String>? = null,\r\n        override var id: Int? = null,\r\n        override var score: Score? = null,\r\n    ) : SearchResponse\r\n\r\n    abstract class AbstractSyncStatus {\r\n        abstract var status: SyncWatchType\r\n        abstract var score: Score?\r\n        abstract var watchedEpisodes: Int?\r\n        abstract var isFavorite: Boolean?\r\n        abstract var maxEpisodes: Int?\r\n    }\r\n\r\n    data class SyncStatus(\r\n        override var status: SyncWatchType,\r\n        override var score: Score?,\r\n        override var watchedEpisodes: Int?,\r\n        override var isFavorite: Boolean? = null,\r\n        override var maxEpisodes: Int? = null,\r\n    ) : AbstractSyncStatus()\r\n\r\n    data class SyncResult(\r\n        /**Used to verify*/\r\n        var id: String,\r\n\r\n        var totalEpisodes: Int? = null,\r\n\r\n        var title: String? = null,\r\n        var publicScore: Score? = null,\r\n        /**In minutes*/\r\n        var duration: Int? = null,\r\n        var synopsis: String? = null,\r\n        var airStatus: ShowStatus? = null,\r\n        var nextAiring: NextAiring? = null,\r\n        var studio: List<String>? = null,\r\n        var genres: List<String>? = null,\r\n        var synonyms: List<String>? = null,\r\n        var trailers: List<String>? = null,\r\n        var isAdult: Boolean? = null,\r\n        var posterUrl: String? = null,\r\n        var backgroundPosterUrl: String? = null,\r\n\r\n        /** In unixtime */\r\n        var startDate: Long? = null,\r\n        /** In unixtime */\r\n        var endDate: Long? = null,\r\n        var recommendations: List<SyncSearchResult>? = null,\r\n        var nextSeason: SyncSearchResult? = null,\r\n        var prevSeason: SyncSearchResult? = null,\r\n        var actors: List<ActorData>? = null,\r\n    )\r\n\r\n    data class Page(\r\n        val title: UiText, var items: List<LibraryItem>\r\n    ) {\r\n        fun sort(method: ListSorting?, query: String? = null) {\r\n            items = when (method) {\r\n                ListSorting.Query ->\r\n                    if (query != null) {\r\n                        items.sortedBy {\r\n                            -FuzzySearch.partialRatio(\r\n                                query.lowercase(), it.name.lowercase()\r\n                            )\r\n                        }\r\n                    } else items\r\n\r\n                ListSorting.RatingHigh -> items.sortedBy { -(it.personalRating?.toInt(100) ?: 0) }\r\n                ListSorting.RatingLow -> items.sortedBy { (it.personalRating?.toInt(100) ?: 0) }\r\n                ListSorting.AlphabeticalA -> items.sortedBy { it.name }\r\n                ListSorting.AlphabeticalZ -> items.sortedBy { it.name }.reversed()\r\n                ListSorting.UpdatedNew -> items.sortedBy { it.lastUpdatedUnixTime?.times(-1) }\r\n                ListSorting.UpdatedOld -> items.sortedBy { it.lastUpdatedUnixTime }\r\n                ListSorting.ReleaseDateNew -> items.sortedByDescending { it.releaseDate }\r\n                ListSorting.ReleaseDateOld -> items.sortedBy { it.releaseDate }\r\n                else -> items\r\n            }\r\n        }\r\n    }\r\n\r\n    data class LibraryMetadata(\r\n        val allLibraryLists: List<LibraryList>,\r\n        val supportedListSorting: Set<ListSorting>\r\n    )\r\n\r\n    data class LibraryList(\r\n        val name: UiText,\r\n        val items: List<LibraryItem>\r\n    )\r\n\r\n    data class LibraryItem(\r\n        override val name: String,\r\n        override val url: String,\r\n        /**\r\n         * Unique unchanging string used for data storage.\r\n         * This should be the actual id when you change scores and status\r\n         * since score changes from library might get added in the future.\r\n         **/\r\n        val syncId: String,\r\n        val episodesCompleted: Int?,\r\n        val episodesTotal: Int?,\r\n        val personalRating: Score?,\r\n        val lastUpdatedUnixTime: Long?,\r\n        override val apiName: String,\r\n        override var type: TvType?,\r\n        override var posterUrl: String?,\r\n        override var posterHeaders: Map<String, String>?,\r\n        override var quality: SearchQuality?,\r\n        val releaseDate: Date?,\r\n        override var id: Int? = null,\r\n        val plot: String? = null,\r\n        override var score: Score? = null,\r\n        val tags: List<String>? = null\r\n    ) : SearchResponse\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/SyncRepo.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders\r\n\r\n/** Stateless safe abstraction of SyncAPI */\r\nclass SyncRepo(override val api: SyncAPI) : AuthRepo(api) {\r\n    val syncIdName = api.syncIdName\r\n    var requireLibraryRefresh: Boolean\r\n        get() = api.requireLibraryRefresh\r\n        set(value) {\r\n            api.requireLibraryRefresh = value\r\n        }\r\n\r\n    suspend fun updateStatus(id: String, newStatus: SyncAPI.AbstractSyncStatus): Result<Boolean> =\r\n        runCatching {\r\n            val status = api.updateStatus(freshAuth() ?: return@runCatching false, id, newStatus)\r\n            requireLibraryRefresh = true\r\n            status\r\n        }\r\n\r\n    suspend fun status(id: String): Result<SyncAPI.AbstractSyncStatus?> = runCatching {\r\n        api.status(freshAuth(), id)\r\n    }\r\n\r\n    suspend fun load(id: String): Result<SyncAPI.SyncResult?> = runCatching {\r\n        api.load(freshAuth(), id)\r\n    }\r\n\r\n    suspend fun library(): Result<SyncAPI.LibraryMetadata?> = runCatching {\r\n        api.library(freshAuth())\r\n    }\r\n}\r\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Addic7ed.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders.providers\n\nimport com.lagradost.cloudstream3.AllLanguagesName\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities.SubtitleEntity\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities.SubtitleSearch\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.syncproviders.SubtitleAPI\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromTagToEnglishLanguageName\n\nclass Addic7ed : SubtitleAPI() {\n    override val name = \"Addic7ed\"\n    override val idPrefix = \"addic7ed\"\n    override val requiresLogin = false\n\n    companion object {\n        const val HOST = \"https://www.addic7ed.com\"\n        const val TAG = \"ADDIC7ED\"\n    }\n\n    private fun String.fixUrl(): String {\n        val url = this\n        return if (url.startsWith(\"/\")) HOST + url\n        else if (!url.startsWith(\"http\")) \"$HOST/$url\"\n        else url\n    }\n\n    override suspend fun search(\n        auth: AuthData?,\n        query: SubtitleSearch\n    ): List<SubtitleEntity>? {\n        val langTagIETF = query.lang ?: AllLanguagesName\n        val langNumAddic7ed =\n            langTagIETF2Addic7ed[langTagIETF]?.first ?: 0 // all languages = 0\n        val langName =\n            langTagIETF2Addic7ed[langTagIETF]?.second ?:\n            fromTagToEnglishLanguageName(langTagIETF) ?:\n            \"Completed\" // this bypasses language filtering\n        val title = query.query.trim()\n        val epNum = query.epNumber ?: 0\n        val seasonNum = query.seasonNumber ?: 0\n        val yearNum = query.year ?: 0\n        val searchQuery = if (seasonNum > 0) \"$title $seasonNum $epNum\" else title\n        var downloadPage = \"\"\n\n        fun newSubtitleEntity (\n            displayName: String?,\n            link: String?,\n            isHearingImpaired: Boolean\n        ): SubtitleEntity? {\n            if (displayName.isNullOrBlank() || link.isNullOrBlank()) return null\n            return SubtitleEntity(\n                idPrefix = this.idPrefix,\n                name = displayName,\n                lang = langTagIETF,\n                data = link,\n                source = this.name,\n                type = if (seasonNum > 0) TvType.TvSeries else TvType.Movie,\n                epNumber = epNum,\n                seasonNumber = seasonNum,\n                year = yearNum,\n                headers = mapOf(\"referer\" to \"$HOST/\"),\n                isHearingImpaired = isHearingImpaired\n            )\n        }\n\n        val response = app.get(url = \"$HOST/search.php?search=$searchQuery&Submit=Search\")\n        val hostDocument = response.document\n\n        // 1st case: found one movie or episode. Redirected to $HOST/movie/1234 or $HOST/serie/show-name/$seasonNum/$epNum/ep-name\n        if (response.url.contains(\"/movie/\") || response.url.contains(\"/serie/\"))\n            downloadPage = response.url\n\n        // 2nd case: found tv series ep list. Redirected to $HOST/show/1234\n        else if (response.url.contains(\"/show/\")) {\n            val showId = response.url.substringAfterLast(\"/\")\n            val doc = app.get(\n                \"$HOST/ajax_loadShow.php?show=$showId&season=$seasonNum&langs=|$langNumAddic7ed|&hd=0&hi=0\",\n                referer = \"$HOST/\"\n            ).document\n\n            // get direct subtitles links from list\n            return doc.select(\"#season tbody tr\").mapNotNull { node ->\n                if (node.select(\"td:eq(1)\").text().toIntOrNull() == epNum)\n                    newSubtitleEntity(\n                        displayName = node.select(\"td:eq(2)\").text() + \"\\n\" + node.select(\"td:eq(4)\").text(),\n                        link = node.selectFirst(\"a[href~=updated\\\\/|original\\\\/]\")?.attr(\"href\")?.fixUrl(),\n                        isHearingImpaired = node.select(\"td:eq(6)\").text().isNotEmpty()\n                    )\n                else null\n            }\n        // 3rd case: found several or no results. Still in $HOST/search.php?search=title\n        } else {// (response.url.contains(\"/search.php\"))\n            downloadPage = hostDocument.select(\"table.tabel a\").selectFirst({\n                // tv series\n                if (seasonNum > 0) \"a[href~=serie\\\\/.+\\\\/$seasonNum\\\\/$epNum\\\\/\\\\w]\"\n                // movie + year\n                else if( yearNum > 0) \"a[href~=movie\\\\/]:contains($yearNum)\"\n                // movie\n                else \"a[href~=movie\\\\/]\"\n            }())?.attr(\"href\")?.fixUrl() ?: return null\n        }\n\n        // filter download page by language. Do not work for movies :/\n        if (downloadPage.contains(\"/serie/\"))\n            downloadPage = downloadPage.substringBeforeLast(\"/\") + \"/$langNumAddic7ed\"\n        val doc = app.get(url = downloadPage).document\n\n        // get subtitles links from download page\n        return doc.select(\".tabel95 .tabel95 tr:has(.language):contains($langName)\").mapNotNull { node ->\n            val displayName =\n                doc.selectFirst(\"span.titulo\")?.text()?.substringBefore(\" Subtitle\") + \"\\n\" +\n                node.parent()!!.select(\".NewsTitle\").text().substringAfter(\"Version \").substringBefore(\", Duration\")\n            val link =\n                node.selectFirst(\"a[href~=updated\\\\/|original\\\\/]\")?.attr(\"href\")?.fixUrl()\n            val isHearingImpaired =\n                node.parent()!!.select(\"tr:last-child [title=\\\"Hearing Impaired\\\"]\").isNotEmpty()\n\n            newSubtitleEntity(displayName, link, isHearingImpaired)\n        }\n    }\n\n    override suspend fun load(\n        auth: AuthData?,\n        subtitle: SubtitleEntity\n    ): String? {\n        return subtitle.data\n    }\n\n    // Missing (?_?)\n    // Pair(\"2\", \"\"),\n    // Pair(\"3\", \"\"),\n    // Pair(\"33\", \"\"),\n    // Pair(\"34\", \"\"),\n    // Do not modify unless Addic7ed changes them!\n    // as they are the exact values from their website\n    private val langTagIETF2Addic7ed = mapOf(\n        \"ar\"      to Pair(\"38\", \"Arabic\"),\n        \"az\"      to Pair(\"48\", \"Azerbaijani\"),\n        \"bg\"      to Pair(\"35\", \"Bulgarian\"),\n        \"bn\"      to Pair(\"47\", \"Bengali\"),\n        \"bs\"      to Pair(\"44\", \"Bosnian\"),\n        \"ca\"      to Pair(\"12\", \"Català\"),\n        \"cs\"      to Pair(\"14\", \"Czech\"),\n        \"cy\"      to Pair(\"65\", \"Welsh\"),\n        \"da\"      to Pair(\"30\", \"Danish\"),\n        \"de\"      to Pair(\"11\", \"German\"),\n        \"el\"      to Pair(\"27\", \"Greek\"),\n        \"en\"      to Pair(\"1\", \"English\"),\n        \"es-419\"  to Pair(\"6\", \"Spanish (Latin America)\"),\n        \"es-ar\"   to Pair(\"69\", \"Spanish (Argentina)\"),\n        \"es-es\"   to Pair(\"5\", \"Spanish (Spain)\"),\n        \"es\"      to Pair(\"4\", \"Spanish\"),\n        \"et\"      to Pair(\"54\", \"Estonian\"),\n        \"eu\"      to Pair(\"13\", \"Euskera\"),\n        \"fa\"      to Pair(\"43\", \"Persian\"),\n        \"fi\"      to Pair(\"28\", \"Finnish\"),\n        \"fr-ca\"   to Pair(\"53\", \"French (Canadian)\"),\n        \"fr\"      to Pair(\"8\", \"French\"),\n        \"gl\"      to Pair(\"15\", \"Galego\"),\n        \"he\"      to Pair(\"23\", \"Hebrew\"),\n        \"hi\"      to Pair(\"55\", \"Hindi\"),\n        \"hr\"      to Pair(\"31\", \"Croatian\"),\n        \"hu\"      to Pair(\"20\", \"Hungarian\"),\n        \"hy\"      to Pair(\"50\", \"Armenian\"),\n        \"id\"      to Pair(\"37\", \"Indonesian\"),\n        \"is\"      to Pair(\"56\", \"Icelandic\"),\n        \"it\"      to Pair(\"7\", \"Italian\"),\n        \"ja\"      to Pair(\"32\", \"Japanese\"),\n        \"kn\"      to Pair(\"66\", \"Kannada\"),\n        \"ko\"      to Pair(\"42\", \"Korean\"),\n        \"lt\"      to Pair(\"58\", \"Lithuanian\"),\n        \"lv\"      to Pair(\"57\", \"Latvian\"),\n        \"mk\"      to Pair(\"49\", \"Macedonian\"),\n        \"ml\"      to Pair(\"67\", \"Malayalam\"),\n        \"mr\"      to Pair(\"62\", \"Marathi\"),\n        \"ms\"      to Pair(\"40\", \"Malay\"),\n        \"nl\"      to Pair(\"17\", \"Dutch\"),\n        \"no\"      to Pair(\"29\", \"Norwegian\"),\n        \"pl\"      to Pair(\"21\", \"Polish\"),\n        \"pt-br\"   to Pair(\"10\", \"Portuguese (Brazilian)\"),\n        \"pt\"      to Pair(\"9\", \"Portuguese\"),\n        \"ro\"      to Pair(\"26\", \"Romanian\"),\n        \"ru\"      to Pair(\"19\", \"Russian\"),\n        \"si\"      to Pair(\"60\", \"Sinhala\"),\n        \"sk\"      to Pair(\"25\", \"Slovak\"),\n        \"sl\"      to Pair(\"22\", \"Slovenian\"),\n        \"sq\"      to Pair(\"52\", \"Albanian\"),\n        \"sr-latn\" to Pair(\"36\", \"Serbian (Latin)\"),\n        \"sr\"      to Pair(\"39\", \"Serbian (Cyrillic)\"),\n        \"sv\"      to Pair(\"18\", \"Swedish\"),\n        \"ta\"      to Pair(\"59\", \"Tamil\"),\n        \"te\"      to Pair(\"63\", \"Telugu\"),\n        \"th\"      to Pair(\"46\", \"Thai\"),\n        \"tl\"      to Pair(\"68\", \"Tagalog\"),\n        \"tlh\"     to Pair(\"61\", \"Klingon\"),\n        \"tr\"      to Pair(\"16\", \"Turkish\"),\n        \"uk\"      to Pair(\"51\", \"Ukrainian\"),\n        \"vi\"      to Pair(\"45\", \"Vietnamese\"),\n        \"yue\"     to Pair(\"64\", \"Cantonese\"),\n        \"zh-hans\" to Pair(\"41\", \"Chinese (Simplified)\"),\n        \"zh-hant\" to Pair(\"24\", \"Chinese (Traditional)\"),\n    )\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders.providers\n\nimport androidx.annotation.StringRes\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.Actor\nimport com.lagradost.cloudstream3.ActorData\nimport com.lagradost.cloudstream3.ActorRole\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.NextAiring\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginPage\nimport com.lagradost.cloudstream3.syncproviders.AuthToken\nimport com.lagradost.cloudstream3.syncproviders.AuthUser\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.syncproviders.SyncIdName\nimport com.lagradost.cloudstream3.ui.SyncWatchType\nimport com.lagradost.cloudstream3.ui.library.ListSorting\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.DataStore.toKotlinObject\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.toYear\nimport com.lagradost.cloudstream3.utils.txt\nimport java.net.URLEncoder\nimport java.util.Locale\n\nclass AniListApi : SyncAPI() {\n    override var name = \"AniList\"\n    override val idPrefix = \"anilist\"\n\n    val key = \"6871\"\n    override val redirectUrlIdentifier = \"anilistlogin\"\n    override var requireLibraryRefresh = true\n    override val hasOAuth2 = true\n    override var mainUrl = \"https://anilist.co\"\n    override val icon = R.drawable.ic_anilist_icon\n    override val createAccountUrl = \"$mainUrl/signup\"\n    override val syncIdName = SyncIdName.Anilist\n\n    override fun loginRequest(): AuthLoginPage? =\n        AuthLoginPage(\"https://anilist.co/api/v2/oauth/authorize?client_id=$key&response_type=token\")\n\n    override suspend fun login(redirectUrl: String, payload: String?): AuthToken? {\n        val sanitizer = splitRedirectUrl(redirectUrl)\n        val token = AuthToken(\n            accessToken = sanitizer[\"access_token\"] ?: throw ErrorLoadingException(\"No access token\"),\n            //refreshToken = sanitizer[\"refresh_token\"],\n            accessTokenLifetime = unixTime + sanitizer[\"expires_in\"]!!.toLong(),\n        )\n        return token\n    }\n\n    // https://docs.anilist.co/guide/auth/\n    override suspend fun refreshToken(token: AuthToken): AuthToken? {\n        // AniList access tokens are long-lived. They will remain valid for 1 year from the time they are issued.\n        // Refresh tokens are not currently supported. Once a token expires, you will need to re-authenticate your users.\n        return super.refreshToken(token)\n    }\n\n    override suspend fun user(token: AuthToken?): AuthUser? {\n        val user = getUser(token ?: return null)\n            ?: throw ErrorLoadingException(\"Unable to fetch user data\")\n\n        return AuthUser(\n            id = user.id,\n            name = user.name,\n            profilePicture = user.picture,\n        )\n    }\n\n    override fun urlToId(url: String): String? =\n        url.removePrefix(\"$mainUrl/anime/\").removeSuffix(\"/\")\n\n\n    private fun getUrlFromId(id: Int): String {\n        return \"$mainUrl/anime/$id\"\n    }\n\n    override suspend fun search(auth : AuthData?, query: String): List<SyncAPI.SyncSearchResult>? {\n        val data = searchShows(name) ?: return null\n        return data.data?.page?.media?.map {\n            SyncAPI.SyncSearchResult(\n                it.title.romaji ?: return null,\n                this.name,\n                it.id.toString(),\n                getUrlFromId(it.id),\n                it.bannerImage\n            )\n        }\n    }\n\n    override suspend fun load(auth : AuthData?, id: String): SyncAPI.SyncResult? {\n        val internalId = (Regex(\"anilist\\\\.co/anime/(\\\\d*)\").find(id)?.groupValues?.getOrNull(1)\n            ?: id).toIntOrNull() ?: throw ErrorLoadingException(\"Invalid internalId\")\n        val season = getSeason(internalId).data.media\n\n        return SyncAPI.SyncResult(\n            season.id.toString(),\n            nextAiring = season.nextAiringEpisode?.let {\n                NextAiring(\n                    it.episode ?: return@let null,\n                    (it.timeUntilAiring ?: return@let null) + unixTime\n                )\n            },\n            title = season.title?.userPreferred,\n            synonyms = season.synonyms,\n            isAdult = season.isAdult,\n            totalEpisodes = season.episodes,\n            synopsis = season.description,\n            actors = season.characters?.edges?.mapNotNull { edge ->\n                val node = edge.node ?: return@mapNotNull null\n                ActorData(\n                    actor = Actor(\n                        name = node.name?.userPreferred ?: node.name?.full ?: node.name?.native\n                        ?: return@mapNotNull null,\n                        image = node.image?.large ?: node.image?.medium\n                    ),\n                    role = when (edge.role) {\n                        \"MAIN\" -> ActorRole.Main\n                        \"SUPPORTING\" -> ActorRole.Supporting\n                        \"BACKGROUND\" -> ActorRole.Background\n                        else -> null\n                    },\n                    voiceActor = edge.voiceActors?.firstNotNullOfOrNull { staff ->\n                        Actor(\n                            name = staff.name?.userPreferred ?: staff.name?.full\n                            ?: staff.name?.native\n                            ?: return@mapNotNull null,\n                            image = staff.image?.large ?: staff.image?.medium\n                        )\n                    }\n                )\n            },\n            publicScore = Score.from100(season.averageScore),\n            recommendations = season.recommendations?.edges?.mapNotNull { rec ->\n                val recMedia = rec.node.mediaRecommendation\n                SyncAPI.SyncSearchResult(\n                    name = recMedia?.title?.userPreferred ?: return@mapNotNull null,\n                    this.name,\n                    recMedia.id?.toString() ?: return@mapNotNull null,\n                    getUrlFromId(recMedia.id),\n                    recMedia.coverImage?.extraLarge ?: recMedia.coverImage?.large\n                    ?: recMedia.coverImage?.medium\n                )\n            },\n            trailers = when (season.trailer?.site?.lowercase()?.trim()) {\n                \"youtube\" -> listOf(\"https://www.youtube.com/watch?v=${season.trailer.id}\")\n                else -> null\n            }\n            //TODO REST\n        )\n    }\n\n    override suspend fun status(auth : AuthData?, id: String): SyncAPI.AbstractSyncStatus? {\n        val internalId = id.toIntOrNull() ?: return null\n        val data = getDataAboutId(auth ?: return null, internalId) ?: return null\n\n        return SyncAPI.SyncStatus(\n            score = Score.from100(data.score),\n            watchedEpisodes = data.progress,\n            status = SyncWatchType.fromInternalId(data.type?.value ?: return null),\n            isFavorite = data.isFavourite,\n            maxEpisodes = data.episodes,\n        )\n    }\n\n    override suspend fun updateStatus(\n        auth: AuthData?,\n        id: String,\n        newStatus: AbstractSyncStatus\n    ): Boolean {\n        return postDataAboutId(\n            auth ?: return false,\n            id.toIntOrNull() ?: return false,\n            fromIntToAnimeStatus(newStatus.status.internalId),\n            newStatus.score,\n            newStatus.watchedEpisodes\n        )\n    }\n\n    companion object {\n        const val MAX_STALE = 60 * 10\n        private val aniListStatusString =\n            arrayOf(\"CURRENT\", \"COMPLETED\", \"PAUSED\", \"DROPPED\", \"PLANNING\", \"REPEATING\")\n\n        const val ANILIST_CACHED_LIST: String = \"anilist_cached_list\"\n\n        private fun fixName(name: String): String {\n            return name.lowercase(Locale.ROOT).replace(\" \", \"\")\n                .replace(\"[^a-zA-Z0-9]\".toRegex(), \"\")\n        }\n\n        private suspend fun searchShows(name: String): GetSearchRoot? {\n            try {\n                val query = \"\"\"\n                query (${\"$\"}id: Int, ${\"$\"}page: Int, ${\"$\"}search: String, ${\"$\"}type: MediaType) {\n                    Page (page: ${\"$\"}page, perPage: 10) {\n                        media (id: ${\"$\"}id, search: ${\"$\"}search, type: ${\"$\"}type) {\n                            id\n                            idMal\n                            seasonYear\n                            startDate { year month day }\n                            title {\n                                romaji\n                            }\n                            averageScore\n                            meanScore\n                            nextAiringEpisode {\n                                timeUntilAiring\n                                episode\n                            }\n                            trailer { id site thumbnail }\n                            bannerImage\n                            recommendations {\n                                nodes {\n                                    id\n                                    mediaRecommendation {\n                                        id\n                                        title {\n                                            english\n                                            romaji\n                                        }\n                                        idMal\n                                        coverImage { medium large extraLarge }\n                                        averageScore\n                                    }\n                                }\n                            }\n                            relations {\n                                edges {\n                                    id\n                                    relationType(version: 2)\n                                    node {\n                                        format\n                                        id\n                                        idMal\n                                        coverImage { medium large extraLarge }\n                                        averageScore\n                                        title {\n                                            english\n                                            romaji\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n                \"\"\"\n                val data =\n                    mapOf(\n                        \"query\" to query,\n                        \"variables\" to\n                                mapOf(\n                                    \"search\" to name,\n                                    \"page\" to 1,\n                                    \"type\" to \"ANIME\"\n                                ).toJson()\n                    )\n\n                val res = app.post(\n                    \"https://graphql.anilist.co/\",\n                    //headers = mapOf(),\n                    data = data,//(if (vars == null) mapOf(\"query\" to q) else mapOf(\"query\" to q, \"variables\" to vars))\n                    timeout = 5000 // REASONABLE TIMEOUT\n                ).text.replace(\"\\\\\", \"\")\n                return res.toKotlinObject()\n            } catch (e: Exception) {\n                logError(e)\n            }\n            return null\n        }\n\n        // Should use https://gist.github.com/purplepinapples/5dc60f15f2837bf1cea71b089cfeaa0a\n        suspend fun getShowId(malId: String?, name: String, year: Int?): GetSearchMedia? {\n            // Strips these from the name\n            val blackList = listOf(\n                \"TV Dubbed\",\n                \"(Dub)\",\n                \"Subbed\",\n                \"(TV)\",\n                \"(Uncensored)\",\n                \"(Censored)\",\n                \"(\\\\d+)\" // year\n            )\n            val blackListRegex =\n                Regex(\n                    \"\"\" (${\n                        blackList.joinToString(separator = \"|\").replace(\"(\", \"\\\\(\")\n                            .replace(\")\", \"\\\\)\")\n                    })\"\"\"\n                )\n            //println(\"NAME $name NEW NAME ${name.replace(blackListRegex, \"\")}\")\n            val shows = searchShows(name.replace(blackListRegex, \"\"))\n\n            shows?.data?.page?.media?.find {\n                (malId ?: \"NONE\") == it.idMal.toString()\n            }?.let { return it }\n\n            val filtered =\n                shows?.data?.page?.media?.filter {\n                    (((it.startDate.year ?: year.toString()) == year.toString()\n                            || year == null))\n                }\n            filtered?.forEach {\n                it.title.romaji?.let { romaji ->\n                    if (fixName(romaji) == fixName(name)) return it\n                }\n            }\n\n            return filtered?.firstOrNull()\n        }\n\n        // Changing names of these will show up in UI\n        enum class AniListStatusType(var value: Int, @StringRes val stringRes: Int) {\n            Watching(0, R.string.type_watching),\n            Completed(1, R.string.type_completed),\n            Paused(2, R.string.type_on_hold),\n            Dropped(3, R.string.type_dropped),\n            Planning(4, R.string.type_plan_to_watch),\n            ReWatching(5, R.string.type_re_watching),\n            None(-1, R.string.none)\n        }\n\n        fun fromIntToAnimeStatus(inp: Int): AniListStatusType {//= AniListStatusType.values().first { it.value == inp }\n            return when (inp) {\n                -1 -> AniListStatusType.None\n                0 -> AniListStatusType.Watching\n                1 -> AniListStatusType.Completed\n                2 -> AniListStatusType.Paused\n                3 -> AniListStatusType.Dropped\n                4 -> AniListStatusType.Planning\n                5 -> AniListStatusType.ReWatching\n                else -> AniListStatusType.None\n            }\n        }\n\n        fun convertAniListStringToStatus(string: String): AniListStatusType {\n            return fromIntToAnimeStatus(aniListStatusString.indexOf(string))\n        }\n\n        private suspend fun getSeason(id: Int): SeasonResponse {\n            val q = \"\"\"\n               query (${'$'}id: Int = $id) {\n                   Media (id: ${'$'}id, type: ANIME) {\n                       id\n                       idMal\n                       coverImage {\n                           extraLarge\n                           large\n                           medium\n                           color\n                       }\n                       title {\n                           romaji\n                           english\n                           native\n                           userPreferred\n                       }\n                       duration\n                       episodes\n                       genres\n                       synonyms\n                       averageScore\n                       isAdult\n                       description(asHtml: false)\n                       characters(sort: ROLE page: 1 perPage: 20) {\n                           edges {\n                               role\n                               voiceActors {\n                                   name {\n                                       userPreferred\n                                       full\n                                       native\n                                   }\n                                   age\n                                   image {\n                                       large\n                                       medium\n                                   }\n                               }\n                               node {\n                                   name {\n                                       userPreferred\n                                       full\n                                       native\n                                   }\n                                   age\n                                   image {\n                                       large\n                                       medium\n                                   }\n                               }\n                           }\n                       }\n                       trailer {\n                           id\n                           site\n                           thumbnail\n                       }\n                       relations {\n                           edges {\n                                id\n                                relationType(version: 2)\n                                node {\n                                     id\n                                     coverImage {\n                                         extraLarge\n                                         large\n                                         medium\n                                         color\n                                     }\n                                }\n                           }\n                       }\n                       recommendations {\n                           edges {\n                               node {\n                                   mediaRecommendation {\n                                       id\n                                       coverImage {\n                                           extraLarge\n                                           large\n                                           medium\n                                           color\n                                       }\n                                       title {\n                                           romaji\n                                           english\n                                           native\n                                           userPreferred\n                                       }\n                                   }\n                               }\n                           }\n                       }\n                       nextAiringEpisode {\n                           timeUntilAiring\n                           episode\n                       }\n                       format\n                   }\n               }\n        \"\"\"\n            val data = app.post(\n                \"https://graphql.anilist.co\",\n                data = mapOf(\"query\" to q),\n                cacheTime = 0,\n            ).text\n\n            return tryParseJson(data) ?: throw ErrorLoadingException(\"Error parsing $data\")\n        }\n    }\n\n    private suspend fun getDataAboutId(auth : AuthData, id: Int): AniListTitleHolder? {\n        val q =\n            \"\"\"query (${'$'}id: Int = $id) { # Define which variables will be used in the query (id)\n                Media (id: ${'$'}id, type: ANIME) { # Insert our variables into the query arguments (id) (type: ANIME is hard-coded in the query)\n                    id\n                    episodes\n                    isFavourite\n                    mediaListEntry {\n                        progress\n                        status\n                        score (format: POINT_100)\n                    }\n                    title {\n                        english\n                        romaji\n                    }\n                }\n            }\"\"\"\n\n        val data = postApi(auth.token, q, true)\n        val d = parseJson<GetDataRoot>(data ?: return null)\n\n        val main = d.data?.media\n        if (main?.mediaListEntry != null) {\n            return AniListTitleHolder(\n                title = main.title,\n                id = id,\n                isFavourite = main.isFavourite,\n                progress = main.mediaListEntry.progress,\n                episodes = main.episodes,\n                score = main.mediaListEntry.score,\n                type = fromIntToAnimeStatus(aniListStatusString.indexOf(main.mediaListEntry.status)),\n            )\n        } else {\n            return AniListTitleHolder(\n                title = main?.title,\n                id = id,\n                isFavourite = main?.isFavourite,\n                progress = 0,\n                episodes = main?.episodes,\n                score = 0,\n                type = AniListStatusType.None,\n            )\n        }\n\n    }\n\n    private suspend fun postApi(token : AuthToken, q: String, cache: Boolean = false): String? {\n        return app.post(\n            \"https://graphql.anilist.co/\",\n            headers = mapOf(\n                \"Authorization\" to \"Bearer ${token.accessToken ?: return null}\",\n                if (cache) \"Cache-Control\" to \"max-stale=$MAX_STALE\" else \"Cache-Control\" to \"no-cache\"\n            ),\n            cacheTime = 0,\n            data = mapOf(\n                \"query\" to URLEncoder.encode(\n                    q,\n                    \"UTF-8\"\n                )\n            ), //(if (vars == null) mapOf(\"query\" to q) else mapOf(\"query\" to q, \"variables\" to vars))\n            timeout = 5 // REASONABLE TIMEOUT\n        ).text.replace(\"\\\\/\", \"/\")\n    }\n\n\n    data class MediaRecommendation(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"title\") val title: Title?,\n        @JsonProperty(\"idMal\") val idMal: Int?,\n        @JsonProperty(\"coverImage\") val coverImage: CoverImage?,\n        @JsonProperty(\"averageScore\") val averageScore: Int?\n    )\n\n    data class FullAnilistList(\n        @JsonProperty(\"data\") val data: Data?\n    )\n\n    data class CompletedAt(\n        @JsonProperty(\"year\") val year: Int,\n        @JsonProperty(\"month\") val month: Int,\n        @JsonProperty(\"day\") val day: Int\n    )\n\n    data class StartedAt(\n        @JsonProperty(\"year\") val year: String?,\n        @JsonProperty(\"month\") val month: String?,\n        @JsonProperty(\"day\") val day: String?\n    )\n\n    data class Title(\n        @JsonProperty(\"english\") val english: String?,\n        @JsonProperty(\"romaji\") val romaji: String?\n    )\n\n    data class CoverImage(\n        @JsonProperty(\"medium\") val medium: String?,\n        @JsonProperty(\"large\") val large: String?,\n        @JsonProperty(\"extraLarge\") val extraLarge: String?\n    )\n\n    data class Media(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"idMal\") val idMal: Int?,\n        @JsonProperty(\"season\") val season: String?,\n        @JsonProperty(\"seasonYear\") val seasonYear: Int,\n        @JsonProperty(\"format\") val format: String?,\n        //@JsonProperty(\"source\") val source: String,\n        @JsonProperty(\"episodes\") val episodes: Int,\n        @JsonProperty(\"title\") val title: Title,\n        @JsonProperty(\"description\") val description: String?,\n        @JsonProperty(\"coverImage\") val coverImage: CoverImage,\n        @JsonProperty(\"synonyms\") val synonyms: List<String>,\n        @JsonProperty(\"nextAiringEpisode\") val nextAiringEpisode: SeasonNextAiringEpisode?,\n    )\n\n    data class Entries(\n        @JsonProperty(\"status\") val status: String?,\n        @JsonProperty(\"completedAt\") val completedAt: CompletedAt,\n        @JsonProperty(\"startedAt\") val startedAt: StartedAt,\n        @JsonProperty(\"updatedAt\") val updatedAt: Int,\n        @JsonProperty(\"progress\") val progress: Int,\n        @JsonProperty(\"score\") val score: Int,\n        @JsonProperty(\"private\") val private: Boolean,\n        @JsonProperty(\"media\") val media: Media\n    ) {\n        fun toLibraryItem(): SyncAPI.LibraryItem {\n            return SyncAPI.LibraryItem(\n                // English title first\n                this.media.title.english ?: this.media.title.romaji\n                ?: this.media.synonyms.firstOrNull()\n                ?: \"\",\n                \"https://anilist.co/anime/${this.media.id}/\",\n                this.media.id.toString(),\n                this.progress,\n                this.media.episodes,\n                Score.from100(this.score),\n                this.updatedAt.toLong(),\n                \"AniList\",\n                TvType.Anime,\n                this.media.coverImage.extraLarge ?: this.media.coverImage.large\n                ?: this.media.coverImage.medium,\n                null,\n                null,\n                this.media.seasonYear.toYear(),\n                null,\n                plot = this.media.description,\n            )\n        }\n    }\n\n    data class Lists(\n        @JsonProperty(\"status\") val status: String?,\n        @JsonProperty(\"entries\") val entries: List<Entries>\n    )\n\n    data class MediaListCollection(\n        @JsonProperty(\"lists\") val lists: List<Lists>\n    )\n\n    data class Data(\n        @JsonProperty(\"MediaListCollection\") val mediaListCollection: MediaListCollection\n    )\n\n    private suspend fun getAniListAnimeListSmart(auth: AuthData): Array<Lists>? {\n        return if (requireLibraryRefresh) {\n            val list = getFullAniListList(auth)?.data?.mediaListCollection?.lists?.toTypedArray()\n            if (list != null) {\n                setKey(ANILIST_CACHED_LIST, auth.user.id.toString(), list)\n            }\n            list\n        } else {\n            getKey<Array<Lists>>(\n                ANILIST_CACHED_LIST,\n                auth.user.id.toString()\n            ) as? Array<Lists>\n        }\n    }\n\n    override suspend fun library(auth : AuthData?): SyncAPI.LibraryMetadata? {\n        val list = getAniListAnimeListSmart(auth ?: return null)?.groupBy {\n            convertAniListStringToStatus(it.status ?: \"\").stringRes\n        }?.mapValues { group ->\n            group.value.map { it.entries.map { entry -> entry.toLibraryItem() } }.flatten()\n        } ?: emptyMap()\n\n        // To fill empty lists when AniList does not return them\n        val baseMap =\n            AniListStatusType.entries.filter { it.value >= 0 }.associate {\n                it.stringRes to emptyList<SyncAPI.LibraryItem>()\n            }\n\n        return SyncAPI.LibraryMetadata(\n            (baseMap + list).map { SyncAPI.LibraryList(txt(it.key), it.value) },\n            setOf(\n                ListSorting.AlphabeticalA,\n                ListSorting.AlphabeticalZ,\n                ListSorting.UpdatedNew,\n                ListSorting.UpdatedOld,\n                ListSorting.ReleaseDateNew,\n                ListSorting.ReleaseDateOld,\n                ListSorting.RatingHigh,\n                ListSorting.RatingLow,\n            )\n        )\n    }\n\n    private suspend fun getFullAniListList(auth : AuthData): FullAnilistList? {\n        val userID = auth.user.id\n        val mediaType = \"ANIME\"\n\n        val query = \"\"\"\n                query (${'$'}userID: Int = $userID, ${'$'}MEDIA: MediaType = $mediaType) {\n                    MediaListCollection (userId: ${'$'}userID, type: ${'$'}MEDIA) { \n                        lists {\n                            status\n                            entries\n                            {\n                                status\n                                completedAt { year month day }\n                                startedAt { year month day }\n                                updatedAt\n                                progress\n                                score (format: POINT_100)\n                                private\n                                media\n                                {\n                                    id\n                                    idMal\n                                    season\n                                    seasonYear\n                                    format\n                                    episodes\n                                    chapters\n                                    title\n                                    {\n                                        english\n                                        romaji\n                                    }\n                                    coverImage { extraLarge large medium }\n                                    synonyms\n                                    nextAiringEpisode {\n                                        timeUntilAiring\n                                        episode\n                                    }\n                                }\n                            }\n                        }\n                    }\n                    }\n            \"\"\"\n        val text = postApi(auth.token, query)\n        return text?.toKotlinObject()\n    }\n\n    suspend fun toggleLike(auth : AuthData, id: Int): Boolean {\n        val q = \"\"\"mutation (${'$'}animeId: Int = $id) {\n\t\t\t\tToggleFavourite (animeId: ${'$'}animeId) {\n\t\t\t\t\tanime {\n\t\t\t\t\t\tnodes {\n\t\t\t\t\t\t\tid\n\t\t\t\t\t\t\ttitle {\n\t\t\t\t\t\t\t\tromaji\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\"\"\"\n        val data = postApi(auth.token, q)\n        return data != \"\"\n    }\n\n    /** Used to query a saved MediaItem on the list to get the id for removal */\n    data class MediaListItemRoot(@JsonProperty(\"data\") val data: MediaListItem? = null)\n    data class MediaListItem(@JsonProperty(\"MediaList\") val mediaList: MediaListId? = null)\n    data class MediaListId(@JsonProperty(\"id\") val id: Long? = null)\n\n    private suspend fun postDataAboutId(\n        auth : AuthData,\n        id: Int,\n        type: AniListStatusType,\n        score: Score?,\n        progress: Int?\n    ): Boolean {\n        val userID = auth.user.id\n\n        val q =\n            // Delete item if status type is None\n            if (type == AniListStatusType.None) {\n                // Get list ID for deletion\n                val idQuery = \"\"\"\n                  query MediaList(${'$'}userId: Int = $userID, ${'$'}mediaId: Int = $id) {\n                    MediaList(userId: ${'$'}userId, mediaId: ${'$'}mediaId) {\n                      id\n                    }\n                  }\n                \"\"\"\n                val response = postApi(auth.token, idQuery)\n                val listId =\n                    tryParseJson<MediaListItemRoot>(response)?.data?.mediaList?.id ?: return false\n                \"\"\"\n                    mutation(${'$'}id: Int = $listId) {\n                        DeleteMediaListEntry(id: ${'$'}id) {\n                            deleted\n                        }\n                    }\n                \"\"\"\n            } else {\n                \"\"\"mutation (${'$'}id: Int = $id, ${'$'}status: MediaListStatus = ${\n                    aniListStatusString[maxOf(\n                        0,\n                        type.value\n                    )]\n                }, ${if (score != null) \"${'$'}scoreRaw: Int = ${score.toInt(100)}\" else \"\"} , ${if (progress != null) \"${'$'}progress: Int = $progress\" else \"\"}) {\n                    SaveMediaListEntry (mediaId: ${'$'}id, status: ${'$'}status, scoreRaw: ${'$'}scoreRaw, progress: ${'$'}progress) {\n                        id\n                        status\n                        progress\n                        score\n                    }\n                }\"\"\"\n            }\n\n        val data = postApi(auth.token, q)\n        return data != \"\"\n    }\n\n    private suspend fun getUser(token : AuthToken): AniListUser? {\n        val q = \"\"\"\n\t\t\t\t{\n  \t\t\t\t\tViewer {\n    \t\t\t\t\tid\n    \t\t\t\t\tname\n\t\t\t\t\t\tavatar {\n\t\t\t\t\t\t\tlarge\n\t\t\t\t\t\t}\n                        favourites {\n                            anime {\n                                nodes {\n                                    id\n                                }\n                            }\n                        }\n  \t\t\t\t\t}\n\t\t\t\t}\"\"\"\n        val data = postApi(token, q)\n        if (data.isNullOrBlank()) return null\n        val userData = parseJson<AniListRoot>(data)\n        val u = userData.data?.viewer ?: return null\n        val user = AniListUser(\n            u.id,\n            u.name,\n            u.avatar?.large,\n        )\n        return user\n    }\n\n    suspend fun getAllSeasons(id: Int): List<SeasonResponse?> {\n        val seasons = mutableListOf<SeasonResponse?>()\n        suspend fun getSeasonRecursive(id: Int) {\n            val season = getSeason(id)\n            seasons.add(season)\n            if (season.data.media.format?.startsWith(\"TV\") == true) {\n                season.data.media.relations?.edges?.forEach {\n                    if (it.node?.format != null) {\n                        if (it.relationType == \"SEQUEL\" && it.node.format.startsWith(\"TV\")) {\n                            getSeasonRecursive(it.node.id)\n                            return@forEach\n                        }\n                    }\n                }\n            }\n        }\n        getSeasonRecursive(id)\n        return seasons.toList()\n    }\n\n    data class SeasonResponse(\n        @JsonProperty(\"data\") val data: SeasonData,\n    )\n\n    data class SeasonData(\n        @JsonProperty(\"Media\") val media: SeasonMedia,\n    )\n\n    data class SeasonMedia(\n        @JsonProperty(\"id\") val id: Int?,\n        @JsonProperty(\"title\") val title: MediaTitle?,\n        @JsonProperty(\"idMal\") val idMal: Int?,\n        @JsonProperty(\"format\") val format: String?,\n        @JsonProperty(\"nextAiringEpisode\") val nextAiringEpisode: SeasonNextAiringEpisode?,\n        @JsonProperty(\"relations\") val relations: SeasonEdges?,\n        @JsonProperty(\"coverImage\") val coverImage: MediaCoverImage?,\n        @JsonProperty(\"duration\") val duration: Int?,\n        @JsonProperty(\"episodes\") val episodes: Int?,\n        @JsonProperty(\"genres\") val genres: List<String>?,\n        @JsonProperty(\"synonyms\") val synonyms: List<String>?,\n        @JsonProperty(\"averageScore\") val averageScore: Int?,\n        @JsonProperty(\"isAdult\") val isAdult: Boolean?,\n        @JsonProperty(\"trailer\") val trailer: MediaTrailer?,\n        @JsonProperty(\"description\") val description: String?,\n        @JsonProperty(\"characters\") val characters: CharacterConnection?,\n        @JsonProperty(\"recommendations\") val recommendations: RecommendationConnection?,\n    )\n\n    data class RecommendationConnection(\n        @JsonProperty(\"edges\") val edges: List<RecommendationEdge> = emptyList(),\n        @JsonProperty(\"nodes\") val nodes: List<Recommendation> = emptyList(),\n        //@JsonProperty(\"pageInfo\") val pageInfo: PageInfo,\n    )\n\n    data class RecommendationEdge(\n        //@JsonProperty(\"rating\") val rating: Int,\n        @JsonProperty(\"node\") val node: Recommendation,\n    )\n\n    data class Recommendation(\n        val id: Long,\n        @JsonProperty(\"mediaRecommendation\") val mediaRecommendation: SeasonMedia?,\n    )\n\n    data class CharacterName(\n        @JsonProperty(\"name\") val first: String?,\n        @JsonProperty(\"middle\") val middle: String?,\n        @JsonProperty(\"last\") val last: String?,\n        @JsonProperty(\"full\") val full: String?,\n        @JsonProperty(\"native\") val native: String?,\n        @JsonProperty(\"alternative\") val alternative: List<String>?,\n        @JsonProperty(\"alternativeSpoiler\") val alternativeSpoiler: List<String>?,\n        @JsonProperty(\"userPreferred\") val userPreferred: String?,\n    )\n\n    data class CharacterImage(\n        @JsonProperty(\"large\") val large: String?,\n        @JsonProperty(\"medium\") val medium: String?,\n    )\n\n    data class Character(\n        @JsonProperty(\"name\") val name: CharacterName?,\n        @JsonProperty(\"age\") val age: String?,\n        @JsonProperty(\"image\") val image: CharacterImage?,\n    )\n\n    data class CharacterEdge(\n        @JsonProperty(\"id\") val id: Int?,\n        /**\n        MAIN\n        A primary character role in the media\n\n        SUPPORTING\n        A supporting character role in the media\n\n        BACKGROUND\n        A background character in the media\n         */\n        @JsonProperty(\"role\") val role: String?,\n        @JsonProperty(\"name\") val name: String?,\n        @JsonProperty(\"voiceActors\") val voiceActors: List<Staff>?,\n        @JsonProperty(\"favouriteOrder\") val favouriteOrder: Int?,\n        @JsonProperty(\"media\") val media: List<SeasonMedia>?,\n        @JsonProperty(\"node\") val node: Character?,\n    )\n\n    data class StaffImage(\n        @JsonProperty(\"large\") val large: String?,\n        @JsonProperty(\"medium\") val medium: String?,\n    )\n\n    data class StaffName(\n        @JsonProperty(\"name\") val first: String?,\n        @JsonProperty(\"middle\") val middle: String?,\n        @JsonProperty(\"last\") val last: String?,\n        @JsonProperty(\"full\") val full: String?,\n        @JsonProperty(\"native\") val native: String?,\n        @JsonProperty(\"alternative\") val alternative: List<String>?,\n        @JsonProperty(\"userPreferred\") val userPreferred: String?,\n    )\n\n    data class Staff(\n        @JsonProperty(\"image\") val image: StaffImage?,\n        @JsonProperty(\"name\") val name: StaffName?,\n        @JsonProperty(\"age\") val age: Int?,\n    )\n\n    data class CharacterConnection(\n        @JsonProperty(\"edges\") val edges: List<CharacterEdge>?,\n        @JsonProperty(\"nodes\") val nodes: List<Character>?,\n        //@JsonProperty(\"pageInfo\")  pageInfo: PageInfo\n    )\n\n    data class MediaTrailer(\n        @JsonProperty(\"id\") val id: String?,\n        @JsonProperty(\"site\") val site: String?,\n        @JsonProperty(\"thumbnail\") val thumbnail: String?,\n    )\n\n    data class MediaCoverImage(\n        @JsonProperty(\"extraLarge\") val extraLarge: String?,\n        @JsonProperty(\"large\") val large: String?,\n        @JsonProperty(\"medium\") val medium: String?,\n        @JsonProperty(\"color\") val color: String?,\n    )\n\n    data class SeasonNextAiringEpisode(\n        @JsonProperty(\"episode\") val episode: Int?,\n        @JsonProperty(\"timeUntilAiring\") val timeUntilAiring: Int?,\n    )\n\n    data class SeasonEdges(\n        @JsonProperty(\"edges\") val edges: List<SeasonEdge>?,\n    )\n\n    data class SeasonEdge(\n        @JsonProperty(\"id\") val id: Int?,\n        @JsonProperty(\"relationType\") val relationType: String?,\n        @JsonProperty(\"node\") val node: SeasonNode?,\n    )\n\n    data class AniListFavoritesMediaConnection(\n        @JsonProperty(\"nodes\") val nodes: List<LikeNode>,\n    )\n\n    data class AniListFavourites(\n        @JsonProperty(\"anime\") val anime: AniListFavoritesMediaConnection,\n    )\n\n    data class MediaTitle(\n        @JsonProperty(\"romaji\") val romaji: String?,\n        @JsonProperty(\"english\") val english: String?,\n        @JsonProperty(\"native\") val native: String?,\n        @JsonProperty(\"userPreferred\") val userPreferred: String?,\n    )\n\n    data class SeasonNode(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"format\") val format: String?,\n        @JsonProperty(\"title\") val title: Title?,\n        @JsonProperty(\"idMal\") val idMal: Int?,\n        @JsonProperty(\"coverImage\") val coverImage: CoverImage?,\n        @JsonProperty(\"averageScore\") val averageScore: Int?\n//        @JsonProperty(\"nextAiringEpisode\") val nextAiringEpisode: SeasonNextAiringEpisode?,\n    )\n\n    data class AniListAvatar(\n        @JsonProperty(\"large\") val large: String?,\n    )\n\n    data class AniListViewer(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"avatar\") val avatar: AniListAvatar?,\n        @JsonProperty(\"favourites\") val favourites: AniListFavourites?,\n    )\n\n    data class AniListData(\n        @JsonProperty(\"Viewer\") val viewer: AniListViewer?,\n    )\n\n    data class AniListRoot(\n        @JsonProperty(\"data\") val data: AniListData?,\n    )\n\n    data class AniListUser(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"picture\") val picture: String?,\n    )\n\n    data class LikeNode(\n        @JsonProperty(\"id\") val id: Int?,\n        //@JsonProperty(\"idMal\") public int idMal;\n    )\n\n    data class LikePageInfo(\n        @JsonProperty(\"total\") val total: Int?,\n        @JsonProperty(\"currentPage\") val currentPage: Int?,\n        @JsonProperty(\"lastPage\") val lastPage: Int?,\n        @JsonProperty(\"perPage\") val perPage: Int?,\n        @JsonProperty(\"hasNextPage\") val hasNextPage: Boolean?,\n    )\n\n    data class LikeAnime(\n        @JsonProperty(\"nodes\") val nodes: List<LikeNode>?,\n        @JsonProperty(\"pageInfo\") val pageInfo: LikePageInfo?,\n    )\n\n    data class LikeFavourites(\n        @JsonProperty(\"anime\") val anime: LikeAnime?,\n    )\n\n    data class LikeViewer(\n        @JsonProperty(\"favourites\") val favourites: LikeFavourites?,\n    )\n\n    data class LikeData(\n        @JsonProperty(\"Viewer\") val viewer: LikeViewer?,\n    )\n\n    data class LikeRoot(\n        @JsonProperty(\"data\") val data: LikeData?,\n    )\n\n    data class AniListTitleHolder(\n        @JsonProperty(\"title\") val title: Title?,\n        @JsonProperty(\"isFavourite\") val isFavourite: Boolean?,\n        @JsonProperty(\"id\") val id: Int?,\n        @JsonProperty(\"progress\") val progress: Int?,\n        @JsonProperty(\"episodes\") val episodes: Int?,\n        @JsonProperty(\"score\") val score: Int?,\n        @JsonProperty(\"type\") val type: AniListStatusType?,\n    )\n\n    data class GetDataMediaListEntry(\n        @JsonProperty(\"progress\") val progress: Int?,\n        @JsonProperty(\"status\") val status: String?,\n        @JsonProperty(\"score\") val score: Int?,\n    )\n\n    data class Nodes(\n        @JsonProperty(\"id\") val id: Int?,\n        @JsonProperty(\"mediaRecommendation\") val mediaRecommendation: MediaRecommendation?\n    )\n\n    data class GetDataMedia(\n        @JsonProperty(\"isFavourite\") val isFavourite: Boolean?,\n        @JsonProperty(\"episodes\") val episodes: Int?,\n        @JsonProperty(\"title\") val title: Title?,\n        @JsonProperty(\"mediaListEntry\") val mediaListEntry: GetDataMediaListEntry?\n    )\n\n    data class Recommendations(\n        @JsonProperty(\"nodes\") val nodes: List<Nodes>?\n    )\n\n    data class GetDataData(\n        @JsonProperty(\"Media\") val media: GetDataMedia?,\n    )\n\n    data class GetDataRoot(\n        @JsonProperty(\"data\") val data: GetDataData?,\n    )\n\n    data class GetSearchTitle(\n        @JsonProperty(\"romaji\") val romaji: String?,\n    )\n\n    data class TrailerObject(\n        @JsonProperty(\"id\") val id: String?,\n        @JsonProperty(\"thumbnail\") val thumbnail: String?,\n        @JsonProperty(\"site\") val site: String?,\n    )\n\n    data class GetSearchMedia(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"idMal\") val idMal: Int?,\n        @JsonProperty(\"seasonYear\") val seasonYear: Int,\n        @JsonProperty(\"title\") val title: GetSearchTitle,\n        @JsonProperty(\"startDate\") val startDate: StartedAt,\n        @JsonProperty(\"averageScore\") val averageScore: Int?,\n        @JsonProperty(\"meanScore\") val meanScore: Int?,\n        @JsonProperty(\"bannerImage\") val bannerImage: String?,\n        @JsonProperty(\"trailer\") val trailer: TrailerObject?,\n        @JsonProperty(\"nextAiringEpisode\") val nextAiringEpisode: SeasonNextAiringEpisode?,\n        @JsonProperty(\"recommendations\") val recommendations: Recommendations?,\n        @JsonProperty(\"relations\") val relations: SeasonEdges?\n    )\n\n    data class GetSearchPage(\n        @JsonProperty(\"Page\") val page: GetSearchData?,\n    )\n\n    data class GetSearchData(\n        @JsonProperty(\"media\") val media: List<GetSearchMedia>?,\n    )\n\n    data class GetSearchRoot(\n        @JsonProperty(\"data\") val data: GetSearchPage?,\n    )\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders.providers\n\n\nimport androidx.annotation.StringRes\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.ShowStatus\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginRequirement\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginResponse\nimport com.lagradost.cloudstream3.syncproviders.AuthToken\nimport com.lagradost.cloudstream3.syncproviders.AuthUser\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.syncproviders.SyncIdName\nimport com.lagradost.cloudstream3.ui.SyncWatchType\nimport com.lagradost.cloudstream3.ui.library.ListSorting\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.txt\nimport kotlinx.coroutines.flow.asFlow\nimport kotlinx.coroutines.flow.collect\nimport kotlinx.coroutines.flow.onEach\nimport kotlinx.coroutines.flow.withIndex\nimport okhttp3.RequestBody.Companion.toRequestBody\nimport java.text.SimpleDateFormat\nimport java.time.Instant\nimport java.time.LocalDate\nimport java.time.format.DateTimeFormatter\nimport java.util.Date\nimport java.util.Locale\nimport kotlin.collections.set\n\nconst val KITSU_MAX_SEARCH_LIMIT = 20\n\nclass KitsuApi: SyncAPI() {\n    override var name = \"Kitsu\"\n    override val idPrefix = \"kitsu\"\n\n    private val apiUrl = \"https://kitsu.io/api/edge\"\n    private val oauthUrl = \"https://kitsu.io/api/oauth\"\n    override val hasInApp = true\n    override val mainUrl = \"https://kitsu.app\"\n    override val icon = R.drawable.kitsu_icon\n    override val syncIdName = SyncIdName.Kitsu\n    override val createAccountUrl = mainUrl\n\n    override val supportedWatchTypes = setOf(\n        SyncWatchType.WATCHING,\n        SyncWatchType.COMPLETED,\n        SyncWatchType.PLANTOWATCH,\n        SyncWatchType.DROPPED,\n        SyncWatchType.ONHOLD,\n        SyncWatchType.NONE\n    )\n\n    override val inAppLoginRequirement = AuthLoginRequirement(\n        password = true,\n        email = true\n    )\n\n    override suspend fun login(form: AuthLoginResponse): AuthToken? {\n        val username = form.email ?: return null\n        val password = form.password ?: return null\n\n        val grantType = \"password\"\n\n        val token = app.post(\n            \"$oauthUrl/token\",\n            data = mapOf(\n                \"grant_type\" to grantType,\n                \"username\" to username,\n                \"password\" to password\n            )\n        ).parsed<ResponseToken>()\n        return AuthToken(\n            accessTokenLifetime = unixTime + token.expiresIn.toLong(),\n            refreshToken = token.refreshToken,\n            accessToken = token.accessToken,\n        )\n    }\n\n    override suspend fun refreshToken(token: AuthToken): AuthToken {\n        val res = app.post(\n            \"$oauthUrl/token\",\n            data = mapOf(\n                \"grant_type\" to \"refresh_token\",\n                \"refresh_token\" to token.refreshToken!!\n            )\n        ).parsed<ResponseToken>()\n\n        return AuthToken(\n            accessToken = res.accessToken,\n            refreshToken = res.refreshToken,\n            accessTokenLifetime = unixTime + res.expiresIn.toLong()\n        )\n    }\n\n    override suspend fun user(token: AuthToken?): AuthUser? {\n        val user = app.get(\n            \"$apiUrl/users?filter[self]=true\",\n            headers = mapOf(\n                \"Authorization\" to \"Bearer ${token?.accessToken ?: return null}\"\n            ), cacheTime = 0\n        ).parsed<KitsuResponse>()\n\n        if (user.data.isEmpty()) {\n           return null\n        }\n\n        return AuthUser(\n            id = user.data[0].id.toInt(),\n            name = user.data[0].attributes.name,\n            profilePicture = user.data[0].attributes.avatar?.original\n        )\n    }\n\n    override suspend fun search(auth: AuthData?, query: String): List<SyncSearchResult>? {\n        val auth = auth?.token?.accessToken ?: return null\n        val animeSelectedFields = arrayOf(\"titles\",\"canonicalTitle\",\"posterImage\",\"episodeCount\")\n        val url = \"$apiUrl/anime?filter[text]=$query&page[limit]=$KITSU_MAX_SEARCH_LIMIT&fields[anime]=${animeSelectedFields.joinToString(\",\")}\"\n        val res = app.get(\n            url, headers = mapOf(\n                \"Authorization\" to \"Bearer $auth\",\n            ), cacheTime = 0\n        ).parsed<KitsuResponse>()\n        return res.data.map {\n            val attributes = it.attributes\n\n            val title = attributes.canonicalTitle ?: attributes.titles?.enJp ?: attributes.titles?.jaJp ?: \"No title\"\n\n            SyncSearchResult(\n                title,\n                this.name,\n                it.id,\n                \"$mainUrl/anime/${it.id}/\",\n                attributes.posterImage?.large ?: attributes.posterImage?.medium\n            )\n        }\n    }\n\n    override suspend fun load(auth : AuthData?, id: String): SyncResult? {\n        val auth = auth?.token?.accessToken ?: return null\n        if (id.toIntOrNull() == null) {\n            return null\n        }\n\n        data class KitsuResponse(\n            @field:JsonProperty(value = \"data\")\n            val data: KitsuNode,\n        )\n\n        val url =\n            \"$apiUrl/anime/$id\"\n\n        val anime = app.get(\n            url, headers = mapOf(\n                \"Authorization\" to \"Bearer $auth\"\n            )\n        ).parsed<KitsuResponse>().data.attributes\n\n        return SyncResult(\n            id = id,\n            totalEpisodes = anime.episodeCount,\n            title = anime.canonicalTitle ?: anime.titles?.enJp ?: anime.titles?.jaJp.orEmpty(),\n            publicScore =  Score.from(anime.ratingTwenty.toString(), 20),\n            duration = anime.episodeLength,\n            synopsis = anime.synopsis,\n            airStatus = when(anime.status) {\n                \"finished\" -> ShowStatus.Completed\n                \"current\" -> ShowStatus.Ongoing\n                else -> null\n            },\n            nextAiring = null,\n            studio = null,\n            genres = null,\n            trailers = null,\n            startDate = LocalDate.parse(anime.startDate).toEpochDay(),\n            endDate = LocalDate.parse(anime.endDate).toEpochDay(),\n            recommendations = null,\n            nextSeason =null,\n            prevSeason = null,\n            actors = null,\n        )\n\n    }\n\n    override suspend fun status(auth : AuthData?, id: String): AbstractSyncStatus? {\n        val accessToken = auth?.token?.accessToken ?: return null\n        val userId = auth.user.id\n\n        val selectedFields = arrayOf(\"status\",\"ratingTwenty\", \"progress\")\n\n        val url =\n            \"$apiUrl/library-entries?filter[userId]=$userId&filter[animeId]=$id&fields[libraryEntries]=${selectedFields.joinToString(\",\")}\"\n\n        val anime = app.get(\n            url, headers = mapOf(\n                \"Authorization\" to \"Bearer $accessToken\"\n            )\n        ).parsed<KitsuResponse>().data.firstOrNull()?.attributes\n\n        if (anime == null) {\n            return SyncStatus(\n                score = null,\n                status = SyncWatchType.NONE,\n                isFavorite = null,\n                watchedEpisodes = null\n            )\n        }\n\n        return SyncStatus(\n            score = Score.from(anime.ratingTwenty.toString(), 20),\n            status = SyncWatchType.fromInternalId(kitsuStatusAsString.indexOf(anime.status)),\n            isFavorite = null,\n            watchedEpisodes = anime.progress,\n        )\n    }\n    suspend fun getAnimeIdByTitle(title: String): String? {\n\n        val animeSelectedFields = arrayOf(\"titles\",\"canonicalTitle\")\n        val url = \"$apiUrl/anime?filter[text]=$title&page[limit]=$KITSU_MAX_SEARCH_LIMIT&fields[anime]=${animeSelectedFields.joinToString(\",\")}\"\n        val res = app.get(url).parsed<KitsuResponse>()\n\n        return res.data.firstOrNull()?.id\n\n    }\n\n    override fun urlToId(url: String): String? =\n        Regex(\"\"\"/anime/((.*)/|(.*))\"\"\").find(url)?.groupValues?.first()\n\n    override suspend fun updateStatus(\n        auth : AuthData?,\n        id: String,\n        newStatus: AbstractSyncStatus\n    ): Boolean {\n\n        return setScoreRequest(\n            auth ?: return false,\n            id.toIntOrNull() ?: return false,\n            fromIntToAnimeStatus(newStatus.status),\n            newStatus.score?.toInt(20),\n            newStatus.watchedEpisodes\n        )\n    }\n\n    private suspend fun setScoreRequest(\n        auth : AuthData,\n        id: Int,\n        status: KitsuStatusType? = null,\n        score: Int? = null,\n        numWatchedEpisodes: Int? = null,\n    ): Boolean {\n\n        val libraryEntryId = getAnimeLibraryEntryId(auth, id)\n\n        // Exists entry for anime in library\n        if (libraryEntryId != null) {\n\n            // Delete anime from library\n            if (status == null || status == KitsuStatusType.None) {\n\n                val res = app.delete(\n                    \"$apiUrl/library-entries/$libraryEntryId\",\n                    headers = mapOf(\n                        \"Authorization\" to \"Bearer ${auth.token.accessToken}\"\n                    ),\n                )\n\n                return res.isSuccessful\n\n            }\n\n            return setScoreRequest(\n                auth,\n                libraryEntryId,\n                kitsuStatusAsString[maxOf(0, status.value)],\n                score,\n                numWatchedEpisodes\n            )\n\n        }\n\n        val data = mapOf(\n            \"data\" to mapOf(\n                \"type\" to \"libraryEntries\",\n                \"attributes\" to mapOf(\n                    \"ratingTwenty\" to score,\n                    \"progress\" to numWatchedEpisodes,\n                    \"status\" to if (status == null) null else kitsuStatusAsString[maxOf(0, status.value)],\n                ),\n                \"relationships\" to mapOf(\n                    \"anime\" to mapOf(\n                        \"data\" to mapOf(\n                            \"type\" to \"anime\",\n                            \"id\" to id.toString()\n                        )\n                    ),\n                    \"user\" to mapOf(\n                        \"data\" to mapOf(\n                            \"type\" to \"users\",\n                            \"id\" to auth.user.id\n                        )\n                    )\n                )\n            )\n        )\n\n        val res = app.post(\n            \"$apiUrl/library-entries\",\n            headers = mapOf(\n                \"content-type\" to \"application/vnd.api+json\",\n                \"Authorization\" to \"Bearer ${auth.token.accessToken}\"\n            ),\n            requestBody = data.toJson().toRequestBody()\n        )\n\n        return res.isSuccessful\n\n    }\n\n    @Suppress(\"UNCHECKED_CAST\")\n    private suspend fun setScoreRequest(\n        auth : AuthData,\n        id: Int,\n        status: String? = null,\n        score: Int? = null,\n        numWatchedEpisodes: Int? = null,\n    ):  Boolean {\n        val data = mapOf(\n            \"data\" to mapOf(\n                \"type\" to \"libraryEntries\",\n                \"id\" to id.toString(),\n                \"attributes\" to mapOf(\n                    \"ratingTwenty\" to score,\n                    \"progress\" to numWatchedEpisodes,\n                    \"status\" to status\n                )\n            )\n        )\n\n        val res = app.patch(\n            \"$apiUrl/library-entries/$id\",\n            headers = mapOf(\n                \"content-type\" to \"application/vnd.api+json\",\n                \"Authorization\" to \"Bearer ${auth.token.accessToken}\"\n            ),\n            requestBody = data.toJson().toRequestBody()\n        )\n\n        return res.isSuccessful\n\n    }\n\n    private suspend fun getAnimeLibraryEntryId(auth: AuthData, id: Int): Int? {\n\n        val userId = auth.user.id\n\n        val res = app.get(\n            \"$apiUrl/library-entries?filter[userId]=$userId&filter[animeId]=$id\",\n            headers = mapOf(\n                \"Authorization\" to \"Bearer ${auth.token.accessToken}\"\n            ),\n        ).parsed<KitsuResponse>().data.firstOrNull() ?: return null\n\n        return res.id.toInt()\n\n    }\n\n    override suspend fun library(auth : AuthData?): LibraryMetadata? {\n        val list = getKitsuAnimeListSmart(auth ?: return null)?.groupBy {\n            convertToStatus(it.attributes.status ?: \"\").stringRes\n        }?.mapValues { group ->\n            group.value.map { it.toLibraryItem() }\n        } ?: emptyMap()\n\n        // To fill empty lists when Kitsu does not return them\n        val baseMap =\n            KitsuStatusType.entries.filter { it.value >= 0 }.associate {\n                it.stringRes to emptyList<LibraryItem>()\n            }\n\n        return LibraryMetadata(\n            (baseMap + list).map { LibraryList(txt(it.key), it.value) },\n            setOf(\n                ListSorting.AlphabeticalA,\n                ListSorting.AlphabeticalZ,\n                ListSorting.UpdatedNew,\n                ListSorting.UpdatedOld,\n                ListSorting.ReleaseDateNew,\n                ListSorting.ReleaseDateOld,\n                ListSorting.RatingHigh,\n                ListSorting.RatingLow,\n            )\n        )\n    }\n\n    private suspend fun getKitsuAnimeListSmart(auth : AuthData): Array<KitsuNode>? {\n        return if (requireLibraryRefresh) {\n            val list = getKitsuAnimeList(auth.token, auth.user.id)\n            setKey(KITSU_CACHED_LIST, auth.user.id.toString(), list)\n            list\n        } else {\n            getKey<Array<KitsuNode>>(KITSU_CACHED_LIST, auth.user.id.toString()) as? Array<KitsuNode>\n        }\n    }\n\n    private suspend fun getKitsuAnimeList(token: AuthToken, userId: Int): Array<KitsuNode> {\n\n        val animeSelectedFields = arrayOf(\"titles\",\"canonicalTitle\",\"posterImage\",\"synopsis\",\"startDate\",\"episodeCount\")\n        val libraryEntriesSelectedFields = arrayOf(\"progress\",\"rating\",\"updatedAt\", \"status\")\n        val limit = 500\n        var url = \"$apiUrl/library-entries?filter[userId]=$userId&filter[kind]=anime&include=anime&page[limit]=$limit&page[offset]=0&fields[anime]=${animeSelectedFields.joinToString(\",\")}&fields[libraryEntries]=${libraryEntriesSelectedFields.joinToString(\",\")}\"\n\n        val fullList = mutableListOf<KitsuNode>()\n\n        while (true) {\n\n            val data: KitsuResponse = getKitsuAnimeListSlice(token, url)\n\n            data.data.forEachIndexed { index, value ->\n                value.anime = data.included?.get(index)\n            }\n\n            fullList.addAll(data.data)\n\n            url = data.links?.next ?: break\n        }\n\n\n        return fullList.toTypedArray()\n    }\n\n    private suspend fun getKitsuAnimeListSlice(token: AuthToken, url: String): KitsuResponse {\n        val res = app.get(\n            url, headers = mapOf(\n                \"Authorization\" to \"Bearer ${token.accessToken}\",\n            )\n        ).parsed<KitsuResponse>()\n        return res\n    }\n\n\n    data class ResponseToken(\n        @JsonProperty(\"token_type\") val tokenType: String,\n        @JsonProperty(\"expires_in\") val expiresIn: Int,\n        @JsonProperty(\"access_token\") val accessToken: String,\n        @JsonProperty(\"refresh_token\") val refreshToken: String,\n    )\n\n    data class KitsuNode(\n        @JsonProperty(\"id\") val id: String,\n        @JsonProperty(\"attributes\") val attributes: KitsuNodeAttributes,\n        /* User list anime node */\n        @JsonProperty(\"relationships\") val relationships: KitsuRelationships?,\n        var anime: KitsuAnimeData?\n    ) {\n        fun toLibraryItem(): LibraryItem {\n\n            val animeItem = this.anime\n\n            val numEpisodes = animeItem?.attributes?.episodeCount\n\n            val startDate = animeItem?.attributes?.startDate\n\n            val posterImage = animeItem?.attributes?.posterImage\n\n            val canonicalTitle = animeItem?.attributes?.canonicalTitle\n            val titles = animeItem?.attributes?.titles\n\n            val animeId = animeItem?.id\n\n            val description: String? = animeItem?.attributes?.synopsis\n\n            return LibraryItem(\n                canonicalTitle ?: titles?.enJp ?: titles?.jaJp.orEmpty(),\n                \"https://kitsu.app/anime/${animeId}/\",\n                this.id,\n                this.attributes.progress,\n                numEpisodes,\n                Score.from(this.attributes.ratingTwenty.toString(), 20),\n                parseDateLong(this.attributes.updatedAt),\n                \"Kitsu\",\n                TvType.Anime,\n                posterImage?.large ?: posterImage?.medium,\n                null,\n                null,\n                plot = description,\n                releaseDate = if (startDate == null) null else try {\n                    Date.from(\n                        Instant.from(\n                            DateTimeFormatter.ofPattern(if (startDate.length == 4) \"yyyy\" else if (startDate.length == 7) \"yyyy-MM\" else \"yyyy-MM-dd\")\n                                .parse(startDate)\n                        )\n                    )\n                } catch (_: RuntimeException) {\n                    null\n                }\n            )\n        }\n\n    }\n\n    data class KitsuAnimeAttributes(\n        @JsonProperty(\"titles\") val titles: KitsuTitles?,\n        @JsonProperty(\"canonicalTitle\") val canonicalTitle: String?,\n        @JsonProperty(\"posterImage\") val posterImage: KitsuPosterImage?,\n        @JsonProperty(\"synopsis\") val synopsis: String?,\n        @JsonProperty(\"startDate\") val startDate: String?,\n        @JsonProperty(\"endDate\") val endDate: String?,\n        @JsonProperty(\"episodeCount\") val episodeCount: Int?,\n        @JsonProperty(\"episodeLength\") val episodeLength: Int?,\n    )\n\n    data class KitsuAnimeData(\n        @JsonProperty(\"id\") val id: String,\n        @JsonProperty(\"attributes\") val attributes: KitsuAnimeAttributes,\n    )\n\n\n    data class KitsuNodeAttributes(\n        /* General attributes */\n        @JsonProperty(\"titles\") val titles: KitsuTitles?,\n        @JsonProperty(\"canonicalTitle\") val canonicalTitle: String?,\n        @JsonProperty(\"posterImage\") val posterImage: KitsuPosterImage?,\n        @JsonProperty(\"synopsis\") val synopsis: String?,\n        @JsonProperty(\"startDate\") val startDate: String?,\n        @JsonProperty(\"endDate\") val endDate: String?,\n        @JsonProperty(\"episodeCount\") val episodeCount: Int?,\n        @JsonProperty(\"episodeLength\") val episodeLength: Int?,\n        /* User attributes */\n        @JsonProperty(\"name\") val name: String?,\n        @JsonProperty(\"location\") val location: String?,\n        @JsonProperty(\"createdAt\") val createdAt: String?,\n        @JsonProperty(\"avatar\") val avatar: KitsuUserAvatar?,\n        /* User list anime attributes */\n        @JsonProperty(\"progress\") val progress: Int?,\n        @JsonProperty(\"ratingTwenty\") val ratingTwenty: Float?,\n        @JsonProperty(\"updatedAt\") val updatedAt: String?,\n        @JsonProperty(\"status\") val status: String?,\n    )\n\n    data class KitsuRelationships(\n        @JsonProperty(\"anime\") val anime: KitsuRelationshipsAnime?\n    )\n\n    data class KitsuRelationshipsAnime(\n        @JsonProperty(\"links\") val links: KitsuLinks?\n    )\n\n    data class KitsuPosterImage(\n        @JsonProperty(\"large\") val large: String?,\n        @JsonProperty(\"medium\") val medium: String?,\n    )\n\n    data class KitsuTitles(\n        @JsonProperty(\"en_jp\") val enJp: String?,\n        @JsonProperty(\"ja_jp\") val jaJp: String?\n    )\n\n    data class KitsuUserAvatar(\n        @JsonProperty(\"original\") val original: String?\n    )\n\n    data class KitsuLinks(\n        /* Pagination */\n        @JsonProperty(\"first\") val first: String?,\n        @JsonProperty(\"next\") val next: String?,\n        @JsonProperty(\"last\") val last: String?,\n        /* Relationships */\n        @JsonProperty(\"related\") val related: String?\n    )\n\n    data class KitsuResponse(\n        @JsonProperty(\"links\") val links: KitsuLinks?,\n        @JsonProperty(\"data\") val data: List<KitsuNode>,\n        /* When requesting related info (User library entry -> anime) */\n        @JsonProperty(\"included\") val included: List<KitsuAnimeData>?,\n    )\n\n\n    companion object {\n\n        const val KITSU_CACHED_LIST: String = \"kitsu_cached_list\"\n        private fun parseDateLong(string: String?): Long? {\n            return try {\n                SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ssZ\", Locale.getDefault()).parse(\n                    string ?: return null\n                )?.time?.div(1000)\n            } catch (e: Exception) {\n                null\n            }\n        }\n\n        private val kitsuStatusAsString =\n            arrayOf(\"current\", \"completed\", \"on_hold\", \"dropped\", \"planned\")\n        private fun fromIntToAnimeStatus(inp: SyncWatchType): KitsuStatusType {\n            return when (inp) {\n                SyncWatchType.NONE ->  KitsuStatusType.None\n                SyncWatchType.WATCHING ->  KitsuStatusType.Watching\n                SyncWatchType.COMPLETED ->  KitsuStatusType.Completed\n                SyncWatchType.ONHOLD ->  KitsuStatusType.OnHold\n                SyncWatchType.DROPPED ->  KitsuStatusType.Dropped\n                SyncWatchType.PLANTOWATCH ->  KitsuStatusType.PlanToWatch\n                SyncWatchType.REWATCHING ->  KitsuStatusType.Watching\n            }\n        }\n\n        enum class KitsuStatusType(var value: Int, @StringRes val stringRes: Int) {\n            Watching(0, R.string.type_watching),\n            Completed(1, R.string.type_completed),\n            OnHold(2, R.string.type_on_hold),\n            Dropped(3, R.string.type_dropped),\n            PlanToWatch(4, R.string.type_plan_to_watch),\n            None(-1, R.string.type_none)\n        }\n\n        private fun convertToStatus(string: String): KitsuStatusType {\n            return when (string) {\n                \"current\" ->  KitsuStatusType.Watching\n                \"completed\" ->  KitsuStatusType.Completed\n                \"on_hold\" ->  KitsuStatusType.OnHold\n                \"dropped\" ->  KitsuStatusType.Dropped\n                \"planned\" ->  KitsuStatusType.PlanToWatch\n                else ->  KitsuStatusType.None\n            }\n        }\n    }\n}\n\n// modified code from from https://github.com/saikou-app/saikou/blob/main/app/src/main/java/ani/saikou/others/Kitsu.kt\n// GNU General Public License v3.0 https://github.com/saikou-app/saikou/blob/main/LICENSE.md\nobject Kitsu {\n    private suspend fun getKitsuData(query: String): KitsuResponse {\n        val headers = mapOf(\n            \"Content-Type\" to \"application/json\",\n            \"Accept\" to \"application/json\",\n            \"Connection\" to \"keep-alive\",\n            \"DNT\" to \"1\",\n            \"Origin\" to \"https://kitsu.io\"\n        )\n\n        return app.post(\n            \"https://kitsu.io/api/graphql\",\n            headers = headers,\n            data = mapOf(\"query\" to query)\n        ).parsed()\n    }\n\n    private val cache: MutableMap<Pair<String, String>, Map<Int, KitsuResponse.Node>> =\n        mutableMapOf()\n\n    var isEnabled = true\n\n    suspend fun getEpisodesDetails(\n        malId: String?,\n        anilistId: String?,\n        isResponseRequired: Boolean = true, // overrides isEnabled\n    ): Map<Int, KitsuResponse.Node>? {\n        if (!isResponseRequired && !isEnabled) return null\n        if (anilistId != null) {\n            try {\n                val map = getKitsuEpisodesDetails(anilistId, \"ANILIST_ANIME\")\n                if (!map.isNullOrEmpty()) return map\n            } catch (e: Exception) {\n                logError(e)\n            }\n        }\n        if (malId != null) {\n            try {\n                val map = getKitsuEpisodesDetails(malId, \"MYANIMELIST_ANIME\")\n                if (!map.isNullOrEmpty()) return map\n            } catch (e: Exception) {\n                logError(e)\n            }\n        }\n        return null\n    }\n\n    @Throws\n    suspend fun getKitsuEpisodesDetails(id: String, site: String): Map<Int, KitsuResponse.Node>? {\n        require(id.isNotBlank()) {\n            \"Black id\"\n        }\n\n        require(site.isNotBlank()) {\n            \"invalid site\"\n        }\n\n        if (cache.containsKey(id to site)) {\n            return cache[id to site]\n        }\n\n        val query =\n            \"\"\"\nquery {\n  lookupMapping(externalId: $id, externalSite: $site) {\n    __typename\n    ... on Anime {\n      id\n      episodes(first: 2000) {\n        nodes {\n          number\n          titles {\n            canonical\n          }\n          description\n          thumbnail {\n            original {\n              url\n            }\n          }\n        }\n      }\n    }\n  }\n}\"\"\"\n        val result = getKitsuData(query)\n        val map = (result.data?.lookupMapping?.episodes?.nodes ?: return null).mapNotNull { ep ->\n            val num = ep?.num ?: return@mapNotNull null\n            num to ep\n        }.toMap()\n        if (map.isNotEmpty()) {\n            cache[id to site] = map\n        }\n        return map\n    }\n\n    data class KitsuResponse(\n        val data: Data? = null\n    ) {\n        data class Data(\n            val lookupMapping: LookupMapping? = null\n        )\n\n        data class LookupMapping(\n            val id: String? = null,\n            val episodes: Episodes? = null\n        )\n\n        data class Episodes(\n            val nodes: List<Node?>? = null\n        )\n\n        data class Node(\n            @JsonProperty(\"number\")\n            val num: Int? = null,\n            val titles: Titles? = null,\n            val description: Description? = null,\n            val thumbnail: Thumbnail? = null\n        )\n\n        data class Description(\n            val en: String? = null\n        )\n\n        data class Thumbnail(\n            val original: Original? = null\n        )\n\n        data class Original(\n            val url: String? = null\n        )\n\n        data class Titles(\n            val canonical: String? = null\n        )\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/LocalList.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders.providers\n\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.syncproviders.SyncIdName\nimport com.lagradost.cloudstream3.ui.WatchType\nimport com.lagradost.cloudstream3.ui.library.ListSorting\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.Coroutines.ioWork\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllFavorites\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllSubscriptions\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState\nimport com.lagradost.cloudstream3.utils.txt\n\nclass LocalList : SyncAPI() {\n    override val name = \"Local\"\n    override val idPrefix = \"local\"\n\n    override val icon: Int = R.drawable.ic_baseline_storage_24\n    override val requiresLogin = false\n    override val createAccountUrl = null\n    override var requireLibraryRefresh = true\n    override val syncIdName = SyncIdName.LocalList\n\n    override suspend fun library(auth : AuthData?): SyncAPI.LibraryMetadata? {\n        val watchStatusIds = ioWork {\n            getAllWatchStateIds()?.map { id ->\n                Pair(id, getResultWatchState(id))\n            }\n        }?.distinctBy { it.first } ?: return null\n\n        val list = ioWork {\n            val isTrueTv = isLayout(TV)\n\n            val baseMap = WatchType.entries.filter { it != WatchType.NONE }.associate {\n                // None is not something to display\n                it.stringRes to emptyList<SyncAPI.LibraryItem>()\n            } + mapOf(\n                R.string.favorites_list_name to emptyList()\n            ) + if (!isTrueTv) {\n                mapOf(\n                    R.string.subscription_list_name to emptyList()\n                )\n            } else {\n                emptyMap()\n            }\n\n            val watchStatusMap = watchStatusIds.groupBy { it.second.stringRes }.mapValues { group ->\n                group.value.mapNotNull {\n                    getBookmarkedData(it.first)?.toLibraryItem(it.first.toString())\n                }\n            }\n\n            val favoritesMap = mapOf(R.string.favorites_list_name to getAllFavorites().mapNotNull {\n                it.toLibraryItem()\n            })\n\n            // Don't show subscriptions on TV\n            val result = if (isTrueTv) {\n                baseMap + watchStatusMap + favoritesMap\n            } else {\n                val subscriptionsMap =\n                    mapOf(R.string.subscription_list_name to getAllSubscriptions().mapNotNull {\n                        it.toLibraryItem()\n                    })\n\n                baseMap + watchStatusMap + subscriptionsMap + favoritesMap\n            }\n\n            result\n        }\n\n        return LibraryMetadata(\n            list.map { LibraryList(txt(it.key), it.value) },\n            setOf(\n                ListSorting.AlphabeticalA,\n                ListSorting.AlphabeticalZ,\n                ListSorting.UpdatedNew,\n                ListSorting.UpdatedOld,\n                ListSorting.ReleaseDateNew,\n                ListSorting.ReleaseDateOld,\n//                ListSorting.RatingHigh,\n//                ListSorting.RatingLow,\n\n            )\n        )\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders.providers\n\nimport androidx.annotation.StringRes\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.ShowStatus\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginPage\nimport com.lagradost.cloudstream3.syncproviders.AuthToken\nimport com.lagradost.cloudstream3.syncproviders.AuthUser\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.syncproviders.SyncIdName\nimport com.lagradost.cloudstream3.ui.SyncWatchType\nimport com.lagradost.cloudstream3.ui.library.ListSorting\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.DataStore.toKotlinObject\nimport com.lagradost.cloudstream3.utils.txt\nimport java.text.SimpleDateFormat\nimport java.time.Instant\nimport java.time.format.DateTimeFormatter\nimport java.util.Date\nimport java.util.Locale\n\n/** max 100 via https://myanimelist.net/apiconfig/references/api/v2#tag/anime */\nconst val MAL_MAX_SEARCH_LIMIT = 25\n\nclass MALApi : SyncAPI() {\n    override var name = \"MAL\"\n    override val idPrefix = \"mal\"\n\n    val key = \"1714d6f2f4f7cc19644384f8c4629910\"\n    private val apiUrl = \"https://api.myanimelist.net\"\n    override val hasOAuth2 = true\n    override val redirectUrlIdentifier: String? = \"mallogin\"\n    override val mainUrl = \"https://myanimelist.net\"\n    override val icon = R.drawable.mal_logo\n    override val syncIdName = SyncIdName.MyAnimeList\n    override val createAccountUrl = \"$mainUrl/register.php\"\n\n    override val supportedWatchTypes = setOf(\n        SyncWatchType.WATCHING,\n        SyncWatchType.COMPLETED,\n        SyncWatchType.PLANTOWATCH,\n        SyncWatchType.DROPPED,\n        SyncWatchType.ONHOLD,\n        SyncWatchType.NONE\n    )\n\n    data class PayLoad(\n        val requestId: Int,\n        val codeVerifier: String\n    )\n\n    override suspend fun login(redirectUrl: String, payload: String?): AuthToken? {\n        val payloadData = parseJson<PayLoad>(payload!!)\n        val sanitizer = splitRedirectUrl(redirectUrl)\n        val state = sanitizer[\"state\"]!!\n\n        if (state != \"RequestID${payloadData.requestId}\") {\n            return null\n        }\n\n        val currentCode = sanitizer[\"code\"]!!\n\n        val token = app.post(\n            \"$mainUrl/v1/oauth2/token\",\n            data = mapOf(\n                \"client_id\" to key,\n                \"code\" to currentCode,\n                \"code_verifier\" to payloadData.codeVerifier,\n                \"grant_type\" to \"authorization_code\"\n            )\n        ).parsed<ResponseToken>()\n        return AuthToken(\n            accessTokenLifetime = unixTime + token.expiresIn.toLong(),\n            refreshToken = token.refreshToken,\n            accessToken = token.accessToken\n        )\n    }\n\n    override suspend fun user(token: AuthToken?): AuthUser? {\n        val user = app.get(\n            \"$apiUrl/v2/users/@me\",\n            headers = mapOf(\n                \"Authorization\" to \"Bearer ${token?.accessToken ?: return null}\"\n            ), cacheTime = 0\n        ).parsed<MalUser>()\n        return AuthUser(\n            id = user.id,\n            name = user.name,\n            profilePicture = user.picture\n        )\n    }\n\n    override suspend fun search(auth : AuthData?, query: String): List<SyncAPI.SyncSearchResult>? {\n        val auth = auth?.token?.accessToken ?: return null\n        val url = \"$apiUrl/v2/anime?q=$name&limit=$MAL_MAX_SEARCH_LIMIT\"\n        val res = app.get(\n            url, headers = mapOf(\n                \"Authorization\" to \"Bearer $auth\",\n            ), cacheTime = 0\n        ).parsed<MalSearch>()\n        return res.data.map {\n            val node = it.node\n            SyncAPI.SyncSearchResult(\n                node.title,\n                this.name,\n                node.id.toString(),\n                \"$mainUrl/anime/${node.id}/\",\n                node.mainPicture?.large ?: node.mainPicture?.medium\n            )\n        }\n    }\n\n    override fun urlToId(url: String): String? =\n        Regex(\"\"\"/anime/((.*)/|(.*))\"\"\").find(url)!!.groupValues.first()\n\n    override suspend fun updateStatus(\n        auth : AuthData?,\n        id: String,\n        newStatus: SyncAPI.AbstractSyncStatus\n    ): Boolean {\n        return setScoreRequest(\n            auth?.token ?: return false,\n            id.toIntOrNull() ?: return false,\n            fromIntToAnimeStatus(newStatus.status),\n            newStatus.score?.toInt(10),\n            newStatus.watchedEpisodes\n        )\n    }\n\n    data class MalAnime(\n        @JsonProperty(\"id\") val id: Int?,\n        @JsonProperty(\"title\") val title: String?,\n        @JsonProperty(\"main_picture\") val mainPicture: MainPicture?,\n        @JsonProperty(\"alternative_titles\") val alternativeTitles: AlternativeTitles?,\n        @JsonProperty(\"start_date\") val startDate: String?,\n        @JsonProperty(\"end_date\") val endDate: String?,\n        @JsonProperty(\"synopsis\") val synopsis: String?,\n        @JsonProperty(\"mean\") val mean: Double?,\n        @JsonProperty(\"rank\") val rank: Int?,\n        @JsonProperty(\"popularity\") val popularity: Int?,\n        @JsonProperty(\"num_list_users\") val numListUsers: Int?,\n        @JsonProperty(\"num_scoring_users\") val numScoringUsers: Int?,\n        @JsonProperty(\"nsfw\") val nsfw: String?,\n        @JsonProperty(\"created_at\") val createdAt: String?,\n        @JsonProperty(\"updated_at\") val updatedAt: String?,\n        @JsonProperty(\"media_type\") val mediaType: String?,\n        @JsonProperty(\"status\") val status: String?,\n        @JsonProperty(\"genres\") val genres: ArrayList<Genres>?,\n        @JsonProperty(\"my_list_status\") val myListStatus: MyListStatus?,\n        @JsonProperty(\"num_episodes\") val numEpisodes: Int?,\n        @JsonProperty(\"start_season\") val startSeason: StartSeason?,\n        @JsonProperty(\"broadcast\") val broadcast: Broadcast?,\n        @JsonProperty(\"source\") val source: String?,\n        @JsonProperty(\"average_episode_duration\") val averageEpisodeDuration: Int?,\n        @JsonProperty(\"rating\") val rating: String?,\n        @JsonProperty(\"pictures\") val pictures: ArrayList<MainPicture>?,\n        @JsonProperty(\"background\") val background: String?,\n        @JsonProperty(\"related_anime\") val relatedAnime: ArrayList<RelatedAnime>?,\n        @JsonProperty(\"related_manga\") val relatedManga: ArrayList<String>?,\n        @JsonProperty(\"recommendations\") val recommendations: ArrayList<Recommendations>?,\n        @JsonProperty(\"studios\") val studios: ArrayList<Studios>?,\n        @JsonProperty(\"statistics\") val statistics: Statistics?,\n    )\n\n    data class Recommendations(\n        @JsonProperty(\"node\") val node: Node? = null,\n        @JsonProperty(\"num_recommendations\") val numRecommendations: Int? = null\n    )\n\n    data class Studios(\n        @JsonProperty(\"id\") val id: Int? = null,\n        @JsonProperty(\"name\") val name: String? = null\n    )\n\n    data class MyListStatus(\n        @JsonProperty(\"status\") val status: String? = null,\n        @JsonProperty(\"score\") val score: Int? = null,\n        @JsonProperty(\"num_episodes_watched\") val numEpisodesWatched: Int? = null,\n        @JsonProperty(\"is_rewatching\") val isRewatching: Boolean? = null,\n        @JsonProperty(\"updated_at\") val updatedAt: String? = null\n    )\n\n    data class RelatedAnime(\n        @JsonProperty(\"node\") val node: Node? = null,\n        @JsonProperty(\"relation_type\") val relationType: String? = null,\n        @JsonProperty(\"relation_type_formatted\") val relationTypeFormatted: String? = null\n    )\n\n    data class Status(\n        @JsonProperty(\"watching\") val watching: String? = null,\n        @JsonProperty(\"completed\") val completed: String? = null,\n        @JsonProperty(\"on_hold\") val onHold: String? = null,\n        @JsonProperty(\"dropped\") val dropped: String? = null,\n        @JsonProperty(\"plan_to_watch\") val planToWatch: String? = null\n    )\n\n    data class Statistics(\n        @JsonProperty(\"status\") val status: Status? = null,\n        @JsonProperty(\"num_list_users\") val numListUsers: Int? = null\n    )\n\n    private fun parseDate(string: String?): Long? {\n        return try {\n            SimpleDateFormat(\"yyyy-MM-dd\", Locale.getDefault()).parse(string ?: return null)?.time\n        } catch (e: Exception) {\n            null\n        }\n    }\n\n    private fun toSearchResult(node: Node?): SyncAPI.SyncSearchResult? {\n        return SyncAPI.SyncSearchResult(\n            name = node?.title ?: return null,\n            apiName = this.name,\n            syncId = node.id.toString(),\n            url = \"$mainUrl/anime/${node.id}\",\n            posterUrl = node.mainPicture?.large\n        )\n    }\n\n    override suspend fun load(auth : AuthData?, id: String): SyncAPI.SyncResult? {\n        val auth = auth?.token?.accessToken ?: return null\n        val internalId = id.toIntOrNull() ?: return null\n        val url =\n            \"$apiUrl/v2/anime/$internalId?fields=id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,created_at,updated_at,media_type,status,genres,my_list_status,num_episodes,start_season,broadcast,source,average_episode_duration,rating,pictures,background,related_anime,related_manga,recommendations,studios,statistics\"\n\n        val res = app.get(\n            url, headers = mapOf(\n                \"Authorization\" to \"Bearer $auth\"\n            )\n        ).text\n        return parseJson<MalAnime>(res).let { malAnime ->\n            SyncAPI.SyncResult(\n                id = internalId.toString(),\n                totalEpisodes = malAnime.numEpisodes,\n                title = malAnime.title,\n                publicScore = Score.from10(malAnime.mean),\n                duration = malAnime.averageEpisodeDuration,\n                synopsis = malAnime.synopsis,\n                airStatus = when (malAnime.status) {\n                    \"finished_airing\" -> ShowStatus.Completed\n                    \"currently_airing\" -> ShowStatus.Ongoing\n                    //\"not_yet_aired\"\n                    else -> null\n                },\n                nextAiring = null,\n                studio = malAnime.studios?.mapNotNull { it.name },\n                genres = malAnime.genres?.map { it.name },\n                trailers = null,\n                startDate = parseDate(malAnime.startDate),\n                endDate = parseDate(malAnime.endDate),\n                recommendations = malAnime.recommendations?.mapNotNull { rec ->\n                    val node = rec.node ?: return@mapNotNull null\n                    toSearchResult(node)\n                },\n                nextSeason = malAnime.relatedAnime?.firstOrNull {\n                    return@firstOrNull it.relationType == \"sequel\"\n                }?.let { toSearchResult(it.node) },\n                prevSeason = malAnime.relatedAnime?.firstOrNull {\n                    return@firstOrNull it.relationType == \"prequel\"\n                }?.let { toSearchResult(it.node) },\n                actors = null,\n            )\n        }\n    }\n\n    override suspend fun status(auth : AuthData?, id: String): SyncAPI.AbstractSyncStatus? {\n        val auth = auth?.token?.accessToken ?: return null\n\n        // https://myanimelist.net/apiconfig/references/api/v2#operation/anime_anime_id_get\n        val url =\n            \"$apiUrl/v2/anime/$id?fields=id,title,num_episodes,my_list_status\"\n        val data = app.get(\n            url, headers = mapOf(\n                \"Authorization\" to \"Bearer $auth\"\n            ), cacheTime = 0\n        ).parsed<SmallMalAnime>().myListStatus\n\n        return SyncAPI.SyncStatus(\n            score = Score.from10(data?.score),\n            status = SyncWatchType.fromInternalId(malStatusAsString.indexOf(data?.status)),\n            isFavorite = null,\n            watchedEpisodes = data?.numEpisodesWatched,\n        )\n    }\n\n    companion object {\n        private val malStatusAsString =\n            arrayOf(\"watching\", \"completed\", \"on_hold\", \"dropped\", \"plan_to_watch\")\n\n        const val MAL_CACHED_LIST: String = \"mal_cached_list\"\n\n        fun convertToStatus(string: String): MalStatusType {\n            return when (string) {\n                \"watching\" -> MalStatusType.Watching\n                \"completed\" -> MalStatusType.Completed\n                \"on_hold\" -> MalStatusType.OnHold\n                \"dropped\" -> MalStatusType.Dropped\n                \"plan_to_watch\" -> MalStatusType.PlanToWatch\n                else -> MalStatusType.None\n            }\n        }\n\n        enum class MalStatusType(var value: Int, @StringRes val stringRes: Int) {\n            Watching(0, R.string.type_watching),\n            Completed(1, R.string.type_completed),\n            OnHold(2, R.string.type_on_hold),\n            Dropped(3, R.string.type_dropped),\n            PlanToWatch(4, R.string.type_plan_to_watch),\n            None(-1, R.string.type_none)\n        }\n\n        private fun fromIntToAnimeStatus(inp: SyncWatchType): MalStatusType {//= AniListStatusType.values().first { it.value == inp }\n            return when (inp) {\n                SyncWatchType.NONE -> MalStatusType.None\n                SyncWatchType.WATCHING -> MalStatusType.Watching\n                SyncWatchType.COMPLETED -> MalStatusType.Completed\n                SyncWatchType.ONHOLD -> MalStatusType.OnHold\n                SyncWatchType.DROPPED -> MalStatusType.Dropped\n                SyncWatchType.PLANTOWATCH -> MalStatusType.PlanToWatch\n                SyncWatchType.REWATCHING -> MalStatusType.Watching\n            }\n        }\n\n        private fun parseDateLong(string: String?): Long? {\n            return try {\n                SimpleDateFormat(\"yyyy-MM-dd'T'HH:mm:ssZ\", Locale.getDefault()).parse(\n                    string ?: return null\n                )?.time?.div(1000)\n            } catch (e: Exception) {\n                null\n            }\n        }\n    }\n\n    override fun loginRequest(): AuthLoginPage? {\n        val codeVerifier = generateCodeVerifier()\n        val requestId = ++requestIdCounter\n        val codeChallenge = codeVerifier\n        val request =\n            \"$mainUrl/v1/oauth2/authorize?response_type=code&client_id=$key&code_challenge=$codeChallenge&state=RequestID$requestId\"\n\n        return AuthLoginPage(\n            url = request,\n            payload = PayLoad(requestId, codeVerifier).toJson()\n        )\n    }\n\n    override suspend fun refreshToken(token: AuthToken): AuthToken? {\n        val res = app.post(\n            \"$mainUrl/v1/oauth2/token\",\n            data = mapOf(\n                \"client_id\" to key,\n                \"grant_type\" to \"refresh_token\",\n                \"refresh_token\" to token.refreshToken!!\n            )\n        ).parsed<ResponseToken>()\n\n        return AuthToken(\n            accessToken = res.accessToken,\n            refreshToken = res.refreshToken,\n            accessTokenLifetime = unixTime + res.expiresIn.toLong()\n        )\n    }\n\n    private var requestIdCounter = 0\n\n\n    private val allTitles = hashMapOf<Int, MalTitleHolder>()\n\n    data class MalList(\n        @JsonProperty(\"data\") val data: List<Data>,\n        @JsonProperty(\"paging\") val paging: Paging\n    )\n\n    data class MainPicture(\n        @JsonProperty(\"medium\") val medium: String,\n        @JsonProperty(\"large\") val large: String\n    )\n\n    data class Node(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"title\") val title: String,\n        @JsonProperty(\"main_picture\") val mainPicture: MainPicture?,\n        @JsonProperty(\"alternative_titles\") val alternativeTitles: AlternativeTitles?,\n        @JsonProperty(\"media_type\") val mediaType: String?,\n        @JsonProperty(\"num_episodes\") val numEpisodes: Int?,\n        @JsonProperty(\"status\") val status: String?,\n        @JsonProperty(\"start_date\") val startDate: String?,\n        @JsonProperty(\"end_date\") val endDate: String?,\n        @JsonProperty(\"average_episode_duration\") val averageEpisodeDuration: Int?,\n        @JsonProperty(\"synopsis\") val synopsis: String?,\n        @JsonProperty(\"mean\") val mean: Double?,\n        @JsonProperty(\"genres\") val genres: List<Genres>?,\n        @JsonProperty(\"rank\") val rank: Int?,\n        @JsonProperty(\"popularity\") val popularity: Int?,\n        @JsonProperty(\"num_list_users\") val numListUsers: Int?,\n        @JsonProperty(\"num_favorites\") val numFavorites: Int?,\n        @JsonProperty(\"num_scoring_users\") val numScoringUsers: Int?,\n        @JsonProperty(\"start_season\") val startSeason: StartSeason?,\n        @JsonProperty(\"broadcast\") val broadcast: Broadcast?,\n        @JsonProperty(\"nsfw\") val nsfw: String?,\n        @JsonProperty(\"created_at\") val createdAt: String?,\n        @JsonProperty(\"updated_at\") val updatedAt: String?\n    )\n\n    data class ListStatus(\n        @JsonProperty(\"status\") val status: String?,\n        @JsonProperty(\"score\") val score: Int,\n        @JsonProperty(\"num_episodes_watched\") val numEpisodesWatched: Int,\n        @JsonProperty(\"is_rewatching\") val isRewatching: Boolean,\n        @JsonProperty(\"updated_at\") val updatedAt: String,\n    )\n\n    data class Data(\n        @JsonProperty(\"node\") val node: Node,\n        @JsonProperty(\"list_status\") val listStatus: ListStatus?,\n    ) {\n        fun toLibraryItem(): SyncAPI.LibraryItem {\n            return SyncAPI.LibraryItem(\n                this.node.title,\n                \"https://myanimelist.net/anime/${this.node.id}/\",\n                this.node.id.toString(),\n                this.listStatus?.numEpisodesWatched,\n                this.node.numEpisodes,\n                Score.from10(this.listStatus?.score),\n                parseDateLong(this.listStatus?.updatedAt),\n                \"MAL\",\n                TvType.Anime,\n                this.node.mainPicture?.large ?: this.node.mainPicture?.medium,\n                null,\n                null,\n                plot = this.node.synopsis,\n                releaseDate = if (this.node.startDate == null) null else try {\n                    Date.from(\n                        Instant.from(\n                            DateTimeFormatter.ofPattern(if (this.node.startDate.length == 4) \"yyyy\" else if (this.node.startDate.length == 7) \"yyyy-MM\" else \"yyyy-MM-dd\")\n                                .parse(this.node.startDate)\n                        )\n                    )\n                } catch (_: RuntimeException) {\n                    null\n                }\n            )\n        }\n    }\n\n    data class Paging(\n        @JsonProperty(\"next\") val next: String?\n    )\n\n    data class AlternativeTitles(\n        @JsonProperty(\"synonyms\") val synonyms: List<String>,\n        @JsonProperty(\"en\") val en: String,\n        @JsonProperty(\"ja\") val ja: String\n    )\n\n    data class Genres(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"name\") val name: String\n    )\n\n    data class StartSeason(\n        @JsonProperty(\"year\") val year: Int,\n        @JsonProperty(\"season\") val season: String\n    )\n\n    data class Broadcast(\n        @JsonProperty(\"day_of_the_week\") val dayOfTheWeek: String?,\n        @JsonProperty(\"start_time\") val startTime: String?\n    )\n\n    override suspend fun library(auth : AuthData?): LibraryMetadata? {\n        val list = getMalAnimeListSmart(auth ?: return null)?.groupBy {\n            convertToStatus(it.listStatus?.status ?: \"\").stringRes\n        }?.mapValues { group ->\n            group.value.map { it.toLibraryItem() }\n        } ?: emptyMap()\n\n        // To fill empty lists when MAL does not return them\n        val baseMap =\n            MalStatusType.entries.filter { it.value >= 0 }.associate {\n                it.stringRes to emptyList<SyncAPI.LibraryItem>()\n            }\n\n        return SyncAPI.LibraryMetadata(\n            (baseMap + list).map { SyncAPI.LibraryList(txt(it.key), it.value) },\n            setOf(\n                ListSorting.AlphabeticalA,\n                ListSorting.AlphabeticalZ,\n                ListSorting.UpdatedNew,\n                ListSorting.UpdatedOld,\n                ListSorting.ReleaseDateNew,\n                ListSorting.ReleaseDateOld,\n                ListSorting.RatingHigh,\n                ListSorting.RatingLow,\n            )\n        )\n    }\n\n    private suspend fun getMalAnimeListSmart(auth : AuthData): Array<Data>? {\n        return if (requireLibraryRefresh) {\n            val list = getMalAnimeList(auth.token)\n            setKey(MAL_CACHED_LIST, auth.user.id.toString(), list)\n            list\n        } else {\n            getKey<Array<Data>>(MAL_CACHED_LIST, auth.user.id.toString()) as? Array<Data>\n        }\n    }\n\n    private suspend fun getMalAnimeList(token: AuthToken): Array<Data> {\n        var offset = 0\n        val fullList = mutableListOf<Data>()\n        val offsetRegex = Regex(\"\"\"offset=(\\d+)\"\"\")\n        while (true) {\n            val data: MalList = getMalAnimeListSlice(token, offset) ?: break\n            fullList.addAll(data.data)\n            offset =\n                data.paging.next?.let { offsetRegex.find(it)?.groupValues?.get(1)?.toInt() }\n                    ?: break\n        }\n        return fullList.toTypedArray()\n    }\n\n    private suspend fun getMalAnimeListSlice(token: AuthToken, offset: Int = 0): MalList? {\n        val user = \"@me\"\n        // Very lackluster docs\n        // https://myanimelist.net/apiconfig/references/api/v2#operation/users_user_id_animelist_get\n        val url =\n            \"$apiUrl/v2/users/$user/animelist?fields=list_status,num_episodes,media_type,status,start_date,end_date,synopsis,alternative_titles,mean,genres,rank,num_list_users,nsfw,average_episode_duration,num_favorites,popularity,num_scoring_users,start_season,favorites_info,broadcast,created_at,updated_at&nsfw=1&limit=100&offset=$offset\"\n        val res = app.get(\n            url, headers = mapOf(\n                \"Authorization\" to \"Bearer ${token.accessToken}\",\n            ), cacheTime = 0\n        ).text\n        return res.toKotlinObject()\n    }\n\n    private suspend fun setScoreRequest(\n        token: AuthToken,\n        id: Int,\n        status: MalStatusType? = null,\n        score: Int? = null,\n        numWatchedEpisodes: Int? = null,\n    ): Boolean {\n        val res = setScoreRequest(\n            token,\n            id,\n            if (status == null) null else malStatusAsString[maxOf(0, status.value)],\n            score,\n            numWatchedEpisodes\n        )\n\n        return if (res.isNullOrBlank()) {\n            false\n        } else {\n            val malStatus = parseJson<MalStatus>(res)\n            if (allTitles.containsKey(id)) {\n                val currentTitle = allTitles[id]!!\n                allTitles[id] = MalTitleHolder(malStatus, id, currentTitle.name)\n            } else {\n                allTitles[id] = MalTitleHolder(malStatus, id, \"\")\n            }\n            true\n        }\n    }\n\n    @Suppress(\"UNCHECKED_CAST\")\n    private suspend fun setScoreRequest(\n        token: AuthToken,\n        id: Int,\n        status: String? = null,\n        score: Int? = null,\n        numWatchedEpisodes: Int? = null,\n    ): String? {\n        val data = mapOf(\n            \"status\" to status,\n            \"score\" to score?.toString(),\n            \"num_watched_episodes\" to numWatchedEpisodes?.toString()\n        ).filterValues { it != null } as Map<String, String>\n\n        return app.put(\n            \"$apiUrl/v2/anime/$id/my_list_status\",\n            headers = mapOf(\n                \"Authorization\" to \"Bearer ${token.accessToken}\"\n            ),\n            data = data\n        ).text\n    }\n\n\n    data class ResponseToken(\n        @JsonProperty(\"token_type\") val tokenType: String,\n        @JsonProperty(\"expires_in\") val expiresIn: Int,\n        @JsonProperty(\"access_token\") val accessToken: String,\n        @JsonProperty(\"refresh_token\") val refreshToken: String,\n    )\n\n    data class MalRoot(\n        @JsonProperty(\"data\") val data: List<MalDatum>,\n    )\n\n    data class MalDatum(\n        @JsonProperty(\"node\") val node: MalNode,\n        @JsonProperty(\"list_status\") val listStatus: MalStatus,\n    )\n\n    data class MalNode(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"title\") val title: String,\n        /*\n        also, but not used\n        main_picture ->\n            public string medium;\n\t\t\tpublic string large;\n         */\n    )\n\n    data class MalStatus(\n        @JsonProperty(\"status\") val status: String,\n        @JsonProperty(\"score\") val score: Int,\n        @JsonProperty(\"num_episodes_watched\") val numEpisodesWatched: Int,\n        @JsonProperty(\"is_rewatching\") val isRewatching: Boolean,\n        @JsonProperty(\"updated_at\") val updatedAt: String,\n    )\n\n    data class MalUser(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"location\") val location: String,\n        @JsonProperty(\"joined_at\") val joinedAt: String,\n        @JsonProperty(\"picture\") val picture: String?,\n    )\n\n    data class MalMainPicture(\n        @JsonProperty(\"large\") val large: String?,\n        @JsonProperty(\"medium\") val medium: String?,\n    )\n\n    // Used for getDataAboutId()\n    data class SmallMalAnime(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"title\") val title: String?,\n        @JsonProperty(\"num_episodes\") val numEpisodes: Int,\n        @JsonProperty(\"my_list_status\") val myListStatus: MalStatus?,\n        @JsonProperty(\"main_picture\") val mainPicture: MalMainPicture?,\n    )\n\n    data class MalSearchNode(\n        @JsonProperty(\"node\") val node: Node,\n    )\n\n    data class MalSearch(\n        @JsonProperty(\"data\") val data: List<MalSearchNode>,\n        //paging\n    )\n\n    data class MalTitleHolder(\n        val status: MalStatus,\n        val id: Int,\n        val name: String,\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/OpenSubtitlesApi.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders.providers\n\nimport android.util.Log\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginRequirement\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginResponse\nimport com.lagradost.cloudstream3.syncproviders.AuthToken\nimport com.lagradost.cloudstream3.syncproviders.AuthUser\nimport com.lagradost.cloudstream3.syncproviders.SubtitleAPI\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.utils.AppUtils\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromCodeToLangTagIETF\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromCodeToOpenSubtitlesTag\n\nclass OpenSubtitlesApi : SubtitleAPI() {\n    override val name = \"OpenSubtitles\"\n    override val idPrefix = \"opensubtitles\"\n\n    override val icon = R.drawable.open_subtitles_icon\n    override val hasInApp = true\n    override val inAppLoginRequirement = AuthLoginRequirement(\n        password = true,\n        username = true,\n    )\n\n    override val createAccountUrl = \"https://www.opensubtitles.com/en/users/sign_up\"\n\n    companion object {\n        const val API_KEY = \"uyBLgFD17MgrYmA0gSXoKllMJBelOYj2\"\n        const val HOST = \"https://api.opensubtitles.com/api/v1\"\n        const val TAG = \"OPENSUBS\"\n        const val COOLDOWN_DURATION: Long = 1000L * 30L // CoolDown if 429 error code in ms\n        var currentCoolDown: Long = 0L\n        const val userAgent = \"Cloudstream3 v0.2\"\n        val headers = mapOf(\"user-agent\" to userAgent, \"Api-Key\" to API_KEY)\n    }\n\n    private fun canDoRequest(): Boolean {\n        return unixTimeMs > currentCoolDown\n    }\n\n    private fun throwIfCantDoRequest() {\n        if (!canDoRequest()) {\n            throw ErrorLoadingException(\"Too many requests wait for ${(currentCoolDown - unixTimeMs) / 1000L}s\")\n        }\n    }\n\n    private fun throwGotTooManyRequests() {\n        currentCoolDown = unixTimeMs + COOLDOWN_DURATION\n        throw ErrorLoadingException(\"Too many requests\")\n    }\n\n    override suspend fun refreshToken(token: AuthToken): AuthToken? {\n        return login(parseJson<AuthLoginResponse>(token.payload ?: return null))\n    }\n\n    override suspend fun user(token: AuthToken?): AuthUser? {\n        val user = parseJson<AuthLoginResponse>(token?.payload ?: return null)\n        val username = user.username ?: return null\n        return AuthUser(\n            id = username.hashCode(),\n            name = username\n        )\n    }\n\n    override suspend fun login(form: AuthLoginResponse): AuthToken? {\n        val username = form.username ?: return null\n        val password = form.password ?: return null\n\n        val response = app.post(\n            url = \"$HOST/login\",\n            headers = mapOf(\n                \"Content-Type\" to \"application/json\",\n            ) + headers,\n            json = mapOf(\n                \"username\" to username,\n                \"password\" to password\n            ),\n        ).parsed<OAuthToken>()\n\n        return AuthToken(\n            accessToken = response.token\n                ?: throw ErrorLoadingException(\"Invalid password or username\"),\n            /// JWT token is valid 24 hours after successfully authentication of user\n            accessTokenLifetime = unixTime + 60 * 60 * 24,\n            payload = form.toJson()\n        )\n    }\n\n    /**\n     * Fetch subtitles using token authenticated on previous method (see authorize).\n     * Returns list of Subtitles which user can select to download (see load).\n     * */\n    override suspend fun search(\n        auth : AuthData?,\n        query: AbstractSubtitleEntities.SubtitleSearch\n    ): List<AbstractSubtitleEntities.SubtitleEntity>? {\n        throwIfCantDoRequest()\n        val langOpenSubTag = fromCodeToOpenSubtitlesTag(query.lang) ?: query.lang ?: \"\"\n\n        val imdbId = query.imdbId?.replace(\"tt\", \"\")?.toInt() ?: 0\n        val queryText = query.query\n        val epNum = query.epNumber ?: 0\n        val seasonNum = query.seasonNumber ?: 0\n        val yearNum = query.year ?: 0\n        val epQuery = if (epNum > 0) \"&episode_number=$epNum\" else \"\"\n        val seasonQuery = if (seasonNum > 0) \"&season_number=$seasonNum\" else \"\"\n        val yearQuery = if (yearNum > 0) \"&year=$yearNum\" else \"\"\n\n        val searchQueryUrl = when (imdbId > 0) {\n            //Use imdb_id to search if its valid\n            true -> \"$HOST/subtitles?imdb_id=$imdbId&languages=${langOpenSubTag}$yearQuery$epQuery$seasonQuery\"\n            false -> \"$HOST/subtitles?query=${queryText}&languages=${langOpenSubTag}$yearQuery$epQuery$seasonQuery\"\n        }\n\n        val req = app.get(\n            url = searchQueryUrl,\n            headers = mapOf(\n                Pair(\"Content-Type\", \"application/json\")\n            ) + headers,\n        )\n        Log.i(TAG, \"searchQueryUrl => ${searchQueryUrl}\")\n        Log.i(TAG, \"Search Req => ${req.text}\")\n        if (!req.isSuccessful) {\n            if (req.code == 429)\n                throwGotTooManyRequests()\n            return null\n        }\n\n        val results = mutableListOf<AbstractSubtitleEntities.SubtitleEntity>()\n\n        AppUtils.tryParseJson<Results>(req.text)?.let {\n            it.data?.forEach { item ->\n                val attr = item.attributes ?: return@forEach\n                val featureDetails = attr.featDetails\n                //Use filename as name, if its valid\n                val filename = attr.files?.firstNotNullOfOrNull { subfile ->\n                    subfile.fileName\n                }\n                //Use any valid name/title in hierarchy\n                val name = filename ?: featureDetails?.movieName ?: featureDetails?.title\n                ?: featureDetails?.parentTitle ?: attr.release ?: query.query\n                val langTagIETF = fromCodeToLangTagIETF(attr.language) ?: \"\"\n                val resEpNum = featureDetails?.episodeNumber ?: query.epNumber\n                val resSeasonNum = featureDetails?.seasonNumber ?: query.seasonNumber\n                val year = featureDetails?.year ?: query.year\n                val type = if ((resSeasonNum ?: 0) > 0) TvType.TvSeries else TvType.Movie\n                val isHearingImpaired = attr.hearingImpaired ?: false\n                //Log.i(TAG, \"Result id/name => ${item.id} / $name\")\n                item.attributes?.files?.forEach { file ->\n                    val resultData = file.fileId?.toString() ?: \"\"\n                    //Log.i(TAG, \"Result file => ${file.fileId} / ${file.fileName}\")\n                    results.add(\n                        AbstractSubtitleEntities.SubtitleEntity(\n                            idPrefix = this.idPrefix,\n                            name = name,\n                            lang = langTagIETF,\n                            data = resultData,\n                            type = type,\n                            source = this.name,\n                            epNumber = resEpNum,\n                            seasonNumber = resSeasonNum,\n                            year = year,\n                            isHearingImpaired = isHearingImpaired\n                        )\n                    )\n                }\n            }\n        }\n        return results\n    }\n\n    /*\n        Process data returned from search.\n        Returns string url for the subtitle file.\n    */\n\n    override suspend fun load(\n        auth : AuthData?,\n        subtitle: AbstractSubtitleEntities.SubtitleEntity\n    ): String? {\n        if(auth == null) return null\n        throwIfCantDoRequest()\n\n        val req = app.post(\n            url = \"$HOST/download\",\n            headers = mapOf(\n                Pair(\n                    \"Authorization\",\n                    \"Bearer ${auth.token.accessToken ?: throw ErrorLoadingException(\"No access token active in current session\")}\"\n                ),\n                Pair(\"Content-Type\", \"application/json\"),\n                Pair(\"Accept\", \"*/*\")\n            ) + headers,\n            data = mapOf(\n                Pair(\"file_id\", subtitle.data)\n            )\n        )\n        Log.i(TAG, \"Request result  => (${req.code}) ${req.text}\")\n        //Log.i(TAG, \"Request headers => ${req.headers}\")\n        if (req.isSuccessful) {\n            AppUtils.tryParseJson<ResultDownloadLink>(req.text)?.let {\n                val link = it.link ?: \"\"\n                Log.i(TAG, \"Request load link => $link\")\n                return link\n            }\n        } else {\n            if (req.code == 429)\n                throwGotTooManyRequests()\n        }\n        return null\n    }\n\n    data class OAuthToken(\n        @JsonProperty(\"token\") var token: String? = null,\n        @JsonProperty(\"status\") var status: Int? = null\n    )\n\n    data class Results(\n        @JsonProperty(\"data\") var data: List<ResultData>? = listOf()\n    )\n\n    data class ResultData(\n        @JsonProperty(\"id\") var id: String? = null,\n        @JsonProperty(\"type\") var type: String? = null,\n        @JsonProperty(\"attributes\") var attributes: ResultAttributes? = ResultAttributes()\n    )\n\n    data class ResultAttributes(\n        @JsonProperty(\"subtitle_id\") var subtitleId: String? = null,\n        @JsonProperty(\"language\") var language: String? = null,\n        @JsonProperty(\"release\") var release: String? = null,\n        @JsonProperty(\"url\") var url: String? = null,\n        @JsonProperty(\"files\") var files: List<ResultFiles>? = listOf(),\n        @JsonProperty(\"feature_details\") var featDetails: ResultFeatureDetails? = ResultFeatureDetails(),\n        @JsonProperty(\"hearing_impaired\") var hearingImpaired: Boolean? = null,\n    )\n\n    data class ResultFiles(\n        @JsonProperty(\"file_id\") var fileId: Int? = null,\n        @JsonProperty(\"file_name\") var fileName: String? = null\n    )\n\n    data class ResultDownloadLink(\n        @JsonProperty(\"link\") var link: String? = null,\n        @JsonProperty(\"file_name\") var fileName: String? = null,\n        @JsonProperty(\"requests\") var requests: Int? = null,\n        @JsonProperty(\"remaining\") var remaining: Int? = null,\n        @JsonProperty(\"message\") var message: String? = null,\n        @JsonProperty(\"reset_time\") var resetTime: String? = null,\n        @JsonProperty(\"reset_time_utc\") var resetTimeUtc: String? = null\n    )\n\n    data class ResultFeatureDetails(\n        @JsonProperty(\"year\") var year: Int? = null,\n        @JsonProperty(\"title\") var title: String? = null,\n        @JsonProperty(\"movie_name\") var movieName: String? = null,\n        @JsonProperty(\"imdb_id\") var imdbId: Int? = null,\n        @JsonProperty(\"tmdb_id\") var tmdbId: Int? = null,\n        @JsonProperty(\"season_number\") var seasonNumber: Int? = null,\n        @JsonProperty(\"episode_number\") var episodeNumber: Int? = null,\n        @JsonProperty(\"parent_imdb_id\") var parentImdbId: Int? = null,\n        @JsonProperty(\"parent_title\") var parentTitle: String? = null,\n        @JsonProperty(\"parent_tmdb_id\") var parentTmdbId: Int? = null,\n        @JsonProperty(\"parent_feature_id\") var parentFeatureId: Int? = null\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders.providers\n\nimport androidx.annotation.StringRes\nimport androidx.core.net.toUri\nimport com.fasterxml.jackson.annotation.JsonInclude\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.CloudStreamApp\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.LoadResponse.Companion.readIdFromString\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.SimklSyncServices\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mapper\nimport com.lagradost.cloudstream3.mvvm.debugPrint\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginPage\nimport com.lagradost.cloudstream3.syncproviders.AuthPinData\nimport com.lagradost.cloudstream3.syncproviders.AuthToken\nimport com.lagradost.cloudstream3.syncproviders.AuthUser\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.syncproviders.SyncIdName\nimport com.lagradost.cloudstream3.ui.SyncWatchType\nimport com.lagradost.cloudstream3.ui.library.ListSorting\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.toYear\nimport com.lagradost.cloudstream3.utils.txt\nimport java.math.BigInteger\nimport java.security.SecureRandom\nimport java.text.SimpleDateFormat\nimport java.time.Instant\nimport java.util.Date\nimport java.util.Locale\nimport java.util.TimeZone\nimport kotlin.time.Duration\nimport kotlin.time.DurationUnit\nimport kotlin.time.toDuration\n\nclass SimklApi : SyncAPI() {\n    override var name = \"Simkl\"\n    override val idPrefix = \"simkl\"\n\n    val key = \"simkl-key\"\n    override val redirectUrlIdentifier = \"simkl\"\n    override val hasOAuth2 = true\n    override val hasPin = true\n    override var requireLibraryRefresh = true\n    override var mainUrl = \"https://api.simkl.com\"\n    override val icon = R.drawable.simkl_logo\n    override val createAccountUrl = \"$mainUrl/signup\"\n    override val syncIdName = SyncIdName.Simkl\n\n    /** Automatically adds simkl auth headers */\n    // private val interceptor = HeaderInterceptor()\n\n    /**\n     * This is required to override the reported last activity as simkl activites\n     * may not always update based on testing.\n     */\n    private var lastScoreTime = -1L\n\n    private object SimklCache {\n        private const val SIMKL_CACHE_KEY = \"SIMKL_API_CACHE\"\n\n        enum class CacheTimes(val value: String) {\n            OneMonth(\"30d\"),\n            ThirtyMinutes(\"30m\")\n        }\n\n        private class SimklCacheWrapper<T>(\n            @JsonProperty(\"obj\") val obj: T?,\n            @JsonProperty(\"validUntil\") val validUntil: Long,\n            @JsonProperty(\"cacheTime\") val cacheTime: Long = unixTime,\n        ) {\n            /** Returns true if cache is newer than cacheDays */\n            fun isFresh(): Boolean {\n                return validUntil > unixTime\n            }\n\n            fun remainingTime(): Duration {\n                val unixTime = unixTime\n                return if (validUntil > unixTime) {\n                    (validUntil - unixTime).toDuration(DurationUnit.SECONDS)\n                } else {\n                    Duration.ZERO\n                }\n            }\n        }\n\n        fun cleanOldCache() {\n            getKeys(SIMKL_CACHE_KEY)?.forEach {\n                val isOld = CloudStreamApp.getKey<SimklCacheWrapper<Any>>(it)?.isFresh() == false\n                if (isOld) {\n                    removeKey(it)\n                }\n            }\n        }\n\n        fun <T> setKey(path: String, value: T, cacheTime: Duration) {\n            debugPrint { \"Set cache: $SIMKL_CACHE_KEY/$path for ${cacheTime.inWholeDays} days or ${cacheTime.inWholeSeconds} seconds.\" }\n            setKey(\n                SIMKL_CACHE_KEY,\n                path,\n                // Storing as plain sting is required to make generics work.\n                SimklCacheWrapper(value, unixTime + cacheTime.inWholeSeconds).toJson()\n            )\n        }\n\n        /**\n         * Gets cached object, if object is not fresh returns null and removes it from cache\n         */\n        inline fun <reified T : Any> getKey(path: String): T? {\n            // Required for generic otherwise \"LinkedHashMap cannot be cast to MediaObject\"\n            val type = mapper.typeFactory.constructParametricType(\n                SimklCacheWrapper::class.java,\n                T::class.java\n            )\n            val cache = getKey<String>(SIMKL_CACHE_KEY, path)?.let {\n                mapper.readValue<SimklCacheWrapper<T>>(it, type)\n            }\n\n            return if (cache?.isFresh() == true) {\n                debugPrint {\n                    \"Cache hit at: $SIMKL_CACHE_KEY/$path. \" +\n                            \"Remains fresh for ${cache.remainingTime().inWholeDays} days or ${cache.remainingTime().inWholeSeconds} seconds.\"\n                }\n                cache.obj\n            } else {\n                debugPrint { \"Cache miss at: $SIMKL_CACHE_KEY/$path\" }\n                removeKey(SIMKL_CACHE_KEY, path)\n                null\n            }\n        }\n    }\n\n    companion object {\n        private const val CLIENT_ID: String = BuildConfig.SIMKL_CLIENT_ID\n        private const val CLIENT_SECRET: String = BuildConfig.SIMKL_CLIENT_SECRET\n        const val SIMKL_CACHED_LIST: String = \"simkl_cached_list\"\n        const val SIMKL_CACHED_LIST_TIME: String = \"simkl_cached_time\"\n\n        /** 2014-09-01T09:10:11Z -> 1409562611 */\n        private const val SIMKL_DATE_FORMAT = \"yyyy-MM-dd'T'HH:mm:ss'Z'\"\n        fun getUnixTime(string: String?): Long? {\n            return try {\n                SimpleDateFormat(SIMKL_DATE_FORMAT, Locale.getDefault()).apply {\n                    this.timeZone = TimeZone.getTimeZone(\"UTC\")\n                }.parse(\n                    string ?: return null\n                )?.toInstant()?.epochSecond\n            } catch (e: Exception) {\n                logError(e)\n                return null\n            }\n        }\n\n        /** 1409562611 -> 2014-09-01T09:10:11Z */\n        fun getDateTime(unixTime: Long?): String? {\n            return try {\n                SimpleDateFormat(SIMKL_DATE_FORMAT, Locale.getDefault()).apply {\n                    this.timeZone = TimeZone.getTimeZone(\"UTC\")\n                }.format(\n                    Date.from(\n                        Instant.ofEpochSecond(\n                            unixTime ?: return null\n                        )\n                    )\n                )\n            } catch (e: Exception) {\n                null\n            }\n        }\n\n        fun getPosterUrl(poster: String): String {\n            return \"https://wsrv.nl/?url=https://simkl.in/posters/${poster}_m.webp\"\n        }\n\n        private fun getUrlFromId(id: Int): String {\n            return \"https://simkl.com/shows/$id\"\n        }\n\n        enum class SimklListStatusType(\n            var value: Int,\n            @StringRes val stringRes: Int,\n            val originalName: String?\n        ) {\n            Watching(0, R.string.type_watching, \"watching\"),\n            Completed(1, R.string.type_completed, \"completed\"),\n            Paused(2, R.string.type_on_hold, \"hold\"),\n            Dropped(3, R.string.type_dropped, \"dropped\"),\n            Planning(4, R.string.type_plan_to_watch, \"plantowatch\"),\n            ReWatching(5, R.string.type_re_watching, \"watching\"),\n            None(-1, R.string.none, null);\n\n            companion object {\n                fun fromString(string: String): SimklListStatusType? {\n                    return SimklListStatusType.entries.firstOrNull {\n                        it.originalName == string\n                    }\n                }\n            }\n        }\n\n        // -------------------\n        @JsonInclude(JsonInclude.Include.NON_EMPTY)\n        data class TokenRequest(\n            @JsonProperty(\"code\") val code: String,\n            @JsonProperty(\"client_id\") val clientId: String = CLIENT_ID,\n            @JsonProperty(\"client_secret\") val clientSecret: String = CLIENT_SECRET,\n            @JsonProperty(\"redirect_uri\") val redirectUri: String = \"$APP_STRING://simkl\",\n            @JsonProperty(\"grant_type\") val grantType: String = \"authorization_code\"\n        )\n\n        data class TokenResponse(\n            /** No expiration date */\n            @JsonProperty(\"access_token\") val accessToken: String,\n            @JsonProperty(\"token_type\") val tokenType: String,\n            @JsonProperty(\"scope\") val scope: String\n        )\n        // -------------------\n\n        /** https://simkl.docs.apiary.io/#reference/users/settings/receive-settings */\n        data class SettingsResponse(\n            @JsonProperty(\"user\")\n            val user: User,\n            @JsonProperty(\"account\")\n            val account: Account,\n        ) {\n            data class User(\n                @JsonProperty(\"name\")\n                val name: String,\n                /** Url */\n                @JsonProperty(\"avatar\")\n                val avatar: String\n            )\n\n            data class Account(\n                @JsonProperty(\"id\")\n                val id: Int,\n            )\n        }\n\n        data class PinAuthResponse(\n            @JsonProperty(\"result\") val result: String,\n            @JsonProperty(\"device_code\") val deviceCode: String,\n            @JsonProperty(\"user_code\") val userCode: String,\n            @JsonProperty(\"verification_url\") val verificationUrl: String,\n            @JsonProperty(\"expires_in\") val expiresIn: Int,\n            @JsonProperty(\"interval\") val interval: Int,\n        )\n\n        data class PinExchangeResponse(\n            @JsonProperty(\"result\") val result: String,\n            @JsonProperty(\"message\") val message: String? = null,\n            @JsonProperty(\"access_token\") val accessToken: String? = null,\n        )\n\n        // -------------------\n        data class ActivitiesResponse(\n            @JsonProperty(\"all\") val all: String?,\n            @JsonProperty(\"tv_shows\") val tvShows: UpdatedAt,\n            @JsonProperty(\"anime\") val anime: UpdatedAt,\n            @JsonProperty(\"movies\") val movies: UpdatedAt,\n        ) {\n            data class UpdatedAt(\n                @JsonProperty(\"all\") val all: String?,\n                @JsonProperty(\"removed_from_list\") val removedFromList: String?,\n                @JsonProperty(\"rated_at\") val ratedAt: String?,\n            )\n        }\n\n        /** https://simkl.docs.apiary.io/#reference/tv/episodes/get-tv-show-episodes */\n        @JsonInclude(JsonInclude.Include.NON_EMPTY)\n        data class EpisodeMetadata(\n            @JsonProperty(\"title\") val title: String?,\n            @JsonProperty(\"description\") val description: String?,\n            @JsonProperty(\"season\") val season: Int?,\n            @JsonProperty(\"episode\") val episode: Int,\n            @JsonProperty(\"img\") val img: String?\n        ) {\n            companion object {\n                fun convertToEpisodes(list: List<EpisodeMetadata>?): List<MediaObject.Season.Episode>? {\n                    return list?.map {\n                        MediaObject.Season.Episode(it.episode)\n                    }\n                }\n\n                fun convertToSeasons(list: List<EpisodeMetadata>?): List<MediaObject.Season>? {\n                    return list?.filter { it.season != null }?.groupBy {\n                        it.season\n                    }?.mapNotNull { (season, episodes) ->\n                        convertToEpisodes(episodes)?.let { MediaObject.Season(season!!, it) }\n                    }?.ifEmpty { null }\n                }\n            }\n        }\n\n        /**\n         * https://simkl.docs.apiary.io/#introduction/about-simkl-api/standard-media-objects\n         * Useful for finding shows from metadata\n         */\n        @JsonInclude(JsonInclude.Include.NON_EMPTY)\n        open class MediaObject(\n            @JsonProperty(\"title\") val title: String?,\n            @JsonProperty(\"year\") val year: Int?,\n            @JsonProperty(\"ids\") val ids: Ids?,\n            @JsonProperty(\"total_episodes\") val totalEpisodes: Int? = null,\n            @JsonProperty(\"status\") val status: String? = null,\n            @JsonProperty(\"poster\") val poster: String? = null,\n            @JsonProperty(\"type\") val type: String? = null,\n            @JsonProperty(\"seasons\") val seasons: List<Season>? = null,\n            @JsonProperty(\"episodes\") val episodes: List<Season.Episode>? = null\n        ) {\n            fun hasEnded(): Boolean {\n                return status == \"released\" || status == \"ended\"\n            }\n\n            @JsonInclude(JsonInclude.Include.NON_EMPTY)\n            data class Season(\n                @JsonProperty(\"number\") val number: Int,\n                @JsonProperty(\"episodes\") val episodes: List<Episode>\n            ) {\n                data class Episode(@JsonProperty(\"number\") val number: Int)\n            }\n\n            @JsonInclude(JsonInclude.Include.NON_EMPTY)\n            data class Ids(\n                @JsonProperty(\"simkl\") val simkl: Int?,\n                @JsonProperty(\"imdb\") val imdb: String? = null,\n                @JsonProperty(\"tmdb\") val tmdb: String? = null,\n                @JsonProperty(\"mal\") val mal: String? = null,\n                @JsonProperty(\"anilist\") val anilist: String? = null,\n            ) {\n                companion object {\n                    fun fromMap(map: Map<SimklSyncServices, String>): Ids {\n                        return Ids(\n                            simkl = map[SimklSyncServices.Simkl]?.toIntOrNull(),\n                            imdb = map[SimklSyncServices.Imdb],\n                            tmdb = map[SimklSyncServices.Tmdb],\n                            mal = map[SimklSyncServices.Mal],\n                            anilist = map[SimklSyncServices.AniList]\n                        )\n                    }\n                }\n            }\n\n            fun toSyncSearchResult(): SyncAPI.SyncSearchResult? {\n                return SyncAPI.SyncSearchResult(\n                    this.title ?: return null,\n                    \"Simkl\",\n                    this.ids?.simkl?.toString() ?: return null,\n                    getUrlFromId(this.ids.simkl),\n                    this.poster?.let { getPosterUrl(it) },\n                    if (this.type == \"movie\") TvType.Movie else TvType.TvSeries\n                )\n            }\n        }\n\n        class SimklScoreBuilder private constructor() {\n            data class Builder(\n                private var url: String? = null,\n                private var headers: Map<String, String>? = null,\n                private var ids: MediaObject.Ids? = null,\n                private var score: Int? = null,\n                private var status: Int? = null,\n                private var addEpisodes: Pair<List<MediaObject.Season>?, List<MediaObject.Season.Episode>?>? = null,\n                private var removeEpisodes: Pair<List<MediaObject.Season>?, List<MediaObject.Season.Episode>?>? = null,\n                // Required for knowing if the status should be overwritten\n                private var onList: Boolean = false\n            ) {\n                fun token(token: AuthToken) = apply { this.headers = getHeaders(token) }\n                fun apiUrl(url: String) = apply { this.url = url }\n                fun ids(ids: MediaObject.Ids) = apply { this.ids = ids }\n                fun score(score: Int?, oldScore: Int?) = apply {\n                    if (score != oldScore) {\n                        this.score = score\n                    }\n                }\n\n                fun status(newStatus: Int?, oldStatus: Int?) = apply {\n                    onList = oldStatus != null\n                    // Only set status if its new\n                    if (newStatus != oldStatus) {\n                        this.status = newStatus\n                    } else {\n                        this.status = null\n                    }\n                }\n\n                fun episodes(\n                    allEpisodes: List<EpisodeMetadata>?,\n                    newEpisodes: Int?,\n                    oldEpisodes: Int?,\n                ) = apply {\n                    if (allEpisodes == null || newEpisodes == null) return@apply\n\n                    fun getEpisodes(rawEpisodes: List<EpisodeMetadata>) =\n                        if (rawEpisodes.any { it.season != null }) {\n                            EpisodeMetadata.convertToSeasons(rawEpisodes) to null\n                        } else {\n                            null to EpisodeMetadata.convertToEpisodes(rawEpisodes)\n                        }\n\n                    // Do not add episodes if there is no change\n                    if (newEpisodes > (oldEpisodes ?: 0)) {\n                        this.addEpisodes = getEpisodes(allEpisodes.take(newEpisodes))\n\n                        // Set to watching if episodes are added and there is no current status\n                        if (!onList) {\n                            status = SimklListStatusType.Watching.value\n                        }\n                    }\n                    if ((oldEpisodes ?: 0) > newEpisodes) {\n                        this.removeEpisodes = getEpisodes(allEpisodes.drop(newEpisodes))\n                    }\n                }\n\n                suspend fun execute(): Boolean {\n                    val time = getDateTime(unixTime)\n                    val headers = this.headers ?: emptyMap()\n                    return if (this.status == SimklListStatusType.None.value) {\n                        app.post(\n                            \"$url/sync/history/remove\",\n                            json = StatusRequest(\n                                shows = listOf(HistoryMediaObject(ids = ids)),\n                                movies = emptyList()\n                            ),\n                            headers = headers\n                        ).isSuccessful\n                    } else {\n                        val statusResponse = this.status?.let { setStatus ->\n                            val newStatus =\n                                SimklListStatusType.entries\n                                    .firstOrNull { it.value == setStatus }?.originalName\n                                    ?: SimklListStatusType.Watching.originalName!!\n\n                            app.post(\n                                \"${this.url}/sync/add-to-list\",\n                                json = StatusRequest(\n                                    shows = listOf(\n                                        StatusMediaObject(\n                                            null,\n                                            null,\n                                            ids,\n                                            newStatus,\n                                        )\n                                    ), movies = emptyList()\n                                ),\n                                headers = headers\n                            ).isSuccessful\n                        } ?: true\n\n                        val episodeRemovalResponse = removeEpisodes?.let { (seasons, episodes) ->\n                            app.post(\n                                \"${this.url}/sync/history/remove\",\n                                json = StatusRequest(\n                                    shows = listOf(\n                                        HistoryMediaObject(\n                                            ids = ids,\n                                            seasons = seasons,\n                                            episodes = episodes\n                                        )\n                                    ),\n                                    movies = emptyList()\n                                ),\n                                headers = headers\n                            ).isSuccessful\n                        } ?: true\n\n                        // You cannot rate if you are planning to watch it.\n                        val shouldRate =\n                            score != null && status != SimklListStatusType.Planning.value\n                        val realScore = if (shouldRate) score else null\n\n                        val historyResponse =\n                            // Only post if there are episodes or score to upload\n                            if (addEpisodes != null || shouldRate) {\n                                app.post(\n                                    \"${this.url}/sync/history\",\n                                    json = StatusRequest(\n                                        shows = listOf(\n                                            HistoryMediaObject(\n                                                null,\n                                                null,\n                                                ids,\n                                                addEpisodes?.first,\n                                                addEpisodes?.second,\n                                                realScore,\n                                                realScore?.let { time },\n                                            )\n                                        ), movies = emptyList()\n                                    ),\n                                    headers = headers\n                                ).isSuccessful\n                            } else {\n                                true\n                            }\n\n                        statusResponse && episodeRemovalResponse && historyResponse\n                    }\n                }\n            }\n        }\n\n        fun getHeaders(token: AuthToken): Map<String, String> =\n            mapOf(\"Authorization\" to \"Bearer ${token.accessToken}\", \"simkl-api-key\" to CLIENT_ID)\n\n        suspend fun getEpisodes(\n            simklId: Int?,\n            type: String?,\n            episodes: Int?,\n            hasEnded: Boolean?\n        ): Array<EpisodeMetadata>? {\n            if (simklId == null) return null\n\n            val cacheKey = \"Episodes/$simklId\"\n            val cache = SimklCache.getKey<Array<EpisodeMetadata>>(cacheKey)\n\n            // Return cached result if its higher or equal the amount of episodes.\n            if (cache != null && cache.size >= (episodes ?: 0)) {\n                return cache\n            }\n\n            // There is always one season in Anime -> no request necessary\n            if (type == \"anime\" && episodes != null) {\n                return episodes.takeIf { it > 0 }?.let {\n                    (1..it).map { episode ->\n                        EpisodeMetadata(\n                            null, null, null, episode, null\n                        )\n                    }.toTypedArray()\n                }\n            }\n            val url = when (type) {\n                \"anime\" -> \"https://api.simkl.com/anime/episodes/$simklId\"\n                \"tv\" -> \"https://api.simkl.com/tv/episodes/$simklId\"\n                \"movie\" -> return null\n                else -> return null\n            }\n\n            debugPrint { \"Requesting episodes from $url\" }\n            return app.get(url, params = mapOf(\"client_id\" to CLIENT_ID))\n                .parsedSafe<Array<EpisodeMetadata>>()?.also {\n                    val cacheTime =\n                        if (hasEnded == true) SimklCache.CacheTimes.OneMonth.value else SimklCache.CacheTimes.ThirtyMinutes.value\n\n                    // 1 Month cache\n                    SimklCache.setKey(cacheKey, it, Duration.parse(cacheTime))\n                }\n        }\n\n        @JsonInclude(JsonInclude.Include.NON_EMPTY)\n        class HistoryMediaObject(\n            @JsonProperty(\"title\") title: String? = null,\n            @JsonProperty(\"year\") year: Int? = null,\n            @JsonProperty(\"ids\") ids: Ids? = null,\n            @JsonProperty(\"seasons\") seasons: List<Season>? = null,\n            @JsonProperty(\"episodes\") episodes: List<Season.Episode>? = null,\n            @JsonProperty(\"rating\") val rating: Int? = null,\n            @JsonProperty(\"rated_at\") val ratedAt: String? = null,\n        ) : MediaObject(title, year, ids, seasons = seasons, episodes = episodes)\n\n        @JsonInclude(JsonInclude.Include.NON_EMPTY)\n        class RatingMediaObject(\n            @JsonProperty(\"title\") title: String?,\n            @JsonProperty(\"year\") year: Int?,\n            @JsonProperty(\"ids\") ids: Ids?,\n            @JsonProperty(\"rating\") val rating: Int,\n            @JsonProperty(\"rated_at\") val ratedAt: String? = getDateTime(unixTime)\n        ) : MediaObject(title, year, ids)\n\n        @JsonInclude(JsonInclude.Include.NON_EMPTY)\n        class StatusMediaObject(\n            @JsonProperty(\"title\") title: String?,\n            @JsonProperty(\"year\") year: Int?,\n            @JsonProperty(\"ids\") ids: Ids?,\n            @JsonProperty(\"to\") val to: String,\n            @JsonProperty(\"watched_at\") val watchedAt: String? = getDateTime(unixTime)\n        ) : MediaObject(title, year, ids)\n\n        @JsonInclude(JsonInclude.Include.NON_EMPTY)\n        data class StatusRequest(\n            @JsonProperty(\"movies\") val movies: List<MediaObject>,\n            @JsonProperty(\"shows\") val shows: List<MediaObject>\n        )\n\n        /** https://simkl.docs.apiary.io/#reference/sync/get-all-items/get-all-items-in-the-user's-watchlist */\n        data class AllItemsResponse(\n            @JsonProperty(\"shows\")\n            val shows: List<ShowMetadata> = emptyList(),\n            @JsonProperty(\"anime\")\n            val anime: List<ShowMetadata> = emptyList(),\n            @JsonProperty(\"movies\")\n            val movies: List<MovieMetadata> = emptyList(),\n        ) {\n            companion object {\n                fun merge(first: AllItemsResponse?, second: AllItemsResponse?): AllItemsResponse {\n\n                    // Replace the first item with the same id, or add the new item\n                    fun <T> MutableList<T>.replaceOrAddItem(newItem: T, predicate: (T) -> Boolean) {\n                        for (i in this.indices) {\n                            if (predicate(this[i])) {\n                                this[i] = newItem\n                                return\n                            }\n                        }\n                        this.add(newItem)\n                    }\n\n                    //\n                    fun <T : Metadata> merge(\n                        first: List<T>?,\n                        second: List<T>?\n                    ): List<T> {\n                        return (first?.toMutableList() ?: mutableListOf()).apply {\n                            second?.forEach { secondShow ->\n                                this.replaceOrAddItem(secondShow) {\n                                    it.getIds().simkl == secondShow.getIds().simkl\n                                }\n                            }\n                        }\n                    }\n\n                    return AllItemsResponse(\n                        merge(first?.shows, second?.shows),\n                        merge(first?.anime, second?.anime),\n                        merge(first?.movies, second?.movies),\n                    )\n                }\n            }\n\n            interface Metadata {\n                val lastWatchedAt: String?\n                val status: String?\n                val userRating: Int?\n                val lastWatched: String?\n                val watchedEpisodesCount: Int?\n                val totalEpisodesCount: Int?\n\n                fun getIds(): ShowMetadata.Show.Ids\n                fun toLibraryItem(): SyncAPI.LibraryItem\n            }\n\n            data class MovieMetadata(\n                @JsonProperty(\"last_watched_at\") override val lastWatchedAt: String?,\n                @JsonProperty(\"status\") override val status: String,\n                @JsonProperty(\"user_rating\") override val userRating: Int?,\n                @JsonProperty(\"last_watched\") override val lastWatched: String?,\n                @JsonProperty(\"watched_episodes_count\") override val watchedEpisodesCount: Int?,\n                @JsonProperty(\"total_episodes_count\") override val totalEpisodesCount: Int?,\n                val movie: ShowMetadata.Show\n            ) : Metadata {\n                override fun getIds(): ShowMetadata.Show.Ids {\n                    return this.movie.ids\n                }\n\n                override fun toLibraryItem(): SyncAPI.LibraryItem {\n                    return SyncAPI.LibraryItem(\n                        this.movie.title,\n                        \"https://simkl.com/tv/${movie.ids.simkl}\",\n                        movie.ids.simkl.toString(),\n                        this.watchedEpisodesCount,\n                        this.totalEpisodesCount,\n                        Score.from10(this.userRating),\n                        getUnixTime(lastWatchedAt) ?: 0,\n                        \"Simkl\",\n                        TvType.Movie,\n                        this.movie.poster?.let { getPosterUrl(it) },\n                        null,\n                        null,\n                        this.movie.year?.toYear(),\n                        movie.ids.simkl\n                    )\n                }\n            }\n\n            data class ShowMetadata(\n                @JsonProperty(\"last_watched_at\") override val lastWatchedAt: String?,\n                @JsonProperty(\"status\") override val status: String,\n                @JsonProperty(\"user_rating\") override val userRating: Int?,\n                @JsonProperty(\"last_watched\") override val lastWatched: String?,\n                @JsonProperty(\"watched_episodes_count\") override val watchedEpisodesCount: Int?,\n                @JsonProperty(\"total_episodes_count\") override val totalEpisodesCount: Int?,\n                @JsonProperty(\"show\") val show: Show\n            ) : Metadata {\n                override fun getIds(): Show.Ids {\n                    return this.show.ids\n                }\n\n                override fun toLibraryItem(): SyncAPI.LibraryItem {\n                    return SyncAPI.LibraryItem(\n                        this.show.title,\n                        \"https://simkl.com/tv/${show.ids.simkl}\",\n                        show.ids.simkl.toString(),\n                        this.watchedEpisodesCount,\n                        this.totalEpisodesCount,\n                        Score.from10(this.userRating),\n                        getUnixTime(lastWatchedAt) ?: 0,\n                        \"Simkl\",\n                        TvType.Anime,\n                        this.show.poster?.let { getPosterUrl(it) },\n                        null,\n                        null,\n                        this.show.year?.toYear(),\n                        show.ids.simkl\n                    )\n                }\n\n                data class Show(\n                    @JsonProperty(\"title\") val title: String,\n                    @JsonProperty(\"poster\") val poster: String?,\n                    @JsonProperty(\"year\") val year: Int?,\n                    @JsonProperty(\"ids\") val ids: Ids,\n                ) {\n                    data class Ids(\n                        @JsonProperty(\"simkl\") val simkl: Int,\n                        @JsonProperty(\"slug\") val slug: String?,\n                        @JsonProperty(\"imdb\") val imdb: String?,\n                        @JsonProperty(\"zap2it\") val zap2it: String?,\n                        @JsonProperty(\"tmdb\") val tmdb: String?,\n                        @JsonProperty(\"offen\") val offen: String?,\n                        @JsonProperty(\"tvdb\") val tvdb: String?,\n                        @JsonProperty(\"mal\") val mal: String?,\n                        @JsonProperty(\"anidb\") val anidb: String?,\n                        @JsonProperty(\"anilist\") val anilist: String?,\n                        @JsonProperty(\"traktslug\") val traktslug: String?\n                    ) {\n                        fun matchesId(database: SimklSyncServices, id: String): Boolean {\n                            return when (database) {\n                                SimklSyncServices.Simkl -> this.simkl == id.toIntOrNull()\n                                SimklSyncServices.AniList -> this.anilist == id\n                                SimklSyncServices.Mal -> this.mal == id\n                                SimklSyncServices.Tmdb -> this.tmdb == id\n                                SimklSyncServices.Imdb -> this.imdb == id\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Appends api keys to the requests\n     **/\n    /*private inner class HeaderInterceptor : Interceptor {\n        override fun intercept(chain: Interceptor.Chain): Response {\n            debugPrint { \"${this@SimklApi.name} made request to ${chain.request().url}\" }\n            return chain.proceed(\n                chain.request()\n                    .newBuilder()\n                    .addHeader(\"Authorization\", \"Bearer $token\")\n                    .addHeader(\"simkl-api-key\", CLIENT_ID)\n                    .build()\n            )\n        }\n    }*/\n\n    private suspend fun getUser(token: AuthToken): SettingsResponse =\n        app.post(\"$mainUrl/users/settings\", headers = getHeaders(token))\n            .parsed<SettingsResponse>()\n\n\n    /**\n     * Useful to get episodes on demand to prevent unnecessary requests.\n     */\n    class SimklEpisodeConstructor(\n        private val simklId: Int?,\n        private val type: String?,\n        private val totalEpisodeCount: Int?,\n        private val hasEnded: Boolean?\n    ) {\n        suspend fun getEpisodes(): Array<EpisodeMetadata>? {\n            return getEpisodes(simklId, type, totalEpisodeCount, hasEnded)\n        }\n    }\n\n    class SimklSyncStatus(\n        override var status: SyncWatchType,\n        override var score: Score?,\n        val oldScore: Int?,\n        override var watchedEpisodes: Int?,\n        val episodeConstructor: SimklEpisodeConstructor,\n        override var isFavorite: Boolean? = null,\n        override var maxEpisodes: Int? = null,\n        /** Save seen episodes separately to know the change from old to new.\n         * Required to remove seen episodes if count decreases */\n        val oldEpisodes: Int,\n        val oldStatus: String?\n    ) : SyncAPI.AbstractSyncStatus()\n\n    override suspend fun status(auth: AuthData?, id: String): SyncAPI.AbstractSyncStatus? {\n        if (auth == null) return null\n        val realIds = readIdFromString(id)\n\n        // Key which assumes all ids are the same each time :/\n        // This could be some sort of reference system to make multiple IDs\n        // point to the same key.\n        val idKey =\n            realIds.toList().map { \"${it.first.originalName}=${it.second}\" }.sorted().joinToString()\n\n        val cachedObject = SimklCache.getKey<MediaObject>(idKey)\n        val searchResult: MediaObject = cachedObject\n            ?: (searchByIds(realIds)?.firstOrNull()?.also { result ->\n                val cacheTime =\n                    if (result.hasEnded()) SimklCache.CacheTimes.OneMonth.value else SimklCache.CacheTimes.ThirtyMinutes.value\n                SimklCache.setKey(idKey, result, Duration.parse(cacheTime))\n            }) ?: return null\n\n        val episodeConstructor = SimklEpisodeConstructor(\n            searchResult.ids?.simkl,\n            searchResult.type,\n            searchResult.totalEpisodes,\n            searchResult.hasEnded()\n        )\n\n        val foundItem = getSyncListSmart(auth)?.let { list ->\n            listOf(list.shows, list.anime, list.movies).flatten().firstOrNull { show ->\n                realIds.any { (database, id) ->\n                    show.getIds().matchesId(database, id)\n                }\n            }\n        }\n\n        if (foundItem != null) {\n            return SimklSyncStatus(\n                status = foundItem.status?.let {\n                    SyncWatchType.fromInternalId(\n                        SimklListStatusType.fromString(\n                            it\n                        )?.value\n                    )\n                }\n                    ?: return null,\n                score = Score.from10(foundItem.userRating),\n                watchedEpisodes = foundItem.watchedEpisodesCount,\n                maxEpisodes = searchResult.totalEpisodes,\n                episodeConstructor = episodeConstructor,\n                oldEpisodes = foundItem.watchedEpisodesCount ?: 0,\n                oldScore = foundItem.userRating,\n                oldStatus = foundItem.status\n            )\n        } else {\n            return SimklSyncStatus(\n                status = SyncWatchType.fromInternalId(SimklListStatusType.None.value),\n                score = null,\n                watchedEpisodes = 0,\n                maxEpisodes = if (searchResult.type == \"movie\") 0 else searchResult.totalEpisodes,\n                episodeConstructor = episodeConstructor,\n                oldEpisodes = 0,\n                oldStatus = null,\n                oldScore = null\n            )\n        }\n    }\n\n    override suspend fun updateStatus(\n        auth: AuthData?,\n        id: String,\n        newStatus: AbstractSyncStatus\n    ): Boolean {\n        val parsedId = readIdFromString(id)\n        lastScoreTime = unixTime\n        val simklStatus = newStatus as? SimklSyncStatus\n\n        val builder = SimklScoreBuilder.Builder()\n            .apiUrl(this.mainUrl)\n            .score(newStatus.score?.toInt(10), simklStatus?.oldScore)\n            .status(\n                newStatus.status.internalId,\n                (newStatus as? SimklSyncStatus)?.oldStatus?.let { oldStatus ->\n                    SimklListStatusType.entries.firstOrNull {\n                        it.originalName == oldStatus\n                    }?.value\n                })\n            .token(auth?.token ?: return false)\n            .ids(MediaObject.Ids.fromMap(parsedId))\n\n\n        // Get episodes only when required\n        val episodes = simklStatus?.episodeConstructor?.getEpisodes()\n\n        // All episodes if marked as completed\n        val watchedEpisodes =\n            if (newStatus.status.internalId == SimklListStatusType.Completed.value) {\n                episodes?.size\n            } else {\n                newStatus.watchedEpisodes\n            }\n\n        builder.episodes(episodes?.toList(), watchedEpisodes, simklStatus?.oldEpisodes)\n\n        requireLibraryRefresh = true\n        return builder.execute()\n    }\n\n\n    /** See https://simkl.docs.apiary.io/#reference/search/id-lookup/get-items-by-id */\n    private suspend fun searchByIds(serviceMap: Map<SimklSyncServices, String>): Array<MediaObject>? {\n        if (serviceMap.isEmpty()) return emptyArray()\n\n        return app.get(\n            \"$mainUrl/search/id\",\n            params = mapOf(\"client_id\" to CLIENT_ID) + serviceMap.map { (service, id) ->\n                service.originalName to id\n            }\n        ).parsedSafe()\n    }\n\n    override suspend fun search(auth: AuthData?, query: String): List<SyncAPI.SyncSearchResult>? {\n        return app.get(\n            \"$mainUrl/search/\", params = mapOf(\"client_id\" to CLIENT_ID, \"q\" to name)\n        ).parsedSafe<Array<MediaObject>>()?.mapNotNull { it.toSyncSearchResult() }\n    }\n\n    override fun loginRequest(): AuthLoginPage? {\n        val lastLoginState = BigInteger(130, SecureRandom()).toString(32)\n        val url =\n            \"https://simkl.com/oauth/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=$APP_STRING://${redirectUrlIdentifier}&state=$lastLoginState\"\n\n        return AuthLoginPage(\n            url = url,\n            payload = lastLoginState\n        )\n    }\n\n    override suspend fun load(auth: AuthData?, id: String): SyncResult? = null\n\n    private suspend fun getSyncListSince(auth: AuthData, since: Long?): AllItemsResponse? {\n        val params = getDateTime(since)?.let {\n            mapOf(\"date_from\" to it)\n        } ?: emptyMap()\n\n        // Can return null on no change.\n        return app.get(\n            \"$mainUrl/sync/all-items/\",\n            params = params,\n            headers = getHeaders(auth.token)\n        ).parsedSafe()\n    }\n\n    private suspend fun getActivities(token: AuthToken): ActivitiesResponse? {\n        return app.post(\"$mainUrl/sync/activities\", headers = getHeaders(token)).parsedSafe()\n    }\n\n    private fun getSyncListCached(auth: AuthData): AllItemsResponse? {\n        return getKey<AllItemsResponse>(SIMKL_CACHED_LIST, auth.user.id.toString())\n    }\n\n    private suspend fun getSyncListSmart(auth: AuthData): AllItemsResponse? {\n        val activities = getActivities(auth.token)\n        val userId = auth.user.id.toString()\n        val lastCacheUpdate = getKey<Long>(SIMKL_CACHED_LIST_TIME, auth.user.id.toString())\n        val lastRemoval = listOf(\n            activities?.tvShows?.removedFromList,\n            activities?.anime?.removedFromList,\n            activities?.movies?.removedFromList\n        ).maxOf {\n            getUnixTime(it) ?: -1\n        }\n        val lastRealUpdate =\n            listOf(\n                activities?.tvShows?.all,\n                activities?.anime?.all,\n                activities?.movies?.all,\n            ).maxOf {\n                getUnixTime(it) ?: -1\n            }\n\n        debugPrint { \"Cache times: lastCacheUpdate=$lastCacheUpdate, lastRemoval=$lastRemoval, lastRealUpdate=$lastRealUpdate\" }\n        val list = if (lastCacheUpdate == null || lastCacheUpdate < lastRemoval) {\n            debugPrint { \"Full list update in ${this.name}.\" }\n            setKey(SIMKL_CACHED_LIST_TIME, userId, lastRemoval)\n            getSyncListSince(auth, null)\n        } else if (lastCacheUpdate < lastRealUpdate || lastCacheUpdate < lastScoreTime) {\n            debugPrint { \"Partial list update in ${this.name}.\" }\n            setKey(SIMKL_CACHED_LIST_TIME, userId, lastCacheUpdate)\n            AllItemsResponse.merge(\n                getSyncListCached(auth),\n                getSyncListSince(auth, lastCacheUpdate)\n            )\n        } else {\n            debugPrint { \"Cached list update in ${this.name}.\" }\n            getSyncListCached(auth)\n        }\n        debugPrint { \"List sizes: movies=${list?.movies?.size}, shows=${list?.shows?.size}, anime=${list?.anime?.size}\" }\n\n        setKey(SIMKL_CACHED_LIST, userId, list)\n\n        return list\n    }\n\n    override suspend fun library(auth: AuthData?): SyncAPI.LibraryMetadata? {\n        val list = getSyncListSmart(auth ?: return null) ?: return null\n\n        val baseMap =\n            SimklListStatusType.entries\n                .filter { it.value >= 0 && it.value != SimklListStatusType.ReWatching.value }\n                .associate {\n                    it.stringRes to emptyList<SyncAPI.LibraryItem>()\n                }\n\n        val syncMap = listOf(list.anime, list.movies, list.shows)\n            .flatten()\n            .groupBy {\n                it.status\n            }\n            .mapNotNull { (status, list) ->\n                val stringRes =\n                    status?.let { SimklListStatusType.fromString(it)?.stringRes }\n                        ?: return@mapNotNull null\n                val libraryList = list.map { it.toLibraryItem() }\n                stringRes to libraryList\n            }.toMap()\n\n        return SyncAPI.LibraryMetadata(\n            (baseMap + syncMap).map { SyncAPI.LibraryList(txt(it.key), it.value) }, setOf(\n                ListSorting.AlphabeticalA,\n                ListSorting.AlphabeticalZ,\n                ListSorting.UpdatedNew,\n                ListSorting.UpdatedOld,\n                ListSorting.ReleaseDateNew,\n                ListSorting.ReleaseDateOld,\n                ListSorting.RatingHigh,\n                ListSorting.RatingLow,\n            )\n        )\n    }\n\n    override fun urlToId(url: String): String? {\n        val simklUrlRegex = Regex(\"\"\"https://simkl\\.com/[^/]*/(\\d+).*\"\"\")\n        return simklUrlRegex.find(url)?.groupValues?.get(1) ?: \"\"\n    }\n\n    override suspend fun pinRequest(): AuthPinData? {\n        val pinAuthResp = app.get(\n            \"$mainUrl/oauth/pin?client_id=$CLIENT_ID&redirect_uri=$APP_STRING://${redirectUrlIdentifier}\"\n        ).parsedSafe<PinAuthResponse>() ?: return null\n\n        return AuthPinData(\n            deviceCode = pinAuthResp.deviceCode,\n            userCode = pinAuthResp.userCode,\n            verificationUrl = pinAuthResp.verificationUrl,\n            expiresIn = pinAuthResp.expiresIn,\n            interval = pinAuthResp.interval\n        )\n    }\n\n    override suspend fun login(payload: AuthPinData): AuthToken? {\n        val pinAuthResp = app.get(\n            \"$mainUrl/oauth/pin/${payload.userCode}?client_id=$CLIENT_ID\"\n        ).parsedSafe<PinExchangeResponse>() ?: return null\n\n        return AuthToken(\n            accessToken = pinAuthResp.accessToken ?: return null,\n        )\n    }\n\n    override suspend fun login(redirectUrl: String, payload: String?): AuthToken? {\n        val uri = redirectUrl.toUri()\n        val state = uri.getQueryParameter(\"state\")\n        // Ensure consistent state\n        if (state != payload) return null\n\n        val code = uri.getQueryParameter(\"code\") ?: return null\n        val tokenResponse = app.post(\n            \"$mainUrl/oauth/token\", json = TokenRequest(code)\n        ).parsedSafe<TokenResponse>() ?: return null\n\n        return AuthToken(\n            accessToken = tokenResponse.accessToken,\n        )\n    }\n\n    override suspend fun user(token: AuthToken?): AuthUser? {\n        val user = getUser(token ?: return null)\n        return AuthUser(\n            id = user.account.id,\n            name = user.user.name,\n            profilePicture = user.user.avatar\n        )\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SubSource.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders.providers\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities\nimport com.lagradost.cloudstream3.subtitles.SubtitleResource\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.syncproviders.SubtitleAPI\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.SubtitleHelper\n\nclass SubSourceApi : SubtitleAPI() {\n    override val name = \"SubSource\"\n    override val idPrefix = \"subsource\"\n\n    override val requiresLogin = false\n\n    companion object {\n        const val APIURL = \"https://api.subsource.net/api\"\n        const val DOWNLOADENDPOINT = \"https://api.subsource.net/api/downloadSub\"\n    }\n\n    override suspend fun search(\n        auth: AuthData?,\n        query: AbstractSubtitleEntities.SubtitleSearch\n    ): List<AbstractSubtitleEntities.SubtitleEntity>? {\n\n        //Only supports Imdb Id search for now\n        if (query.imdbId == null) return null\n        val queryLang = SubtitleHelper.fromTagToEnglishLanguageName(query.lang)\n        val type = if ((query.seasonNumber ?: 0) > 0) TvType.TvSeries else TvType.Movie\n\n        val searchRes = app.post(\n            url = \"$APIURL/searchMovie\",\n            data = mapOf(\n                \"query\" to query.imdbId!!\n            )\n        ).parsedSafe<ApiSearch>() ?: return null\n\n        val postData = if (type == TvType.TvSeries) {\n            mapOf(\n                \"langs\" to \"[]\",\n                \"movieName\" to searchRes.found.first().linkName,\n                \"season\" to \"season-${query.seasonNumber}\"\n            )\n        } else {\n            mapOf(\n                \"langs\" to \"[]\",\n                \"movieName\" to searchRes.found.first().linkName,\n            )\n        }\n\n        val getMovieRes = app.post(\n            url = \"$APIURL/getMovie\",\n            data = postData\n        ).parsedSafe<ApiResponse>().let {\n            // api doesn't has episode number or lang filtering\n            if (type == TvType.Movie) {\n                it?.subs?.filter { sub ->\n                    sub.lang == queryLang\n                }\n            } else {\n                it?.subs?.filter { sub ->\n                    sub.releaseName!!.contains(\n                        String.format(\n                            null,\n                            \"E%02d\",\n                            query.epNumber\n                        )\n                    ) && sub.lang == queryLang\n                }\n            }\n        } ?: return null\n\n        return getMovieRes.map { subtitle ->\n            AbstractSubtitleEntities.SubtitleEntity(\n                idPrefix = this.idPrefix,\n                name = subtitle.releaseName!!,\n                lang = subtitle.lang!!,\n                data = SubData(\n                    movie = subtitle.linkName!!,\n                    lang = subtitle.lang,\n                    id = subtitle.subId.toString(),\n                ).toJson(),\n                type = type,\n                source = this.name,\n                epNumber = query.epNumber,\n                seasonNumber = query.seasonNumber,\n                isHearingImpaired = subtitle.hi == 1,\n            )\n        }\n    }\n\n    override suspend fun SubtitleResource.getResources(\n        auth: AuthData?,\n        subtitle: AbstractSubtitleEntities.SubtitleEntity\n    ) {\n        val parsedSub = parseJson<SubData>(subtitle.data)\n\n        val subRes = app.post(\n            url = \"$APIURL/getSub\",\n            data = mapOf(\n                \"movie\" to parsedSub.movie,\n                \"lang\" to subtitle.lang,\n                \"id\" to parsedSub.id\n            )\n        ).parsedSafe<SubTitleLink>() ?: return\n\n        this.addZipUrl(\n            \"$DOWNLOADENDPOINT/${subRes.sub.downloadToken}\"\n        ) { name, _ ->\n            name\n        }\n    }\n\n    data class ApiSearch(\n        @JsonProperty(\"success\") val success: Boolean,\n        @JsonProperty(\"found\") val found: List<Found>,\n    )\n\n    data class Found(\n        @JsonProperty(\"id\") val id: Long,\n        @JsonProperty(\"title\") val title: String,\n        @JsonProperty(\"seasons\") val seasons: Long,\n        @JsonProperty(\"type\") val type: String,\n        @JsonProperty(\"releaseYear\") val releaseYear: Long,\n        @JsonProperty(\"linkName\") val linkName: String,\n    )\n\n    data class ApiResponse(\n        @JsonProperty(\"success\") val success: Boolean,\n        @JsonProperty(\"movie\") val movie: Movie,\n        @JsonProperty(\"subs\") val subs: List<Sub>,\n    )\n\n    data class Movie(\n        @JsonProperty(\"id\") val id: Long? = null,\n        @JsonProperty(\"type\") val type: String? = null,\n        @JsonProperty(\"year\") val year: Long? = null,\n        @JsonProperty(\"fullName\") val fullName: String? = null,\n    )\n\n    data class Sub(\n        @JsonProperty(\"hi\") val hi: Int? = null,\n        @JsonProperty(\"fullLink\") val fullLink: String? = null,\n        @JsonProperty(\"linkName\") val linkName: String? = null,\n        @JsonProperty(\"lang\") val lang: String? = null,\n        @JsonProperty(\"releaseName\") val releaseName: String? = null,\n        @JsonProperty(\"subId\") val subId: Long? = null,\n    )\n\n    data class SubData(\n        @JsonProperty(\"movie\") val movie: String,\n        @JsonProperty(\"lang\") val lang: String,\n        @JsonProperty(\"id\") val id: String,\n    )\n\n    data class SubTitleLink(\n        @JsonProperty(\"sub\") val sub: SubToken,\n    )\n\n    data class SubToken(\n        @JsonProperty(\"downloadToken\") val downloadToken: String,\n    )\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Subdl.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders.providers\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities\nimport com.lagradost.cloudstream3.subtitles.SubtitleResource\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginRequirement\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginResponse\nimport com.lagradost.cloudstream3.syncproviders.AuthToken\nimport com.lagradost.cloudstream3.syncproviders.AuthUser\nimport com.lagradost.cloudstream3.syncproviders.SubtitleAPI\nimport com.lagradost.cloudstream3.TvType\n\nclass SubDlApi : SubtitleAPI() {\n    override val name = \"SubDL\"\n    override val idPrefix = \"subdl\"\n\n    override val icon = R.drawable.subdl_logo_big\n    override val hasInApp = true\n    override val inAppLoginRequirement = AuthLoginRequirement(password = true, email = true)\n    override val requiresLogin = true\n    override val createAccountUrl = \"https://subdl.com/panel/register\"\n\n    companion object {\n        const val APIURL = \"https://apiold.subdl.com\"\n        const val APIENDPOINT = \"$APIURL/api/v1/subtitles\"\n        const val DOWNLOADENDPOINT = \"https://dl.subdl.com\"\n    }\n\n    override suspend fun login(form: AuthLoginResponse): AuthToken? {\n        val email = form.email ?: return null\n        val password = form.password ?: return null\n        val tokenResponse = app.post(\n            url = \"$APIURL/login\",\n            json = mapOf(\n                \"email\" to email,\n                \"password\" to password\n            )\n        ).parsed<OAuthTokenResponse>()\n\n        val apiResponse = app.get(\n            url = \"$APIURL/user/userApi\",\n            headers = mapOf(\n                \"Authorization\" to \"Bearer ${tokenResponse.token}\"\n            )\n        ).parsed<ApiKeyResponse>()\n\n        return AuthToken(accessToken = apiResponse.apiKey, payload = email)\n    }\n\n    override suspend fun user(token: AuthToken?): AuthUser? {\n        val name = token?.payload ?: return null\n        return AuthUser(id = name.hashCode(), name = name)\n    }\n\n    override suspend fun search(\n        auth : AuthData?,\n        query: AbstractSubtitleEntities.SubtitleSearch\n    ): List<AbstractSubtitleEntities.SubtitleEntity>? {\n        if (auth == null) return null\n        val apiKey = auth.token.accessToken ?: return null\n        val queryText = query.query\n        val epNum = query.epNumber ?: 0\n        val seasonNum = query.seasonNumber ?: 0\n        val yearNum = query.year ?: 0\n        val langSubdlCode = langTagIETF2subdl[query.lang.toString()] ?: query.lang\n\n        val idQuery = when {\n            query.imdbId != null -> \"&imdb_id=${query.imdbId}\"\n            query.tmdbId != null -> \"&tmdb_id=${query.tmdbId}\"\n            else -> null\n        }\n\n        val epQuery = if (epNum > 0) \"&episode_number=$epNum\" else \"\"\n        val seasonQuery = if (seasonNum > 0) \"&season_number=$seasonNum\" else \"\"\n        val yearQuery = if (yearNum > 0) \"&year=$yearNum\" else \"\"\n\n        val searchQueryUrl = when (idQuery) {\n            //Use imdb/tmdb id to search if its valid\n            null -> \"$APIENDPOINT?api_key=${apiKey}&film_name=$queryText&languages=$langSubdlCode$epQuery$seasonQuery$yearQuery\"\n            else -> \"$APIENDPOINT?api_key=${apiKey}$idQuery&languages=$langSubdlCode$epQuery$seasonQuery$yearQuery\"\n        }\n\n        val req = app.get(\n            url = searchQueryUrl,\n            headers = mapOf(\n                \"Accept\" to \"application/json\"\n            )\n        )\n\n        return req.parsedSafe<ApiResponse>()?.subtitles?.map { subtitle ->\n\n            val langTagIETF =\n                langTagIETF2subdl.entries.find { it.value == subtitle.lang }?.key ?:\n                subtitle.lang\n            val resEpNum = subtitle.episode ?: query.epNumber\n            val resSeasonNum = subtitle.season ?: query.seasonNumber\n            val type = if ((resSeasonNum ?: 0) > 0) TvType.TvSeries else TvType.Movie\n\n            AbstractSubtitleEntities.SubtitleEntity(\n                idPrefix = this.idPrefix,\n                name = subtitle.releaseName,\n                lang = langTagIETF,\n                data = \"${DOWNLOADENDPOINT}${subtitle.url}\",\n                type = type,\n                source = this.name,\n                epNumber = resEpNum,\n                seasonNumber = resSeasonNum,\n                isHearingImpaired = subtitle.hearingImpaired ?: false,\n            )\n        }\n    }\n\n    override suspend fun SubtitleResource.getResources(\n        auth: AuthData?,\n        subtitle: AbstractSubtitleEntities.SubtitleEntity\n    ) {\n        this.addZipUrl(subtitle.data) { name, _ ->\n            name\n        }\n    }\n\n    data class SubtitleOAuthEntity(\n        @JsonProperty(\"userEmail\") var userEmail: String,\n        @JsonProperty(\"pass\") var pass: String,\n        @JsonProperty(\"name\") var name: String? = null,\n        @JsonProperty(\"accessToken\") var accessToken: String? = null,\n        @JsonProperty(\"apiKey\") var apiKey: String? = null,\n    )\n\n    data class OAuthTokenResponse(\n        @JsonProperty(\"token\") val token: String,\n        @JsonProperty(\"userData\") val userData: UserData? = null,\n        @JsonProperty(\"status\") val status: Boolean? = null,\n        @JsonProperty(\"message\") val message: String? = null,\n    )\n\n    data class UserData(\n        @JsonProperty(\"email\") val email: String,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"country\") val country: String,\n        @JsonProperty(\"scStepCode\") val scStepCode: String,\n        @JsonProperty(\"scVerified\") val scVerified: Boolean,\n        @JsonProperty(\"username\") val username: String? = null,\n        @JsonProperty(\"scUsername\") val scUsername: String,\n    )\n\n    data class ApiKeyResponse(\n        @JsonProperty(\"ok\") val ok: Boolean? = false,\n        @JsonProperty(\"api_key\") val apiKey: String,\n        @JsonProperty(\"usage\") val usage: Usage? = null,\n    )\n\n    data class Usage(\n        @JsonProperty(\"total\") val total: Long? = 0,\n        @JsonProperty(\"today\") val today: Long? = 0,\n    )\n\n    data class ApiResponse(\n        @JsonProperty(\"status\") val status: Boolean? = null,\n        @JsonProperty(\"results\") val results: List<Result>? = null,\n        @JsonProperty(\"subtitles\") val subtitles: List<Subtitle>? = null,\n    )\n\n    data class Result(\n        @JsonProperty(\"sd_id\") val sdId: Int? = null,\n        @JsonProperty(\"type\") val type: String? = null,\n        @JsonProperty(\"name\") val name: String? = null,\n        @JsonProperty(\"imdb_id\") val imdbId: String? = null,\n        @JsonProperty(\"tmdb_id\") val tmdbId: Long? = null,\n        @JsonProperty(\"first_air_date\") val firstAirDate: String? = null,\n        @JsonProperty(\"year\") val year: Int? = null,\n    )\n\n    data class Subtitle(\n        @JsonProperty(\"release_name\") val releaseName: String,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"lang\") val lang: String, // subdl language code\n        @JsonProperty(\"author\") val author: String? = null,\n        @JsonProperty(\"url\") val url: String? = null,\n        @JsonProperty(\"subtitlePage\") val subtitlePage: String? = null,\n        @JsonProperty(\"season\") val season: Int? = null,\n        @JsonProperty(\"episode\") val episode: Int? = null,\n        @JsonProperty(\"language\") val language: String? = null, // full language name\n        @JsonProperty(\"hi\") val hearingImpaired: Boolean? = null,\n    )\n\n    // https://subdl.com/api-files/language_list.json\n    // most of it is IETF BPC 47 conformant tag\n    // but there are some exceptions\n    private val langTagIETF2subdl = mapOf(\n        \"en-bg\" to \"BG_EN\", // \"Bulgarian_English\"\n        \"en-de\" to \"EN_DE\", // \"English_German\"\n        \"en-hu\" to \"HU_EN\", // \"Hungarian_English\"\n        \"en-nl\" to \"NL_EN\", // \"Dutch_English\"\n        \"pt-br\" to \"BR_PT\", // \"Brazillian Portuguese\"\n        \"zh-hant\" to \"ZH_BG\", // \"Big 5 code\" -> traditional Chinese (?_?)\n        // \"ar\" to \"AR\", // \"Arabic\"\n        // \"az\" to \"AZ\", // \"Azerbaijani\"\n        // \"be\" to \"BE\", // \"Belarusian\"\n        // \"bg\" to \"BG\", // \"Bulgarian\"\n        // \"bn\" to \"BN\", // \"Bengali\"\n        // \"bs\" to \"BS\", // \"Bosnian\"\n        // \"ca\" to \"CA\", // \"Catalan\"\n        // \"cs\" to \"CS\", // \"Czech\"\n        // \"da\" to \"DA\", // \"Danish\"\n        // \"de\" to \"DE\", // \"German\"\n        // \"el\" to \"EL\", // \"Greek\"\n        // \"en\" to \"EN\", // \"English\"\n        // \"eo\" to \"EO\", // \"Esperanto\"\n        // \"es\" to \"ES\", // \"Spanish\"\n        // \"et\" to \"ET\", // \"Estonian\"\n        // \"fa\" to \"FA\", // \"Farsi_Persian\"\n        // \"fi\" to \"FI\", // \"Finnish\"\n        // \"fr\" to \"FR\", // \"French\"\n        // \"he\" to \"HE\", // \"Hebrew\"\n        // \"hi\" to \"HI\", // \"Hindi\"\n        // \"hr\" to \"HR\", // \"Croatian\"\n        // \"hu\" to \"HU\", // \"Hungarian\"\n        // \"id\" to \"ID\", // \"Indonesian\"\n        // \"is\" to \"IS\", // \"Icelandic\"\n        // \"it\" to \"IT\", // \"Italian\"\n        // \"ja\" to \"JA\", // \"Japanese\"\n        // \"ka\" to \"KA\", // \"Georgian\"\n        // \"kl\" to \"KL\", // \"Greenlandic\"\n        // \"ko\" to \"KO\", // \"Korean\"\n        // \"ku\" to \"KU\", // \"Kurdish\"\n        // \"lt\" to \"LT\", // \"Lithuanian\"\n        // \"lv\" to \"LV\", // \"Latvian\"\n        // \"mk\" to \"MK\", // \"Macedonian\"\n        // \"ml\" to \"ML\", // \"Malayalam\"\n        // \"mni\" to \"MNI\", // \"Manipuri\"\n        // \"ms\" to \"MS\", // \"Malay\"\n        // \"my\" to \"MY\", // \"Burmese\"\n        // \"nl\" to \"NL\", // \"Dutch\"\n        // \"no\" to \"NO\", // \"Norwegian\"\n        // \"pl\" to \"PL\", // \"Polish\"\n        // \"pt\" to \"PT\", // \"Portuguese\"\n        // \"ro\" to \"RO\", // \"Romanian\"\n        // \"ru\" to \"RU\", // \"Russian\"\n        // \"si\" to \"SI\", // \"Sinhala\"\n        // \"sk\" to \"SK\", // \"Slovak\"\n        // \"sl\" to \"SL\", // \"Slovenian\"\n        // \"sq\" to \"SQ\", // \"Albanian\"\n        // \"sr\" to \"SR\", // \"Serbian\"\n        // \"sv\" to \"SV\", // \"Swedish\"\n        // \"ta\" to \"TA\", // \"Tamil\"\n        // \"te\" to \"TE\", // \"Telugu\"\n        // \"th\" to \"TH\", // \"Thai\"\n        // \"tl\" to \"TL\", // \"Tagalog\"\n        // \"tr\" to \"TR\", // \"Turkish\"\n        // \"uk\" to \"UK\", // \"Ukranian\"\n        // \"ur\" to \"UR\", // \"Urdu\"\n        // \"vi\" to \"VI\", // \"Vietnamese\"\n        // \"zh\" to \"ZH\", // \"Chinese BG code\"\n    )\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/APIRepository.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport com.lagradost.cloudstream3.APIHolder.unixTime\nimport com.lagradost.cloudstream3.APIHolder.unixTimeMS\nimport com.lagradost.cloudstream3.DubStatus\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.HomePageResponse\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent\nimport com.lagradost.cloudstream3.MainPageRequest\nimport com.lagradost.cloudstream3.SearchResponseList\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.fixUrl\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safeApiCall\nimport com.lagradost.cloudstream3.newSearchResponseList\nimport com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.async\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.withTimeout\n\nclass APIRepository(val api: MainAPI) {\n    companion object {\n        // 2 minute timeout to prevent bad extensions/extractors from hogging the resources\n        // No real provider should take longer, so we hard kill them.\n        private const val DEFAULT_TIMEOUT = 120_000L\n        private const val MAX_TIMEOUT = 4 * DEFAULT_TIMEOUT\n        private const val MIN_TIMEOUT = 5_000L\n\n        var dubStatusActive = HashSet<DubStatus>()\n\n        val noneApi = object : MainAPI() {\n            override var name = \"None\"\n            override val supportedTypes = emptySet<TvType>()\n            override var lang = \"\"\n        }\n        val randomApi = object : MainAPI() {\n            override var name = \"Random\"\n            override val supportedTypes = emptySet<TvType>()\n            override var lang = \"\"\n        }\n\n        fun isInvalidData(data: String): Boolean {\n            return data.isEmpty() || data == \"[]\" || data == \"about:blank\"\n        }\n\n        data class SavedLoadResponse(\n            val unixTime: Long,\n            val response: LoadResponse,\n            val hash: Pair<String, String>\n        )\n\n        private val cache = threadSafeListOf<SavedLoadResponse>()\n        private var cacheIndex: Int = 0\n        const val CACHE_SIZE = 20\n\n        fun getTimeout(desired: Long?): Long {\n            return (desired ?: DEFAULT_TIMEOUT).coerceIn(MIN_TIMEOUT, MAX_TIMEOUT)\n        }\n    }\n\n    private fun afterPluginsLoaded(forceReload: Boolean) {\n        if (forceReload) {\n            synchronized(cache) {\n                cache.clear()\n            }\n        }\n    }\n\n    init {\n        afterPluginsLoadedEvent += ::afterPluginsLoaded\n    }\n\n    val hasMainPage = api.hasMainPage\n    val providerType = api.providerType\n    val name = api.name\n    val mainUrl = api.mainUrl\n    val mainPage = api.mainPage\n    val hasQuickSearch = api.hasQuickSearch\n    val vpnStatus = api.vpnStatus\n\n    suspend fun load(url: String): Resource<LoadResponse> {\n        return safeApiCall {\n            withTimeout(getTimeout(api.loadTimeoutMs)) {\n                if (isInvalidData(url)) throw ErrorLoadingException()\n                val fixedUrl = api.fixUrl(url)\n                val lookingForHash = Pair(api.name, fixedUrl)\n\n                synchronized(cache) {\n                    for (item in cache) {\n                        // 10 min save\n                        if (item.hash == lookingForHash && (unixTime - item.unixTime) < 60 * 10) {\n                            return@withTimeout item.response\n                        }\n                    }\n                }\n\n                api.load(fixedUrl)?.also { response ->\n                    // Remove all blank tags as early as possible\n                    response.tags = response.tags?.filter { it.isNotBlank() }\n                    val add = SavedLoadResponse(unixTime, response, lookingForHash)\n\n                    synchronized(cache) {\n                        if (cache.size > CACHE_SIZE) {\n                            cache[cacheIndex] = add // rolling cache\n                            cacheIndex = (cacheIndex + 1) % CACHE_SIZE\n                        } else {\n                            cache.add(add)\n                        }\n                    }\n                } ?: throw ErrorLoadingException()\n            }\n        }\n    }\n\n    suspend fun search(query: String, page: Int): Resource<SearchResponseList> {\n        if (query.isEmpty())\n            return Resource.Success(newSearchResponseList(emptyList()))\n\n        return safeApiCall {\n            withTimeout(getTimeout(api.searchTimeoutMs)) {\n                (api.search(query, page)\n                    ?: throw ErrorLoadingException())\n                //                .filter { typesActive.contains(it.type) }\n            }\n        }\n    }\n\n    suspend fun quickSearch(query: String): Resource<SearchResponseList> {\n        if (query.isEmpty())\n            return Resource.Success(newSearchResponseList(emptyList()))\n\n        return safeApiCall {\n            withTimeout(getTimeout(api.quickSearchTimeoutMs)) {\n                newSearchResponseList(\n                    api.quickSearch(query) ?: throw ErrorLoadingException(),\n                    false\n                )\n            }\n        }\n    }\n\n    suspend fun waitForHomeDelay() {\n        val delta = api.sequentialMainPageScrollDelay + api.lastHomepageRequest - unixTimeMS\n        if (delta < 0) return\n        delay(delta)\n    }\n\n    suspend fun getMainPage(page: Int, nameIndex: Int? = null): Resource<List<HomePageResponse?>> {\n        return safeApiCall {\n            withTimeout(getTimeout(api.getMainPageTimeoutMs)) {\n                api.lastHomepageRequest = unixTimeMS\n\n                nameIndex?.let { api.mainPage.getOrNull(it) }?.let { data ->\n                    listOf(\n                        api.getMainPage(\n                            page,\n                            MainPageRequest(data.name, data.data, data.horizontalImages)\n                        )\n                    )\n                } ?: run {\n                    if (api.sequentialMainPage) {\n                        var first = true\n                        api.mainPage.map { data ->\n                            if (!first) // dont want to sleep on first request\n                                delay(api.sequentialMainPageDelay)\n                            first = false\n\n                            api.getMainPage(\n                                page,\n                                MainPageRequest(data.name, data.data, data.horizontalImages)\n                            )\n                        }\n                    } else {\n                        with(CoroutineScope(coroutineContext)) {\n                            api.mainPage.map { data ->\n                                async {\n                                    api.getMainPage(\n                                        page,\n                                        MainPageRequest(data.name, data.data, data.horizontalImages)\n                                    )\n                                }\n                            }.map { it.await() }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    suspend fun extractorVerifierJob(extractorData: String?) {\n        safeApiCall {\n            api.extractorVerifierJob(extractorData)\n        }\n    }\n\n    suspend fun loadLinks(\n        data: String,\n        isCasting: Boolean,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit,\n    ): Boolean {\n        if (isInvalidData(data)) return false // this makes providers cleaner\n        return try {\n            withTimeout(getTimeout(api.loadLinksTimeoutMs)) {\n                api.loadLinks(data, isCasting, subtitleCallback, callback)\n            }\n        } catch (throwable: Throwable) {\n            logError(throwable)\n            return false\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/BaseAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport android.content.Context\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport androidx.core.view.children\nimport androidx.recyclerview.widget.AsyncDifferConfig\nimport androidx.recyclerview.widget.AsyncListDiffer\nimport androidx.recyclerview.widget.DiffUtil\nimport androidx.recyclerview.widget.RecyclerView\nimport androidx.recyclerview.widget.RecyclerView.ViewHolder\nimport androidx.viewbinding.ViewBinding\nimport coil3.dispose\nimport java.util.WeakHashMap\nimport java.util.concurrent.CopyOnWriteArrayList\n\nopen class ViewHolderState<T>(val view: ViewBinding) : ViewHolder(view.root) {\n    open fun save(): T? = null\n    open fun restore(state: T) = Unit\n}\n\nabstract class NoStateAdapter<T : Any>(\n    diffCallback: DiffUtil.ItemCallback<T> = BaseDiffCallback()\n) : BaseAdapter<T, Any>(0, diffCallback)\n\n/** Creates a new shared pool, using the supplied lambda as a constructor.\n *\n * The reason for this complicated structure is that a pool should not be shared between contexts\n * as it makes coil fuck up, and theming.\n * */\nfun newSharedPool(lambda: RecyclerView.RecycledViewPool.() -> Unit = { }): Pair<WeakHashMap<Context, RecyclerView.RecycledViewPool>, RecyclerView.RecycledViewPool.() -> Unit> =\n    WeakHashMap<Context, RecyclerView.RecycledViewPool>() to lambda\n\n/** Sets the shared pool of the recyclerview */\nfun RecyclerView.setRecycledViewPool(pool: Pair<WeakHashMap<Context, RecyclerView.RecycledViewPool>, RecyclerView.RecycledViewPool.() -> Unit>) {\n    val ctx = context ?: return\n    synchronized(pool.first) {\n        this.setRecycledViewPool(pool.first.getOrPut(ctx) {\n            RecyclerView.RecycledViewPool().apply(pool.second)\n        })\n    }\n}\n\n/** Clears the shared pool of views */\nfun Pair<WeakHashMap<Context, RecyclerView.RecycledViewPool>, RecyclerView.RecycledViewPool.() -> Unit>.clear() {\n    synchronized(this.first) {\n        for (pool in this.first.values) {\n            pool?.clear()\n        }\n    }\n}\n\n/**\n * BaseAdapter is a persistent state stored adapter that supports headers and footers.\n * This should be used for restoring eg scroll or focus related to a view when it is recreated.\n *\n * Id is a per fragment based unique id used to store the underlying data done in an internal ViewModel.\n *\n * diffCallback is how the view should be handled when updating, override onUpdateContent for updates\n *\n * NOTE:\n *\n * By default it should save automatically, but you can also call save(recycle)\n *\n * By default no state is stored, but doing an id != 0 will store\n *\n * By default no headers or footers exist, override footers and headers count\n */\nabstract class BaseAdapter<\n        T : Any,\n        S : Any>(\n    val id: Int = 0,\n    diffCallback: DiffUtil.ItemCallback<T> = BaseDiffCallback()\n) : RecyclerView.Adapter<ViewHolderState<S>>() {\n    open val footers: Int = 0\n    open val headers: Int = 0\n\n    val immutableCurrentList: List<T> get() = mDiffer.currentList\n\n    fun getItem(position: Int): T {\n        return mDiffer.currentList[position]\n    }\n\n    fun getItemOrNull(position: Int): T? {\n        return mDiffer.currentList.getOrNull(position)\n    }\n\n    private val mDiffer: AsyncListDiffer<T> = AsyncListDiffer(\n        object : NonFinalAdapterListUpdateCallback(this) {\n            override fun onMoved(fromPosition: Int, toPosition: Int) {\n                super.onMoved(fromPosition + headers, toPosition + headers)\n            }\n\n            override fun onRemoved(position: Int, count: Int) {\n                super.onRemoved(position + headers, count)\n            }\n\n            override fun onChanged(position: Int, count: Int, payload: Any?) {\n                super.onChanged(position + headers, count, payload)\n            }\n\n            override fun onInserted(position: Int, count: Int) {\n                super.onInserted(position + headers, count)\n            }\n        },\n        AsyncDifferConfig.Builder(diffCallback).build()\n    )\n\n    /**\n     * Instantly submits a **new and fresh** list. This means that no changes like moves are done as\n     * we assume the new list is not the same thing as the old list, nothing is shared.\n     *\n     * The views are rendered instantly as a result, so no fade/pop-ins or similar.\n     *\n     * Use `submitList` for general use, as that can reuse old views.\n     * */\n    open fun submitIncomparableList(list: List<T>?, commitCallback : Runnable? = null) {\n        // This leverages a quirk in the submitList function that has a fast case for null arrays\n        // What this implies is that as long as we do a double submit we can ensure no pop-ins,\n        // as the changes are the entire list instead of calculating deltas\n        submitList(null)\n        submitList(list, commitCallback)\n    }\n\n    /**\n     * @param commitCallback Optional runnable that is executed when the List is committed, if it is committed.\n     * This is needed for some tasks as submitList will use a background thread for diff\n     * */\n    open fun submitList(list: Collection<T>?, commitCallback : Runnable? = null) {\n        // deep copy at least the top list, because otherwise adapter can go crazy\n        if (list.isNullOrEmpty()) {\n            mDiffer.submitList(null, commitCallback) // It is \"faster\" to submit null than emptyList()\n        } else {\n            mDiffer.submitList(CopyOnWriteArrayList(list), commitCallback)\n        }\n    }\n\n    override fun getItemCount(): Int {\n        return mDiffer.currentList.size + footers + headers\n    }\n\n    open fun onUpdateContent(holder: ViewHolderState<S>, item: T, position: Int) =\n        onBindContent(holder, item, position)\n\n    open fun onBindContent(holder: ViewHolderState<S>, item: T, position: Int) = Unit\n    open fun onBindFooter(holder: ViewHolderState<S>) = Unit\n    open fun onBindHeader(holder: ViewHolderState<S>) = Unit\n    open fun onCreateContent(parent: ViewGroup): ViewHolderState<S> = throw NotImplementedError()\n    open fun onCreateCustomContent(\n        parent: ViewGroup,\n        viewType: Int\n    ) = onCreateContent(parent)\n\n    open fun onCreateFooter(parent: ViewGroup): ViewHolderState<S> = throw NotImplementedError()\n    open fun onCreateCustomFooter(\n        parent: ViewGroup,\n        viewType: Int\n    ) = onCreateFooter(parent)\n\n    open fun onCreateHeader(parent: ViewGroup): ViewHolderState<S> = throw NotImplementedError()\n    open fun onCreateCustomHeader(\n        parent: ViewGroup,\n        viewType: Int\n    ) = onCreateHeader(parent)\n\n    override fun onViewAttachedToWindow(holder: ViewHolderState<S>) {}\n    override fun onViewDetachedFromWindow(holder: ViewHolderState<S>) {}\n\n    @Suppress(\"UNCHECKED_CAST\")\n    fun save(recyclerView: RecyclerView) {\n        for (child in recyclerView.children) {\n            val holder =\n                recyclerView.findContainingViewHolder(child) as? ViewHolderState<S> ?: continue\n            setState(holder)\n        }\n    }\n\n    fun clearState() {\n        layoutManagerStates[id]?.clear()\n    }\n\n    @Suppress(\"UNCHECKED_CAST\")\n    private fun getState(holder: ViewHolderState<S>): S? =\n        layoutManagerStates[id]?.get(holder.absoluteAdapterPosition) as? S\n\n    private fun setState(holder: ViewHolderState<S>) {\n        if (id == 0) return\n        if (!layoutManagerStates.contains(id)) {\n            layoutManagerStates[id] = HashMap()\n        }\n        layoutManagerStates[id]?.let { map ->\n            map[holder.absoluteAdapterPosition] = holder.save()\n        }\n    }\n\n    private val attachListener = object : View.OnAttachStateChangeListener {\n        override fun onViewAttachedToWindow(v: View) = Unit\n        override fun onViewDetachedFromWindow(v: View) {\n            if (v !is RecyclerView) return\n            save(v)\n        }\n    }\n\n    final override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {\n        recyclerView.addOnAttachStateChangeListener(attachListener)\n        super.onAttachedToRecyclerView(recyclerView)\n    }\n\n    final override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {\n        recyclerView.removeOnAttachStateChangeListener(attachListener)\n        super.onDetachedFromRecyclerView(recyclerView)\n    }\n\n    open fun customContentViewType(item: T): Int = 0\n    open fun customFooterViewType(): Int = 0\n    open fun customHeaderViewType(): Int = 0\n\n    final override fun getItemViewType(position: Int): Int {\n        if (position < headers) {\n            return HEADER or customHeaderViewType()\n        }\n        val realPosition = position - headers\n        if (realPosition >= mDiffer.currentList.size) {\n            return FOOTER or customFooterViewType()\n        }\n        return CONTENT or customContentViewType(getItem(realPosition))\n    }\n\n    final override fun onViewRecycled(holder: ViewHolderState<S>) {\n        setState(holder)\n        onClearView(holder)\n        super.onViewRecycled(holder)\n    }\n\n    /** Same as onViewRecycled, but for the purpose of cleaning the view of any relevant data.\n     *\n     * If an item view has large or expensive data bound to it such as large bitmaps, this may be a good place to release those resources.\n     *\n     * Use this with `clearImage`\n     * */\n    open fun onClearView(holder: ViewHolderState<S>) {}\n\n    final override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolderState<S> {\n        return when (viewType and TYPE_MASK) {\n            CONTENT -> onCreateCustomContent(parent, viewType and CUSTOM_MASK)\n            HEADER -> onCreateCustomHeader(parent, viewType and CUSTOM_MASK)\n            FOOTER -> onCreateCustomFooter(parent, viewType and CUSTOM_MASK)\n            else -> throw NotImplementedError()\n        }\n    }\n\n    // https://medium.com/@domen.lanisnik/efficiently-updating-recyclerview-items-using-payloads-1305f65f3068\n    override fun onBindViewHolder(\n        holder: ViewHolderState<S>,\n        position: Int,\n        payloads: MutableList<Any>\n    ) {\n        if (payloads.isEmpty()) {\n            super.onBindViewHolder(holder, position, payloads)\n            return\n        }\n        when (getItemViewType(position) and TYPE_MASK) {\n            CONTENT -> {\n                val realPosition = position - headers\n                val item = getItem(realPosition)\n                onUpdateContent(holder, item, realPosition)\n            }\n\n            FOOTER -> {\n                onBindFooter(holder)\n            }\n\n            HEADER -> {\n                onBindHeader(holder)\n            }\n        }\n    }\n\n    final override fun onBindViewHolder(holder: ViewHolderState<S>, position: Int) {\n        when (getItemViewType(position) and TYPE_MASK) {\n            CONTENT -> {\n                val realPosition = position - headers\n                val item = getItem(realPosition)\n                onBindContent(holder, item, realPosition)\n            }\n\n            FOOTER -> {\n                onBindFooter(holder)\n            }\n\n            HEADER -> {\n                onBindHeader(holder)\n            }\n        }\n\n        getState(holder)?.let { state ->\n            holder.restore(state)\n        }\n    }\n\n    companion object {\n        val layoutManagerStates = hashMapOf<Int, HashMap<Int, Any?>>()\n        fun clearImage(image: ImageView?) {\n            image?.dispose()\n        }\n\n        // Use the lowermost MASK_SIZE bits for the custom content,\n        // use the uppermost 32 - MASK_SIZE to the type\n        private const val MASK_SIZE = 28\n        private const val CUSTOM_MASK = (1 shl MASK_SIZE) - 1\n        private const val TYPE_MASK = CUSTOM_MASK.inv()\n        const val HEADER: Int = 3 shl MASK_SIZE\n        const val FOOTER: Int = 2 shl MASK_SIZE\n        /** For custom content, write `CONTENT or X` when calling setMaxRecycledViews  */\n        const val CONTENT: Int = 1 shl MASK_SIZE\n    }\n}\n\nclass BaseDiffCallback<T : Any>(\n    val itemSame: (T, T) -> Boolean = { a, b -> a.hashCode() == b.hashCode() },\n    val contentSame: (T, T) -> Boolean = { a, b -> a.hashCode() == b.hashCode() }\n) : DiffUtil.ItemCallback<T>() {\n    override fun areItemsTheSame(oldItem: T, newItem: T): Boolean = itemSame(oldItem, newItem)\n    override fun areContentsTheSame(oldItem: T, newItem: T): Boolean = contentSame(oldItem, newItem)\n    override fun getChangePayload(oldItem: T, newItem: T): Any? = Any()\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/BaseFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport android.content.res.Configuration\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.Toast\nimport androidx.annotation.LayoutRes\nimport androidx.fragment.app.DialogFragment\nimport androidx.fragment.app.Fragment\nimport androidx.preference.PreferenceFragmentCompat\nimport androidx.viewbinding.ViewBinding\nimport com.google.android.material.bottomsheet.BottomSheetDialogFragment\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.txt\n\n/**\n * A base Fragment class that simplifies ViewBinding usage and handles view inflation safely.\n *\n * This class allows two modes of creating ViewBinding:\n * 1. Inflate: Using the standard `inflate()` method provided by generated ViewBinding classes.\n * 2. Bind: Using `bind()` on an existing root view.\n *\n * It also provides hooks for:\n * - Safe initialization of the binding (`onBindingCreated`)\n * - Automatic padding adjustment for system bars (`fixPadding`)\n * - Optional layout resource selection via `pickLayout()`\n *\n * @param T The type of ViewBinding for this Fragment.\n * @param bindingCreator The strategy used to create the binding instance.\n */\nprivate interface BaseFragmentHelper<T : ViewBinding> {\n    val bindingCreator: BaseFragment.BindingCreator<T>\n\n    var _binding: T?\n    val binding: T? get() = _binding\n\n    fun createBinding(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? {\n        val layoutId = pickLayout()\n        val root: View? = layoutId?.let { inflater.inflate(it, container, false) }\n        _binding = try {\n            when (val creator = bindingCreator) {\n                is BaseFragment.BindingCreator.Inflate -> creator.fn(inflater, container, false)\n                is BaseFragment.BindingCreator.Bind -> {\n                    if (root != null) creator.fn(root)\n                    else throw IllegalStateException(\"Root view is null for bind()\")\n                }\n            }\n        } catch (t: Throwable) {\n            showToast(\n                txt(R.string.unable_to_inflate, t.message ?: \"\"),\n                Toast.LENGTH_LONG\n            )\n            logError(t)\n            null\n        }\n\n        return _binding?.root ?: root\n    }\n\n    /**\n     * Called after the fragment's view has been created.\n     *\n     * This method is `final` to ensure that the binding is properly initialized and\n     * system bar padding adjustments are applied before any subclass logic runs.\n     * Subclasses should use [onBindingCreated] instead of overriding this method directly.\n     */\n    fun onViewReady(view: View, savedInstanceState: Bundle?) {\n        fixLayout(view)\n        binding?.let { onBindingCreated(it, savedInstanceState) }\n    }\n\n    /**\n     * Called when the binding is safely created and view is ready.\n     * Can be overridden to provide fragment-specific initialization.\n     *\n     * @param binding The safely created ViewBinding.\n     * @param savedInstanceState Saved state bundle or null.\n     */\n    fun onBindingCreated(binding: T, savedInstanceState: Bundle?) {\n        onBindingCreated(binding)\n    }\n\n    /**\n     * Called when the binding is safely created and view is ready.\n     * Overload without savedInstanceState for convenience.\n     *\n     * @param binding The safely created ViewBinding.\n     */\n    fun onBindingCreated(binding: T) {}\n\n    /**\n     * Pick a layout resource ID for the fragment.\n     *\n     * Return `null` by default. Override to provide a layout resource when using\n     * `BindingCreator.Bind`. Not needed if using `BindingCreator.Inflate`.\n     *\n     * @return Layout resource ID or null.\n     */\n    @LayoutRes\n    fun pickLayout(): Int? = null\n\n    /**\n     * Ensures the layout of the root view is correctly adjusted for the current configuration.\n     *\n     * This may include applying padding for system bars, adjusting insets, or performing other\n     * layout updates. `fixLayout` should remain idempotent, as it can be called multiple\n     * times on the same view, such as during configuration changes (e.g. device rotation) or when\n     * the view is recreated.\n     *\n     * @param view The root view to adjust.\n     */\n    fun fixLayout(view: View)\n}\n\nabstract class BaseFragment<T : ViewBinding>(\n    override val bindingCreator: BindingCreator<T>\n) : Fragment(), BaseFragmentHelper<T> {\n    override var _binding: T? = null\n\n    /** Safer activity?.onBackPressedDispatcher?.onBackPressed() with fallback behavior instead of app crash */\n    fun dispatchBackPressed() {\n        try {\n            activity?.onBackPressedDispatcher?.onBackPressed()\n        } catch (_: IllegalStateException) {\n            // FragmentManager is already executing transactions, so try again\n            delayedDispatchBackPressed(5)\n        } catch (t: Throwable) {\n            logError(t)\n        }\n    }\n\n    /** Recursive back press when available */\n    private fun delayedDispatchBackPressed(remaining: Int) {\n        if (remaining <= 0) return\n        binding?.root?.postDelayed({\n            try {\n                activity?.onBackPressedDispatcher?.onBackPressed()\n            } catch (_: IllegalStateException) {\n                // FragmentManager is already executing transactions, so try again\n                delayedDispatchBackPressed(remaining - 1)\n            } catch (t: Throwable) {\n                logError(t)\n            }\n        }, 200)\n    }\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? = createBinding(inflater, container, savedInstanceState)\n\n    final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        onViewReady(view, savedInstanceState)\n    }\n\n    /**\n     * Called when the device configuration changes (e.g., orientation).\n     * Re-applies system bar padding fixes to the root view to ensure it\n     * readjusts for orientation changes.\n     */\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n        view?.let { fixLayout(it) }\n    }\n\n    /** Cleans up the binding reference when the view is destroyed to avoid memory leaks. */\n    override fun onDestroyView() {\n        super.onDestroyView()\n        _binding = null\n    }\n\n    /**\n     * Sealed class representing the two strategies for creating a ViewBinding instance.\n     */\n    sealed class BindingCreator<T : ViewBinding> {\n\n        /**\n         * Use the standard inflate() method for creating the binding.\n         *\n         * @param fn Lambda that inflates the binding.\n         */\n        class Inflate<T : ViewBinding>(\n            val fn: (LayoutInflater, ViewGroup?, Boolean) -> T\n        ) : BindingCreator<T>()\n\n        /**\n         * Use bind() on an existing root view to create the binding. This should\n         * be used if you are differing per device layouts, such as different\n         * layouts for TV and Phone.\n         *\n         * @param fn Lambda that binds the root view.\n         */\n        class Bind<T : ViewBinding>(\n            val fn: (View) -> T\n        ) : BindingCreator<T>()\n    }\n}\n\nabstract class BaseDialogFragment<T : ViewBinding>(\n    override val bindingCreator: BaseFragment.BindingCreator<T>\n) : DialogFragment(), BaseFragmentHelper<T> {\n    override var _binding: T? = null\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? = createBinding(inflater, container, savedInstanceState)\n\n    final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        onViewReady(view, savedInstanceState)\n    }\n\n    /** @see [BaseFragment.onConfigurationChanged] for documentation. */\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n        view?.let { fixLayout(it) }\n    }\n\n    /** Cleans up the binding reference when the view is destroyed to avoid memory leaks. */\n    override fun onDestroyView() {\n        super.onDestroyView()\n        _binding = null\n    }\n}\n\nabstract class BaseBottomSheetDialogFragment<T : ViewBinding>(\n    override val bindingCreator: BaseFragment.BindingCreator<T>\n) : BottomSheetDialogFragment(), BaseFragmentHelper<T> {\n    override var _binding: T? = null\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? = createBinding(inflater, container, savedInstanceState)\n\n    final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        onViewReady(view, savedInstanceState)\n    }\n\n    /** @see [BaseFragment.onConfigurationChanged] for documentation. */\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n        view?.let { fixLayout(it) }\n    }\n\n    /** Cleans up the binding reference when the view is destroyed to avoid memory leaks. */\n    override fun onDestroyView() {\n        super.onDestroyView()\n        _binding = null\n    }\n}\n\nabstract class BasePreferenceFragmentCompat() : PreferenceFragmentCompat() {\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        setSystemBarsPadding()\n    }\n\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n        setSystemBarsPadding()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.Menu\nimport android.view.View.GONE\nimport android.view.View.INVISIBLE\nimport android.view.View.VISIBLE\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport android.widget.ImageView\nimport android.widget.LinearLayout\nimport android.widget.ListView\nimport androidx.appcompat.app.AlertDialog\nimport com.fasterxml.jackson.databind.DeserializationFeature\nimport com.fasterxml.jackson.databind.json.JsonMapper\nimport com.fasterxml.jackson.module.kotlin.kotlinModule\nimport com.google.android.gms.cast.MediaLoadOptions\nimport com.google.android.gms.cast.MediaQueueItem\nimport com.google.android.gms.cast.MediaSeekOptions\nimport com.google.android.gms.cast.MediaStatus.REPEAT_MODE_REPEAT_OFF\nimport com.google.android.gms.cast.MediaTrack\nimport com.google.android.gms.cast.TextTrackStyle\nimport com.google.android.gms.cast.framework.CastButtonFactory\nimport com.google.android.gms.cast.framework.CastSession\nimport com.google.android.gms.cast.framework.media.RemoteMediaClient\nimport com.google.android.gms.cast.framework.media.uicontroller.UIController\nimport com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safeApiCall\nimport com.lagradost.cloudstream3.sortUrls\nimport com.lagradost.cloudstream3.ui.player.LOADTYPE_CHROMECAST\nimport com.lagradost.cloudstream3.ui.player.RepoLinkGenerator\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.ui.subtitles.ChromecastSubtitlesFragment\nimport com.lagradost.cloudstream3.utils.AppContextUtils.sortSubs\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.CastHelper.awaitLinks\nimport com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.DataStore.toKotlinObject\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport org.json.JSONObject\n\n/*class SkipOpController(val view: ImageView) : UIController() {\n    init {\n        view.setImageResource(R.drawable.exo_controls_fastforward)\n        view.setOnClickListener {\n            remoteMediaClient?.let {\n                val options = MediaSeekOptions.Builder()\n                    .setPosition(it.approximateStreamPosition + 85000)\n                it.seek(options.build())\n            }\n        }\n    }\n}*/\n\nprivate fun RemoteMediaClient.getItemIndex(): Int? {\n    return try {\n        val index = this.mediaQueue.itemIds.indexOf(this.currentItem?.itemId ?: 0)\n        if (index < 0) null else index\n    } catch (e: Exception) {\n        null\n    }\n}\n\nclass SkipNextEpisodeController(val view: ImageView) : UIController() {\n    init {\n        view.setImageResource(R.drawable.ic_baseline_skip_next_24)\n        view.setOnClickListener {\n            remoteMediaClient?.let {\n                it.queueNext(JSONObject())\n                view.visibility = GONE // TO PREVENT MULTI CLICK\n            }\n        }\n    }\n\n    override fun onMediaStatusUpdated() {\n        super.onMediaStatusUpdated()\n        view.visibility = GONE\n        val currentIdIndex = remoteMediaClient?.getItemIndex() ?: return\n        val itemCount = remoteMediaClient?.mediaQueue?.itemCount ?: return\n        if (itemCount - currentIdIndex > 1 && remoteMediaClient?.isLoadingNextItem == false) {\n            view.visibility = VISIBLE\n        }\n    }\n}\n\ndata class MetadataHolder(\n    val apiName: String,\n    val isMovie: Boolean,\n    val title: String?,\n    val poster: String?,\n    val currentEpisodeIndex: Int,\n    val episodes: List<ResultEpisode>,\n    val currentLinks: List<ExtractorLink>,\n    val currentSubtitles: List<SubtitleData>\n)\n\nclass SelectSourceController(val view: ImageView, val activity: ControllerActivity) :\n    UIController() {\n    private val mapper: JsonMapper = JsonMapper.builder().addModule(kotlinModule())\n        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()\n\n    init {\n        view.setImageResource(R.drawable.ic_baseline_playlist_play_24)\n        view.setOnClickListener {\n            //  lateinit var dialog: AlertDialog\n            val holder = getCurrentMetaData()\n\n            if (holder != null) {\n                val items = holder.currentLinks\n                if (items.isNotEmpty() && remoteMediaClient?.currentItem != null) {\n                    val subTracks =\n                        remoteMediaClient?.mediaInfo?.mediaTracks?.filter { it.type == MediaTrack.TYPE_TEXT }\n                            ?: ArrayList()\n\n                    val bottomSheetDialogBuilder =\n                        AlertDialog.Builder(view.context, R.style.AlertDialogCustomBlack)\n                    bottomSheetDialogBuilder.setView(R.layout.sort_bottom_sheet)\n                    val bottomSheetDialog = bottomSheetDialogBuilder.create()\n                    bottomSheetDialog.show()\n                    //  bottomSheetDialog.setContentView(R.layout.sort_bottom_sheet)\n                    val providerList =\n                        bottomSheetDialog.findViewById<ListView>(R.id.sort_providers)!!\n                    val subtitleList =\n                        bottomSheetDialog.findViewById<ListView>(R.id.sort_subtitles)!!\n                    if (subTracks.isEmpty()) {\n                        bottomSheetDialog.findViewById<LinearLayout>(R.id.sort_subtitles_holder)?.visibility =\n                            GONE\n                    } else {\n                        val arrayAdapter =\n                            ArrayAdapter<String>(view.context, R.layout.sort_bottom_single_choice)\n                        arrayAdapter.add(view.context.getString(R.string.no_subtitles))\n                        arrayAdapter.addAll(subTracks.mapNotNull { it.name })\n\n                        subtitleList.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n                        subtitleList.adapter = arrayAdapter\n\n                        val currentTracks = remoteMediaClient?.mediaStatus?.activeTrackIds\n\n                        val subtitleIndex =\n                            if (currentTracks == null) 0 else subTracks.map { it.id }\n                                .indexOfFirst { currentTracks.contains(it) } + 1\n\n                        subtitleList.setSelection(subtitleIndex)\n                        subtitleList.setItemChecked(subtitleIndex, true)\n\n                        subtitleList.setOnItemClickListener { _, _, which, _ ->\n                            if (which == 0) {\n                                remoteMediaClient?.setActiveMediaTracks(longArrayOf()) // NO SUBS\n                            } else {\n                                ChromecastSubtitlesFragment.getCurrentSavedStyle().apply {\n                                    val font = TextTrackStyle()\n                                    font.setFontFamily(fontFamily ?: \"Google Sans\")\n                                    fontGenericFamily?.let {\n                                        font.fontGenericFamily = it\n                                    }\n                                    font.windowColor = windowColor\n                                    font.backgroundColor = backgroundColor\n\n                                    font.edgeColor = edgeColor\n                                    font.edgeType = edgeType\n                                    font.foregroundColor = foregroundColor\n                                    font.fontScale = fontScale\n\n                                    remoteMediaClient?.setTextTrackStyle(font)\n                                }\n\n                                remoteMediaClient?.setActiveMediaTracks(longArrayOf(subTracks[which - 1].id))\n                                    ?.setResultCallback {\n                                        if (!it.status.isSuccess) {\n                                            Log.e(\n                                                \"CHROMECAST\", \"Failed with status code:\" +\n                                                        it.status.statusCode + \" > \" + it.status.statusMessage\n                                            )\n                                        }\n                                    }\n                            }\n                            bottomSheetDialog.dismissSafe(activity)\n                        }\n                    }\n\n                    //https://developers.google.com/cast/docs/reference/web_receiver/cast.framework.messages.MediaInformation\n                    val contentUrl = (remoteMediaClient?.currentItem?.media?.contentUrl\n                        ?: remoteMediaClient?.currentItem?.media?.contentId)\n\n                    val sortingMethods =\n                        items.map { \"${it.name} ${Qualities.getStringByInt(it.quality)}\" }\n                            .toTypedArray()\n                    val sotringIndex = items.indexOfFirst { it.url == contentUrl }\n\n                    val arrayAdapter =\n                        ArrayAdapter<String>(view.context, R.layout.sort_bottom_single_choice)\n                    arrayAdapter.addAll(sortingMethods.toMutableList())\n\n                    providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n                    providerList.adapter = arrayAdapter\n                    providerList.setSelection(sotringIndex)\n                    providerList.setItemChecked(sotringIndex, true)\n\n                    providerList.setOnItemClickListener { _, _, which, _ ->\n                        val epData = holder.episodes[holder.currentEpisodeIndex]\n\n                        fun loadMirror(index: Int) {\n                            if (holder.currentLinks.size <= index) return\n\n                            val mediaItem = getMediaInfo(\n                                epData,\n                                holder,\n                                index,\n                                remoteMediaClient?.mediaInfo?.customData,\n                                holder.currentSubtitles,\n                            )\n\n                            val startAt = remoteMediaClient?.approximateStreamPosition ?: 0\n\n                            //remoteMediaClient.load(mediaItem, true, startAt)\n                            try { // THIS IS VERY IMPORTANT BECAUSE WE NEVER WANT TO AUTOLOAD THE NEXT EPISODE\n                                val currentIdIndex = remoteMediaClient?.getItemIndex()\n\n                                val nextId = remoteMediaClient?.mediaQueue?.itemIds?.get(\n                                    currentIdIndex?.plus(1) ?: 0\n                                )\n                                if (currentIdIndex == null && nextId != null) {\n                                    awaitLinks(\n                                        remoteMediaClient?.queueInsertAndPlayItem(\n                                            MediaQueueItem.Builder(mediaItem).build(),\n                                            nextId,\n                                            startAt,\n                                            JSONObject()\n                                        )\n                                    ) {\n                                        loadMirror(index + 1)\n                                    }\n                                } else {\n                                    val mediaLoadOptions =\n                                        MediaLoadOptions.Builder()\n                                            .setPlayPosition(startAt)\n                                            .setAutoplay(true)\n                                            .build()\n                                    awaitLinks(\n                                        remoteMediaClient?.load(\n                                            mediaItem,\n                                            mediaLoadOptions\n                                        )\n                                    ) {\n                                        loadMirror(index + 1)\n                                    }\n                                }\n                            } catch (e: Exception) {\n                                val mediaLoadOptions =\n                                    MediaLoadOptions.Builder()\n                                        .setPlayPosition(startAt)\n                                        .setAutoplay(true)\n                                        .build()\n                                awaitLinks(remoteMediaClient?.load(mediaItem, mediaLoadOptions)) {\n                                    loadMirror(index + 1)\n                                }\n                            }\n                        }\n                        loadMirror(which)\n\n                        bottomSheetDialog.dismissSafe(activity)\n                    }\n                }\n            }\n        }\n    }\n\n    private fun getCurrentMetaData(): MetadataHolder? {\n        return try {\n            val data = remoteMediaClient?.mediaInfo?.customData?.toString()\n            data?.toKotlinObject()\n        } catch (e: Exception) {\n            null\n        }\n    }\n\n    var isLoadingMore = false\n\n\n    override fun onMediaStatusUpdated() {\n        super.onMediaStatusUpdated()\n        val meta = getCurrentMetaData()\n\n        view.visibility = if ((meta?.currentLinks?.size\n                ?: 0) > 1\n        ) VISIBLE else INVISIBLE\n        try {\n            if (meta != null && meta.episodes.size > meta.currentEpisodeIndex + 1) {\n                val currentIdIndex = remoteMediaClient?.getItemIndex() ?: return\n                val itemCount = remoteMediaClient?.mediaQueue?.itemCount\n                val index = meta.currentEpisodeIndex + 1\n                val epData = meta.episodes[index]\n\n                try {\n                    val currentDuration = remoteMediaClient?.streamDuration\n                    val currentPosition = remoteMediaClient?.approximateStreamPosition\n                    if (currentDuration != null && currentPosition != null)\n                        DataStoreHelper.setViewPosAndResume(\n                            epData.id,\n                            currentPosition,\n                            currentDuration,\n                            epData,\n                            meta.episodes.getOrNull(index + 1)\n                        )\n                } catch (t: Throwable) {\n                    logError(t)\n                }\n\n                if (itemCount != null && itemCount - currentIdIndex == 1 && !isLoadingMore) {\n                    isLoadingMore = true\n                    ioSafe {\n                        val currentLinks = mutableSetOf<ExtractorLink>()\n                        val currentSubs = mutableSetOf<SubtitleData>()\n\n                        val generator = RepoLinkGenerator(listOf(epData))\n\n                        val isSuccessful = safeApiCall {\n                            generator.generateLinks(\n                                clearCache = false,\n                                sourceTypes = LOADTYPE_CHROMECAST,\n                                callback = {\n                                    it.first?.let { link ->\n                                        currentLinks.add(link)\n                                    }\n                                }, subtitleCallback = {\n                                    currentSubs.add(it)\n                                },\n                                isCasting = true\n                            )\n                        }\n\n                        val sortedLinks = sortUrls(currentLinks)\n                        val sortedSubs = sortSubs(currentSubs)\n                        if (isSuccessful == Resource.Success(true)) {\n                            if (currentLinks.isNotEmpty()) {\n                                val jsonCopy = meta.copy(\n                                    currentLinks = sortedLinks,\n                                    currentSubtitles = sortedSubs,\n                                    currentEpisodeIndex = index\n                                )\n\n                                val done =\n                                    JSONObject(jsonCopy.toJson())\n\n                                val mediaInfo = getMediaInfo(\n                                    epData,\n                                    jsonCopy,\n                                    0,\n                                    done,\n                                    sortedSubs\n                                )\n\n                                /*fun loadIndex(index: Int) {\n                                    println(\"LOAD INDEX::::: $index\")\n                                    if (meta.currentLinks.size <= index) return\n                                    val info = getMediaInfo(\n                                        epData,\n                                        meta,\n                                        index,\n                                        done)\n                                    awaitLinks(remoteMediaClient?.load(info, true, 0)) {\n                                        loadIndex(index + 1)\n                                    }\n                                }*/\n                                activity.runOnUiThread {\n                                    awaitLinks(\n                                        remoteMediaClient?.queueAppendItem(\n                                            MediaQueueItem.Builder(mediaInfo).build(),\n                                            JSONObject()\n                                        )\n                                    ) {\n                                        println(\"FAILED TO LOAD NEXT ITEM\")\n                                        //  loadIndex(1)\n                                    }\n                                    isLoadingMore = false\n                                }\n                            }\n\n                        }\n                    }\n                }\n            }\n        } catch (e: Exception) {\n            println(e)\n        }\n    }\n\n    override fun onSessionConnected(castSession: CastSession) {\n        super.onSessionConnected(castSession)\n        remoteMediaClient?.queueSetRepeatMode(REPEAT_MODE_REPEAT_OFF, JSONObject())\n    }\n}\n\nclass SkipTimeController(val view: ImageView, forwards: Boolean) : UIController() {\n    init {\n        //val settingsManager = PreferenceManager.getDefaultSharedPreferences()\n        //val time = settingsManager?.getInt(\"chromecast_tap_time\", 30) ?: 30\n        val time = 30\n        //view.setImageResource(if (forwards) R.drawable.netflix_skip_forward else R.drawable.netflix_skip_back)\n        view.setImageResource(if (forwards) R.drawable.go_forward_30 else R.drawable.go_back_30)\n        view.setOnClickListener {\n            remoteMediaClient?.let {\n                val options = MediaSeekOptions.Builder()\n                    .setPosition(it.approximateStreamPosition + time * 1000 * if (forwards) 1 else -1)\n                it.seek(options.build())\n            }\n        }\n    }\n}\n\nclass ControllerActivity : ExpandedControllerActivity() {\n    override fun onCreateOptionsMenu(menu: Menu): Boolean {\n        super.onCreateOptionsMenu(menu)\n        menuInflater.inflate(R.menu.cast_expanded_controller_menu, menu)\n        CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item)\n        return true\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        val sourcesButton: ImageView = getButtonImageViewAt(0)\n        val skipBackButton: ImageView = getButtonImageViewAt(1)\n        val skipForwardButton: ImageView = getButtonImageViewAt(2)\n        val skipOpButton: ImageView = getButtonImageViewAt(3)\n        uiMediaController.bindViewToUIController(\n            sourcesButton,\n            SelectSourceController(sourcesButton, this)\n        )\n        uiMediaController.bindViewToUIController(\n            skipBackButton,\n            SkipTimeController(skipBackButton, false)\n        )\n        uiMediaController.bindViewToUIController(\n            skipForwardButton,\n            SkipTimeController(skipForwardButton, true)\n        )\n        uiMediaController.bindViewToUIController(\n            skipOpButton,\n            SkipNextEpisodeController(skipOpButton)\n        )\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/CustomRecyclerViews.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.view.View\nimport androidx.core.content.withStyledAttributes\nimport androidx.core.view.children\nimport androidx.recyclerview.widget.GridLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport kotlin.math.abs\n\nclass GrdLayoutManager(val context: Context, spanCount: Int) :\n    GridLayoutManager(context, spanCount) {\n    override fun onFocusSearchFailed(\n        focused: View,\n        focusDirection: Int,\n        recycler: RecyclerView.Recycler,\n        state: RecyclerView.State\n    ): View? {\n        return try {\n            val fromPos = getPosition(focused)\n            val nextPos = getNextViewPos(fromPos, focusDirection)\n            findViewByPosition(nextPos)\n        } catch (e: Exception) {\n            null\n        }\n    }\n\n    /*override fun onRequestChildFocus(\n        parent: RecyclerView,\n        state: RecyclerView.State,\n        child: View,\n        focused: View?\n    ): Boolean {\n        // android.widget.FrameLayout$LayoutParams cannot be cast to androidx.recyclerview.widget.RecyclerView$LayoutParams\n        return try {\n            if(focused != null) {\n              //  val pos = maxOf(0, getPosition(focused) - 2) // IDK WHY\n                val pos = getPosition(focused)\n                if(pos >= 0) parent.scrollToPosition(pos)\n            }\n\n            super.onRequestChildFocus(parent, state, child, focused)\n        } catch (e: Exception) {\n            false\n        }\n    }*/\n\n    // Allows moving right and left with focus https://gist.github.com/vganin/8930b41f55820ec49e4d\n    override fun onInterceptFocusSearch(focused: View, direction: Int): View? {\n        return try {\n            val fromPos = getPosition(focused)\n            val nextPos = getNextViewPos(fromPos, direction)\n            findViewByPosition(nextPos)\n        } catch (e: Exception) {\n            null\n        }\n    }\n\n    private fun getNextViewPos(fromPos: Int, direction: Int): Int {\n        val offset = calcOffsetToNextView(direction)\n\n        if (hitBorder(fromPos, offset)) {\n            return fromPos\n        }\n\n        return fromPos + offset\n    }\n\n    private fun calcOffsetToNextView(direction: Int): Int {\n        val spanCount = this.spanCount\n        val orientation = this.orientation\n\n        // fixes arabic by inverting left and right layout focus\n        val correctDirection = if (this.isLayoutRTL) {\n            when (direction) {\n                View.FOCUS_RIGHT -> View.FOCUS_LEFT\n                View.FOCUS_LEFT -> View.FOCUS_RIGHT\n                else -> direction\n            }\n        } else direction\n\n        if (orientation == VERTICAL) {\n            when (correctDirection) {\n                View.FOCUS_DOWN -> {\n                    return spanCount\n                }\n\n                View.FOCUS_UP -> {\n                    return -spanCount\n                }\n\n                View.FOCUS_RIGHT -> {\n                    return 1\n                }\n\n                View.FOCUS_LEFT -> {\n                    return -1\n                }\n            }\n        } else if (orientation == HORIZONTAL) {\n            when (correctDirection) {\n                View.FOCUS_DOWN -> {\n                    return 1\n                }\n\n                View.FOCUS_UP -> {\n                    return -1\n                }\n\n                View.FOCUS_RIGHT -> {\n                    return spanCount\n                }\n\n                View.FOCUS_LEFT -> {\n                    return -spanCount\n                }\n            }\n        }\n        return 0\n    }\n\n    private fun hitBorder(from: Int, offset: Int): Boolean {\n        val spanCount = spanCount\n\n        return if (abs(offset) == 1) {\n            val spanIndex = from % spanCount\n            val newSpanIndex = spanIndex + offset\n            newSpanIndex < 0 || newSpanIndex >= spanCount\n        } else {\n            val newPos = from + offset\n            newPos in spanCount..-1\n        }\n    }\n}\n\n// https://riptutorial.com/android/example/4810/gridlayoutmanager-with-dynamic-span-count\nclass AutofitRecyclerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :\n    RecyclerView(context, attrs) {\n\n    private val manager = GrdLayoutManager(context, 2) // THIS CONTROLS SPANS\n\n    private var columnWidth = -1\n\n    var spanCount = 0\n        set(value) {\n            field = value\n            if (value > 0) {\n                manager.spanCount = value\n            }\n        }\n\n    val itemWidth: Int\n        get() = measuredWidth / manager.spanCount\n\n    init {\n        if (attrs != null) {\n            context.withStyledAttributes(attrs, intArrayOf(android.R.attr.columnWidth)) {\n                columnWidth = getDimensionPixelSize(0, -1)\n            }\n        }\n\n        layoutManager = manager\n    }\n}\n\n/**\n * Recyclerview wherein the max item width or height is set by the biggest view to prevent inconsistent view sizes.\n */\nclass MaxRecyclerView(ctx: Context, attrs: AttributeSet) : RecyclerView(ctx, attrs) {\n    private var biggestObserved: Int = 0\n    private val orientation = LayoutManager.getProperties(context, attrs, 0, 0).orientation\n    private val isHorizontal = orientation == HORIZONTAL\n    private fun View.updateMaxSize() {\n        if (isHorizontal) {\n            this.minimumHeight = biggestObserved\n        } else {\n            this.minimumWidth = biggestObserved\n        }\n    }\n\n    override fun onChildAttachedToWindow(child: View) {\n        child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)\n        val observed = if (isHorizontal) child.measuredHeight else child.measuredWidth\n        if (observed > biggestObserved) {\n            biggestObserved = observed\n            children.forEach { it.updateMaxSize() }\n        } else {\n            child.updateMaxSize()\n        }\n        super.onChildAttachedToWindow(child)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/EasterEggMonkeFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport android.animation.Animator\nimport android.animation.AnimatorListenerAdapter\nimport android.animation.ObjectAnimator\nimport android.annotation.SuppressLint\nimport android.view.MotionEvent\nimport android.view.View\nimport android.view.animation.AccelerateInterpolator\nimport android.view.animation.LinearInterpolator\nimport android.widget.FrameLayout\nimport android.widget.ImageView\nimport androidx.core.view.isVisible\nimport androidx.lifecycle.lifecycleScope\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.FragmentEasterEggMonkeBinding\nimport com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI\nimport com.lagradost.cloudstream3.utils.UIHelper.showSystemUI\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.isActive\nimport kotlinx.coroutines.launch\nimport kotlin.random.Random\n\nclass EasterEggMonkeFragment : BaseFragment<FragmentEasterEggMonkeBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentEasterEggMonkeBinding::inflate)\n) {\n\n    // planet of monks\n    private val monkeys: List<Int> = listOf(\n        R.drawable.monke_benene,\n        R.drawable.monke_burrito,\n        R.drawable.monke_coco,\n        R.drawable.monke_cookie,\n        R.drawable.monke_flusdered,\n        R.drawable.monke_funny,\n        R.drawable.monke_like,\n        R.drawable.monke_party,\n        R.drawable.monke_sob,\n        R.drawable.monke_drink,\n        R.drawable.benene,\n        R.drawable.ic_launcher_foreground,\n        R.drawable.quick_novel_icon,\n    )\n\n    private val activeMonkeys = mutableListOf<ImageView>()\n    private var spawningJob: Job? = null\n\n    override fun fixLayout(view: View) = Unit\n\n    override fun onBindingCreated(binding: FragmentEasterEggMonkeBinding) {\n        activity?.hideSystemUI()\n        spawningJob = lifecycleScope.launch {\n            delay(1000)\n            while (isActive) {\n                spawnMonkey(binding)\n                delay(500)\n            }\n        }\n    }\n\n    private fun spawnMonkey(binding: FragmentEasterEggMonkeBinding) {\n        val newMonkey = ImageView(context ?: return).apply {\n            setImageResource(monkeys.random())\n            isVisible = true\n        }\n\n        val initialScale = Random.nextFloat() * 1.5f + 0.5f\n        newMonkey.scaleX = initialScale\n        newMonkey.scaleY = initialScale\n\n        newMonkey.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)\n        val monkeyW = newMonkey.measuredWidth * initialScale\n        val monkeyH = newMonkey.measuredHeight * initialScale\n\n        newMonkey.x = Random.nextFloat() * (binding.frame.width.toFloat() - monkeyW)\n        newMonkey.y = Random.nextFloat() * (binding.frame.height.toFloat() - monkeyH)\n\n        binding.frame.addView(newMonkey, FrameLayout.LayoutParams(\n            FrameLayout.LayoutParams.WRAP_CONTENT, FrameLayout.LayoutParams.WRAP_CONTENT\n        ))\n\n        activeMonkeys.add(newMonkey)\n\n        newMonkey.alpha = 0f\n        ObjectAnimator.ofFloat(newMonkey, View.ALPHA, 0f, 1f).apply {\n            duration = Random.nextLong(1000, 2500)\n            interpolator = AccelerateInterpolator()\n            start()\n        }\n\n        @SuppressLint(\"ClickableViewAccessibility\")\n        newMonkey.setOnTouchListener { view, event -> handleTouch(view, event, binding) }\n\n        startFloatingAnimation(newMonkey, binding)\n    }\n\n    private fun startFloatingAnimation(monkey: ImageView, binding: FragmentEasterEggMonkeBinding) {\n        val floatUpAnimator = ObjectAnimator.ofFloat(\n            monkey, View.TRANSLATION_Y, monkey.y, -monkey.height.toFloat()\n        ).apply {\n            duration = Random.nextLong(8000, 15000)\n            interpolator = LinearInterpolator()\n        }\n\n        floatUpAnimator.addListener(object : AnimatorListenerAdapter() {\n            override fun onAnimationEnd(animation: Animator) {\n                binding.frame.removeView(monkey)\n                activeMonkeys.remove(monkey)\n            }\n        })\n\n        floatUpAnimator.start()\n        monkey.tag = floatUpAnimator\n    }\n\n    private fun handleTouch(\n        view: View,\n        event: MotionEvent,\n        binding: FragmentEasterEggMonkeBinding\n    ): Boolean {\n        val monkey = view as ImageView\n        when (event.action) {\n            MotionEvent.ACTION_DOWN -> {\n                (monkey.tag as? ObjectAnimator)?.pause()\n                return true\n            }\n\n            MotionEvent.ACTION_MOVE -> {\n                // Update both X and Y positions properly\n                monkey.x = event.rawX - monkey.width / 2\n                monkey.y = event.rawY - monkey.height / 2\n\n                // Check if monkey touches the screen edge\n                if (isTouchingEdge(monkey, binding)) {\n                    removeMonkey(monkey, binding)\n                }\n                return true\n            }\n\n            MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {\n                if (isTouchingEdge(monkey, binding)) {\n                    removeMonkey(monkey, binding)\n                } else {\n                    startFloatingAnimation(monkey, binding)\n                }\n                return true\n            }\n        }\n        return false\n    }\n\n    private fun isTouchingEdge(monkey: ImageView, binding: FragmentEasterEggMonkeBinding): Boolean {\n        return monkey.x <= 0 || monkey.x + monkey.width >= binding.frame.width ||\n                monkey.y <= 0 || monkey.y + monkey.height >= binding.frame.height\n    }\n\n    private fun removeMonkey(monkey: ImageView, binding: FragmentEasterEggMonkeBinding) {\n        // Fade out and remove the monkey\n        ObjectAnimator.ofFloat(monkey, View.ALPHA, 1f, 0f).apply {\n            duration = 300\n            addListener(object : AnimatorListenerAdapter() {\n                override fun onAnimationEnd(animation: Animator) {\n                    binding.frame.removeView(monkey)\n                    activeMonkeys.remove(monkey)\n                }\n            })\n            start()\n        }\n    }\n\n    override fun onDestroyView() {\n        super.onDestroyView()\n        activity?.showSystemUI()\n        spawningJob?.cancel()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/MiniControllerFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.util.AttributeSet\nimport android.view.View\nimport android.widget.LinearLayout\nimport android.widget.ProgressBar\nimport android.widget.RelativeLayout\nimport androidx.core.content.withStyledAttributes\nimport com.google.android.gms.cast.framework.media.widget.MiniControllerFragment\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.utils.UIHelper.adjustAlpha\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\n\n\nclass MyMiniControllerFragment : MiniControllerFragment() {\n    var currentColor: Int = 0\n\n    override fun onDestroy() {\n        currentColor = 0\n        super.onDestroy()\n    }\n\n    // I KNOW, KINDA SPAGHETTI SOLUTION, BUT IT WORKS\n    override fun onInflate(context: Context, attributeSet: AttributeSet, bundle: Bundle?) {\n        if (currentColor == 0) {\n            context.withStyledAttributes(attributeSet, R.styleable.CustomCast, 0, 0) {\n                if (hasValue(R.styleable.CustomCast_customCastBackgroundColor)) {\n                    currentColor = getColor(R.styleable.CustomCast_customCastBackgroundColor, 0)\n                }\n            }\n        }\n\n        super.onInflate(context, attributeSet, bundle)\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        // SEE https://github.com/dandar3/android-google-play-services-cast-framework/blob/master/res/layout/cast_mini_controller.xml\n        try {\n            val progressBar: ProgressBar? = view.findViewById(R.id.progressBar)\n            val containerAll: LinearLayout? = view.findViewById(com.google.android.gms.cast.framework.R.id.container_all)\n            val containerCurrent: RelativeLayout? = view.findViewById(com.google.android.gms.cast.framework.R.id.container_current)\n\n            context?.let { ctx ->\n                progressBar?.setBackgroundColor(\n                    adjustAlpha(\n                        ctx.colorFromAttribute(R.attr.colorPrimary),\n                        0.35f\n                    )\n                )\n                val params = RelativeLayout.LayoutParams(\n                    RelativeLayout.LayoutParams.MATCH_PARENT,\n                    2.toPx\n                )\n\n                progressBar?.layoutParams = params\n                val color = currentColor\n                if (color != 0)\n                    containerCurrent?.setBackgroundColor(color)\n            }\n            val child = containerAll?.getChildAt(0)\n            child?.alpha = 0f // REMOVE GRADIENT\n        } catch (e: Exception) {\n            // JUST IN CASE\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/NonFinalAdapterListUpdateCallback.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport android.annotation.SuppressLint\nimport androidx.recyclerview.widget.DiffUtil\nimport androidx.recyclerview.widget.ListUpdateCallback\nimport androidx.recyclerview.widget.RecyclerView\n\n\n/**\n * ListUpdateCallback that dispatches update events to the given adapter.\n *\n * @see DiffUtil.DiffResult.dispatchUpdatesTo\n */\nopen class NonFinalAdapterListUpdateCallback\n/**\n * Creates an AdapterListUpdateCallback that will dispatch update events to the given adapter.\n *\n * @param mAdapter The Adapter to send updates to.\n */(private var mAdapter: RecyclerView.Adapter<*>) :\n    ListUpdateCallback {\n\n        override fun onInserted(position: Int, count: Int) {\n        mAdapter.notifyItemRangeInserted(position, count)\n    }\n\n    override fun onRemoved(position: Int, count: Int) {\n        mAdapter.notifyItemRangeRemoved(position, count)\n    }\n\n    override fun onMoved(fromPosition: Int, toPosition: Int) {\n        mAdapter.notifyItemMoved(fromPosition, toPosition)\n    }\n\n    @SuppressLint(\"UnknownNullness\") // b/240775049: Cannot annotate properly\n    override fun onChanged(position: Int, count: Int, payload: Any?) {\n        mAdapter.notifyItemRangeChanged(position, count, payload)\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/WatchType.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport androidx.annotation.DrawableRes\nimport androidx.annotation.StringRes\nimport com.lagradost.cloudstream3.R\n\nenum class WatchType(val internalId: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int) {\n    WATCHING(0, R.string.type_watching, R.drawable.ic_baseline_bookmark_24),\n    COMPLETED(1, R.string.type_completed, R.drawable.ic_baseline_bookmark_24),\n    ONHOLD(2, R.string.type_on_hold, R.drawable.ic_baseline_bookmark_24),\n    DROPPED(3, R.string.type_dropped, R.drawable.ic_baseline_bookmark_24),\n    PLANTOWATCH(4, R.string.type_plan_to_watch, R.drawable.ic_baseline_bookmark_24),\n    NONE(5, R.string.type_none, R.drawable.ic_baseline_add_24);\n\n    companion object {\n        fun fromInternalId(id: Int?) = entries.find { value -> value.internalId == id } ?: NONE\n    }\n}\n\nenum class SyncWatchType(val internalId: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int) {\n    NONE(-1, R.string.type_none, R.drawable.ic_baseline_add_24),\n    WATCHING(0, R.string.type_watching, R.drawable.ic_baseline_bookmark_24),\n    COMPLETED(1, R.string.type_completed, R.drawable.ic_baseline_bookmark_24),\n    ONHOLD(2, R.string.type_on_hold, R.drawable.ic_baseline_bookmark_24),\n    DROPPED(3, R.string.type_dropped, R.drawable.ic_baseline_bookmark_24),\n    PLANTOWATCH(4, R.string.type_plan_to_watch, R.drawable.ic_baseline_bookmark_24),\n    REWATCHING(5, R.string.type_re_watching, R.drawable.ic_baseline_bookmark_24);\n\n    companion object {\n        fun fromInternalId(id: Int?) = entries.find { value -> value.internalId == id } ?: NONE\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/WebviewFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui\n\nimport android.os.Bundle\nimport android.view.View\nimport android.webkit.JavascriptInterface\nimport android.webkit.WebResourceRequest\nimport android.webkit.WebView\nimport android.webkit.WebViewClient\nimport androidx.fragment.app.FragmentActivity\nimport androidx.navigation.fragment.findNavController\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.databinding.FragmentWebviewBinding\nimport com.lagradost.cloudstream3.network.WebViewResolver\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadRepository\n\nclass WebviewFragment : BaseFragment<FragmentWebviewBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentWebviewBinding::inflate)\n) {\n\n    override fun fixLayout(view: View) = Unit\n\n    override fun onBindingCreated(binding: FragmentWebviewBinding) {\n        val url = arguments?.getString(WEBVIEW_URL) ?: \"\".also {\n            findNavController().popBackStack()\n        }\n\n        binding.webView.webViewClient = object : WebViewClient() {\n            override fun shouldOverrideUrlLoading(\n                view: WebView?,\n                request: WebResourceRequest?\n            ): Boolean {\n                val requestUrl = request?.url.toString()\n                val performedAction = MainActivity.handleAppIntentUrl(activity, requestUrl, true)\n                if (performedAction) {\n                    findNavController().popBackStack()\n                    return true\n                }\n\n                return super.shouldOverrideUrlLoading(view, request)\n            }\n        }\n\n        binding.webView.apply {\n            WebViewResolver.webViewUserAgent = settings.userAgentString\n\n            addJavascriptInterface(RepoApi(activity), \"RepoApi\")\n            settings.javaScriptEnabled = true\n            settings.userAgentString = USER_AGENT\n            settings.domStorageEnabled = true\n\n            loadUrl(url)\n        }\n    }\n\n    companion object {\n        private const val WEBVIEW_URL = \"webview_url\"\n        fun newInstance(webViewUrl: String) =\n            Bundle().apply {\n                putString(WEBVIEW_URL, webViewUrl)\n            }\n    }\n\n    private class RepoApi(val activity: FragmentActivity?) {\n        @JavascriptInterface\n        fun installRepo(repoUrl: String) {\n            activity?.loadRepository(repoUrl)\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.account\n\nimport android.os.Build\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.core.content.ContextCompat\nimport androidx.core.view.isVisible\nimport coil3.transform.RoundedCornersTransformation\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.AccountListItemAddBinding\nimport com.lagradost.cloudstream3.databinding.AccountListItemBinding\nimport com.lagradost.cloudstream3.databinding.AccountListItemEditBinding\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.account.AccountHelper.showAccountEditDialog\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\n\nclass AccountAdapter(\n    private val accountSelectCallback: (DataStoreHelper.Account) -> Unit,\n    private val accountCreateCallback: (DataStoreHelper.Account) -> Unit,\n    private val accountEditCallback: (DataStoreHelper.Account) -> Unit,\n    private val accountDeleteCallback: (DataStoreHelper.Account) -> Unit\n) : NoStateAdapter<DataStoreHelper.Account>() {\n\n    companion object {\n        const val VIEW_TYPE_SELECT_ACCOUNT = 0\n        const val VIEW_TYPE_EDIT_ACCOUNT = 2\n    }\n\n\n    override val footers: Int = 1\n    var viewType = VIEW_TYPE_SELECT_ACCOUNT\n\n    override fun customContentViewType(item: DataStoreHelper.Account): Int {\n        return viewType\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Any>,\n        item: DataStoreHelper.Account,\n        position: Int\n    ) {\n        when (val binding = holder.view) {\n            is AccountListItemBinding -> binding.apply {\n                val isTv = isLayout(TV or EMULATOR) || !root.isInTouchMode\n\n                val isLastUsedAccount = item.keyIndex == DataStoreHelper.selectedKeyIndex\n\n                accountName.text = item.name\n                accountImage.loadImage(item.image)\n                lockIcon.isVisible = item.lockPin != null\n                outline.isVisible = !isTv && isLastUsedAccount\n\n                if (isTv) {\n                    // For emulator but this is fine on TV also\n                    root.isFocusableInTouchMode = true\n                    if (isLastUsedAccount) {\n                        root.requestFocus()\n                    }\n\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                        root.foreground = ContextCompat.getDrawable(\n                            root.context,\n                            R.drawable.outline_drawable\n                        )\n                    }\n                } else {\n                    root.setOnLongClickListener {\n                        showAccountEditDialog(\n                            context = root.context,\n                            account = item,\n                            isNewAccount = false,\n                            accountEditCallback = { account ->\n                                accountEditCallback.invoke(\n                                    account\n                                )\n                            },\n                            accountDeleteCallback = { account ->\n                                accountDeleteCallback.invoke(\n                                    account\n                                )\n                            }\n                        )\n\n                        true\n                    }\n                }\n\n                root.setOnClickListener {\n                    accountSelectCallback.invoke(item)\n                }\n            }\n\n            is AccountListItemEditBinding -> binding.apply {\n                val isTv = isLayout(TV or EMULATOR) || !root.isInTouchMode\n\n                val isLastUsedAccount = item.keyIndex == DataStoreHelper.selectedKeyIndex\n\n                accountName.text = item.name\n                accountImage.loadImage(item.image) {\n                    RoundedCornersTransformation(10f)\n                }\n                lockIcon.isVisible = item.lockPin != null\n                outline.isVisible = !isTv && isLastUsedAccount\n\n                if (isTv) {\n                    // For emulator but this is fine on TV also\n                    root.isFocusableInTouchMode = true\n                    if (isLastUsedAccount) {\n                        root.requestFocus()\n                    }\n\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                        root.foreground = ContextCompat.getDrawable(\n                            root.context,\n                            R.drawable.outline_drawable\n                        )\n                    }\n                }\n\n                root.setOnClickListener {\n                    showAccountEditDialog(\n                        context = root.context,\n                        account = item,\n                        isNewAccount = false,\n                        accountEditCallback = { account -> accountEditCallback.invoke(account) },\n                        accountDeleteCallback = { account ->\n                            accountDeleteCallback.invoke(\n                                account\n                            )\n                        }\n                    )\n                }\n            }\n        }\n    }\n\n    override fun onBindFooter(holder: ViewHolderState<Any>) {\n        val binding = holder.view as? AccountListItemAddBinding ?: return\n        binding.apply {\n            root.setOnClickListener {\n                val accounts = this@AccountAdapter.immutableCurrentList\n\n                val remainingImages =\n                    DataStoreHelper.profileImages.toSet() - accounts.filter { it.customImage == null }\n                        .mapNotNull { DataStoreHelper.profileImages.getOrNull(it.defaultImageIndex) }\n                        .toSet()\n\n                val image =\n                    DataStoreHelper.profileImages.indexOf(\n                        remainingImages.randomOrNull()\n                            ?: DataStoreHelper.profileImages.random()\n                    )\n                val keyIndex = (accounts.maxOfOrNull { it.keyIndex } ?: 0) + 1\n\n                val accountName = root.context.getString(R.string.account)\n\n                showAccountEditDialog(\n                    root.context,\n                    DataStoreHelper.Account(\n                        keyIndex = keyIndex,\n                        name = \"$accountName $keyIndex\",\n                        customImage = null,\n                        defaultImageIndex = image\n                    ),\n                    isNewAccount = true,\n                    accountEditCallback = { account -> accountCreateCallback.invoke(account) },\n                    accountDeleteCallback = {}\n                )\n            }\n        }\n    }\n\n    override fun onCreateFooter(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            AccountListItemAddBinding.inflate(\n                LayoutInflater.from(parent.context),\n                parent,\n                false\n            )\n        )\n    }\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            when (viewType) {\n                VIEW_TYPE_SELECT_ACCOUNT -> {\n                    AccountListItemBinding.inflate(\n                        LayoutInflater.from(parent.context),\n                        parent,\n                        false\n                    )\n                }\n\n                VIEW_TYPE_EDIT_ACCOUNT -> {\n                    AccountListItemEditBinding.inflate(\n                        LayoutInflater.from(parent.context),\n                        parent,\n                        false\n                    )\n                }\n\n                else -> throw IllegalArgumentException(\"Invalid view type\")\n            }\n        )\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountHelper.kt",
    "content": "package com.lagradost.cloudstream3.ui.account\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.os.Bundle\nimport android.text.Editable\nimport android.view.LayoutInflater\nimport android.view.inputmethod.EditorInfo\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.annotation.StringRes\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.core.widget.doOnTextChanged\nimport androidx.lifecycle.ViewModelProvider\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport coil3.ImageLoader\nimport coil3.request.ImageRequest\nimport coil3.request.allowHardware\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.AccountEditDialogBinding\nimport com.lagradost.cloudstream3.databinding.AccountSelectLinearBinding\nimport com.lagradost.cloudstream3.databinding.BottomInputDialogBinding\nimport com.lagradost.cloudstream3.databinding.LockPinDialogBinding\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.ui.result.setLinearListLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getDefaultAccount\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UIHelper.showInputMethod\n\nobject AccountHelper {\n    fun showAccountEditDialog(\n        context: Context,\n        account: DataStoreHelper.Account,\n        isNewAccount: Boolean,\n        accountEditCallback: (DataStoreHelper.Account) -> Unit,\n        accountDeleteCallback: (DataStoreHelper.Account) -> Unit\n    ) {\n        val binding = AccountEditDialogBinding.inflate(LayoutInflater.from(context), null, false)\n        val builder = AlertDialog.Builder(context, R.style.AlertDialogCustom)\n            .setView(binding.root)\n\n        var currentEditAccount = account\n        val dialog = builder.show()\n\n        if (!isNewAccount) binding.title.setText(R.string.edit_account)\n\n        // Set up the dialog content\n        binding.accountName.text = Editable.Factory.getInstance()?.newEditable(account.name)\n        binding.accountName.doOnTextChanged { text, _, _, _ ->\n            currentEditAccount = currentEditAccount.copy(name = text?.toString() ?: \"\")\n        }\n\n        binding.deleteBtt.isGone = isNewAccount\n        binding.deleteBtt.setOnClickListener {\n            val dialogClickListener = DialogInterface.OnClickListener { _, which ->\n                when (which) {\n                    DialogInterface.BUTTON_POSITIVE -> {\n                        accountDeleteCallback.invoke(account)\n                        dialog?.dismissSafe()\n                    }\n\n                    DialogInterface.BUTTON_NEGATIVE -> {\n                        dialog?.dismissSafe()\n                    }\n                }\n            }\n\n            try {\n                AlertDialog.Builder(context).setTitle(R.string.delete).setMessage(\n                    context.getString(R.string.delete_message).format(\n                        currentEditAccount.name\n                    )\n                )\n                    .setPositiveButton(R.string.delete, dialogClickListener)\n                    .setNegativeButton(R.string.cancel, dialogClickListener)\n                    .show().setDefaultFocus()\n            } catch (t: Throwable) {\n                logError(t)\n            }\n        }\n\n        binding.cancelBtt.setOnClickListener {\n            dialog?.dismissSafe()\n        }\n\n        // Handle the profile picture and its interactions\n        binding.accountImage.loadImage(account.image)\n        binding.accountImage.setOnClickListener {\n            // Roll the image forwards once\n            currentEditAccount = currentEditAccount.copy(customImage = null)\n            currentEditAccount =\n                currentEditAccount.copy(defaultImageIndex = (currentEditAccount.defaultImageIndex + 1) % DataStoreHelper.profileImages.size)\n            binding.accountImage.loadImage(currentEditAccount.image)\n        }\n\n        // Handle applying changes\n        binding.applyBtt.setOnClickListener {\n            if (currentEditAccount.lockPin != null) {\n                // Ask for the current PIN\n                showPinInputDialog(context, currentEditAccount.lockPin, false) { pin ->\n                    if (pin == null) return@showPinInputDialog\n                    // PIN is correct, proceed to update the account\n                    accountEditCallback.invoke(currentEditAccount)\n                    dialog.dismissSafe()\n                }\n            } else {\n                // No lock PIN set, proceed to update the account\n                accountEditCallback.invoke(currentEditAccount)\n                dialog.dismissSafe()\n            }\n        }\n\n        // Handle setting or changing the PIN\n        if (currentEditAccount.keyIndex == getDefaultAccount(context).keyIndex) {\n            binding.lockProfileCheckbox.isVisible = false\n            if (currentEditAccount.lockPin != null) {\n                currentEditAccount = currentEditAccount.copy(lockPin = null)\n            }\n        }\n\n        var canSetPin = true\n\n        binding.lockProfileCheckbox.isChecked = currentEditAccount.lockPin != null\n\n        binding.lockProfileCheckbox.setOnCheckedChangeListener { _, isChecked ->\n            if (isChecked) {\n                if (canSetPin) {\n                    showPinInputDialog(context, null, true) { pin ->\n                        if (pin == null) {\n                            binding.lockProfileCheckbox.isChecked = false\n                            return@showPinInputDialog\n                        }\n\n                        currentEditAccount = currentEditAccount.copy(lockPin = pin)\n                    }\n                }\n            } else {\n                if (currentEditAccount.lockPin != null) {\n                    // Ask for the current PIN\n                    showPinInputDialog(context, currentEditAccount.lockPin, true) { pin ->\n                        if (pin == null || pin != currentEditAccount.lockPin) {\n                            canSetPin = false\n                            binding.lockProfileCheckbox.isChecked = true\n                        } else {\n                            currentEditAccount = currentEditAccount.copy(lockPin = null)\n                        }\n                    }\n                }\n            }\n        }\n\n        canSetPin = true\n\n        binding.editProfilePhotoButton.setOnClickListener({\n            val bottomSheetDialog = BottomSheetDialog(context)\n            val sheetBinding = BottomInputDialogBinding.inflate(LayoutInflater.from(context))\n            bottomSheetDialog.setContentView(sheetBinding.root)\n            bottomSheetDialog.show()\n\n            sheetBinding.apply {\n                text1.text = context.getString(R.string.edit_profile_image_title)\n                nginxTextInput.hint = context.getString(R.string.edit_profile_image_hint)\n\n                applyBtt.setOnClickListener({\n                    val url = sheetBinding.nginxTextInput.text.toString()\n                    if (url.isNotEmpty()) {\n                        val imageLoader = ImageLoader(context)\n                        val request = ImageRequest.Builder(context)\n                            .data(url)\n                            .allowHardware(false)\n                            .listener(\n                                onSuccess = { _, _ ->\n                                    currentEditAccount = currentEditAccount.copy(customImage = url)\n                                    binding.accountImage.loadImage(url)\n                                    showToast(\n                                        R.string.edit_profile_image_success,\n                                        Toast.LENGTH_SHORT\n                                    )\n                                    bottomSheetDialog.dismiss()\n                                },\n                                onError = { _, _ ->\n                                    showToast(\n                                        R.string.edit_profile_image_error_invalid,\n                                        Toast.LENGTH_SHORT\n                                    )\n                                }\n                            )\n                            .build()\n                        imageLoader.enqueue(request)\n                    } else {\n                        showToast(R.string.edit_profile_image_error_empty, Toast.LENGTH_SHORT)\n                    }\n                    bottomSheetDialog.dismissSafe()\n                })\n                sheetBinding.cancelBtt.setOnClickListener({\n                    bottomSheetDialog.dismissSafe()\n                })\n            }\n        })\n    }\n\n    fun showPinInputDialog(\n        context: Context,\n        currentPin: String?,\n        editAccount: Boolean,\n        forStartup: Boolean = false,\n        errorText: String? = null,\n        callback: (String?) -> Unit\n    ) {\n        fun TextView.visibleWithText(@StringRes textRes: Int) {\n            isVisible = true\n            setText(textRes)\n        }\n\n        fun TextView.visibleWithText(text: String?) {\n            isVisible = true\n            setText(text)\n        }\n\n        val binding = LockPinDialogBinding.inflate(LayoutInflater.from(context))\n\n        val isPinSet = currentPin != null\n        val isNewPin = editAccount && !isPinSet\n        val isEditPin = editAccount && isPinSet\n\n        val titleRes = if (isEditPin) R.string.enter_current_pin else R.string.enter_pin\n\n        var isPinValid = false\n\n        val builder = AlertDialog.Builder(context, R.style.AlertDialogCustom)\n            .setView(binding.root)\n            .setTitle(titleRes)\n            .setNegativeButton(R.string.cancel) { _, _ ->\n                callback.invoke(null)\n            }\n            .setOnCancelListener {\n                callback.invoke(null)\n            }\n            .setOnDismissListener {\n                if (!isPinValid) {\n                    callback.invoke(null)\n                }\n            }\n\n        if (forStartup) {\n            val currentAccount = DataStoreHelper.accounts.firstOrNull {\n                it.keyIndex == DataStoreHelper.selectedKeyIndex\n            }\n\n            builder.setTitle(context.getString(R.string.enter_pin_with_name, currentAccount?.name))\n            builder.setOnDismissListener {\n                if (!isPinValid) {\n                    context.getActivity()?.finish()\n                }\n            }\n            // So that if they don't know the PIN for the current account,\n            // they don't get completely locked out\n            builder.setNeutralButton(R.string.use_default_account) { _, _ ->\n                val activity = context.getActivity()\n                if (activity is AccountSelectActivity) {\n                    isPinValid = true\n                    activity.accountViewModel.handleAccountSelect(getDefaultAccount(context), activity)\n                }\n            }\n        }\n\n        if (isNewPin) {\n            if (errorText != null) binding.pinEditTextError.visibleWithText(errorText)\n            builder.setPositiveButton(R.string.setup_done) { _, _ ->\n                if (!isPinValid) {\n                    // If the done button is pressed and there is an error,\n                    // ask again, and mention the error that caused this.\n                    showPinInputDialog(\n                        context = binding.root.context,\n                        currentPin = null,\n                        editAccount = true,\n                        errorText = binding.pinEditTextError.text.toString(),\n                        callback = callback\n                    )\n                } else {\n                    val enteredPin = binding.pinEditText.text.toString()\n                    callback.invoke(enteredPin)\n                }\n            }\n        }\n\n        val dialog = builder.create()\n\n        binding.pinEditText.doOnTextChanged { text, _, _, _ ->\n            val enteredPin = text.toString()\n            val isEnteredPinValid = enteredPin.length == 4\n\n            if (isEnteredPinValid) {\n                if (isPinSet) {\n                    if (enteredPin != currentPin) {\n                        binding.pinEditTextError.visibleWithText(R.string.pin_error_incorrect)\n                        binding.pinEditText.text = null\n                        isPinValid = false\n                    } else {\n                        binding.pinEditTextError.isVisible = false\n                        isPinValid = true\n\n                        callback.invoke(enteredPin)\n                        dialog.dismissSafe()\n                    }\n                } else {\n                    binding.pinEditTextError.isVisible = false\n                    isPinValid = true\n                }\n            } else if (isNewPin) {\n                binding.pinEditTextError.visibleWithText(R.string.pin_error_length)\n                isPinValid = false\n            }\n        }\n\n        // Detect IME_ACTION_DONE\n        binding.pinEditText.setOnEditorActionListener { _, actionId, _ ->\n            if (actionId == EditorInfo.IME_ACTION_DONE && isPinValid) {\n                val enteredPin = binding.pinEditText.text.toString()\n                callback.invoke(enteredPin)\n                dialog.dismissSafe()\n            }\n            true\n        }\n\n        // We don't want to accidentally have the dialog dismiss when clicking outside of it.\n        // That is what the cancel button is for.\n        dialog.setCanceledOnTouchOutside(false)\n\n        dialog.show()\n\n        // Auto focus on PIN input and show keyboard\n        binding.pinEditText.requestFocus()\n        binding.pinEditText.postDelayed({\n            showInputMethod(binding.pinEditText)\n        }, 200)\n    }\n\n    fun Activity?.showAccountSelectLinear() {\n        val activity = this as? MainActivity ?: return\n        val viewModel = ViewModelProvider(activity)[AccountViewModel::class.java]\n\n        val binding: AccountSelectLinearBinding = AccountSelectLinearBinding.inflate(\n            LayoutInflater.from(activity)\n        )\n\n        val builder = BottomSheetDialog(activity)\n        builder.setContentView(binding.root)\n        builder.show()\n\n        binding.manageAccountsButton.setOnClickListener {\n            activity.navigate(\n                R.id.accountSelectActivity,\n                Bundle().apply { putBoolean(\"isEditingFromMainActivity\", true) }\n            )\n            builder.dismissSafe()\n        }\n\n        val recyclerView: RecyclerView = binding.accountRecyclerView\n\n        val itemSize = recyclerView.resources.getDimensionPixelSize(\n            R.dimen.account_select_linear_item_size\n        )\n\n        recyclerView.addItemDecoration(AccountSelectLinearItemDecoration(itemSize))\n\n        recyclerView.setLinearListLayout(isHorizontal = true)\n\n        val currentAccount = DataStoreHelper.accounts.firstOrNull {\n            it.keyIndex == DataStoreHelper.selectedKeyIndex\n        } ?: getDefaultAccount(activity)\n\n        // We want to make sure the accounts are up-to-date\n        viewModel.handleAccountSelect(\n            currentAccount,\n            activity,\n            reloadForActivity = true\n        )\n\n        activity.observe(viewModel.accounts) { liveAccounts ->\n            recyclerView.adapter = AccountAdapter(\n                accountSelectCallback = { account ->\n                    viewModel.handleAccountSelect(account, activity)\n                    builder.dismissSafe()\n                },\n                accountCreateCallback = { viewModel.handleAccountUpdate(it, activity) },\n                accountEditCallback = { viewModel.handleAccountUpdate(it, activity) },\n                accountDeleteCallback = { viewModel.handleAccountDelete(it, activity) }\n            ).apply {\n                submitList(liveAccounts)\n            }\n\n            activity.observe(viewModel.selectedKeyIndex) { selectedKeyIndex ->\n                // Scroll to current account (which is focused by default)\n                val layoutManager = recyclerView.layoutManager as LinearLayoutManager\n                layoutManager.scrollToPositionWithOffset(selectedKeyIndex, 0)\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectActivity.kt",
    "content": "package com.lagradost.cloudstream3.ui.account\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport android.util.Log\nimport androidx.fragment.app.FragmentActivity\nimport androidx.activity.viewModels\nimport androidx.preference.PreferenceManager\nimport androidx.recyclerview.widget.GridLayoutManager\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.CommonActivity.loadThemes\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.ActivityAccountSelectBinding\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.ui.AutofitRecyclerView\nimport com.lagradost.cloudstream3.ui.account.AccountAdapter.Companion.VIEW_TYPE_EDIT_ACCOUNT\nimport com.lagradost.cloudstream3.ui.account.AccountAdapter.Companion.VIEW_TYPE_SELECT_ACCOUNT\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.BiometricCallback\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.biometricPrompt\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.promptInfo\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.accounts\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.selectedKeyIndex\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setAccount\nimport com.lagradost.cloudstream3.utils.UIHelper.enableEdgeToEdgeCompat\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.openActivity\nimport com.lagradost.cloudstream3.utils.UIHelper.setNavigationBarColorCompat\n\nclass AccountSelectActivity : FragmentActivity(), BiometricCallback {\n\n    val accountViewModel: AccountViewModel by viewModels()\n\n    @SuppressLint(\"NotifyDataSetChanged\")\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        loadThemes(this)\n\n        enableEdgeToEdgeCompat()\n        setNavigationBarColorCompat(R.attr.primaryBlackBackground)\n\n        // Are we editing and coming from MainActivity?\n        val isEditingFromMainActivity = intent.getBooleanExtra(\n            \"isEditingFromMainActivity\",\n            false\n        )\n\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        val skipStartup = settingsManager.getBoolean(\n            getString(R.string.skip_startup_account_select_key), false\n        ) || accounts.count() <= 1\n\n        fun askBiometricAuth() {\n\n            if (isLayout(PHONE) && isAuthEnabled(this)) {\n                if (deviceHasPasswordPinLock(this)) {\n                    startBiometricAuthentication(\n                        this,\n                        R.string.biometric_authentication_title,\n                        false\n                    )\n\n                    promptInfo?.let { prompt ->\n                        biometricPrompt?.authenticate(prompt)\n                    }\n                }\n            }\n        }\n\n        observe(accountViewModel.isAllowedLogin) { isAllowedLogin ->\n            if (isAllowedLogin) {\n                // We are allowed to continue to MainActivity\n                navigateToMainActivity()\n            }\n        }\n\n        // Don't show account selection if there is only\n        // one account that exists\n        if (!isEditingFromMainActivity && skipStartup) {\n            val currentAccount = accounts.firstOrNull { it.keyIndex == selectedKeyIndex }\n            if (currentAccount?.lockPin != null) {\n                CommonActivity.init(this)\n                accountViewModel.handleAccountSelect(currentAccount, this, true)\n            } else {\n                if (accounts.count() > 1) {\n                    showToast(\n                        this, getString(\n                            R.string.logged_account,\n                            currentAccount?.name\n                        )\n                    )\n                }\n\n                navigateToMainActivity()\n            }\n\n            return\n        }\n\n        CommonActivity.init(this)\n\n        val binding = ActivityAccountSelectBinding.inflate(layoutInflater)\n        setContentView(binding.root)\n        fixSystemBarsPadding(binding.root, padTop = false)\n\n        val recyclerView: AutofitRecyclerView = binding.accountRecyclerView\n\n        observe(accountViewModel.accounts) { liveAccounts ->\n            val adapter = AccountAdapter(\n                // Handle the selected account\n                accountSelectCallback = {\n                    accountViewModel.handleAccountSelect(it, this)\n                },\n                accountCreateCallback = { accountViewModel.handleAccountUpdate(it, this) },\n                accountEditCallback = {\n                    accountViewModel.handleAccountUpdate(it, this)\n                    // We came from MainActivity, return there\n                    // and switch to the edited account\n                    if (isEditingFromMainActivity) {\n                        setAccount(it)\n                        navigateToMainActivity()\n                    }\n                },\n                accountDeleteCallback = { accountViewModel.handleAccountDelete(it, this) }\n            ).apply {\n                submitList(liveAccounts)\n            }\n\n            recyclerView.adapter = adapter\n\n            if (isLayout(TV or EMULATOR)) {\n                binding.editAccountButton.setBackgroundResource(\n                    R.drawable.player_button_tv_attr_no_bg\n                )\n            }\n\n            observe(accountViewModel.selectedKeyIndex) { selectedKeyIndex ->\n                // Scroll to current account (which is focused by default)\n                val layoutManager = recyclerView.layoutManager as GridLayoutManager\n                layoutManager.scrollToPositionWithOffset(selectedKeyIndex, 0)\n            }\n\n            observe(accountViewModel.isEditing) { isEditing ->\n                if (isEditing) {\n                    binding.editAccountButton.setImageResource(R.drawable.ic_baseline_close_24)\n                    binding.title.setText(R.string.manage_accounts)\n                    adapter.viewType = VIEW_TYPE_EDIT_ACCOUNT\n                } else {\n                    binding.editAccountButton.setImageResource(R.drawable.ic_baseline_edit_24)\n                    binding.title.setText(R.string.select_an_account)\n                    adapter.viewType = VIEW_TYPE_SELECT_ACCOUNT\n                }\n\n                adapter.notifyDataSetChanged()\n            }\n\n            if (isEditingFromMainActivity) {\n                accountViewModel.setIsEditing(true)\n            }\n\n            binding.editAccountButton.setOnClickListener {\n                // We came from MainActivity, return there\n                // and resume its state\n                if (isEditingFromMainActivity) {\n                    navigateToMainActivity()\n                    return@setOnClickListener\n                }\n\n                accountViewModel.toggleIsEditing()\n            }\n\n            if (isLayout(TV or EMULATOR)) {\n                recyclerView.spanCount = if (liveAccounts.count() + 1 <= 6) {\n                    liveAccounts.count() + 1\n                } else 6\n            }\n        }\n\n        askBiometricAuth()\n    }\n\n    private fun navigateToMainActivity() {\n        openActivity(MainActivity::class.java)\n        finish() // Finish the account selection activity\n    }\n\n    override fun onAuthenticationSuccess() {\n        Log.i(BiometricAuthenticator.TAG, \"Authentication successful in AccountSelectActivity\")\n    }\n\n    override fun onAuthenticationError() {\n        finish()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountSelectLinearItemDecoration.kt",
    "content": "package com.lagradost.cloudstream3.ui.account\n\nimport android.graphics.Rect\nimport android.view.View\nimport androidx.recyclerview.widget.RecyclerView\n\nclass AccountSelectLinearItemDecoration(private val size: Int) : RecyclerView.ItemDecoration() {\n    override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {\n        val layoutParams = view.layoutParams as RecyclerView.LayoutParams\n        layoutParams.width = size\n        layoutParams.height = size\n        view.layoutParams = layoutParams\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.account\n\nimport android.content.Context\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.context\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKeys\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.ui.account.AccountHelper.showPinInputDialog\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAccounts\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getDefaultAccount\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setAccount\n\nclass AccountViewModel : ViewModel() {\n    private fun getAllAccounts(): List<DataStoreHelper.Account> {\n        return context?.let { getAccounts(it) } ?: DataStoreHelper.accounts.toList()\n    }\n\n    private val _accounts: MutableLiveData<List<DataStoreHelper.Account>> = MutableLiveData(getAllAccounts())\n    val accounts: LiveData<List<DataStoreHelper.Account>> = _accounts\n\n    private val _isEditing = MutableLiveData(false)\n    val isEditing: LiveData<Boolean> = _isEditing\n\n    private val _isAllowedLogin = MutableLiveData(false)\n    val isAllowedLogin: LiveData<Boolean> = _isAllowedLogin\n\n    private val _selectedKeyIndex = MutableLiveData(\n        getAllAccounts().indexOfFirst {\n            it.keyIndex == DataStoreHelper.selectedKeyIndex\n        }\n    )\n    val selectedKeyIndex: LiveData<Int> = _selectedKeyIndex\n\n    fun setIsEditing(value: Boolean) {\n        _isEditing.postValue(value)\n    }\n\n    fun toggleIsEditing() {\n        _isEditing.postValue(!(_isEditing.value ?: false))\n    }\n\n    fun handleAccountUpdate(\n        account: DataStoreHelper.Account,\n        context: Context\n    ) {\n        val currentAccounts = getAccounts(context).toMutableList()\n\n        val overrideIndex = currentAccounts.indexOfFirst { it.keyIndex == account.keyIndex }\n\n        if (overrideIndex != -1) {\n            currentAccounts[overrideIndex] = account\n        } else currentAccounts.add(account)\n\n        val currentHomePage = DataStoreHelper.currentHomePage\n\n        setAccount(account)\n\n        DataStoreHelper.currentHomePage = currentHomePage\n        DataStoreHelper.accounts = currentAccounts.toTypedArray()\n\n        _accounts.postValue(getAccounts(context))\n        _selectedKeyIndex.postValue(getAccounts(context).indexOf(account))\n        MainActivity.reloadAccountEvent(true)\n    }\n\n    fun handleAccountDelete(\n        account: DataStoreHelper.Account,\n        context: Context\n    ) {\n        removeKeys(account.keyIndex.toString())\n\n        val currentAccounts = getAccounts(context).toMutableList()\n\n        currentAccounts.removeIf { it.keyIndex == account.keyIndex }\n\n        DataStoreHelper.accounts = currentAccounts.toTypedArray()\n\n        if (account.keyIndex == DataStoreHelper.selectedKeyIndex) {\n            setAccount(getDefaultAccount(context))\n        }\n\n        _accounts.postValue(getAccounts(context))\n        _selectedKeyIndex.postValue(getAllAccounts().indexOfFirst {\n            it.keyIndex == DataStoreHelper.selectedKeyIndex\n        })\n        MainActivity.reloadAccountEvent(true)\n    }\n\n    fun handleAccountSelect(\n        account: DataStoreHelper.Account,\n        context: Context,\n        forStartup: Boolean = false,\n        reloadForActivity: Boolean = false\n    ) {\n        if (reloadForActivity) {\n            _accounts.postValue(getAccounts(context))\n            _selectedKeyIndex.postValue(getAccounts(context).indexOf(account))\n            MainActivity.reloadAccountEvent(true)\n            return\n        }\n\n        // Check if the selected account has a lock PIN set\n        if (account.lockPin != null) {\n            // The selected account has a PIN set, prompt the user to enter the PIN\n            showPinInputDialog(\n                context,\n                account.lockPin,\n                false,\n                forStartup\n            ) { pin ->\n                if (pin == null) return@showPinInputDialog\n                // Pin is correct, proceed\n                _isAllowedLogin.postValue(true)\n                _selectedKeyIndex.postValue(getAccounts(context).indexOf(account))\n                setAccount(account)\n                MainActivity.reloadAccountEvent(true)\n            }\n        } else {\n            // No PIN set for the selected account, proceed\n            _isAllowedLogin.postValue(true)\n            _selectedKeyIndex.postValue(getAccounts(context).indexOf(account))\n            setAccount(account)\n            MainActivity.reloadAccountEvent(true)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.download\r\n\r\nimport android.annotation.SuppressLint\r\nimport android.text.format.Formatter.formatShortFileSize\r\nimport android.view.LayoutInflater\r\nimport android.view.ViewGroup\r\nimport android.widget.CheckBox\r\nimport androidx.core.content.ContextCompat\r\nimport androidx.core.view.isVisible\r\nimport androidx.recyclerview.widget.DiffUtil\r\nimport androidx.viewbinding.ViewBinding\r\nimport com.lagradost.cloudstream3.R\r\nimport com.lagradost.cloudstream3.databinding.DownloadChildEpisodeBinding\r\nimport com.lagradost.cloudstream3.databinding.DownloadHeaderEpisodeBinding\r\nimport com.lagradost.cloudstream3.mvvm.logError\r\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\r\nimport com.lagradost.cloudstream3.ui.ViewHolderState\r\nimport com.lagradost.cloudstream3.ui.download.button.DownloadStatusTell\r\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull\r\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\r\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\r\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\r\n\r\nconst val DOWNLOAD_ACTION_PLAY_FILE = 0\r\nconst val DOWNLOAD_ACTION_DELETE_FILE = 1\r\nconst val DOWNLOAD_ACTION_RESUME_DOWNLOAD = 2\r\nconst val DOWNLOAD_ACTION_PAUSE_DOWNLOAD = 3\r\nconst val DOWNLOAD_ACTION_DOWNLOAD = 4\r\nconst val DOWNLOAD_ACTION_LONG_CLICK = 5\r\nconst val DOWNLOAD_ACTION_CANCEL_PENDING = 6\r\n\r\nconst val DOWNLOAD_ACTION_GO_TO_CHILD = 0\r\nconst val DOWNLOAD_ACTION_LOAD_RESULT = 1\r\n\r\nsealed class VisualDownloadCached {\r\n    abstract val currentBytes: Long\r\n    abstract val totalBytes: Long\r\n    abstract val data: DownloadObjects.DownloadCached\r\n    abstract var isSelected: Boolean\r\n\r\n    data class Child(\r\n        override val currentBytes: Long,\r\n        override val totalBytes: Long,\r\n        override val data: DownloadObjects.DownloadEpisodeCached,\r\n        override var isSelected: Boolean,\r\n    ) : VisualDownloadCached()\r\n\r\n    data class Header(\r\n        override val currentBytes: Long,\r\n        override val totalBytes: Long,\r\n        override val data: DownloadObjects.DownloadHeaderCached,\r\n        override var isSelected: Boolean,\r\n        val child: DownloadObjects.DownloadEpisodeCached?,\r\n        val currentOngoingDownloads: Int,\r\n        val totalDownloads: Int,\r\n    ) : VisualDownloadCached()\r\n}\r\n\r\ndata class DownloadClickEvent(\r\n    val action: Int,\r\n    val data: DownloadObjects.DownloadEpisodeCached\r\n)\r\n\r\ndata class DownloadHeaderClickEvent(\r\n    val action: Int,\r\n    val data: DownloadObjects.DownloadHeaderCached\r\n)\r\n\r\nclass DownloadAdapter(\r\n    private val onHeaderClickEvent: (DownloadHeaderClickEvent) -> Unit,\r\n    private val onItemClickEvent: (DownloadClickEvent) -> Unit,\r\n    private val onItemSelectionChanged: (Int, Boolean) -> Unit,\r\n) : NoStateAdapter<VisualDownloadCached>(DiffCallback()) {\r\n\r\n    private var isMultiDeleteState: Boolean = false\r\n\r\n    companion object {\r\n        private const val VIEW_TYPE_HEADER = 0\r\n        private const val VIEW_TYPE_CHILD = 1\r\n    }\r\n\r\n\r\n    private fun bindHeader(binding: ViewBinding, card: VisualDownloadCached.Header?) {\r\n        if (binding !is DownloadHeaderEpisodeBinding || card == null) return\r\n\r\n        val data = card.data\r\n        binding.apply {\r\n            episodeHolder.apply {\r\n                if (isMultiDeleteState) {\r\n                    setOnClickListener {\r\n                        toggleIsChecked(deleteCheckbox, data.id)\r\n                    }\r\n                    setOnLongClickListener {\r\n                        toggleIsChecked(deleteCheckbox, data.id)\r\n                        true\r\n                    }\r\n                } else {\r\n                    setOnLongClickListener {\r\n                        onItemSelectionChanged.invoke(data.id, true)\r\n                        true\r\n                    }\r\n                }\r\n            }\r\n\r\n            downloadHeaderPoster.apply {\r\n                loadImage(data.poster)\r\n                if (isMultiDeleteState) {\r\n                    setOnClickListener {\r\n                        toggleIsChecked(deleteCheckbox, data.id)\r\n                    }\r\n                } else {\r\n                    setOnClickListener {\r\n                        onHeaderClickEvent.invoke(\r\n                            DownloadHeaderClickEvent(\r\n                                DOWNLOAD_ACTION_LOAD_RESULT,\r\n                                data\r\n                            )\r\n                        )\r\n                    }\r\n                }\r\n\r\n                setOnLongClickListener {\r\n                    toggleIsChecked(deleteCheckbox, data.id)\r\n                    true\r\n                }\r\n            }\r\n            downloadHeaderTitle.text = data.name\r\n            val formattedSize = formatShortFileSize(binding.root.context, card.totalBytes)\r\n\r\n            if (card.child != null) {\r\n                handleChildDownload(card, formattedSize)\r\n            } else handleParentDownload(card, formattedSize)\r\n\r\n            if (isMultiDeleteState) {\r\n                deleteCheckbox.setOnCheckedChangeListener { _, isChecked ->\r\n                    onItemSelectionChanged.invoke(data.id, isChecked)\r\n                }\r\n            } else deleteCheckbox.setOnCheckedChangeListener(null)\r\n\r\n            deleteCheckbox.apply {\r\n                isVisible = isMultiDeleteState\r\n                isChecked = card.isSelected\r\n            }\r\n        }\r\n    }\r\n\r\n    private fun DownloadHeaderEpisodeBinding.handleChildDownload(\r\n        card: VisualDownloadCached.Header,\r\n        formattedSize: String\r\n    ) {\r\n        card.child ?: return\r\n        downloadHeaderGotoChild.isVisible = false\r\n\r\n        val posDur = getViewPos(card.data.id)\r\n        watchProgressContainer.isVisible = true\r\n        downloadHeaderEpisodeProgress.apply {\r\n            isVisible = posDur != null\r\n            posDur?.let {\r\n                val max = (it.duration / 1000).toInt()\r\n                val progress = (it.position / 1000).toInt()\r\n\r\n                if (max > 0 && progress >= (0.95 * max).toInt()) {\r\n                    playIcon.setImageResource(R.drawable.ic_baseline_check_24)\r\n                    isVisible = false\r\n                } else {\r\n                    playIcon.setImageResource(R.drawable.netflix_play)\r\n                    this.max = max\r\n                    this.progress = progress\r\n                    isVisible = true\r\n                }\r\n            }\r\n        }\r\n\r\n        downloadButton.resetView()\r\n        val status = downloadButton.getStatus(card.child.id, card.currentBytes, card.totalBytes)\r\n        if (status == DownloadStatusTell.IsDone) {\r\n            // We do this here instead if we are finished downloading\r\n            // so that we can use the value from the view model\r\n            // rather than extra unneeded disk operations and to prevent a\r\n            // delay in updating download icon state.\r\n            downloadButton.setProgress(card.currentBytes, card.totalBytes)\r\n            downloadButton.applyMetaData(card.child.id, card.currentBytes, card.totalBytes)\r\n            // We will let the view model handle this\r\n            downloadButton.doSetProgress = false\r\n            downloadButton.progressBar.progressDrawable =\r\n                downloadButton.getDrawableFromStatus(status)\r\n                    ?.let { ContextCompat.getDrawable(downloadButton.context, it) }\r\n            downloadHeaderInfo.text = formattedSize\r\n        } else {\r\n            // We need to make sure we restore the correct progress\r\n            // when we refresh data in the adapter.\r\n            val drawable = downloadButton.getDrawableFromStatus(status)?.let {\r\n                ContextCompat.getDrawable(downloadButton.context, it)\r\n            }\r\n            downloadButton.statusView.setImageDrawable(drawable)\r\n            downloadButton.progressBar.progressDrawable =\r\n                ContextCompat.getDrawable(\r\n                    downloadButton.context,\r\n                    downloadButton.progressDrawable\r\n                )\r\n        }\r\n\r\n        downloadHeaderInfo.isVisible = true\r\n        downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, onItemClickEvent)\r\n        downloadButton.isVisible = !isMultiDeleteState\r\n\r\n        if (!isMultiDeleteState) {\r\n            episodeHolder.setOnClickListener {\r\n                onItemClickEvent.invoke(\r\n                    DownloadClickEvent(\r\n                        DOWNLOAD_ACTION_PLAY_FILE,\r\n                        card.child\r\n                    )\r\n                )\r\n            }\r\n        }\r\n    }\r\n\r\n    private fun DownloadHeaderEpisodeBinding.handleParentDownload(\r\n        card: VisualDownloadCached.Header,\r\n        formattedSize: String\r\n    ) {\r\n        downloadButton.resetViewData()\r\n        watchProgressContainer.isVisible = false\r\n        downloadButton.isVisible = false\r\n        downloadHeaderEpisodeProgress.isVisible = false\r\n        downloadHeaderGotoChild.isVisible = !isMultiDeleteState\r\n\r\n        try {\r\n            downloadHeaderInfo.isVisible = true\r\n            downloadHeaderInfo.text =\r\n                downloadHeaderInfo.context.getString(R.string.extra_info_format).format(\r\n                    card.totalDownloads,\r\n                    downloadHeaderInfo.context.resources.getQuantityString(\r\n                        R.plurals.episodes,\r\n                        card.totalDownloads\r\n                    ),\r\n                    formattedSize\r\n                )\r\n        } catch (e: Exception) {\r\n            downloadHeaderInfo.text = null\r\n            logError(e)\r\n        }\r\n\r\n        if (!isMultiDeleteState) {\r\n            episodeHolder.setOnClickListener {\r\n                onHeaderClickEvent.invoke(\r\n                    DownloadHeaderClickEvent(\r\n                        DOWNLOAD_ACTION_GO_TO_CHILD,\r\n                        card.data\r\n                    )\r\n                )\r\n            }\r\n        }\r\n    }\r\n\r\n    private fun bindChild(binding: ViewBinding, card: VisualDownloadCached.Child?) {\r\n        if (binding !is DownloadChildEpisodeBinding || card == null) return\r\n\r\n        val data = card.data\r\n        binding.apply {\r\n            val posDur = getViewPos(data.id)\r\n            downloadChildEpisodeProgress.apply {\r\n                isVisible = posDur != null\r\n                posDur?.let {\r\n                    val max = (it.duration / 1000).toInt()\r\n                    val progress = (it.position / 1000).toInt()\r\n\r\n                    if (max > 0 && progress >= (0.95 * max).toInt()) {\r\n                        downloadChildEpisodePlay.setImageResource(R.drawable.ic_baseline_check_24)\r\n                        isVisible = false\r\n                    } else {\r\n                        downloadChildEpisodePlay.setImageResource(R.drawable.play_button_transparent)\r\n                        this.max = max\r\n                        this.progress = progress\r\n                        isVisible = true\r\n                    }\r\n                }\r\n            }\r\n\r\n            downloadButton.resetView()\r\n            val status = downloadButton.getStatus(data.id, card.currentBytes, card.totalBytes)\r\n            if (status == DownloadStatusTell.IsDone) {\r\n                // We do this here instead if we are finished downloading\r\n                // so that we can use the value from the view model\r\n                // rather than extra unneeded disk operations and to prevent a\r\n                // delay in updating download icon state.\r\n                downloadButton.setProgress(card.currentBytes, card.totalBytes)\r\n                downloadButton.applyMetaData(data.id, card.currentBytes, card.totalBytes)\r\n                // We will let the view model handle this\r\n                downloadButton.doSetProgress = false\r\n                downloadButton.progressBar.progressDrawable =\r\n                    downloadButton.getDrawableFromStatus(status)\r\n                        ?.let { ContextCompat.getDrawable(downloadButton.context, it) }\r\n                downloadChildEpisodeTextExtra.text =\r\n                    formatShortFileSize(downloadChildEpisodeTextExtra.context, card.totalBytes)\r\n            } else {\r\n                // We need to make sure we restore the correct progress\r\n                // when we refresh data in the adapter.\r\n                val drawable = downloadButton.getDrawableFromStatus(status)?.let {\r\n                    ContextCompat.getDrawable(downloadButton.context, it)\r\n                }\r\n                downloadButton.statusView.setImageDrawable(drawable)\r\n                downloadButton.progressBar.progressDrawable =\r\n                    ContextCompat.getDrawable(\r\n                        downloadButton.context,\r\n                        downloadButton.progressDrawable\r\n                    )\r\n            }\r\n\r\n            downloadButton.setDefaultClickListener(\r\n                data,\r\n                downloadChildEpisodeTextExtra,\r\n                onItemClickEvent\r\n            )\r\n            downloadButton.isVisible = !isMultiDeleteState\r\n\r\n            downloadChildEpisodeText.apply {\r\n                text = context.getNameFull(data.name, data.episode, data.season)\r\n                isSelected = true // Needed for text repeating\r\n            }\r\n\r\n            downloadChildEpisodeHolder.setOnClickListener {\r\n                onItemClickEvent.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, data))\r\n            }\r\n\r\n            downloadChildEpisodeHolder.apply {\r\n                when {\r\n                    isMultiDeleteState -> {\r\n                        setOnClickListener {\r\n                            toggleIsChecked(deleteCheckbox, data.id)\r\n                        }\r\n                        setOnLongClickListener {\r\n                            toggleIsChecked(deleteCheckbox, data.id)\r\n                            true\r\n                        }\r\n                    }\r\n\r\n                    else -> {\r\n                        setOnClickListener {\r\n                            onItemClickEvent.invoke(\r\n                                DownloadClickEvent(\r\n                                    DOWNLOAD_ACTION_PLAY_FILE,\r\n                                    data\r\n                                )\r\n                            )\r\n                        }\r\n\r\n                        setOnLongClickListener {\r\n                            onItemSelectionChanged.invoke(data.id, true)\r\n                            true\r\n                        }\r\n                    }\r\n                }\r\n            }\r\n\r\n            if (isMultiDeleteState) {\r\n                deleteCheckbox.setOnCheckedChangeListener { _, isChecked ->\r\n                    onItemSelectionChanged.invoke(data.id, isChecked)\r\n                }\r\n            } else deleteCheckbox.setOnCheckedChangeListener(null)\r\n\r\n            deleteCheckbox.apply {\r\n                isVisible = isMultiDeleteState\r\n                isChecked = card.isSelected\r\n            }\r\n        }\r\n    }\r\n\r\n    override fun onCreateCustomContent(parent: ViewGroup, viewType: Int): ViewHolderState<Any> {\r\n        val inflater = LayoutInflater.from(parent.context)\r\n        val binding = when (viewType) {\r\n            VIEW_TYPE_HEADER -> DownloadHeaderEpisodeBinding.inflate(inflater, parent, false)\r\n            VIEW_TYPE_CHILD -> DownloadChildEpisodeBinding.inflate(inflater, parent, false)\r\n            else -> throw IllegalArgumentException(\"Invalid view type\")\r\n        }\r\n        return ViewHolderState(binding)\r\n    }\r\n\r\n    override fun onBindContent(\r\n        holder: ViewHolderState<Any>,\r\n        item: VisualDownloadCached,\r\n        position: Int\r\n    ) {\r\n        when (val binding = holder.view) {\r\n            is DownloadHeaderEpisodeBinding -> bindHeader(\r\n                binding,\r\n                item as? VisualDownloadCached.Header\r\n            )\r\n\r\n            is DownloadChildEpisodeBinding -> bindChild(\r\n                binding,\r\n                item as? VisualDownloadCached.Child\r\n            )\r\n        }\r\n    }\r\n\r\n    override fun customContentViewType(item: VisualDownloadCached): Int {\r\n        return when (item) {\r\n            is VisualDownloadCached.Child -> VIEW_TYPE_CHILD\r\n            is VisualDownloadCached.Header -> VIEW_TYPE_HEADER\r\n        }\r\n    }\r\n\r\n    @SuppressLint(\"NotifyDataSetChanged\")\r\n    fun setIsMultiDeleteState(value: Boolean) {\r\n        if (isMultiDeleteState == value) return\r\n        isMultiDeleteState = value\r\n        notifyDataSetChanged() // This is shit, but what can you do?\r\n    }\r\n\r\n    private fun toggleIsChecked(checkbox: CheckBox, itemId: Int) {\r\n        val isChecked = !checkbox.isChecked\r\n        checkbox.isChecked = isChecked\r\n        onItemSelectionChanged.invoke(itemId, isChecked)\r\n    }\r\n\r\n    class DiffCallback : DiffUtil.ItemCallback<VisualDownloadCached>() {\r\n        override fun areItemsTheSame(\r\n            oldItem: VisualDownloadCached,\r\n            newItem: VisualDownloadCached\r\n        ): Boolean {\r\n            return oldItem.data.id == newItem.data.id\r\n        }\r\n\r\n        override fun areContentsTheSame(\r\n            oldItem: VisualDownloadCached,\r\n            newItem: VisualDownloadCached\r\n        ): Boolean {\r\n            return oldItem == newItem\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadButtonSetup.kt",
    "content": "package com.lagradost.cloudstream3.ui.download\n\nimport android.content.DialogInterface\nimport android.net.Uri\nimport androidx.appcompat.app.AlertDialog\nimport com.google.android.material.snackbar.Snackbar\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.player.DownloadFileGenerator\nimport com.lagradost.cloudstream3.ui.player.ExtractorUri\nimport com.lagradost.cloudstream3.ui.player.GeneratorPlayer\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE\nimport com.lagradost.cloudstream3.utils.SnackbarHelper.showSnackbar\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\nimport kotlinx.coroutines.MainScope\n\nobject DownloadButtonSetup {\n    fun handleDownloadClick(click: DownloadClickEvent) {\n        val id = click.data.id\n        when (click.action) {\n            DOWNLOAD_ACTION_DELETE_FILE -> {\n                activity?.let { ctx ->\n                    val builder: AlertDialog.Builder = AlertDialog.Builder(ctx)\n                    val dialogClickListener =\n                        DialogInterface.OnClickListener { _, which ->\n                            when (which) {\n                                DialogInterface.BUTTON_POSITIVE -> {\n                                    VideoDownloadManager.deleteFilesAndUpdateSettings(\n                                        ctx,\n                                        setOf(id),\n                                        MainScope()\n                                    )\n                                }\n\n                                DialogInterface.BUTTON_NEGATIVE -> {\n                                    // Do nothing on cancel\n                                }\n                            }\n                        }\n\n                    try {\n                        builder.setTitle(R.string.delete_file)\n                            .setMessage(\n                                ctx.getString(R.string.delete_message).format(\n                                    ctx.getNameFull(\n                                        click.data.name,\n                                        click.data.episode,\n                                        click.data.season\n                                    )\n                                )\n                            )\n                            .setPositiveButton(R.string.delete, dialogClickListener)\n                            .setNegativeButton(R.string.cancel, dialogClickListener)\n                            .show().setDefaultFocus()\n                    } catch (e: Exception) {\n                        logError(e)\n                        // ye you somehow fucked up formatting did you?\n                    }\n                }\n            }\n\n            DOWNLOAD_ACTION_PAUSE_DOWNLOAD -> {\n                VideoDownloadManager.downloadEvent.invoke(\n                    Pair(click.data.id, VideoDownloadManager.DownloadActionType.Pause)\n                )\n            }\n\n            DOWNLOAD_ACTION_RESUME_DOWNLOAD -> {\n                activity?.let { ctx ->\n                    if (VideoDownloadManager.downloadStatus.containsKey(id) && VideoDownloadManager.downloadStatus[id] == VideoDownloadManager.DownloadType.IsPaused) {\n                        VideoDownloadManager.downloadEvent.invoke(\n                            Pair(click.data.id, VideoDownloadManager.DownloadActionType.Resume)\n                        )\n                    } else {\n                        val pkg = VideoDownloadManager.getDownloadResumePackage(ctx, id)\n                        if (pkg != null) {\n                            DownloadQueueManager.addToQueue(pkg.toWrapper())\n                        } else {\n                            VideoDownloadManager.downloadEvent.invoke(\n                                Pair(click.data.id, VideoDownloadManager.DownloadActionType.Resume)\n                            )\n                        }\n                    }\n                }\n            }\n\n            DOWNLOAD_ACTION_LONG_CLICK -> {\n                activity?.let { act ->\n                    val length =\n                        VideoDownloadManager.getDownloadFileInfo(\n                            act,\n                            click.data.id\n                        )?.fileLength\n                            ?: 0\n                    if (length > 0) {\n                        showSnackbar(\n                            act,\n                            R.string.offline_file,\n                            Snackbar.LENGTH_LONG\n                        )\n                    }\n                }\n            }\n\n            DOWNLOAD_ACTION_CANCEL_PENDING -> {\n                DownloadQueueManager.cancelDownload(id)\n            }\n\n            DOWNLOAD_ACTION_PLAY_FILE -> {\n                activity?.let { act ->\n                    val parent = getKey<DownloadObjects.DownloadHeaderCached>(\n                        DOWNLOAD_HEADER_CACHE,\n                        click.data.parentId.toString()\n                    ) ?: return\n\n                    val episodes = getKeys(DOWNLOAD_EPISODE_CACHE)\n                        ?.mapNotNull {\n                            getKey<DownloadObjects.DownloadEpisodeCached>(it)\n                        }\n                        ?.filter { it.parentId == click.data.parentId }\n\n                    val items = mutableListOf<ExtractorUri>()\n                    val allRelevantEpisodes =\n                        episodes?.sortedWith(compareBy<DownloadObjects.DownloadEpisodeCached> {\n                            it.season ?: 0\n                        }.thenBy { it.episode })\n\n                    allRelevantEpisodes?.forEach {\n                        val keyInfo = getKey<DownloadObjects.DownloadedFileInfo>(\n                            VideoDownloadManager.KEY_DOWNLOAD_INFO,\n                            it.id.toString()\n                        ) ?: return@forEach\n\n                        items.add(\n                            ExtractorUri(\n                                // We just use a temporary placeholder for the URI,\n                                // it will be updated in generateLinks().\n                                // We just do this for performance since getting\n                                // all paths at once can be quite expensive.\n                                uri = Uri.EMPTY,\n                                id = it.id,\n                                parentId = it.parentId,\n                                name = it.name ?: act.getString(R.string.downloaded_file),\n                                season = it.season,\n                                episode = it.episode,\n                                headerName = parent.name,\n                                tvType = parent.type,\n                                basePath = keyInfo.basePath,\n                                displayName = keyInfo.displayName,\n                                relativePath = keyInfo.relativePath,\n                            )\n                        )\n                    }\n                    act.navigate(\n                        R.id.global_to_navigation_player, GeneratorPlayer.newInstance(\n                            DownloadFileGenerator(items).apply { goto(items.indexOfFirst { it.id == click.data.id }) }\n                        )\n                    )\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.download\n\nimport android.os.Bundle\nimport android.text.format.Formatter.formatShortFileSize\nimport android.view.View\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.fragment.app.activityViewModels\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.FragmentChildDownloadsBinding\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.mvvm.observeNullable\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick\nimport com.lagradost.cloudstream3.ui.result.FOCUS_SELF\nimport com.lagradost.cloudstream3.ui.result.setLinearListLayout\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.setAppBarNoScrollFlagsOnTV\n\nclass DownloadChildFragment : BaseFragment<FragmentChildDownloadsBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentChildDownloadsBinding::inflate)\n) {\n\n    private val downloadViewModel: DownloadViewModel by activityViewModels()\n\n    companion object {\n        fun newInstance(headerName: String, folder: String): Bundle {\n            return Bundle().apply {\n                putString(\"folder\", folder)\n                putString(\"name\", headerName)\n            }\n        }\n    }\n\n    override fun onDestroyView() {\n        activity?.detachBackPressedCallback(\"Downloads\")\n        downloadViewModel.clearChildren()\n        super.onDestroyView()\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padBottom = isLandscape(),\n            padLeft = isLayout(TV or EMULATOR)\n        )\n    }\n\n    override fun onBindingCreated(binding: FragmentChildDownloadsBinding) {\n        val folder = arguments?.getString(\"folder\")\n        val name = arguments?.getString(\"name\")\n        if (folder == null) {\n            dispatchBackPressed()\n            return\n        }\n\n        context?.let { downloadViewModel.updateChildList(it, folder) }\n\n        binding.downloadChildToolbar.apply {\n            title = name\n            if (isLayout(PHONE or EMULATOR)) {\n                setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)\n                setNavigationOnClickListener {\n                    dispatchBackPressed()\n                }\n            }\n            setAppBarNoScrollFlagsOnTV()\n        }\n\n        binding.downloadDeleteAppbar.setAppBarNoScrollFlagsOnTV()\n\n        observe(downloadViewModel.childCards) { cards ->\n            when (cards) {\n                is Resource.Success -> {\n                    if (cards.value.isEmpty()) {\n                        dispatchBackPressed()\n                    }\n                    (binding.downloadChildList.adapter as? DownloadAdapter)?.submitList(cards.value)\n                }\n\n                else -> {\n                    (binding.downloadChildList.adapter as? DownloadAdapter)?.submitList(null)\n                }\n            }\n        }\n\n        observe(downloadViewModel.selectedBytes) {\n            updateDeleteButton(downloadViewModel.selectedItemIds.value?.count() ?: 0, it)\n        }\n\n\n        binding.apply {\n            btnDelete.setOnClickListener { view ->\n                downloadViewModel.handleMultiDelete(view.context ?: return@setOnClickListener)\n            }\n\n            btnCancel.setOnClickListener {\n                downloadViewModel.cancelSelection()\n            }\n\n            btnToggleAll.setOnClickListener {\n                val allSelected = downloadViewModel.isAllChildrenSelected()\n                if (allSelected) {\n                    downloadViewModel.clearSelectedItems()\n                } else {\n                    downloadViewModel.selectAllChildren()\n                }\n            }\n        }\n\n        observeNullable(downloadViewModel.selectedItemIds) { selection ->\n            val isMultiDeleteState = selection != null\n            val adapter = binding.downloadChildList.adapter as? DownloadAdapter\n            adapter?.setIsMultiDeleteState(isMultiDeleteState)\n            binding.downloadDeleteAppbar.isVisible = isMultiDeleteState\n            binding.downloadChildToolbar.isGone = isMultiDeleteState\n\n            if (selection == null) {\n                activity?.detachBackPressedCallback(\"Downloads\")\n                return@observeNullable\n            }\n            activity?.attachBackPressedCallback(\"Downloads\") {\n                downloadViewModel.cancelSelection()\n            }\n\n            updateDeleteButton(selection.count(), downloadViewModel.selectedBytes.value ?: 0L)\n\n            binding.btnDelete.isVisible = selection.isNotEmpty()\n            binding.selectItemsText.isVisible = selection.isEmpty()\n\n            val allSelected = downloadViewModel.isAllChildrenSelected()\n            if (allSelected) {\n                binding.btnToggleAll.setText(R.string.deselect_all)\n            } else binding.btnToggleAll.setText(R.string.select_all)\n        }\n\n        val adapter = DownloadAdapter(\n            {},\n            { click ->\n                if (click.action == DOWNLOAD_ACTION_DELETE_FILE) {\n                    context?.let { ctx ->\n                        downloadViewModel.handleSingleDelete(ctx, click.data.id)\n                    }\n                } else handleDownloadClick(click)\n            },\n            { itemId, isChecked ->\n                if (isChecked) {\n                    downloadViewModel.addSelected(itemId)\n                } else downloadViewModel.removeSelected(itemId)\n            }\n        )\n\n        binding.downloadChildList.apply {\n            setHasFixedSize(true)\n            setItemViewCacheSize(20)\n            this.adapter = adapter\n            setLinearListLayout(\n                isHorizontal = false,\n                nextRight = FOCUS_SELF,\n                nextDown = FOCUS_SELF,\n            )\n        }\n    }\n\n    private fun updateDeleteButton(count: Int, selectedBytes: Long) {\n        val formattedSize = formatShortFileSize(context, selectedBytes)\n        binding?.btnDelete?.text =\n            getString(R.string.delete_format).format(count, formattedSize)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.download\n\nimport android.app.Activity\nimport android.app.Dialog\nimport android.content.ClipboardManager\nimport android.content.Context\nimport android.content.Intent\nimport android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION\nimport android.os.Build\nimport android.text.format.Formatter.formatShortFileSize\nimport android.view.View\nimport android.widget.LinearLayout\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.annotation.StringRes\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.core.widget.doOnTextChanged\nimport androidx.fragment.app.activityViewModels\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.FragmentDownloadsBinding\nimport com.lagradost.cloudstream3.databinding.StreamInputBinding\nimport com.lagradost.cloudstream3.isEpisodeBased\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.mvvm.observeNullable\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick\nimport com.lagradost.cloudstream3.ui.download.queue.DownloadQueueViewModel\nimport com.lagradost.cloudstream3.ui.player.BasicLink\nimport com.lagradost.cloudstream3.ui.player.GeneratorPlayer\nimport com.lagradost.cloudstream3.ui.player.LinkGenerator\nimport com.lagradost.cloudstream3.ui.player.OfflinePlaybackHelper.playUri\nimport com.lagradost.cloudstream3.ui.result.FOCUS_SELF\nimport com.lagradost.cloudstream3.ui.result.setLinearListLayout\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadResult\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE\nimport com.lagradost.cloudstream3.utils.DataStore.getFolderName\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UIHelper.setAppBarNoScrollFlagsOnTV\nimport java.net.URI\n\nconst val DOWNLOAD_NAVIGATE_TO = \"downloadpage\"\n\nclass DownloadFragment : BaseFragment<FragmentDownloadsBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentDownloadsBinding::inflate)\n) {\n\n    private val downloadViewModel: DownloadViewModel by activityViewModels()\n    private val downloadQueueViewModel: DownloadQueueViewModel by activityViewModels()\n\n    private fun View.setLayoutWidth(weight: Long) {\n        val param = LinearLayout.LayoutParams(\n            0,\n            LinearLayout.LayoutParams.MATCH_PARENT,\n            maxOf((weight / 1000000000f), 0.1f) // 100mb\n        )\n        this.layoutParams = param\n    }\n\n    override fun onDestroyView() {\n        activity?.detachBackPressedCallback(\"Downloads\")\n        super.onDestroyView()\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padBottom = isLandscape(),\n            padLeft = isLayout(TV or EMULATOR)\n        )\n    }\n\n    override fun onBindingCreated(binding: FragmentDownloadsBinding) {\n        hideKeyboard()\n        binding.downloadAppbar.setAppBarNoScrollFlagsOnTV()\n        binding.downloadDeleteAppbar.setAppBarNoScrollFlagsOnTV()\n\n        observe(downloadViewModel.headerCards) { cards ->\n            when (cards) {\n                is Resource.Success -> {\n                    (binding.downloadList.adapter as? DownloadAdapter)?.submitList(cards.value)\n                    binding.textNoDownloads.isVisible = cards.value.isEmpty()\n                    binding.downloadLoading.isVisible = false\n                    binding.downloadList.isVisible = true\n                }\n\n                is Resource.Loading -> {\n                    binding.downloadList.isVisible = false\n                    binding.downloadLoading.isVisible = true\n                }\n\n                is Resource.Failure -> {\n                    binding.downloadList.isVisible = true\n                    binding.downloadLoading.isVisible = false\n                }\n            }\n        }\n\n        observe(downloadViewModel.availableBytes) {\n            updateStorageInfo(\n                binding.root.context,\n                it,\n                R.string.free_storage,\n                binding.downloadFreeTxt,\n                binding.downloadFree\n            )\n        }\n        observe(downloadViewModel.usedBytes) {\n            updateStorageInfo(\n                binding.root.context,\n                it,\n                R.string.used_storage,\n                binding.downloadUsedTxt,\n                binding.downloadUsed\n            )\n\n            val hasBytes = it > 0\n            if (hasBytes) {\n                binding.downloadLoadingBytes.stopShimmer()\n            } else binding.downloadLoadingBytes.startShimmer()\n\n            binding.downloadBytesBar.isVisible = hasBytes\n            binding.downloadLoadingBytes.isGone = hasBytes\n        }\n        observe(downloadViewModel.downloadBytes) {\n            updateStorageInfo(\n                binding.root.context,\n                it,\n                R.string.app_storage,\n                binding.downloadAppTxt,\n                binding.downloadApp\n            )\n        }\n        observe(downloadQueueViewModel.childCards) { cards ->\n            val size = cards.currentDownloads.size + cards.queue.size\n            val context = binding.root.context\n            val baseText = context.getString(R.string.download_queue)\n            binding.downloadQueueText.text =  if (size > 0) {\n                \"$baseText (${cards.currentDownloads.size}/$size)\"\n            } else {\n                baseText\n            }\n        }\n\n        observe(downloadViewModel.selectedBytes) {\n            updateDeleteButton(downloadViewModel.selectedItemIds.value?.count() ?: 0, it)\n        }\n\n        binding.apply {\n            btnDelete.setOnClickListener { view ->\n                downloadViewModel.handleMultiDelete(view.context ?: return@setOnClickListener)\n            }\n\n            btnCancel.setOnClickListener {\n                downloadViewModel.cancelSelection()\n            }\n\n            btnToggleAll.setOnClickListener {\n                val allSelected = downloadViewModel.isAllHeadersSelected()\n                if (allSelected) {\n                    downloadViewModel.clearSelectedItems()\n                } else {\n                    downloadViewModel.selectAllHeaders()\n                }\n            }\n        }\n\n        observeNullable(downloadViewModel.selectedItemIds) { selection ->\n            val isMultiDeleteState = selection != null\n            val adapter = binding.downloadList.adapter as? DownloadAdapter\n            adapter?.setIsMultiDeleteState(isMultiDeleteState)\n            binding.downloadDeleteAppbar.isVisible = isMultiDeleteState\n            binding.downloadAppbar.isGone = isMultiDeleteState\n\n            if (selection == null) {\n                activity?.detachBackPressedCallback(\"Downloads\")\n                return@observeNullable\n            }\n            activity?.attachBackPressedCallback(\"Downloads\") {\n                downloadViewModel.cancelSelection()\n            }\n            updateDeleteButton(selection.count(), downloadViewModel.selectedBytes.value ?: 0L)\n\n            binding.btnDelete.isVisible = selection.isNotEmpty()\n            binding.selectItemsText.isVisible = selection.isEmpty()\n\n            val allSelected = downloadViewModel.isAllHeadersSelected()\n            if (allSelected) {\n                binding.btnToggleAll.setText(R.string.deselect_all)\n            } else binding.btnToggleAll.setText(R.string.select_all)\n        }\n\n        val adapter = DownloadAdapter(\n            { click -> handleItemClick(click) },\n            { click ->\n                if (click.action == DOWNLOAD_ACTION_DELETE_FILE) {\n                    context?.let { ctx ->\n                        downloadViewModel.handleSingleDelete(ctx, click.data.id)\n                    }\n                } else handleDownloadClick(click)\n            },\n            { itemId, isChecked ->\n                if (isChecked) {\n                    downloadViewModel.addSelected(itemId)\n                } else downloadViewModel.removeSelected(itemId)\n            }\n        )\n\n        binding.downloadList.apply {\n            setHasFixedSize(true)\n            setItemViewCacheSize(20)\n            this.adapter = adapter\n            setLinearListLayout(\n                isHorizontal = false,\n                nextRight = FOCUS_SELF,\n                nextDown = R.id.download_queue_button,\n            )\n        }\n\n        binding.apply {\n            openLocalVideoButton.apply {\n                isGone = isLayout(TV)\n                setOnClickListener { openLocalVideo() }\n            }\n            downloadStreamButton.apply {\n                isGone = isLayout(TV)\n                setOnClickListener { showStreamInputDialog(it.context) }\n            }\n\n            downloadQueueButton.setOnClickListener {\n                activity?.navigate(R.id.action_navigation_global_to_navigation_download_queue)\n            }\n\n            downloadStreamButtonTv.isFocusableInTouchMode = isLayout(TV)\n            downloadAppbar.isFocusableInTouchMode = isLayout(TV)\n\n            downloadStreamButtonTv.setOnClickListener { showStreamInputDialog(it.context) }\n            steamImageviewHolder.isVisible = isLayout(TV)\n        }\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            binding.downloadList.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->\n                handleScroll(scrollY - oldScrollY)\n            }\n        }\n\n        context?.let { downloadViewModel.updateHeaderList(it) }\n    }\n\n    private fun handleItemClick(click: DownloadHeaderClickEvent) {\n        when (click.action) {\n            DOWNLOAD_ACTION_GO_TO_CHILD -> {\n                if (click.data.type.isEpisodeBased()) {\n                    val folder =\n                        getFolderName(DOWNLOAD_EPISODE_CACHE, click.data.id.toString())\n                    activity?.navigate(\n                        R.id.action_navigation_downloads_to_navigation_download_child,\n                        DownloadChildFragment.newInstance(click.data.name, folder)\n                    )\n                }\n            }\n\n            DOWNLOAD_ACTION_LOAD_RESULT -> {\n                activity?.loadResult(click.data.url, click.data.apiName, click.data.name)\n            }\n        }\n    }\n\n    private fun updateDeleteButton(count: Int, selectedBytes: Long) {\n        val formattedSize = formatShortFileSize(context, selectedBytes)\n        binding?.btnDelete?.text =\n            getString(R.string.delete_format).format(count, formattedSize)\n    }\n\n    private fun updateStorageInfo(\n        context: Context,\n        bytes: Long,\n        @StringRes stringRes: Int,\n        textView: TextView?,\n        view: View?\n    ) {\n        textView?.text = getString(R.string.storage_size_format).format(\n            getString(stringRes),\n            formatShortFileSize(context, bytes)\n        )\n        view?.setLayoutWidth(bytes)\n    }\n\n    private fun openLocalVideo() {\n        val intent = Intent()\n            .setAction(Intent.ACTION_GET_CONTENT)\n            .setType(\"video/*\")\n            .addCategory(Intent.CATEGORY_OPENABLE)\n            .addFlags(FLAG_GRANT_READ_URI_PERMISSION) // Request temporary access\n        safe {\n            videoResultLauncher.launch(\n                Intent.createChooser(\n                    intent,\n                    getString(R.string.open_local_video)\n                )\n            )\n        }\n    }\n\n    private fun showStreamInputDialog(context: Context) {\n        val dialog = Dialog(context, R.style.AlertDialogCustom)\n        val binding = StreamInputBinding.inflate(dialog.layoutInflater)\n        dialog.setContentView(binding.root)\n        dialog.show()\n\n        var preventAutoSwitching = false\n        binding.hlsSwitch.setOnClickListener { preventAutoSwitching = true }\n\n        binding.streamReferer.doOnTextChanged { text, _, _, _ ->\n            if (!preventAutoSwitching) activateSwitchOnHls(text?.toString(), binding)\n        }\n\n        (activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager)?.primaryClip?.getItemAt(\n            0\n        )?.text?.toString()?.let { copy ->\n            val fixedText = copy.trim()\n            binding.streamUrl.setText(fixedText)\n            activateSwitchOnHls(fixedText, binding)\n        }\n\n        binding.applyBtt.setOnClickListener {\n            val url = binding.streamUrl.text?.toString()\n            if (url.isNullOrEmpty()) {\n                showToast(R.string.error_invalid_url, Toast.LENGTH_SHORT)\n            } else {\n                val referer = binding.streamReferer.text?.toString()\n                activity?.navigate(\n                    R.id.global_to_navigation_player,\n                    GeneratorPlayer.newInstance(\n                        LinkGenerator(\n                            listOf(BasicLink(url)),\n                            extract = true,\n                            refererUrl = referer,\n                        )\n                    )\n                )\n                dialog.dismissSafe(activity)\n            }\n        }\n\n        binding.cancelBtt.setOnClickListener {\n            dialog.dismissSafe(activity)\n        }\n    }\n\n    private fun activateSwitchOnHls(text: String?, binding: StreamInputBinding) {\n        binding.hlsSwitch.isChecked = safe {\n            URI(text).path?.substringAfterLast(\".\")?.contains(\"m3u\")\n        } == true\n    }\n\n    private fun handleScroll(dy: Int) {\n        if (dy > 0) {\n            binding?.downloadStreamButton?.shrink()\n        } else if (dy < -5) {\n            binding?.downloadStreamButton?.extend()\n        }\n    }\n\n    // Open local video from files using content provider x safeFile\n    private val videoResultLauncher = registerForActivityResult(\n        ActivityResultContracts.StartActivityForResult()\n    ) { result ->\n        if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult\n        val selectedVideoUri = result.data?.data ?: return@registerForActivityResult\n        playUri(activity ?: return@registerForActivityResult, selectedVideoUri)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.download\n\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.os.Environment\nimport android.os.StatFs\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.edit\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.isEpisodeBased\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.launchSafe\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.services.DownloadQueueService\nimport com.lagradost.cloudstream3.services.DownloadQueueService.Companion.downloadInstances\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.ConsistentLiveData\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.ioWork\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE_BACKUP\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE_BACKUP\nimport com.lagradost.cloudstream3.utils.DataStore.getFolderName\nimport com.lagradost.cloudstream3.utils.DataStore.getKey\nimport com.lagradost.cloudstream3.utils.DataStore.getKeys\nimport com.lagradost.cloudstream3.utils.DataStore.getSharedPrefs\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getLastWatched\nimport com.lagradost.cloudstream3.utils.ResourceLiveData\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.deleteFilesAndUpdateSettings\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getDownloadFileInfo\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\n\nclass DownloadViewModel : ViewModel() {\n    companion object {\n        const val TAG = \"DownloadViewModel\"\n    }\n\n    private val _headerCards =\n        ResourceLiveData<List<VisualDownloadCached.Header>>(Resource.Loading())\n    val headerCards: LiveData<Resource<List<VisualDownloadCached.Header>>> = _headerCards\n\n    private val _childCards = ResourceLiveData<List<VisualDownloadCached.Child>>(Resource.Loading())\n    val childCards: LiveData<Resource<List<VisualDownloadCached.Child>>> = _childCards\n\n    private val _usedBytes = ConsistentLiveData<Long>()\n    val usedBytes: LiveData<Long> = _usedBytes\n\n    private val _availableBytes = ConsistentLiveData<Long>()\n    val availableBytes: LiveData<Long> = _availableBytes\n\n    private val _downloadBytes = ConsistentLiveData<Long>()\n    val downloadBytes: LiveData<Long> = _downloadBytes\n\n    private val _selectedBytes = ConsistentLiveData<Long>(0)\n    val selectedBytes: LiveData<Long> = _selectedBytes\n\n    private val _selectedItemIds = ConsistentLiveData<Set<Int>?>(null)\n    val selectedItemIds: LiveData<Set<Int>?> = _selectedItemIds\n\n\n    fun cancelSelection() {\n        updateSelectedItems { null }\n    }\n\n    fun addSelected(itemId: Int) {\n        updateSelectedItems { it?.plus(itemId) ?: setOf(itemId) }\n    }\n\n    fun removeSelected(itemId: Int) {\n        updateSelectedItems { it?.minus(itemId) ?: emptySet() }\n    }\n\n    fun selectAllHeaders() {\n        updateSelectedItems {\n            _headerCards.success.orEmpty()\n                .map { item -> item.data.id }.toSet()\n        }\n    }\n\n    fun selectAllChildren() {\n        updateSelectedItems {\n            _childCards.success.orEmpty()\n                .map { item -> item.data.id }.toSet()\n        }\n    }\n\n    fun clearSelectedItems() {\n        // We need this to be done immediately\n        // so we can't use postValue\n        updateSelectedItems { emptySet() }\n    }\n\n    fun isAllChildrenSelected(): Boolean {\n        val currentSelected = selectedItemIds.value ?: return false\n        val children = _childCards.success.orEmpty()\n        return currentSelected.size == children.size && children.all { it.data.id in currentSelected }\n    }\n\n    fun isAllHeadersSelected(): Boolean {\n        val currentSelected = selectedItemIds.value ?: return false\n        val headers = _headerCards.success.orEmpty()\n        return currentSelected.size == headers.size && headers.all { it.data.id in currentSelected }\n    }\n\n    private fun updateSelectedItems(action: (Set<Int>?) -> Set<Int>?) {\n        val currentSelected = action(selectedItemIds.value)\n        _selectedItemIds.postValue(currentSelected)\n        postHeaders()\n        postChildren()\n        updateSelectedBytes()\n    }\n\n    private fun updateSelectedBytes() = viewModelScope.launchSafe {\n        val selectedItemsList = getSelectedItemsData() ?: return@launchSafe\n        val totalSelectedBytes = selectedItemsList.sumOf { it.totalBytes }\n        _selectedBytes.postValue(totalSelectedBytes)\n    }\n\n\n    fun removeRedundantEpisodeKeys(context: Context, keys: List<Pair<Int, Int>>) {\n        val settingsManager = context.getSharedPrefs()\n        ioSafe {\n            settingsManager.edit {\n                keys.forEach { (parentId, childId) ->\n                    Log.i(TAG, \"Removing download episode key: ${parentId}/${childId}\")\n                    val oldPath = getFolderName(\n                        getFolderName(\n                            DOWNLOAD_EPISODE_CACHE,\n                            parentId.toString()\n                        ),\n                        childId.toString()\n                    )\n                    val newPath = getFolderName(\n                        getFolderName(\n                            DOWNLOAD_EPISODE_CACHE_BACKUP,\n                            parentId.toString()\n                        ),\n                        childId.toString()\n                    )\n\n                    val oldPref = settingsManager.getString(oldPath, null)\n                    // Cowardly future backup solution in case the key removal fails in some edge case.\n                    // This and all backup keys may be removed in a future update if the key removal is proven to be robust.\n                    this.putString(newPath, oldPref)\n                    this.remove(oldPath)\n                }\n            }\n        }\n    }\n\n    fun removeRedundantHeaderKeys(\n        context: Context,\n        cached: List<DownloadObjects.DownloadHeaderCached>,\n        totalBytesUsedByChild: Map<Int, Long>,\n        totalDownloads: Map<Int, Int>\n    ) {\n        val settingsManager = context.getSharedPrefs()\n        ioSafe {\n           // Do not remove headers used by resume watching\n            val resumeWatchingIds =\n                getAllResumeStateIds()?.mapNotNull { id ->\n                    getLastWatched(id)?.parentId\n                }?.toSet() ?: emptySet()\n\n            settingsManager.edit {\n                cached.forEach { header ->\n                    val downloads = totalDownloads[header.id] ?: 0\n                    val bytes = totalBytesUsedByChild[header.id] ?: 0\n\n                    if ( (downloads <= 0 || bytes <= 0) && !resumeWatchingIds.contains(header.id) ) {\n                        Log.i(TAG, \"Removing download header key: ${header.id}\")\n                        val oldPAth = getFolderName(DOWNLOAD_HEADER_CACHE, header.id.toString())\n                        val newPath =\n                            getFolderName(DOWNLOAD_HEADER_CACHE_BACKUP, header.id.toString())\n                        val oldPref = settingsManager.getString(oldPAth, null)\n                        // Cowardly future backup solution in case the key removal fails in some edge case.\n                        // This and all backup keys may be removed in a future update if the key removal is proven to be robust.\n                        this.putString(newPath, oldPref)\n                        this.remove(oldPAth)\n                    }\n                }\n            }\n        }\n    }\n\n    fun updateHeaderList(context: Context) = viewModelScope.launchSafe {\n        // Do not push loading as it interrupts the UI\n        //_headerCards.postValue(Resource.Loading())\n\n        val visual = ioWork {\n            val children = context.getKeys(DOWNLOAD_EPISODE_CACHE)\n                .mapNotNull { context.getKey<DownloadObjects.DownloadEpisodeCached>(it) }\n                .distinctBy { it.id } // Remove duplicates\n\n            val isCurrentlyDownloading =\n                DownloadQueueService.isRunning || downloadInstances.value.isNotEmpty() || DownloadQueueManager.queue.value.isNotEmpty()\n\n            val downloadStats =\n                calculateDownloadStats(context, children)\n\n            val cached = context.getKeys(DOWNLOAD_HEADER_CACHE)\n                .mapNotNull { context.getKey<DownloadObjects.DownloadHeaderCached>(it) }\n\n            // Download stats and header keys may change when downloading.\n            // To prevent the downloader and key removal from colliding, simply do not prune keys when downloading.\n            if (!isCurrentlyDownloading) {\n                removeRedundantHeaderKeys(\n                    context,\n                    cached,\n                    downloadStats.totalBytesUsedByChild,\n                    downloadStats.totalDownloads\n                )\n            }\n            // calculateDownloadStats already performed checks when creating redundantDownloads, no extra check required\n            removeRedundantEpisodeKeys(context, downloadStats.redundantDownloads)\n\n            createVisualDownloadList(\n                context,\n                cached,\n                downloadStats.totalBytesUsedByChild,\n                downloadStats.currentBytesUsedByChild,\n                downloadStats.totalDownloads\n            )\n        }\n\n        updateStorageStats(visual)\n        postHeaders(visual)\n    }\n\n    fun postHeaders(newValue: List<VisualDownloadCached.Header>? = null) {\n        val newValue = newValue ?: _headerCards.success ?: return\n        val selection = selectedItemIds.value ?: emptySet()\n        _headerCards.postValue(Resource.Success(newValue.map {\n            it.copy(\n                isSelected = selection.contains(\n                    it.data.id\n                )\n            )\n        }))\n    }\n\n    fun postChildren(newValue: List<VisualDownloadCached.Child>? = null) {\n        val newValue = newValue ?: _childCards.success ?: return\n        val selection = selectedItemIds.value ?: emptySet()\n        _childCards.postValue(Resource.Success(newValue.map {\n            it.copy(\n                isSelected = selection.contains(\n                    it.data.id\n                )\n            )\n        }))\n    }\n\n    private data class DownloadStats(\n        val totalBytesUsedByChild: Map<Int, Long>,\n        val currentBytesUsedByChild: Map<Int, Long>,\n        val totalDownloads: Map<Int, Int>,\n        /** Parent ID to child ID. Keys to be removed. */\n        val redundantDownloads: List<Pair<Int, Int>>\n    )\n\n    private fun calculateDownloadStats(\n        context: Context,\n        children: List<DownloadObjects.DownloadEpisodeCached>\n    ): DownloadStats {\n        // parentId : bytes\n        val totalBytesUsedByChild = mutableMapOf<Int, Long>()\n        // parentId : bytes\n        val currentBytesUsedByChild = mutableMapOf<Int, Long>()\n        // parentId : downloadsCount\n        val totalDownloads = mutableMapOf<Int, Int>()\n        val redundantDownloads = mutableListOf<Pair<Int, Int>>()\n\n        children.forEach { child ->\n            val childFile = getDownloadFileInfo(context, child.id)\n\n            if (childFile == null) {\n                // It may not be a redundant child if something is currently downloading.\n                // DOWNLOAD_EPISODE_CACHE gets created before KEY_DOWNLOAD_INFO in the downloader\n                // leading to valid situations where getDownloadFileInfo is null, but we do not want to remove DOWNLOAD_EPISODE_CACHE\n                if (!DownloadQueueService.isRunning && downloadInstances.value.isEmpty() && DownloadQueueManager.queue.value.isEmpty()) {\n                    redundantDownloads.add(child.parentId to child.id)\n                }\n                return@forEach\n            }\n            if (childFile.fileLength <= 1) return@forEach\n\n            val len = childFile.totalBytes\n            val flen = childFile.fileLength\n\n            totalBytesUsedByChild.merge(child.parentId, len, Long::plus)\n            currentBytesUsedByChild.merge(child.parentId, flen, Long::plus)\n            totalDownloads.merge(child.parentId, 1, Int::plus)\n        }\n        return DownloadStats(\n            totalBytesUsedByChild,\n            currentBytesUsedByChild,\n            totalDownloads,\n            redundantDownloads\n        )\n    }\n\n    private fun createVisualDownloadList(\n        context: Context,\n        cached: List<DownloadObjects.DownloadHeaderCached>,\n        totalBytesUsedByChild: Map<Int, Long>,\n        currentBytesUsedByChild: Map<Int, Long>,\n        totalDownloads: Map<Int, Int>\n    ): List<VisualDownloadCached.Header> {\n        return cached.mapNotNull {\n            val downloads = totalDownloads[it.id] ?: 0\n            val bytes = totalBytesUsedByChild[it.id] ?: 0\n            val currentBytes = currentBytesUsedByChild[it.id] ?: 0\n\n            if (bytes <= 0 || downloads <= 0) {\n                return@mapNotNull null\n            }\n\n            val isSelected = selectedItemIds.value?.contains(it.id) ?: false\n            val movieEpisode =\n                if (it.type.isEpisodeBased()) null else context.getKey<DownloadObjects.DownloadEpisodeCached>(\n                    DOWNLOAD_EPISODE_CACHE,\n                    getFolderName(it.id.toString(), it.id.toString())\n                )\n\n            VisualDownloadCached.Header(\n                currentBytes = currentBytes,\n                totalBytes = bytes,\n                data = it,\n                child = movieEpisode,\n                currentOngoingDownloads = 0,\n                totalDownloads = downloads,\n                isSelected = isSelected,\n            )\n            // Prevent order being almost completely random,\n            // making things difficult to find.\n        }.sortedWith(compareBy<VisualDownloadCached.Header> {\n            // Sort by isEpisodeBased() ascending. We put those that\n            // are episode based at the bottom for UI purposes and to\n            // make it easier to find by grouping them together.\n            it.data.type.isEpisodeBased()\n        }.thenBy {\n            // Then we sort alphabetically by name (case-insensitive).\n            // Again, we do this to make things easier to find.\n            it.data.name.lowercase()\n        })\n    }\n\n    fun updateChildList(context: Context, folder: String) = viewModelScope.launchSafe {\n        _childCards.postValue(Resource.Loading()) // always push loading\n\n        val visual = withContext(Dispatchers.IO) {\n            context.getKeys(folder).mapNotNull { key ->\n                context.getKey<DownloadObjects.DownloadEpisodeCached>(key)\n            }.mapNotNull {\n                val isSelected = selectedItemIds.value?.contains(it.id) ?: false\n                val info = getDownloadFileInfo(context, it.id) ?: return@mapNotNull null\n                VisualDownloadCached.Child(\n                    currentBytes = info.fileLength,\n                    totalBytes = info.totalBytes,\n                    isSelected = isSelected,\n                    data = it,\n                )\n            }\n        }.sortedWith(\n            compareBy(\n                // Sort by season first, and then by episode number,\n                // to ensure sorting is consistent.\n                { it.data.season ?: 0 },\n                { it.data.episode }\n            ))\n\n        postChildren(visual)\n    }\n\n    private fun removeItems(idsToRemove: Set<Int>) = viewModelScope.launchSafe {\n        _selectedItemIds.postValue(null)\n        postHeaders(_headerCards.success?.filter { it.data.id !in idsToRemove })\n        postChildren(_childCards.success?.filter { it.data.id !in idsToRemove })\n    }\n\n    private fun updateStorageStats(visual: List<VisualDownloadCached.Header>) {\n        try {\n            val stat = StatFs(Environment.getExternalStorageDirectory().path)\n            val localBytesAvailable = stat.availableBytes\n            val localTotalBytes = stat.blockSizeLong * stat.blockCountLong\n            val localDownloadedBytes = visual.sumOf { it.totalBytes }\n            val localUsedBytes = localTotalBytes - localBytesAvailable\n            _usedBytes.postValue(localUsedBytes)\n            _availableBytes.postValue(localBytesAvailable)\n            _downloadBytes.postValue(localDownloadedBytes)\n        } catch (t: Throwable) {\n            _downloadBytes.postValue(0)\n            logError(t)\n        }\n    }\n\n    fun handleMultiDelete(context: Context) = viewModelScope.launchSafe {\n        val selectedItemsList = getSelectedItemsData().orEmpty()\n        val deleteData = processSelectedItems(context, selectedItemsList)\n        val message = buildDeleteMessage(context, deleteData)\n        showDeleteConfirmationDialog(context, message, deleteData.ids, deleteData.parentIds)\n    }\n\n    fun handleSingleDelete(\n        context: Context,\n        itemId: Int\n    ) = viewModelScope.launchSafe {\n        val itemData = getItemDataFromId(itemId)\n        val deleteData = processSelectedItems(context, itemData)\n        val message = buildDeleteMessage(context, deleteData)\n        showDeleteConfirmationDialog(context, message, deleteData.ids, deleteData.parentIds)\n    }\n\n    private fun processSelectedItems(\n        context: Context,\n        selectedItemsList: List<VisualDownloadCached>\n    ): DeleteData {\n        val names = mutableListOf<String>()\n        val seriesNames = mutableListOf<String>()\n\n        val ids = mutableSetOf<Int>()\n        val parentIds = mutableSetOf<Int>()\n\n        var parentName: String? = null\n\n        selectedItemsList.forEach { item ->\n            when (item) {\n                is VisualDownloadCached.Header -> {\n                    if (item.data.type.isEpisodeBased()) {\n                        val episodes = context.getKeys(DOWNLOAD_EPISODE_CACHE)\n                            .mapNotNull {\n                                context.getKey<DownloadObjects.DownloadEpisodeCached>(\n                                    it\n                                )\n                            }\n                            .filter { it.parentId == item.data.id }\n                            .map { it.id }\n                        ids.addAll(episodes)\n                        parentIds.add(item.data.id)\n\n                        val episodeInfo = \"${item.data.name} (${item.totalDownloads} ${\n                            context.resources.getQuantityString(\n                                R.plurals.episodes,\n                                item.totalDownloads\n                            ).lowercase()\n                        })\"\n                        seriesNames.add(episodeInfo)\n                    } else {\n                        ids.add(item.data.id)\n                        names.add(item.data.name)\n                    }\n                }\n\n                is VisualDownloadCached.Child -> {\n                    ids.add(item.data.id)\n                    val parent = context.getKey<DownloadObjects.DownloadHeaderCached>(\n                        DOWNLOAD_HEADER_CACHE,\n                        item.data.parentId.toString()\n                    )\n                    parentName = parent?.name\n                    names.add(\n                        context.getNameFull(\n                            item.data.name,\n                            item.data.episode,\n                            item.data.season\n                        )\n                    )\n                }\n            }\n        }\n\n        return DeleteData(ids, parentIds, seriesNames, names, parentName)\n    }\n\n    private fun buildDeleteMessage(\n        context: Context,\n        data: DeleteData\n    ): String {\n        val formattedNames = data.names.sortedBy { it.lowercase() }\n            .joinToString(separator = \"\\n\") { \"• $it\" }\n        val formattedSeriesNames = data.seriesNames.sortedBy { it.lowercase() }\n            .joinToString(separator = \"\\n\") { \"• $it\" }\n\n        return when {\n            data.seriesNames.isNotEmpty() && data.names.isEmpty() -> {\n                context.getString(R.string.delete_message_series_only).format(formattedSeriesNames)\n            }\n\n            data.ids.count() == 1 -> {\n                context.getString(R.string.delete_message).format(\n                    data.names.firstOrNull()\n                )\n            }\n\n            data.parentName != null && data.names.isNotEmpty() -> {\n                context.getString(R.string.delete_message_series_episodes)\n                    .format(data.parentName, formattedNames)\n            }\n\n            data.seriesNames.isNotEmpty() -> {\n                val seriesSection = context.getString(R.string.delete_message_series_section)\n                    .format(formattedSeriesNames)\n                context.getString(R.string.delete_message_multiple)\n                    .format(formattedNames) + \"\\n\\n\" + seriesSection\n            }\n\n            else -> context.getString(R.string.delete_message_multiple).format(formattedNames)\n        }\n    }\n\n    private fun showDeleteConfirmationDialog(\n        context: Context,\n        message: String,\n        ids: Set<Int>,\n        parentIds: Set<Int>\n    ) {\n        val builder = AlertDialog.Builder(context)\n        val dialogClickListener =\n            DialogInterface.OnClickListener { _, which ->\n                when (which) {\n                    DialogInterface.BUTTON_POSITIVE -> {\n                        viewModelScope.launchSafe {\n                            deleteFilesAndUpdateSettings(context, ids, this) { successfulIds ->\n                                // We always remove parent because if we are deleting from here\n                                // and we have it as non-empty, it was triggered on\n                                // parent header card\n                                removeItems(successfulIds + parentIds)\n                            }\n                        }\n                    }\n\n                    DialogInterface.BUTTON_NEGATIVE -> {\n                        // Do nothing on cancel\n                    }\n                }\n            }\n\n        try {\n            val title = if (ids.count() == 1) {\n                R.string.delete_file\n            } else R.string.delete_files\n            builder.setTitle(title)\n                .setMessage(message)\n                .setPositiveButton(R.string.delete, dialogClickListener)\n                .setNegativeButton(R.string.cancel, dialogClickListener)\n                .show().setDefaultFocus()\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    private fun getSelectedItemsData(): List<VisualDownloadCached>? {\n        val headers = _headerCards.success.orEmpty()\n        val children = _childCards.success.orEmpty()\n\n        return selectedItemIds.value?.mapNotNull { id ->\n            headers.find { it.data.id == id } ?: children.find { it.data.id == id }\n        }\n    }\n\n    private fun getItemDataFromId(itemId: Int): List<VisualDownloadCached> {\n        return (_headerCards.success.orEmpty() + _childCards.success.orEmpty()).filter { it.data.id == itemId }\n    }\n\n    fun clearChildren() {\n        _childCards.postValue(Resource.Loading())\n    }\n\n    private data class DeleteData(\n        val ids: Set<Int>,\n        val parentIds: Set<Int>,\n        val seriesNames: List<String>,\n        val names: List<String>,\n        val parentName: String?\n    )\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/button/BaseFetchButton.kt",
    "content": "package com.lagradost.cloudstream3.ui.download.button\n\nimport android.content.Context\nimport android.text.format.Formatter.formatShortFileSize\nimport android.util.AttributeSet\nimport android.widget.FrameLayout\nimport android.widget.TextView\nimport androidx.annotation.LayoutRes\nimport androidx.core.view.isVisible\nimport androidx.core.widget.ContentLoadingProgressBar\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.mainWork\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\n\ntypealias DownloadStatusTell = VideoDownloadManager.DownloadType\n\ndata class DownloadMetadata(\n    var id: Int,\n    var downloadedLength: Long,\n    var totalLength: Long,\n    var status: DownloadStatusTell? = null\n) {\n    val progressPercentage: Long\n        get() = if (downloadedLength < 1024) 0 else maxOf(\n            0,\n            minOf(100, (downloadedLength * 100L) / (totalLength + 1))\n        )\n}\n\nabstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) :\n    FrameLayout(context, attributeSet) {\n\n    var persistentId: Int? = null // used to save sessions\n\n    lateinit var progressBar: ContentLoadingProgressBar\n    var progressText: TextView? = null\n\n    /* val gid: String? get() = sessionIdToGid[persistentId]\n\n    // used for resuming data\n    var _lastRequestOverride: UriRequest? = null\n    var lastRequest: UriRequest?\n        get() = _lastRequestOverride ?: sessionIdToLastRequest[persistentId]\n        set(value) {\n            _lastRequestOverride = value\n        }\n\n    var files: List<AbstractClient.JsonFile> = emptyList() */\n    protected var isZeroBytes: Boolean = true\n\n    fun inflate(@LayoutRes layout: Int) {\n        inflate(context, layout, this)\n    }\n\n    init {\n        @Suppress(\"LeakingThis\")\n        resetViewData()\n    }\n\n    var doSetProgress = true\n\n    open fun resetViewData() {\n        // lastRequest = null\n        progressText = null\n        isZeroBytes = true\n        doSetProgress = true\n        persistentId = null\n    }\n\n    var currentMetaData: DownloadMetadata =\n        DownloadMetadata(0, 0, 0, null)\n\n    fun setPersistentId(id: Int) {\n        persistentId = id\n        currentMetaData.id = id\n\n        if (!doSetProgress) return\n\n        ioSafe {\n            val savedData = VideoDownloadManager.getDownloadFileInfo(context, id)\n\n            mainWork {\n                if (savedData != null) {\n                    val downloadedBytes = savedData.fileLength\n                    val totalBytes = savedData.totalBytes\n\n                    setProgress(downloadedBytes, totalBytes)\n                    applyMetaData(id, downloadedBytes, totalBytes)\n                }\n            }\n        }\n    }\n\n    abstract fun setStatus(status: VideoDownloadManager.DownloadType?)\n\n    fun getStatus(id: Int, downloadedBytes: Long, totalBytes: Long): DownloadStatusTell {\n        // some extra padding for just in case\n        return VideoDownloadManager.downloadStatus[id]\n            ?: if (downloadedBytes > 1024L && downloadedBytes + 1024L >= totalBytes) {\n                DownloadStatusTell.IsDone\n            } else DownloadStatusTell.IsPaused\n    }\n\n    fun applyMetaData(id: Int, downloadedBytes: Long, totalBytes: Long) {\n        val status = getStatus(id, downloadedBytes, totalBytes)\n\n        currentMetaData.apply {\n            this.id = id\n            this.downloadedLength = downloadedBytes\n            this.totalLength = totalBytes\n            this.status = status\n        }\n        setStatus(status)\n    }\n\n    open fun setProgress(downloadedBytes: Long, totalBytes: Long) {\n        isZeroBytes = downloadedBytes == 0L\n        progressBar.post {\n            val steps = 10000L\n            progressBar.max = steps.toInt()\n            // div by zero error and 1 byte off is ok impo\n\n            val progress = (downloadedBytes * steps / (totalBytes + 1L)).toInt()\n\n            val animation = ProgressBarAnimation(\n                progressBar,\n                progressBar.progress.toFloat(),\n                progress.toFloat()\n            ).apply {\n                fillAfter = true\n                duration =\n                    if (progress > progressBar.progress) // we don't want to animate backward changes in progress\n                        100\n                    else\n                        0L\n            }\n\n            if (isZeroBytes) {\n                progressText?.isVisible = false\n            } else {\n                if (doSetProgress) {\n                    progressText?.apply {\n                        val currentFormattedSizeString =\n                            formatShortFileSize(context, downloadedBytes)\n                        val totalFormattedSizeString = formatShortFileSize(context, totalBytes)\n                        text =\n                                // if (isTextPercentage) \"%d%%\".format(setCurrentBytes * 100L / setTotalBytes) else\n                            context?.getString(R.string.download_size_format)\n                                ?.format(currentFormattedSizeString, totalFormattedSizeString)\n                    }\n                }\n            }\n\n            progressBar.startAnimation(animation)\n        }\n    }\n\n    fun downloadStatusEvent(data: Pair<Int, VideoDownloadManager.DownloadType>) {\n        val (id, status) = data\n        if (id == persistentId) {\n            currentMetaData.status = status\n            setStatus(status)\n        }\n    }\n\n    /*fun downloadDeleteEvent(data: Int) {\n\n    }*/\n\n    /*fun downloadEvent(data: Pair<Int, VideoDownloadManager.DownloadActionType>) {\n        val (id, action) = data\n\n    }*/\n\n    fun downloadProgressEvent(data: Triple<Int, Long, Long>) {\n        val (id, bytesDownloaded, bytesTotal) = data\n        if (id == persistentId) {\n            currentMetaData.downloadedLength = bytesDownloaded\n            currentMetaData.totalLength = bytesTotal\n\n            setProgress(bytesDownloaded, bytesTotal)\n        }\n    }\n\n    override fun onAttachedToWindow() {\n        VideoDownloadManager.downloadStatusEvent += ::downloadStatusEvent\n        // VideoDownloadManager.downloadDeleteEvent += ::downloadDeleteEvent\n        // VideoDownloadManager.downloadEvent += ::downloadEvent\n        VideoDownloadManager.downloadProgressEvent += ::downloadProgressEvent\n\n        val pid = persistentId\n        if (pid != null) {\n            // refresh in case of onDetachedFromWindow -> onAttachedToWindow while still being ???????\n            setPersistentId(pid)\n        }\n\n        super.onAttachedToWindow()\n    }\n\n    override fun onDetachedFromWindow() {\n        VideoDownloadManager.downloadStatusEvent -= ::downloadStatusEvent\n        // VideoDownloadManager.downloadDeleteEvent -= ::downloadDeleteEvent\n        // VideoDownloadManager.downloadEvent -= ::downloadEvent\n        VideoDownloadManager.downloadProgressEvent -= ::downloadProgressEvent\n\n        super.onDetachedFromWindow()\n    }\n\n    /**\n     * No checks required. Arg will always include a download with current id\n     * */\n    abstract fun updateViewOnDownload(metadata: DownloadMetadata)\n\n    /**\n     * Get a clean slate again, might be useful in recyclerview?\n     * */\n    abstract fun resetView()\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/button/DownloadButton.kt",
    "content": "package com.lagradost.cloudstream3.ui.download.button\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.widget.TextView\nimport androidx.core.view.isVisible\nimport com.google.android.material.button.MaterialButton\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.download.DownloadClickEvent\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\n\nclass DownloadButton(context: Context, attributeSet: AttributeSet) :\n    PieFetchButton(context, attributeSet) {\n\n    private var mainText: TextView? = null\n    override fun onAttachedToWindow() {\n        super.onAttachedToWindow()\n        progressText = findViewById(R.id.result_movie_download_text_precentage)\n        mainText = findViewById(R.id.result_movie_download_text)\n        setStatus(null)\n    }\n\n    override fun setStatus(status: DownloadStatusTell?) {\n        mainText?.post {\n            val txt = when (status) {\n                DownloadStatusTell.IsPaused -> R.string.download_paused\n                DownloadStatusTell.IsDownloading -> R.string.downloading\n                DownloadStatusTell.IsDone -> R.string.downloaded\n                else -> R.string.download\n            }\n            mainText?.setText(txt)\n        }\n        super.setStatus(status)\n\n    }\n\n    override fun setDefaultClickListener(\n        card: DownloadObjects.DownloadEpisodeCached,\n        textView: TextView?,\n        callback: (DownloadClickEvent) -> Unit\n    ) {\n        this.setDefaultClickListener(\n            this.findViewById<MaterialButton>(R.id.download_movie_button),\n            textView,\n            card,\n            callback\n        )\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun updateViewOnDownload(metadata: DownloadMetadata) {\n        super.updateViewOnDownload(metadata)\n\n        val isVis = metadata.progressPercentage > 0\n        progressText?.isVisible = isVis\n        if (isVis)\n            progressText?.text = \"${metadata.progressPercentage}%\"\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/button/PieFetchButton.kt",
    "content": "package com.lagradost.cloudstream3.ui.download.button\n\nimport android.content.Context\nimport android.os.Looper\nimport android.util.AttributeSet\nimport android.util.Log\nimport android.view.View\nimport android.view.animation.AnimationUtils\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.annotation.MainThread\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.withStyledAttributes\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.services.DownloadQueueService.Companion.downloadInstances\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_CANCEL_PENDING\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DELETE_FILE\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_LONG_CLICK\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_PAUSE_DOWNLOAD\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_PLAY_FILE\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_RESUME_DOWNLOAD\nimport com.lagradost.cloudstream3.ui.download.DownloadClickEvent\nimport com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager.queue\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_RESUME_PACKAGES\n\nopen class PieFetchButton(context: Context, attributeSet: AttributeSet) :\n    BaseFetchButton(context, attributeSet) {\n\n    private var waitingAnimation: Int = 0\n    private var animateWaiting: Boolean = false\n    private var activeOutline: Int = 0\n    private var nonActiveOutline: Int = 0\n\n    private var iconInit: Int = 0\n    private var iconError: Int = 0\n    private var iconComplete: Int = 0\n    private var iconActive: Int = 0\n    private var iconWaiting: Int = 0\n    private var iconRemoved: Int = 0\n    private var iconPaused: Int = 0\n    private var hideWhenIcon: Boolean = true\n\n    var progressDrawable: Int = 0\n\n    var overrideLayout: Int? = null\n\n    companion object {\n        val fillArray = arrayOf(\n            R.drawable.circular_progress_bar_clockwise,\n            R.drawable.circular_progress_bar_counter_clockwise,\n            R.drawable.circular_progress_bar_small_to_large,\n            R.drawable.circular_progress_bar_top_to_bottom,\n        )\n    }\n\n    private var progressBarBackground: View\n    var statusView: ImageView\n\n    open fun onInflate() {}\n\n    init {\n        context.withStyledAttributes(attributeSet, R.styleable.PieFetchButton, 0, 0) {\n            try {\n                inflate(\n                    overrideLayout ?: getResourceId(\n                        R.styleable.PieFetchButton_download_layout,\n                        R.layout.download_button_view\n                    )\n                )\n            } catch (e: Exception) {\n                recycle() // Manually call recycle first to avoid memory leaks\n                Log.e(\n                    \"PieFetchButton\", \"Error inflating PieFetchButton, \" +\n                            \"check that you have declared the required aria2c attrs: aria2c_icon_scale aria2c_icon_color aria2c_outline_color aria2c_fill_color\"\n                )\n                throw e\n            }\n\n            animateWaiting = getBoolean(\n                R.styleable.PieFetchButton_download_animate_waiting,\n                true\n            )\n            hideWhenIcon = getBoolean(\n                R.styleable.PieFetchButton_download_hide_when_icon,\n                true\n            )\n            waitingAnimation = getResourceId(\n                R.styleable.PieFetchButton_download_waiting_animation,\n                R.anim.rotate_around_center_point\n            )\n            activeOutline = getResourceId(\n                R.styleable.PieFetchButton_download_outline_active, R.drawable.circle_shape\n            )\n            nonActiveOutline = getResourceId(\n                R.styleable.PieFetchButton_download_outline_non_active,\n                R.drawable.circle_shape_dotted\n            )\n            iconInit = getResourceId(\n                R.styleable.PieFetchButton_download_icon_init, R.drawable.netflix_download\n            )\n            iconError = getResourceId(\n                R.styleable.PieFetchButton_download_icon_paused, R.drawable.download_icon_error\n            )\n            iconComplete = getResourceId(\n                R.styleable.PieFetchButton_download_icon_complete, R.drawable.download_icon_done\n            )\n            iconPaused = getResourceId(\n                R.styleable.PieFetchButton_download_icon_paused, 0 // R.drawable.download_icon_pause\n            )\n            iconActive = getResourceId(\n                R.styleable.PieFetchButton_download_icon_active, 0 // R.drawable.download_icon_load\n            )\n            iconWaiting = getResourceId(\n                R.styleable.PieFetchButton_download_icon_waiting, 0\n            )\n            iconRemoved = getResourceId(\n                R.styleable.PieFetchButton_download_icon_removed, R.drawable.netflix_download\n            )\n\n            val fillIndex = getInt(R.styleable.PieFetchButton_download_fill, 0)\n            progressDrawable = getResourceId(\n                R.styleable.PieFetchButton_download_fill_override, fillArray[fillIndex]\n            )\n        }\n        \n        progressBar = findViewById(R.id.progress_downloaded)\n        progressBarBackground = findViewById(R.id.progress_downloaded_background)\n        statusView = findViewById(R.id.image_download_status)\n        \n        progressBar.progressDrawable = ContextCompat.getDrawable(context, progressDrawable)\n\n        // resetView()\n        onInflate()\n    }\n\n\n    override fun onAttachedToWindow() {\n        super.onAttachedToWindow()\n        // Re-run all animations when the view gets visible.\n        // Otherwise views may run without animations after recycled\n        setStatusInternal(currentStatus)\n    }\n\n    private var currentStatus: DownloadStatusTell? = null\n    /*private fun getActivity(): Activity? {\n        var context = context\n        while (context is ContextWrapper) {\n            if (context is Activity) {\n                return context\n            }\n            context = context.baseContext\n        }\n        return null\n    }\n\n    fun callback(event : DownloadClickEvent) {\n        handleDownloadClick(\n            getActivity(),\n            event\n        )\n    }*/\n\n    protected fun setDefaultClickListener(\n        view: View, textView: TextView?, card: DownloadObjects.DownloadEpisodeCached,\n        callback: (DownloadClickEvent) -> Unit\n    ) {\n        this.progressText = textView\n        this.setPersistentId(card.id)\n        view.setOnClickListener {\n            if (isZeroBytes) {\n                val localQueue = queue.value\n                val localInstances = downloadInstances.value\n                val id = card.id\n\n                // If the download is already in queue or active downloads, provide an option to cancel it\n                if (localQueue.any { q -> q.id == id } || localInstances.any { i -> i.downloadQueueWrapper.id == id }) {\n                    it.popupMenuNoIcons(\n                        arrayListOf(\n                            Pair(DOWNLOAD_ACTION_CANCEL_PENDING, R.string.cancel),\n                        )\n                    ) {\n                        callback(DownloadClickEvent(itemId, card))\n                    }\n                } else {\n                    // Otherwise just start a download instantly\n                    removeKey(KEY_RESUME_PACKAGES, card.id.toString())\n                    callback(DownloadClickEvent(DOWNLOAD_ACTION_DOWNLOAD, card))\n                }\n            } else {\n                val list = arrayListOf(\n                    Pair(DOWNLOAD_ACTION_PLAY_FILE, R.string.popup_play_file),\n                    Pair(DOWNLOAD_ACTION_DELETE_FILE, R.string.popup_delete_file),\n                )\n\n                currentMetaData.apply {\n                    // DON'T RESUME A DOWNLOADED FILE lastState != VideoDownloadManager.DownloadType.IsDone &&\n                    if (progressPercentage < 98) {\n                        list.add(\n                            if (status == VideoDownloadManager.DownloadType.IsDownloading)\n                                Pair(DOWNLOAD_ACTION_PAUSE_DOWNLOAD, R.string.popup_pause_download)\n                            else\n                                Pair(\n                                    DOWNLOAD_ACTION_RESUME_DOWNLOAD,\n                                    R.string.popup_resume_download\n                                )\n                        )\n                    }\n                }\n\n\n                it.popupMenuNoIcons(\n                    list\n                ) {\n                    callback(DownloadClickEvent(itemId, card))\n                    // callback.invoke(DownloadClickEvent(itemId, data))\n                }\n            }\n        }\n\n        view.setOnLongClickListener {\n            callback(DownloadClickEvent(DOWNLOAD_ACTION_LONG_CLICK, card))\n\n            // clickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_LONG_CLICK, data))\n            return@setOnLongClickListener true\n        }\n    }\n\n    open fun setDefaultClickListener(\n        card: DownloadObjects.DownloadEpisodeCached,\n        textView: TextView?,\n        callback: (DownloadClickEvent) -> Unit\n    ) {\n        setDefaultClickListener(this, textView, card, callback)\n    }\n\n    /* open fun setDefaultClickListener(requestGetter: suspend BaseFetchButton.() -> List<UriRequest>) {\n        this.setOnClickListener {\n            when (this.currentStatus) {\n                null -> {\n                    setStatus(DownloadStatusTell.IsPending)\n                    ioThread {\n                        val request = requestGetter.invoke(this)\n                        if (request.size == 1) {\n                            performDownload(request.first())\n                        } else if (request.isNotEmpty()) {\n                            performFailQueueDownload(request)\n                        }\n                    }\n                }\n                DownloadStatusTell.Paused -> {\n                    resumeDownload()\n                }\n                DownloadStatusTell.Active -> {\n                    pauseDownload()\n                }\n                DownloadStatusTell.Error -> {\n                    redownload()\n                }\n                else -> {}\n            }\n        }\n    } */\n\n    @MainThread\n    private fun setStatusInternal(status: DownloadStatusTell?) {\n        val isPreActive = isZeroBytes && status == DownloadStatusTell.IsDownloading\n        if (animateWaiting && (status == DownloadStatusTell.IsPending || isPreActive)) {\n            val animation = AnimationUtils.loadAnimation(context, waitingAnimation)\n            progressBarBackground.startAnimation(animation)\n        } else {\n            progressBarBackground.clearAnimation()\n        }\n\n        val progressDrawable =\n            if (status == DownloadStatusTell.IsDownloading && !isPreActive) activeOutline else nonActiveOutline\n\n        progressBarBackground.background =\n            ContextCompat.getDrawable(context, progressDrawable)\n\n        val drawable =\n            getDrawableFromStatus(status)?.let { ContextCompat.getDrawable(this.context, it) }\n        statusView.setImageDrawable(drawable)\n        val isDrawable = drawable != null\n\n        statusView.isVisible = isDrawable\n        val hide = hideWhenIcon && isDrawable\n        if (hide) {\n            progressBar.clearAnimation()\n            progressBarBackground.clearAnimation()\n        }\n        progressBarBackground.isGone = hide\n        progressBar.isGone = hide\n    }\n\n    /** Also sets currentStatus */\n    override fun setStatus(status: DownloadStatusTell?) {\n        currentStatus = status\n\n        // Runs on the main thread, but also instant if it already is\n        if (Looper.myLooper() == Looper.getMainLooper()) {\n            try {\n                setStatusInternal(status)\n            } catch (t: Throwable) {\n                logError(t) // Just in case setStatusInternal throws because thread\n                progressBarBackground.post {\n                    setStatusInternal(status)\n                }\n            }\n        } else {\n            progressBarBackground.post {\n                setStatusInternal(status)\n            }\n        }\n    }\n\n    override fun resetView() {\n        setStatus(null)\n        currentMetaData = DownloadMetadata(0, 0, 0, null)\n        isZeroBytes = true\n        doSetProgress = true\n        progressBar.progress = 0\n    }\n\n    override fun updateViewOnDownload(metadata: DownloadMetadata) {\n\n        val newStatus = metadata.status\n\n        if (newStatus == null) {\n            resetView()\n            return\n        }\n\n        val isDone =\n            newStatus == DownloadStatusTell.IsDone || (metadata.downloadedLength > 1024 && metadata.downloadedLength + 1024 >= metadata.totalLength)\n\n        if (isDone)\n            setStatus(DownloadStatusTell.IsDone)\n        else {\n            setProgress(metadata.downloadedLength, metadata.totalLength)\n            setStatus(newStatus)\n        }\n    }\n\n    open fun getDrawableFromStatus(status: DownloadStatusTell?): Int? = when (status) {\n        DownloadStatusTell.IsPaused -> iconPaused\n        DownloadStatusTell.IsPending -> iconWaiting\n        DownloadStatusTell.IsDownloading -> iconActive\n        DownloadStatusTell.IsFailed -> iconError\n        DownloadStatusTell.IsDone -> iconComplete\n        DownloadStatusTell.IsStopped -> iconRemoved\n        else -> iconInit\n    }.takeIf { it != 0 }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/button/ProgressBarAnimation.kt",
    "content": "package com.lagradost.cloudstream3.ui.download.button\n\nimport android.view.animation.Animation\nimport android.view.animation.Transformation\nimport android.widget.ProgressBar\n\nclass ProgressBarAnimation(\n    private val progressBar: ProgressBar,\n    private val from: Float,\n    private val to: Float\n) :\n    Animation() {\n    override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {\n        super.applyTransformation(interpolatedTime, t)\n        val value = from + (to - from) * interpolatedTime\n        progressBar.progress = value.toInt()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/queue/DownloadQueueAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.download.queue\n\n\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.core.view.isGone\nimport androidx.fragment.app.Fragment\nimport androidx.recyclerview.widget.ItemTouchHelper\nimport androidx.recyclerview.widget.RecyclerView\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.DownloadQueueItemBinding\nimport com.lagradost.cloudstream3.ui.BaseAdapter\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_CANCEL_PENDING\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DELETE_FILE\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_PAUSE_DOWNLOAD\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_RESUME_DOWNLOAD\nimport com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick\nimport com.lagradost.cloudstream3.ui.download.DownloadClickEvent\nimport com.lagradost.cloudstream3.ui.download.queue.DownloadQueueAdapter.Companion.DOWNLOAD_SEPARATOR_TAG\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE\nimport com.lagradost.cloudstream3.utils.DataStore.getFolderName\nimport com.lagradost.cloudstream3.utils.DataStore.getKey\nimport com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIcons\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.DownloadQueueWrapper\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_DOWNLOAD_INFO\n\n/** An item in the adapter can either be a separator or a real item.\n * isCurrentlyDownloading is used to fully update items as opposed to just moving them. */\nclass DownloadAdapterItem(val item: DownloadQueueWrapper?) {\n    val isSeparator = item == null\n}\n\n\nclass DownloadQueueAdapter(val fragment: Fragment) : BaseAdapter<DownloadAdapterItem, Unit>(\n    diffCallback = BaseDiffCallback(\n        itemSame = { a, b -> a.item?.id == b.item?.id },\n        contentSame = { a, b ->\n            a.item == b.item\n        })\n) {\n    var currentDownloads = 0\n\n    companion object {\n        val DOWNLOAD_SEPARATOR_TAG = \"DOWNLOAD_SEPARATOR_TAG\"\n    }\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Unit> {\n        val inflater = LayoutInflater.from(parent.context)\n        val binding = DownloadQueueItemBinding.inflate(inflater, parent, false)\n        return ViewHolderState(binding)\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Unit>,\n        item: DownloadAdapterItem,\n        position: Int\n    ) {\n        when (val binding = holder.view) {\n            is DownloadQueueItemBinding -> {\n                if (item.item == null) {\n                    holder.itemView.tag = DOWNLOAD_SEPARATOR_TAG\n                    bindSeparator(binding)\n                } else {\n                    holder.itemView.tag = null\n                    bind(binding, item.item)\n                }\n            }\n        }\n    }\n\n    fun submitQueue(newQueue: DownloadAdapterQueue) {\n        val index = newQueue.currentDownloads.size\n        val current = newQueue.currentDownloads\n        val queue = newQueue.queue\n        currentDownloads = current.size\n\n        val newList =\n            (current + queue).distinctBy { it.id }.map { DownloadAdapterItem(it) }.toMutableList()\n                .apply {\n                    // Only add the separator if it actually separates something\n                    if (index < this.size) {\n                        add(index, DownloadAdapterItem(null))\n                    }\n                }\n        submitList(newList)\n    }\n\n    fun bindSeparator(binding: DownloadQueueItemBinding) {\n        binding.apply {\n            separatorHolder.isGone = false\n            downloadChildEpisodeHolder.isGone = true\n        }\n    }\n\n    fun bind(\n        binding: DownloadQueueItemBinding,\n        queueWrapper: DownloadQueueWrapper,\n    ) {\n        val context = binding.root.context\n\n        binding.apply {\n            separatorHolder.isGone = true\n            downloadChildEpisodeHolder.isGone = false\n\n            // Only set the child-text if child and parent are not the same\n            // This prevents setting movie titles twice\n            if (queueWrapper.id != queueWrapper.parentId) {\n                val mainName = queueWrapper.downloadItem?.resultName ?: queueWrapper.resumePackage?.item?.ep?.mainName\n                downloadChildEpisodeTextExtra.text = mainName\n            } else {\n                downloadChildEpisodeTextExtra.text = null\n            }\n\n            downloadChildEpisodeTextExtra.isGone = downloadChildEpisodeTextExtra.text.isNullOrBlank()\n\n            val status = VideoDownloadManager.downloadStatus[queueWrapper.id]\n\n            downloadButton.setOnClickListener { view ->\n                val episodeCached =\n                    getKey<DownloadObjects.DownloadEpisodeCached>(\n                        DOWNLOAD_EPISODE_CACHE,\n                        getFolderName(queueWrapper.parentId.toString(), queueWrapper.id.toString())\n                    )\n\n                val downloadInfo = context.getKey<DownloadObjects.DownloadedFileInfo>(\n                    KEY_DOWNLOAD_INFO,\n                    queueWrapper.id.toString()\n                )\n\n                val isCurrentlyDownloading = queueWrapper.isCurrentlyDownloading()\n\n                val actionList = arrayListOf<Pair<Int,Int>>()\n\n                if (isCurrentlyDownloading && episodeCached != null) {\n                    // KEY_DOWNLOAD_INFO is used in the file deletion, and is required to exist to delete anything\n                    if (downloadInfo != null) {\n                        actionList.add(Pair(DOWNLOAD_ACTION_DELETE_FILE, R.string.popup_delete_file))\n                    } else {\n                        actionList.add(Pair(DOWNLOAD_ACTION_CANCEL_PENDING, R.string.cancel))\n                    }\n\n                    val currentStatus = VideoDownloadManager.downloadStatus[queueWrapper.id]\n\n                    when (currentStatus) {\n                        VideoDownloadManager.DownloadType.IsDownloading -> {\n                            actionList.add(\n                                Pair(\n                                    DOWNLOAD_ACTION_PAUSE_DOWNLOAD,\n                                    R.string.popup_pause_download\n                                )\n                            )\n                        }\n\n                        VideoDownloadManager.DownloadType.IsPaused -> {\n                            actionList.add(\n                                Pair(\n                                    DOWNLOAD_ACTION_RESUME_DOWNLOAD,\n                                    R.string.popup_resume_download\n                                )\n                            )\n                        }\n\n                        else -> {}\n                    }\n\n                    view.popupMenuNoIcons(\n                        actionList\n                    ) {\n                        handleDownloadClick(DownloadClickEvent(itemId, episodeCached))\n                    }\n                } else {\n                    actionList.add(Pair(DOWNLOAD_ACTION_CANCEL_PENDING, R.string.cancel))\n\n                    view.popupMenuNoIcons(\n                        actionList\n                    ) {\n                        when (itemId) {\n                            DOWNLOAD_ACTION_CANCEL_PENDING -> {\n                                DownloadQueueManager.cancelDownload(queueWrapper.id)\n                            }\n                        }\n                    }\n                }\n            }\n\n            downloadButton.resetView()\n            downloadButton.setStatus(status)\n            downloadButton.setPersistentId(queueWrapper.id)\n\n            downloadChildEpisodeText.apply {\n                val name = queueWrapper.downloadItem?.episode?.name\n                    ?: queueWrapper.resumePackage?.item?.ep?.name\n                val episode =\n                    queueWrapper.downloadItem?.episode?.episode\n                        ?: queueWrapper.resumePackage?.item?.ep?.episode\n                val season =\n                    queueWrapper.downloadItem?.episode?.season\n                        ?: queueWrapper.resumePackage?.item?.ep?.season\n                text = context.getNameFull(name, episode, season)\n                isSelected = true // Needed for text repeating\n            }\n        }\n    }\n}\n\n\nclass DragAndDropTouchHelper(adapter: DownloadQueueAdapter) :\n    ItemTouchHelper(\n        DragAndDropTouchHelperCallback(adapter)\n    )\n\nprivate class DragAndDropTouchHelperCallback(private val adapter: DownloadQueueAdapter) :\n    ItemTouchHelper.Callback() {\n    override fun getMovementFlags(\n        recyclerView: RecyclerView,\n        viewHolder: RecyclerView.ViewHolder\n    ): Int {\n        val item = adapter.getItem(viewHolder.absoluteAdapterPosition)\n        val isDownloading = item.item?.isCurrentlyDownloading() == true\n        val dragFlags = if (item.isSeparator || isDownloading) {\n            0\n        } else {\n            ItemTouchHelper.UP or ItemTouchHelper.DOWN // Allow drag up/down\n        }\n\n        val swipeFlags = 0 // Disable swipe functionality\n        return makeMovementFlags(dragFlags, swipeFlags)\n    }\n\n    override fun onMove(\n        recyclerView: RecyclerView,\n        source: RecyclerView.ViewHolder,\n        target: RecyclerView.ViewHolder\n    ): Boolean {\n        val fromPosition = source.absoluteAdapterPosition\n        val toPosition = target.absoluteAdapterPosition\n        val separatorPosition = adapter.currentDownloads\n\n        val toPositionNoSeparator =\n            if (separatorPosition < toPosition) toPosition - separatorPosition else toPosition\n\n        if (source.itemView.tag == DOWNLOAD_SEPARATOR_TAG) {\n            return false\n        } else {\n            adapter.getItem(fromPosition).item?.let { downloadQueueInfo ->\n                DownloadQueueManager.reorderItem(\n                    downloadQueueInfo,\n                    toPositionNoSeparator - 1\n                )\n            }\n        }\n\n        return true\n    }\n\n    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {\n\n    }\n\n    override fun isLongPressDragEnabled(): Boolean {\n        return true // Enable drag with long press\n    }\n\n    override fun isItemViewSwipeEnabled(): Boolean {\n        return false // Disable swipe by default\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/queue/DownloadQueueFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.download.queue\n\nimport android.view.View\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.view.isGone\nimport androidx.fragment.app.activityViewModels\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.FragmentDownloadQueueBinding\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.setAppBarNoScrollFlagsOnTV\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager\nimport com.lagradost.cloudstream3.utils.txt\n\n\nclass DownloadQueueFragment :\n    BaseFragment<FragmentDownloadQueueBinding>(BindingCreator.Inflate(FragmentDownloadQueueBinding::inflate)) {\n    private val queueViewModel: DownloadQueueViewModel by activityViewModels()\n\n    override fun onBindingCreated(binding: FragmentDownloadQueueBinding) {\n        val adapter = DownloadQueueAdapter(this@DownloadQueueFragment)\n        val clearQueueItem = binding.downloadQueueToolbar.menu?.findItem(R.id.cancel_all)\n\n        observe(queueViewModel.childCards) { cards ->\n            val size = cards.queue.size + cards.currentDownloads.size\n            val isEmptyQueue = size == 0\n            binding.downloadQueueList.isGone = isEmptyQueue\n            binding.textNoQueue.isGone = !isEmptyQueue\n            clearQueueItem?.isVisible = !isEmptyQueue\n\n            adapter.submitQueue(cards)\n        }\n\n        binding.apply {\n            downloadQueueToolbar.apply {\n                title = txt(R.string.download_queue).asString(context)\n                if (isLayout(PHONE or EMULATOR)) {\n                    setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)\n                    setNavigationOnClickListener {\n                        dispatchBackPressed()\n                    }\n                }\n                setAppBarNoScrollFlagsOnTV()\n                clearQueueItem?.setOnMenuItemClickListener {\n                        AlertDialog.Builder(context, R.style.AlertDialogCustom)\n                            .setTitle(R.string.cancel_all)\n                            .setMessage(R.string.cancel_queue_message)\n                            .setPositiveButton(R.string.yes) { _, _ ->\n                                DownloadQueueManager.removeAllFromQueue()\n                            }\n                            .setNegativeButton(R.string.no) { _, _ ->\n                            }.show()\n\n                    true\n                }\n            }\n\n            downloadQueueList.adapter = adapter\n\n            // Drag and drop\n            val helper = DragAndDropTouchHelper(adapter)\n            helper.attachToRecyclerView(downloadQueueList)\n        }\n    }\n    \n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padBottom = isLandscape(),\n            padLeft = isLayout(TV or EMULATOR)\n        )\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/download/queue/DownloadQueueViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.download.queue\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport com.lagradost.cloudstream3.mvvm.launchSafe\nimport com.lagradost.cloudstream3.services.DownloadQueueService.Companion.downloadInstances\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\nimport kotlinx.coroutines.flow.combine\nimport kotlinx.coroutines.launch\n\ndata class DownloadAdapterQueue(\n    val currentDownloads: List<DownloadObjects.DownloadQueueWrapper>,\n    val queue: List<DownloadObjects.DownloadQueueWrapper>,\n)\n\nclass DownloadQueueViewModel : ViewModel() {\n    private val _childCards = MutableLiveData<DownloadAdapterQueue>()\n    val childCards: LiveData<DownloadAdapterQueue> = _childCards\n    private val totalDownloadFlow =\n        downloadInstances.combine(DownloadQueueManager.queue) { instances, queue ->\n            val current = instances.map { it.downloadQueueWrapper }\n            DownloadAdapterQueue(current, queue.toList())\n        }.combine(VideoDownloadManager.currentDownloads) { total, _ ->\n            // We want to update the flow when currentDownloads updates, but we do not care about its value\n            total\n        }\n\n    init {\n        viewModelScope.launch {\n            totalDownloadFlow.collect { queue ->\n                updateChildList(queue)\n            }\n        }\n    }\n\n    fun updateChildList(downloads: DownloadAdapterQueue) {\n        _childCards.postValue(downloads)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeChildItemAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.home\n\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.FrameLayout\nimport androidx.preference.PreferenceManager\nimport androidx.viewbinding.ViewBinding\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.databinding.HomeRemoveGridBinding\nimport com.lagradost.cloudstream3.databinding.HomeRemoveGridExpandedBinding\nimport com.lagradost.cloudstream3.databinding.HomeResultGridBinding\nimport com.lagradost.cloudstream3.databinding.HomeResultGridExpandedBinding\nimport com.lagradost.cloudstream3.ui.BaseAdapter\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.newSharedPool\nimport com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD\nimport com.lagradost.cloudstream3.ui.search.SearchClickCallback\nimport com.lagradost.cloudstream3.ui.search.SearchResultBuilder\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.UIHelper.isBottomLayout\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\n\nclass HomeScrollViewHolderState(view: ViewBinding) : ViewHolderState<Boolean>(view) {\n    // very shitty that we cant store the state when the view clears,\n    // but this is because the focus clears before the view is removed\n    // so we have to manually store it\n    var wasFocused: Boolean = false\n    override fun save(): Boolean = wasFocused\n    override fun restore(state: Boolean) {\n        if (state) {\n            wasFocused = false\n            // only refocus if tv\n            if (isLayout(TV)) {\n                itemView.requestFocus()\n            }\n        }\n    }\n}\n\nclass ResumeItemAdapter(\n    nextFocusUp: Int? = null,\n    nextFocusDown: Int? = null,\n    clickCallback: (SearchClickCallback) -> Unit,\n    private val removeCallback: (View) -> Unit,\n) : HomeChildItemAdapter(\n    id = \"resumeAdapter\".hashCode(),\n    nextFocusUp = nextFocusUp,\n    nextFocusDown = nextFocusDown,\n    clickCallback = clickCallback\n) {\n    // As there is no popup on TV we instead use the footer to clear\n    override val footers = if (isLayout(TV or EMULATOR)) 1 else 0\n\n    override fun onCreateFooter(parent: ViewGroup): ViewHolderState<Boolean> {\n        val expanded = parent.context.isBottomLayout()\n        val inflater = LayoutInflater.from(parent.context)\n        val binding = if (expanded) HomeRemoveGridExpandedBinding.inflate(\n            inflater,\n            parent,\n            false\n        ) else HomeRemoveGridBinding.inflate(inflater, parent, false)\n        return HomeScrollViewHolderState(binding)\n    }\n\n    override fun onClearView(holder: ViewHolderState<Boolean>) {\n        // Clear the image, idk if this saves ram or not, but I guess?\n        clearImage(holder.view.root.findViewById(R.id.imageView))\n    }\n\n    override fun onBindFooter(holder: ViewHolderState<Boolean>) {\n        this.applyBinding(holder, false)\n        when (val binding = holder.view) {\n            is HomeRemoveGridBinding -> {\n                updateLayoutParms(binding.backgroundCard, setWidth, setHeight)\n            }\n\n            is HomeRemoveGridExpandedBinding -> {\n                updateLayoutParms(binding.backgroundCard, setWidth, setHeight)\n            }\n        }\n        holder.itemView.apply {\n            if (isLayout(TV)) {\n                isFocusableInTouchMode = true\n                isFocusable = true\n            }\n            nextFocusUp?.let {\n                nextFocusUpId = it\n            }\n            nextFocusDown?.let {\n                nextFocusDownId = it\n            }\n\n            setOnClickListener { v ->\n                removeCallback.invoke(v ?: return@setOnClickListener)\n            }\n        }\n    }\n}\n\n/** Remember to set `updatePosterSize` to cache the poster size,\n * otherwise the width and height is unset */\nopen class HomeChildItemAdapter(\n    id: Int,\n    var nextFocusUp: Int? = null,\n    var nextFocusDown: Int? = null,\n    var clickCallback: (SearchClickCallback) -> Unit,\n) :\n    BaseAdapter<SearchResponse, Boolean>(\n        id, diffCallback = BaseDiffCallback(\n            itemSame = { a, b ->\n                a.url == b.url && a.name == b.name\n            },\n            contentSame = { a, b ->\n                a == b\n            })\n    ) {\n    var hasNext: Boolean = false\n    var isHorizontal: Boolean = false\n        set(value) {\n            field = value\n            updateCachedPosterSize()\n        }\n\n    private fun updateCachedPosterSize() {\n        setWidth = if (!isHorizontal) {\n            minPosterSize\n        } else {\n            maxPosterSize\n        }\n        setHeight = if (!isHorizontal) {\n            maxPosterSize\n        } else {\n            minPosterSize\n        }\n    }\n\n    init {\n        updateCachedPosterSize()\n    }\n\n    protected var setWidth = 0\n    protected var setHeight = 0\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Boolean> {\n        val expanded = parent.context.isBottomLayout()\n        val inflater = LayoutInflater.from(parent.context)\n        val binding = if (expanded) HomeResultGridExpandedBinding.inflate(\n            inflater,\n            parent,\n            false\n        ) else HomeResultGridBinding.inflate(inflater, parent, false)\n        return HomeScrollViewHolderState(binding)\n    }\n\n    companion object {\n        // The vast majority of the lag comes from creating the view\n        // This simply shares the views between all HomeChildItemAdapter\n        val sharedPool =\n            newSharedPool { setMaxRecycledViews(CONTENT, 20) }\n\n        var minPosterSize: Int = 0\n        var maxPosterSize: Int = 0\n\n        fun updatePosterSize(context: Context, value: Int? = null) {\n            val scale = value ?: PreferenceManager.getDefaultSharedPreferences(context)\n                ?.getInt(context.getString(R.string.poster_size_key), 0) ?: 0\n            // Scale by +10% per step\n            val mul = 1.0f + scale * 0.1f\n            minPosterSize = (114.toPx.toFloat() * mul).toInt()\n            maxPosterSize = (180.toPx.toFloat() * mul).toInt()\n        }\n\n        fun updateLayoutParms(layout: FrameLayout, width: Int, height: Int) {\n            val params = layout.layoutParams\n            if (params.height == height && params.width == width) return\n\n            params.width = width\n            params.height = height\n\n            layout.layoutParams = params\n        }\n    }\n\n    protected fun applyBinding(holder: ViewHolderState<Boolean>, isFirstItem: Boolean) {\n        when (val binding = holder.view) {\n            is HomeResultGridBinding -> {\n                updateLayoutParms(binding.backgroundCard, setWidth, setHeight)\n            }\n\n            is HomeResultGridExpandedBinding -> {\n                updateLayoutParms(binding.backgroundCard, setWidth, setHeight)\n\n                if (isFirstItem) { // to fix tv\n                    binding.backgroundCard.nextFocusLeftId = R.id.nav_rail_view\n                }\n            }\n        }\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Boolean>,\n        item: SearchResponse,\n        position: Int\n    ) {\n        applyBinding(holder, position == 0)\n\n        SearchResultBuilder.bind(\n            clickCallback = { click ->\n                // ok, so here we hijack the callback to fix the focus\n                when (click.action) {\n                    SEARCH_ACTION_LOAD -> (holder as? HomeScrollViewHolderState)?.wasFocused = true\n                }\n                clickCallback(click)\n            },\n            item,\n            position,\n            holder.itemView,\n            nextFocusUp,\n            nextFocusDown\n        )\n\n        holder.itemView.tag = position\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.home\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport android.widget.ImageView\nimport android.widget.ListView\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.activity.ComponentActivity\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.net.toUri\nimport androidx.core.view.isGone\nimport androidx.core.view.isInvisible\nimport androidx.core.view.isVisible\nimport androidx.fragment.app.activityViewModels\nimport androidx.preference.PreferenceManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.bottomsheet.BottomSheetBehavior\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.google.android.material.chip.Chip\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.APIHolder.apis\nimport com.lagradost.cloudstream3.AllLanguagesName\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.databinding.FragmentHomeBinding\nimport com.lagradost.cloudstream3.databinding.HomeEpisodesExpandedBinding\nimport com.lagradost.cloudstream3.databinding.HomeSelectMainpageBinding\nimport com.lagradost.cloudstream3.databinding.TvtypesChipsBinding\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.mvvm.observeNullable\nimport com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi\nimport com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.account.AccountHelper.showAccountSelectLinear\nimport com.lagradost.cloudstream3.ui.account.AccountViewModel\nimport com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD\nimport com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_PLAY_FILE\nimport com.lagradost.cloudstream3.ui.search.SearchAdapter\nimport com.lagradost.cloudstream3.ui.search.SearchHelper.handleSearchClickCallback\nimport com.lagradost.cloudstream3.ui.setRecycledViewPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.filterProviderByPreferredMedia\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiProviderLangSettings\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isNetworkAvailable\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isRecyclerScrollable\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadSearchResult\nimport com.lagradost.cloudstream3.utils.AppContextUtils.ownHide\nimport com.lagradost.cloudstream3.utils.AppContextUtils.ownShow\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.EmptyEvent\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso\nimport com.lagradost.cloudstream3.utils.TvChannelUtils\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.getSpanCount\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\n\nprivate const val TAG = \"HomeFragment\"\n\nclass HomeFragment : BaseFragment<FragmentHomeBinding>(\n    BindingCreator.Bind(FragmentHomeBinding::bind)\n) {\n    companion object {\n        // Used for configuration changed events to fix any popups that are not attached to a fragment\n        val configEvent = EmptyEvent()\n        var currentSpan = 1\n\n        private val errorProfilePics = listOf(\n            R.drawable.monke_benene,\n            R.drawable.monke_burrito,\n            R.drawable.monke_coco,\n            R.drawable.monke_cookie,\n            R.drawable.monke_flusdered,\n            R.drawable.monke_funny,\n            R.drawable.monke_like,\n            R.drawable.monke_party,\n            R.drawable.monke_sob,\n            R.drawable.monke_drink,\n        )\n\n        val errorProfilePic = errorProfilePics.random()\n\n        //fun Activity.loadHomepageList(\n        //    item: HomePageList,\n        //    deleteCallback: (() -> Unit)? = null,\n        //) {\n        //    loadHomepageList(\n        //        expand = HomeViewModel.ExpandableHomepageList(item, 1, false),\n        //        deleteCallback = deleteCallback,\n        //        expandCallback = null\n        //    )\n        //}\n\n        // returns a BottomSheetDialog that will be hidden with OwnHidden upon hide, and must be saved to be able call ownShow in onCreateView\n\n        fun Activity.loadHomepageList(\n            expand: HomeViewModel.ExpandableHomepageList,\n            deleteCallback: (() -> Unit)? = null,\n            expandCallback: (suspend (String) -> HomeViewModel.ExpandableHomepageList?)? = null,\n            dismissCallback: (() -> Unit),\n        ): BottomSheetDialog {\n            val context = this\n            val bottomSheetDialogBuilder = BottomSheetDialog(context)\n            val binding: HomeEpisodesExpandedBinding = HomeEpisodesExpandedBinding.inflate(\n                bottomSheetDialogBuilder.layoutInflater,\n                null,\n                false\n            )\n            bottomSheetDialogBuilder.setContentView(binding.root)\n            //val title = bottomSheetDialogBuilder.findViewById<TextView>(R.id.home_expanded_text)!!\n\n            //title.findViewTreeLifecycleOwner().lifecycle.addObserver()\n\n            val item = expand.list\n            binding.homeExpandedText.text = item.name\n            // val recycle =\n            //    bottomSheetDialogBuilder.findViewById<AutofitRecyclerView>(R.id.home_expanded_recycler)!!\n            //val titleHolder =\n            //    bottomSheetDialogBuilder.findViewById<FrameLayout>(R.id.home_expanded_drag_down)!!\n\n            // main {\n            //(bottomSheetDialogBuilder.ownerActivity as androidx.fragment.app.FragmentActivity?)?.supportFragmentManager?.fragments?.lastOrNull()?.viewLifecycleOwner?.apply {\n            //    println(\"GOT LIFE: lifecycle $this\")\n            //    this.lifecycle.addObserver(object : DefaultLifecycleObserver {\n            //        override fun onResume(owner: LifecycleOwner) {\n            //            super.onResume(owner)\n            //            println(\"onResume!!!!\")\n            //            bottomSheetDialogBuilder?.ownShow()\n            //        }\n\n            //        override fun onStop(owner: LifecycleOwner) {\n            //            super.onStop(owner)\n            //            bottomSheetDialogBuilder?.ownHide()\n            //        }\n            //    })\n            //}\n            // }\n            //val delete = bottomSheetDialogBuilder.home_expanded_delete\n            binding.homeExpandedDelete.isGone = deleteCallback == null\n            if (deleteCallback != null) {\n                binding.homeExpandedDelete.setOnClickListener {\n                    try {\n                        val builder: AlertDialog.Builder = AlertDialog.Builder(context)\n                        val dialogClickListener =\n                            DialogInterface.OnClickListener { _, which ->\n                                when (which) {\n                                    DialogInterface.BUTTON_POSITIVE -> {\n                                        deleteCallback.invoke()\n                                        bottomSheetDialogBuilder.dismissSafe(this)\n                                    }\n\n                                    DialogInterface.BUTTON_NEGATIVE -> {}\n                                }\n                            }\n\n                        builder.setTitle(R.string.clear_history)\n                            .setMessage(\n                                context.getString(R.string.delete_message).format(\n                                    item.name\n                                )\n                            )\n                            .setPositiveButton(R.string.delete, dialogClickListener)\n                            .setNegativeButton(R.string.cancel, dialogClickListener)\n                            .show().setDefaultFocus()\n                    } catch (e: Exception) {\n                        logError(e)\n                        // ye you somehow fucked up formatting did you?\n                    }\n                }\n            }\n            binding.homeExpandedDragDown.setOnClickListener {\n                bottomSheetDialogBuilder.dismissSafe(this)\n            }\n\n\n            // Span settings\n            binding.homeExpandedRecycler.spanCount = context.getSpanCount(item.isHorizontalImages)\n            binding.homeExpandedRecycler.setRecycledViewPool(SearchAdapter.sharedPool)\n            binding.homeExpandedRecycler.adapter =\n                SearchAdapter(binding.homeExpandedRecycler,item.isHorizontalImages) { callback ->\n                    handleSearchClickCallback(callback)\n                    if (callback.action == SEARCH_ACTION_LOAD || callback.action == SEARCH_ACTION_PLAY_FILE) {\n                        bottomSheetDialogBuilder.ownHide() // we hide here because we want to resume it later\n                        //bottomSheetDialogBuilder.dismissSafe(this)\n                    }\n                }.apply {\n                    submitList(item.list)\n                    hasNext = expand.hasNext\n                }\n\n            binding.homeExpandedRecycler.addOnScrollListener(object :\n                RecyclerView.OnScrollListener() {\n                var expandCount = 0\n                val name = expand.list.name\n\n                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {\n                    super.onScrollStateChanged(recyclerView, newState)\n\n                    val adapter = recyclerView.adapter\n                    if (adapter !is SearchAdapter) return\n\n                    val count = adapter.itemCount\n                    val currentHasNext = adapter.hasNext\n                    //!recyclerView.canScrollVertically(1)\n                    if (!recyclerView.isRecyclerScrollable() && currentHasNext && expandCount != count) {\n                        expandCount = count\n                        ioSafe {\n                            expandCallback?.invoke(name)?.let { newExpand ->\n                                (recyclerView.adapter as? SearchAdapter?)?.apply {\n                                    hasNext = newExpand.hasNext\n                                    submitList(newExpand.list.list)\n                                }\n                            }\n                        }\n                    }\n                }\n            })\n\n            val spanListener = Runnable {\n                binding.homeExpandedRecycler.spanCount = context.getSpanCount(item.isHorizontalImages)\n                // We want to rebind everything to update the UI, however we also want to avoid\n                // any animations ect, this is the easiest way to do this, and the most correct\n                @SuppressLint(\"NotifyDataSetChanged\")\n                binding.homeExpandedRecycler.adapter?.notifyDataSetChanged()\n            }\n\n            configEvent += spanListener\n\n            bottomSheetDialogBuilder.setOnDismissListener {\n                dismissCallback.invoke()\n                configEvent -= spanListener\n            }\n\n            //(recycle.adapter as SearchAdapter).notifyDataSetChanged()\n\n            bottomSheetDialogBuilder.show()\n            return bottomSheetDialogBuilder\n        }\n\n        private fun getPairList(\n            anime: Chip?,\n            cartoons: Chip?,\n            tvs: Chip?,\n            docs: Chip?,\n            movies: Chip?,\n            asian: Chip?,\n            livestream: Chip?,\n            torrent: Chip?,\n            nsfw: Chip?,\n            others: Chip?,\n        ): List<Pair<Chip?, List<TvType>>> {\n            // This list should be same order as home screen to aid navigation\n            return listOf(\n                Pair(movies, listOf(TvType.Movie)),\n                Pair(tvs, listOf(TvType.TvSeries)),\n                Pair(anime, listOf(TvType.Anime, TvType.OVA, TvType.AnimeMovie)),\n                Pair(asian, listOf(TvType.AsianDrama)),\n                Pair(cartoons, listOf(TvType.Cartoon)),\n                Pair(docs, listOf(TvType.Documentary)),\n                Pair(livestream, listOf(TvType.Live)),\n                Pair(torrent, listOf(TvType.Torrent)),\n                Pair(nsfw, listOf(TvType.NSFW)),\n                Pair(others, listOf(TvType.Others)),\n            )\n        }\n\n        private fun getPairList(header: TvtypesChipsBinding) = getPairList(\n            header.homeSelectAnime,\n            header.homeSelectCartoons,\n            header.homeSelectTvSeries,\n            header.homeSelectDocumentaries,\n            header.homeSelectMovies,\n            header.homeSelectAsian,\n            header.homeSelectLivestreams,\n            header.homeSelectTorrents,\n            header.homeSelectNsfw,\n            header.homeSelectOthers\n        )\n\n        fun validateChips(header: TvtypesChipsBinding?, validTypes: List<TvType>) {\n            if (header == null) return\n            val pairList = getPairList(header)\n            for ((button, types) in pairList) {\n                val isValid = validTypes.any { types.contains(it) }\n                button?.isVisible = isValid\n            }\n        }\n\n        fun updateChips(header: TvtypesChipsBinding?, selectedTypes: List<TvType>) {\n            if (header == null) return\n            val pairList = getPairList(header)\n            for ((button, types) in pairList) {\n                button?.isChecked =\n                    button.isVisible && selectedTypes.any { types.contains(it) }\n            }\n        }\n\n        fun bindChips(\n            header: TvtypesChipsBinding?,\n            selectedTypes: List<TvType>,\n            validTypes: List<TvType>,\n            callback: (List<TvType>) -> Unit\n        ) {\n            bindChips(header, selectedTypes, validTypes, callback, null, null)\n        }\n\n        fun bindChips(\n            header: TvtypesChipsBinding?,\n            selectedTypes: List<TvType>,\n            validTypes: List<TvType>,\n            callback: (List<TvType>) -> Unit,\n            nextFocusDown: Int?,\n            nextFocusUp: Int?\n        ) {\n            if (header == null) return\n            val pairList = getPairList(header)\n            for ((button, types) in pairList) {\n                val isValid = validTypes.any { types.contains(it) }\n                button?.isVisible = isValid\n                button?.isChecked = isValid && selectedTypes.any { types.contains(it) }\n                button?.isFocusable = true\n                if (isLayout(TV)) {\n                    button?.isFocusableInTouchMode = true\n                }\n\n                if (nextFocusDown != null)\n                    button?.nextFocusDownId = nextFocusDown\n\n                if (nextFocusUp != null)\n                    button?.nextFocusUpId = nextFocusUp\n\n                button?.setOnCheckedChangeListener { _, _ ->\n                    val list = ArrayList<TvType>()\n                    for ((sbutton, vvalidTypes) in pairList) {\n                        if (sbutton?.isChecked == true)\n                            list.addAll(vvalidTypes)\n                    }\n                    callback(list)\n                }\n            }\n        }\n\n        fun Context.selectHomepage(selectedApiName: String?, callback: (String) -> Unit) {\n            val validAPIs = filterProviderByPreferredMedia().toMutableList()\n\n            validAPIs.add(0, randomApi)\n            validAPIs.add(0, noneApi)\n            //val builder: AlertDialog.Builder = AlertDialog.Builder(this)\n            //builder.setView(R.layout.home_select_mainpage)\n            val builder =\n                BottomSheetDialog(this)\n\n            builder.behavior.state = BottomSheetBehavior.STATE_EXPANDED\n            val binding: HomeSelectMainpageBinding = HomeSelectMainpageBinding.inflate(\n                builder.layoutInflater,\n                null,\n                false\n            )\n\n            builder.setContentView(binding.root)\n            builder.show()\n            builder.let { dialog ->\n                val isMultiLang = getApiProviderLangSettings().let { set ->\n                    set.size > 1 || set.contains(AllLanguagesName)\n                }\n                //dialog.window?.setGravity(Gravity.BOTTOM)\n\n                var currentApiName = selectedApiName\n\n                var currentValidApis: MutableList<MainAPI> = mutableListOf()\n                val preSelectedTypes = DataStoreHelper.homePreference.toMutableList()\n\n                binding.cancelBtt.setOnClickListener {\n                    dialog.dismissSafe()\n                }\n\n                binding.applyBtt.setOnClickListener {\n                    if (currentApiName != selectedApiName) {\n                        currentApiName?.let(callback)\n                    }\n                    dialog.dismissSafe()\n                }\n\n                var pinnedphashset = DataStoreHelper.pinnedProviders.toHashSet()\n\n                val listView = dialog.findViewById<ListView>(R.id.listview1)\n\n                val arrayAdapter = object : ArrayAdapter<String>(\n                    this, R.layout.sort_bottom_single_provider_choice,\n                    mutableListOf()\n                ) {\n                    override fun getView(\n                        position: Int,\n                        convertView: View?,\n                        parent: ViewGroup\n                    ): View {\n                        val view = convertView ?: LayoutInflater.from(context)\n                            .inflate(R.layout.sort_bottom_single_provider_choice, parent, false)\n                        val titleText = view.findViewById<TextView>(R.id.text1)\n                        val pinIcon = view.findViewById<ImageView>(R.id.pinicon)\n                        val name = getItem(position)\n                        titleText?.text = name\n                        val isPinned =\n                            pinnedphashset.contains(currentValidApis[position].name)\n                        pinIcon.visibility = if (isPinned) View.VISIBLE else View.GONE\n                        return view\n                    }\n                }\n                listView?.adapter = arrayAdapter\n                listView?.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n\n                listView?.setOnItemClickListener { _, _, i, _ ->\n                    if (currentValidApis.isNotEmpty()) {\n                        currentApiName = currentValidApis[i].name\n                        //to switch to apply simply remove this\n                        currentApiName.let(callback)\n                        dialog.dismissSafe()\n                    }\n                }\n\n                fun updateList() {\n                    DataStoreHelper.homePreference = preSelectedTypes\n                    val pinnedp = DataStoreHelper.pinnedProviders.toList()\n                    pinnedphashset = pinnedp.toHashSet()\n                    arrayAdapter.clear()\n                    val sortedApis = validAPIs\n                        .filter {\n                            it.hasMainPage && (pinnedphashset.contains(it.name) || it.supportedTypes.any(\n                                preSelectedTypes::contains\n                            ))\n                        }\n                        .sortedBy { it.name.lowercase() }\n\n                    val sortedApiMap = LinkedHashMap<String, MainAPI>().apply {\n                        sortedApis.forEach { put(it.name, it) }\n                    }\n\n                    val pinnedApis = pinnedp.asReversed().mapNotNull { name ->\n                        sortedApiMap[name]\n                    }\n\n                    val remainingApis = sortedApis.filterNot { pinnedphashset.contains(it.name) }\n\n                    currentValidApis = mutableListOf<MainAPI>().apply {\n                        addAll(validAPIs.take(2))\n                        addAll(pinnedApis)\n                        addAll(remainingApis)\n                    }\n\n                    val names =\n                        currentValidApis.map { if (isMultiLang) \"${getFlagFromIso(it.lang)?.plus(\" \") ?: \"\"}${it.name}\" else it.name }\n                    val index = currentValidApis.map { it.name }.indexOf(currentApiName)\n                    listView?.setItemChecked(index, true)\n                    arrayAdapter.addAll(names)\n                    arrayAdapter.notifyDataSetChanged()\n                }\n                // pin provider on hold\n                listView?.setOnItemLongClickListener { _, _, i, _ ->\n                    if (currentValidApis.isNotEmpty() && i > 1) {\n                        val pinnedp = DataStoreHelper.pinnedProviders.toMutableList()\n                        val thisapi = currentValidApis[i].name\n                        if (pinnedp.contains(thisapi)) {\n                            pinnedp.remove(thisapi)\n                        } else {\n                            pinnedp.add(thisapi)\n                        }\n                        DataStoreHelper.pinnedProviders = pinnedp.toTypedArray()\n                        updateList()\n                    }\n                    true\n                }\n\n                bindChips(\n                    binding.tvtypesChipsScroll.tvtypesChips,\n                    preSelectedTypes,\n                    validAPIs.flatMap { it.supportedTypes }.distinct()\n                ) { list ->\n                    preSelectedTypes.clear()\n                    preSelectedTypes.addAll(list)\n                    updateList()\n                }\n                updateList()\n            }\n        }\n    }\n\n    private val homeViewModel: HomeViewModel by activityViewModels()\n    private val accountViewModel: AccountViewModel by activityViewModels()\n\n    fun addMovies(cards: List<SearchResponse>) {\n        val ctx = context ?: run {\n            Log.e(TAG, \"Context is null, aborting addMovies\")\n            return\n        }\n\n        try {\n            val existingId = TvChannelUtils.getChannelId(ctx, getString(R.string.app_name))\n            if (existingId != null) {\n                Log.d(TAG, \"Channel ID: $existingId\")\n\n                val programCards = cards\n\n                TvChannelUtils.addPrograms(\n                    context = ctx,\n                    channelId = existingId,\n                    items = programCards\n                )\n            } else {\n                Log.d(TAG, \"Channel does not exist\")\n            }\n        } catch (e: Exception) {\n            Log.e(TAG, \"Error adding movies: $e\")\n        }\n    }\n\n    private fun deleteAll() {\n        val ctx = context ?: run {\n            Log.e(TAG, \"Context is null, aborting deleteAll\")\n            return\n        }\n\n        try {\n            val existingId = TvChannelUtils.getChannelId(ctx, getString(R.string.app_name))\n            if (existingId != null) {\n                Log.d(TAG, \"Channel ID: $existingId\")\n                TvChannelUtils.deleteStoredPrograms(ctx)\n            } else {\n                Log.d(TAG, \"Channel does not exist\")\n            }\n        } catch (e: Exception) {\n            Log.e(TAG, \"Error deleting programs: ${e.message}\")\n        }\n    }\n\n    override fun pickLayout(): Int? =\n        if (isLayout(PHONE)) R.layout.fragment_home else R.layout.fragment_home_tv\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? {\n        bottomSheetDialog?.ownShow()\n        return super.onCreateView(inflater, container, savedInstanceState)\n    }\n\n    override fun onDestroyView() {\n        (activity as? ComponentActivity)?.detachBackPressedCallback(\"HomeFragment_BackPress\")\n        bottomSheetDialog?.ownHide()\n        super.onDestroyView()\n    }\n\n    private val apiChangeClickListener = View.OnClickListener { view ->\n        view.context.selectHomepage(currentApiName) { api ->\n            homeViewModel.loadAndCancel(api, forceReload = true, fromUI = true)\n        }\n        /*val validAPIs = view.context?.filterProviderByPreferredMedia()?.toMutableList() ?: mutableListOf()\n\n        validAPIs.add(0, randomApi)\n        validAPIs.add(0, noneApi)\n        view.popupMenuNoIconsAndNoStringRes(validAPIs.mapIndexed { index, api -> Pair(index, api.name) }) {\n            homeViewModel.loadAndCancel(validAPIs[itemId].name)\n        }*/\n    }\n\n    private var currentApiName: String? = null\n    private var toggleRandomButton = false\n\n    private var bottomSheetDialog: BottomSheetDialog? = null\n    private var homeMasterAdapter: HomeParentItemAdapterPreview? = null\n\n    var lastSavedHomepage: String? = null\n\n    fun saveHomepageToTV(page: Map<String, HomeViewModel.ExpandableHomepageList>) {\n        // No need to update for phone\n        if (isLayout(PHONE)) {\n            return\n        }\n        val (name, data) = page.entries.firstOrNull() ?: return\n        // Modifying homepage is an expensive operation, and therefore we avoid it at all cost\n        if (name == lastSavedHomepage) {\n            return\n        }\n        Log.i(TAG, \"Adding programs $name to TV\")\n        lastSavedHomepage = name\n        ioSafe {\n            // empty the channel\n            deleteAll()\n            // insert the program from first array\n            addMovies(data.list.list)\n        }\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padTop = false,\n            padBottom = isLandscape(),\n            padLeft = isLayout(TV or EMULATOR)\n        )\n\n        // Fix grid\n        configEvent.invoke()\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onBindingCreated(binding: FragmentHomeBinding) {\n        context?.let { HomeChildItemAdapter.updatePosterSize(it) }\n        (activity as? ComponentActivity)?.attachBackPressedCallback(\"HomeFragment_BackPress\") {\n            handleTvBackPress(this)\n        }\n        binding.apply {\n            //homeChangeApiLoading.setOnClickListener(apiChangeClickListener)\n            //homeChangeApiLoading.setOnClickListener(apiChangeClickListener)\n            homeApiFab.setOnClickListener(apiChangeClickListener)\n            homeApiFab.setOnLongClickListener {\n                if (currentApiName == noneApi.name) return@setOnLongClickListener false\n                homeViewModel.loadAndCancel(currentApiName, forceReload = true, fromUI = true)\n                showToast(R.string.action_reload, Toast.LENGTH_SHORT)\n                true\n            }\n            homeChangeApi.setOnClickListener(apiChangeClickListener)\n            homeSwitchAccount.setOnClickListener {\n                activity?.showAccountSelectLinear()\n            }\n\n            homeMasterAdapter = HomeParentItemAdapterPreview(\n                fragment = this@HomeFragment,\n                homeViewModel, accountViewModel\n            )\n            homeMasterRecycler.setRecycledViewPool(ParentItemAdapter.sharedPool)\n            homeMasterRecycler.adapter = homeMasterAdapter\n\n            homeApiFab.isVisible = isLayout(PHONE)\n\n            homePreviewReloadProvider.setOnClickListener {\n                homeViewModel.loadAndCancel(\n                    homeViewModel.apiName.value ?: noneApi.name,\n                    forceReload = true,\n                    fromUI = true\n                )\n                showToast(R.string.action_reload, Toast.LENGTH_SHORT)\n                true\n            }\n\n            homePreviewSearchButton.setOnClickListener { _ ->\n                // Open blank screen.\n                homeViewModel.queryTextSubmit(\"\")\n            }\n\n            homeMasterRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {\n                override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {\n                    if (isLayout(PHONE)) {\n                        // Fab is only relevant to Phone\n                        if (dy > 0) { //check for scroll down\n                            homeApiFab.shrink() // hide\n                            homeRandom.shrink()\n                        } else if (dy < -5) {\n                            if (isLayout(PHONE)) {\n                                homeApiFab.extend() // show\n                                homeRandom.extend()\n                            }\n                        }\n                    } else {\n                        // Header scrolling is only relevant to TV/Emulator\n\n                        val view = recyclerView.findViewHolderForAdapterPosition(0)?.itemView\n                        val scrollParent = binding.homeApiHolder\n\n                        if (view == null) {\n                            // The first view is not visible, so we can assume we have scrolled past it\n                            scrollParent.isVisible = false\n                        } else {\n                            // A bit weird, but this is a major limitation we are working around here\n                            // 1. We cant have a real parent to the recyclerview as android cant layout that without lagging\n                            // 2. We cant put the view in the recyclerview, as it should always be shown\n                            // 3. We cant mirror the view in the recyclerview as then it causes focus issues when swaping out the mirror view\n                            //\n                            // This means that if we want to have a parent view to the recyclerview we are out of luck\n                            // Instead this uses getLocationInWindow to calculate how much the view should be scrolled\n                            // as recyclerView has no scrollY (always 0)\n                            //\n                            // Then it manually \"scrolls\" it to the correct position\n                            //\n                            // Hopefully getLocationInWindow acts correctly on all devices\n                            val rect = IntArray(2)\n                            view.getLocationInWindow(rect)\n                            scrollParent.isVisible = true\n                            scrollParent.translationY = rect[1].toFloat() - 60.toPx\n                        }\n                    }\n                    super.onScrolled(recyclerView, dx, dy)\n                }\n            })\n\n        }\n\n        //Load value for toggling Random button. Hide at startup\n        context?.let {\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)\n            toggleRandomButton =\n                settingsManager.getBoolean(\n                    getString(R.string.random_button_key),\n                    false\n                )\n            binding.homeRandom.visibility = View.GONE\n            binding.homeRandomButtonTv.visibility = View.GONE\n        }\n\n        observe(homeViewModel.apiName) { apiName ->\n            currentApiName = apiName\n            binding.apply {\n                homeApiFab.text = apiName\n                homeChangeApi.text = apiName\n                homePreviewReloadProvider.isGone = (apiName == noneApi.name)\n                homePreviewSearchButton.isGone = (apiName == noneApi.name)\n            }\n        }\n\n        observe(homeViewModel.page) { data ->\n            binding.apply {\n                when (data) {\n                    is Resource.Success -> {\n                        val d = data.value\n                        (homeMasterRecycler.adapter as? ParentItemAdapter)?.submitList(d.values.map {\n                            it.copy(\n                                list = it.list.copy(list = it.list.list.toMutableList())\n                            )\n                        })\n\n                        saveHomepageToTV(d)\n\n                        homeLoading.isVisible = false\n                        homeLoadingError.isVisible = false\n                        homeMasterRecycler.isVisible = true\n                        homeLoadingShimmer.stopShimmer()\n                        //home_loaded?.isVisible = true\n                        if (toggleRandomButton) {\n                            val distinct = d.values\n                                .flatMap { it.list.list }\n                                .distinctBy { it.url }\n                            val hasItems = distinct.isNotEmpty()\n                            val isPhone = isLayout(PHONE)\n                            val randomClickListener = View.OnClickListener {\n                                distinct.randomOrNull()?.let { activity.loadSearchResult(it) }\n                            }\n\n                            homeRandom.isVisible = isPhone && hasItems\n                            homeRandom.setOnClickListener(randomClickListener)\n                            homeRandomButtonTv.isVisible = !isPhone && hasItems\n                            homeRandomButtonTv.setOnClickListener(randomClickListener)\n                        } else {\n                            homeRandom.isGone = true\n                            homeRandomButtonTv.isGone = true\n                        }\n                    }\n\n                    is Resource.Failure -> {\n                        homeLoadingShimmer.stopShimmer()\n                        homeReloadConnectionerror.setOnClickListener(apiChangeClickListener)\n                        homeReloadConnectionOpenInBrowser.setOnClickListener { view ->\n                            val validAPIs = apis//.filter { api -> api.hasMainPage }\n\n                            view.popupMenuNoIconsAndNoStringRes(validAPIs.mapIndexed { index, api ->\n                                Pair(\n                                    index,\n                                    api.name\n                                )\n                            }) {\n                                try {\n                                    val i = Intent(Intent.ACTION_VIEW)\n                                    i.data = validAPIs[itemId].mainUrl.toUri()\n                                    startActivity(i)\n                                } catch (e: Exception) {\n                                    logError(e)\n                                }\n                            }\n                        }\n\n                        homeLoading.isVisible = false\n                        homeLoadingError.isVisible = true\n                        homeMasterRecycler.isInvisible = true\n\n                        // Based on https://github.com/recloudstream/cloudstream/pull/1438\n                        val hasNoNetworkConnection = context?.isNetworkAvailable() == false\n                        val isNetworkError = data.isNetworkError\n\n                        // Show the downloads button if we have any sort of network shenanigans\n                        homeReloadConnectionGoToDownloads.isVisible =\n                            hasNoNetworkConnection || isNetworkError\n\n                        // Only hide the open in browser button if we know this is not network shenanigans related to cs3\n                        homeReloadConnectionOpenInBrowser.isGone = hasNoNetworkConnection\n\n                        resultErrorText.text = if (hasNoNetworkConnection) {\n                            getString(R.string.no_internet_connection)\n                        } else {\n                            data.errorString\n                        }\n\n                        homeReloadConnectionGoToDownloads.setOnClickListener {\n                            activity.navigate(R.id.navigation_downloads)\n                        }\n\n                        (homeMasterRecycler.adapter as? ParentItemAdapter)?.apply {\n                            submitList(null)\n                            clearState()\n                        }\n                    }\n\n                    is Resource.Loading -> {\n                        homeLoadingShimmer.startShimmer()\n                        homeLoading.isVisible = true\n                        homeLoadingError.isVisible = false\n                        homeMasterRecycler.isInvisible = true\n                        (homeMasterRecycler.adapter as? ParentItemAdapter)?.apply {\n                            submitList(null)\n                            clearState()\n                        }\n                        //home_loaded?.isVisible = false\n                    }\n                }\n            }\n        }\n\n        observeNullable(homeViewModel.popup) { item ->\n            if (item == null) {\n                bottomSheetDialog?.dismissSafe()\n                bottomSheetDialog = null\n                return@observeNullable\n            }\n\n            // don't recreate\n            if (bottomSheetDialog != null) {\n                return@observeNullable\n            }\n\n            val (items, delete) = item\n\n            bottomSheetDialog = activity?.loadHomepageList(items, expandCallback = {\n                homeViewModel.expandAndReturn(it)\n            }, dismissCallback = {\n                homeViewModel.popup(null)\n                bottomSheetDialog = null\n            }, deleteCallback = delete)\n        }\n\n        homeViewModel.reloadStored()\n        homeViewModel.loadAndCancel(DataStoreHelper.currentHomePage, false)\n        //loadHomePage(false)\n\n        // nice profile pic on homepage\n        //home_profile_picture_holder?.isVisible = false\n        // just in case\n\n        //TODO READD THIS\n        /*for (syncApi in OAuth2Apis) {\n            val login = SyncAPI2.loginInfo()\n            val pic = login?.profilePicture\n            if (home_profile_picture?.setImage(\n                    pic,\n                    errorImageDrawable = errorProfilePic\n                ) == true\n            ) {\n                home_profile_picture_holder?.isVisible = true\n                break\n            }\n        }*/\n    }\n\n    private fun handleTvBackPress(helper: BackPressedCallbackHelper.CallbackHelper) {\n        // Only apply custom behavior on TV interface\n        if (!isLayout(TV)) {\n            helper.runDefault()\n            return\n        }\n        val currentFocus = activity?.currentFocus ?: run {\n            helper.runDefault()\n            return\n        }\n        // isInsideRecycle is true when focus is inside home_master_recycler\n        var parent = currentFocus.parent\n        var isInsideRecycler = false\n        while (parent != null) {\n            if (parent is View && parent.id == R.id.home_master_recycler) {\n                isInsideRecycler = true\n                break\n            }\n            parent = parent.parent\n        }\n        when {\n            // Case 1: Focus is within plugin content -> Move to plugin selector\n            isInsideRecycler -> {\n                binding?.homeMasterRecycler?.scrollToPosition(0)\n                // Defer focus request until after scroll ends\n                binding?.homeChangeApi?.post {\n                    binding?.homeChangeApi?.requestFocus()\n                }\n            }\n            // Case 2: Focus is on plugin selector or nearby buttons -> Move to home navigation\n            currentFocus.id == R.id.home_change_api ||\n            currentFocus.id == R.id.home_preview_reload_provider ||\n            currentFocus.id == R.id.home_preview_search_button -> {\n                activity?.findViewById<View>(R.id.navigation_home)?.requestFocus()\n            }\n            // Case 3: Any other location -> Use default back behavior\n            else -> helper.runDefault()\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.home\n\nimport android.os.Build\nimport android.os.Bundle\nimport android.os.Parcelable\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.recyclerview.widget.RecyclerView\nimport androidx.viewbinding.ViewBinding\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.HomepageParentBinding\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.BaseAdapter\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.newSharedPool\nimport com.lagradost.cloudstream3.ui.result.FOCUS_SELF\nimport com.lagradost.cloudstream3.ui.result.setLinearListLayout\nimport com.lagradost.cloudstream3.ui.search.SearchClickCallback\nimport com.lagradost.cloudstream3.ui.setRecycledViewPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isRecyclerScrollable\n\nclass LoadClickCallback(\n    val action: Int = 0,\n    val view: View,\n    val position: Int,\n    val response: LoadResponse\n)\n\nopen class ParentItemAdapter(\n    id: Int,\n    private val clickCallback: (SearchClickCallback) -> Unit,\n    private val moreInfoClickCallback: (HomeViewModel.ExpandableHomepageList) -> Unit,\n    private val expandCallback: ((String) -> Unit)? = null,\n) : BaseAdapter<HomeViewModel.ExpandableHomepageList, Bundle>(\n    id,\n    diffCallback = BaseDiffCallback(\n        itemSame = { a, b -> a.list.name == b.list.name },\n        contentSame = { a, b ->\n            a.list.list == b.list.list\n        })\n) {\n    companion object {\n        val sharedPool =\n            newSharedPool { setMaxRecycledViews(CONTENT, 4) }\n    }\n\n    data class ParentItemHolder(val binding: ViewBinding) : ViewHolderState<Bundle>(binding) {\n        override fun save(): Bundle = Bundle().apply {\n            val recyclerView = (binding as? HomepageParentBinding)?.homeChildRecyclerview\n            putParcelable(\n                \"value\",\n                recyclerView?.layoutManager?.onSaveInstanceState()\n            )\n            (recyclerView?.adapter as? BaseAdapter<*, *>)?.save(recyclerView)\n        }\n\n        override fun restore(state: Bundle) {\n            (binding as? HomepageParentBinding)?.homeChildRecyclerview?.layoutManager?.onRestoreInstanceState(\n                state.getSafeParcelable<Parcelable>(\"value\")\n            )\n        }\n    }\n\n    override fun submitList(\n        list: Collection<HomeViewModel.ExpandableHomepageList>?,\n        commitCallback: Runnable?\n    ) {\n        super.submitList(list?.sortedBy { it.list.list.isEmpty() }, commitCallback)\n    }\n\n    override fun onUpdateContent(\n        holder: ViewHolderState<Bundle>,\n        item: HomeViewModel.ExpandableHomepageList,\n        position: Int\n    ) {\n        val binding = holder.view\n        if (binding !is HomepageParentBinding) return\n        (binding.homeChildRecyclerview.adapter as? HomeChildItemAdapter)?.submitList(item.list.list)\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Bundle>,\n        item: HomeViewModel.ExpandableHomepageList,\n        position: Int\n    ) {\n        val startFocus = R.id.nav_rail_view\n        val endFocus = FOCUS_SELF\n        val binding = holder.view\n        if (binding !is HomepageParentBinding) return\n        val info = item.list\n        binding.apply {\n            val currentAdapter = homeChildRecyclerview.adapter as? HomeChildItemAdapter\n            if (currentAdapter == null) {\n                homeChildRecyclerview.setRecycledViewPool(HomeChildItemAdapter.sharedPool)\n                homeChildRecyclerview.adapter = HomeChildItemAdapter(\n                    id = id + position + 100,\n                    clickCallback = clickCallback,\n                    nextFocusUp = homeChildRecyclerview.nextFocusUpId,\n                    nextFocusDown = homeChildRecyclerview.nextFocusDownId,\n                ).apply {\n                    isHorizontal = info.isHorizontalImages\n                    hasNext = item.hasNext\n                    submitList(item.list.list)\n                }\n            } else {\n                currentAdapter.apply {\n                    isHorizontal = info.isHorizontalImages\n                    hasNext = item.hasNext\n                    this.clickCallback = this@ParentItemAdapter.clickCallback\n                    nextFocusUp = homeChildRecyclerview.nextFocusUpId\n                    nextFocusDown = homeChildRecyclerview.nextFocusDownId\n                    submitIncomparableList(item.list.list)\n                }\n            }\n\n            homeChildRecyclerview.setLinearListLayout(\n                isHorizontal = true,\n                nextLeft = startFocus,\n                nextRight = endFocus,\n            )\n            homeChildMoreInfo.text = info.name\n\n            homeChildRecyclerview.addOnScrollListener(object :\n                RecyclerView.OnScrollListener() {\n                var expandCount = 0\n                val name = item.list.name\n\n                override fun onScrollStateChanged(\n                    recyclerView: RecyclerView,\n                    newState: Int\n                ) {\n                    super.onScrollStateChanged(recyclerView, newState)\n\n                    val adapter = recyclerView.adapter\n                    if (adapter !is HomeChildItemAdapter) return\n\n                    val count = adapter.itemCount\n                    val hasNext = adapter.hasNext\n                    /*println(\n                        \"scolling ${recyclerView.isRecyclerScrollable()} ${\n                            recyclerView.canScrollHorizontally(\n                                1\n                            )\n                        }\"\n                    )*/\n                    //!recyclerView.canScrollHorizontally(1)\n                    if (!recyclerView.isRecyclerScrollable() && hasNext && expandCount != count) {\n                        expandCount = count\n                        expandCallback?.invoke(name)\n                    }\n                }\n            })\n\n            //(recyclerView.adapter as HomeChildItemAdapter).notifyDataSetChanged()\n            if (isLayout(PHONE)) {\n                homeChildMoreInfo.setOnClickListener {\n                    moreInfoClickCallback.invoke(item)\n                }\n            }\n        }\n    }\n\n    override fun onCreateContent(parent: ViewGroup): ParentItemHolder {\n        val layoutResId = when {\n            isLayout(TV) -> R.layout.homepage_parent_tv\n            isLayout(EMULATOR) -> R.layout.homepage_parent_emulator\n            else -> R.layout.homepage_parent\n        }\n\n        val inflater = LayoutInflater.from(parent.context)\n        val binding = try {\n            HomepageParentBinding.bind(inflater.inflate(layoutResId, parent, false))\n        } catch (t: Throwable) {\n            logError(t)\n            // just in case someone forgot we don't want to crash\n            HomepageParentBinding.inflate(inflater)\n        }\n\n        return ParentItemHolder(binding)\n    }\n}\n\n@Suppress(\"DEPRECATION\")\ninline fun <reified T> Bundle.getSafeParcelable(key: String): T? =\n    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) getParcelable(key)\n    else getParcelable(key, T::class.java)"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt",
    "content": "package com.lagradost.cloudstream3.ui.home\n\nimport android.content.Context\nimport android.os.Bundle\nimport android.os.Parcelable\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport androidx.appcompat.app.AlertDialog\nimport androidx.appcompat.widget.SearchView\nimport androidx.core.content.ContextCompat\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.lifecycle.LifecycleOwner\nimport androidx.lifecycle.findViewTreeLifecycleOwner\nimport androidx.recyclerview.widget.RecyclerView\nimport androidx.viewbinding.ViewBinding\nimport androidx.viewpager2.widget.ViewPager2\nimport com.google.android.material.chip.Chip\nimport com.google.android.material.chip.ChipGroup\nimport com.google.android.material.navigation.NavigationBarItemView\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.HomePageList\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.databinding.FragmentHomeHeadBinding\nimport com.lagradost.cloudstream3.databinding.FragmentHomeHeadTvBinding\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.debugException\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.WatchType\nimport com.lagradost.cloudstream3.ui.account.AccountHelper.showAccountEditDialog\nimport com.lagradost.cloudstream3.ui.account.AccountHelper.showAccountSelectLinear\nimport com.lagradost.cloudstream3.ui.account.AccountViewModel\nimport com.lagradost.cloudstream3.ui.result.FOCUS_SELF\nimport com.lagradost.cloudstream3.ui.result.ResultFragment.bindLogo\nimport com.lagradost.cloudstream3.ui.result.ResultViewModel2\nimport com.lagradost.cloudstream3.ui.result.START_ACTION_RESUME_LATEST\nimport com.lagradost.cloudstream3.ui.result.getId\nimport com.lagradost.cloudstream3.ui.result.setLinearListLayout\nimport com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD\nimport com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_SHOW_METADATA\nimport com.lagradost.cloudstream3.ui.search.SearchClickCallback\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showOptionSelectStringRes\nimport com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbarMargin\nimport com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbarView\nimport com.lagradost.cloudstream3.utils.UIHelper.populateChips\nimport androidx.core.graphics.toColorInt\nimport com.lagradost.cloudstream3.ui.setRecycledViewPool\n\nclass HomeParentItemAdapterPreview(\n    val fragment: LifecycleOwner,\n    private val viewModel: HomeViewModel,\n    private val accountViewModel: AccountViewModel\n) : ParentItemAdapter(\n    id = \"HomeParentItemAdapterPreview\".hashCode(),\n    clickCallback = {\n        viewModel.click(it)\n    }, moreInfoClickCallback = {\n        viewModel.popup(it)\n    }, expandCallback = {\n        viewModel.expand(it)\n    }) {\n    override val headers = 1\n    override fun onCreateHeader(parent: ViewGroup): ViewHolderState<Bundle> {\n        val inflater = LayoutInflater.from(parent.context)\n        val binding = if (isLayout(TV or EMULATOR)) FragmentHomeHeadTvBinding.inflate(\n            inflater,\n            parent,\n            false\n        ) else FragmentHomeHeadBinding.inflate(inflater, parent, false)\n\n        if (binding is FragmentHomeHeadTvBinding && isLayout(EMULATOR)) {\n            binding.homeBookmarkParentItemMoreInfo.isVisible = true\n\n            val marginInDp = 50\n            val density = binding.horizontalScrollChips.context.resources.displayMetrics.density\n            val marginInPixels = (marginInDp * density).toInt()\n\n            val params = binding.horizontalScrollChips.layoutParams as ViewGroup.MarginLayoutParams\n            params.marginEnd = marginInPixels\n            binding.horizontalScrollChips.layoutParams = params\n            binding.homeWatchParentItemTitle.setCompoundDrawablesWithIntrinsicBounds(\n                null,\n                null,\n                ContextCompat.getDrawable(\n                    parent.context,\n                    R.drawable.ic_baseline_arrow_forward_24\n                ),\n                null\n            )\n        }\n\n        return HeaderViewHolder(binding, viewModel, accountViewModel, fragment)\n    }\n\n    override fun onBindHeader(holder: ViewHolderState<Bundle>) {\n        (holder as? HeaderViewHolder)?.bind()\n    }\n\n    override fun onViewDetachedFromWindow(holder: ViewHolderState<Bundle>) {\n        when (holder) {\n            is HeaderViewHolder -> {\n                holder.onViewDetachedFromWindow()\n            }\n        }\n    }\n\n    override fun onViewAttachedToWindow(holder: ViewHolderState<Bundle>) {\n        when (holder) {\n            is HeaderViewHolder -> {\n                holder.onViewAttachedToWindow()\n            }\n        }\n    }\n\n    private class HeaderViewHolder(\n        val binding: ViewBinding,\n        val viewModel: HomeViewModel,\n        accountViewModel: AccountViewModel,\n        fragment: LifecycleOwner,\n    ) :\n        ViewHolderState<Bundle>(binding) {\n\n        override fun save(): Bundle =\n            Bundle().apply {\n                putParcelable(\n                    \"resumeRecyclerView\",\n                    resumeRecyclerView.layoutManager?.onSaveInstanceState()\n                )\n                putParcelable(\n                    \"bookmarkRecyclerView\",\n                    bookmarkRecyclerView.layoutManager?.onSaveInstanceState()\n                )\n                //putInt(\"previewViewpager\", previewViewpager.currentItem)\n            }\n\n        override fun restore(state: Bundle) {\n            state.getSafeParcelable<Parcelable>(\"resumeRecyclerView\")?.let { recycle ->\n                resumeRecyclerView.layoutManager?.onRestoreInstanceState(recycle)\n            }\n            state.getSafeParcelable<Parcelable>(\"bookmarkRecyclerView\")?.let { recycle ->\n                bookmarkRecyclerView.layoutManager?.onRestoreInstanceState(recycle)\n            }\n        }\n\n        val previewAdapter = HomeScrollAdapter { view, position, item ->\n            viewModel.click(\n                LoadClickCallback(0, view, position, item)\n            )\n        }\n\n        private val resumeAdapter = ResumeItemAdapter(\n            nextFocusUp = itemView.nextFocusUpId,\n            nextFocusDown = itemView.nextFocusDownId,\n            removeCallback = { v ->\n                try {\n                    val context = v.context ?: return@ResumeItemAdapter\n                    val builder: AlertDialog.Builder =\n                        AlertDialog.Builder(context)\n                    // Copy pasted from https://github.com/recloudstream/cloudstream/pull/1658/files\n                    builder.apply {\n                        setTitle(R.string.clear_history)\n                        setMessage(\n                            context.getString(R.string.delete_message).format(\n                                context.getString(\n                                    R.string.continue_watching\n                                )\n                            )\n                        )\n                        setNegativeButton(R.string.cancel) { _, _ -> /*NO-OP*/ }\n                        setPositiveButton(R.string.delete) { _, _ ->\n                            DataStoreHelper.deleteAllResumeStateIds()\n                            viewModel.reloadStored()\n                        }\n                        show().setDefaultFocus()\n                    }\n                } catch (t: Throwable) {\n                    // This may throw a formatting error\n                    logError(t)\n                }\n            },\n            clickCallback = { callback ->\n                if (callback.action != SEARCH_ACTION_SHOW_METADATA) {\n                    viewModel.click(callback)\n                    return@ResumeItemAdapter\n                }\n                callback.view.context?.getActivity()?.showOptionSelectStringRes(\n                    callback.view,\n                    callback.card.posterUrl,\n                    listOf(\n                        R.string.action_open_watching,\n                        R.string.action_remove_watching\n                    ),\n                    listOf(\n                        R.string.action_open_play,\n                        R.string.action_open_watching,\n                        R.string.action_remove_watching\n                    )\n                ) { (isTv, actionId) ->\n                    when (actionId + if (isTv) 0 else 1) {\n                        // play\n                        0 -> {\n                            viewModel.click(\n                                SearchClickCallback(\n                                    START_ACTION_RESUME_LATEST,\n                                    callback.view,\n                                    -1,\n                                    callback.card\n                                )\n                            )\n                        }\n                        //info\n                        1 -> {\n                            viewModel.click(\n                                SearchClickCallback(\n                                    SEARCH_ACTION_LOAD,\n                                    callback.view,\n                                    -1,\n                                    callback.card\n                                )\n                            )\n                        }\n                        // remove\n                        2 -> {\n                            val card = callback.card\n                            if (card is DataStoreHelper.ResumeWatchingResult) {\n                                DataStoreHelper.removeLastWatched(card.parentId)\n                                viewModel.reloadStored()\n                            }\n                        }\n                    }\n                }\n            })\n        private val bookmarkAdapter = HomeChildItemAdapter(\n            id = \"bookmarkAdapter\".hashCode(),\n            nextFocusUp = itemView.nextFocusUpId,\n            nextFocusDown = itemView.nextFocusDownId\n        ) { callback ->\n            if (callback.action != SEARCH_ACTION_SHOW_METADATA) {\n                viewModel.click(callback)\n                return@HomeChildItemAdapter\n            }\n\n            (callback.view.context?.getActivity() as? MainActivity)?.loadPopup(\n                callback.card,\n                load = false\n            )\n            /*\n            callback.view.context?.getActivity()?.showOptionSelectStringRes(\n                callback.view,\n                callback.card.posterUrl,\n                listOf(\n                    R.string.action_open_watching,\n                    R.string.action_remove_from_bookmarks,\n                ),\n                listOf(\n                    R.string.action_open_play,\n                    R.string.action_open_watching,\n                    R.string.action_remove_from_bookmarks\n                )\n            ) { (isTv, actionId) ->\n                when (actionId + if (isTv) 0 else 1) { // play\n                    0 -> {\n                        viewModel.click(\n                            SearchClickCallback(\n                                START_ACTION_RESUME_LATEST,\n                                callback.view,\n                                -1,\n                                callback.card\n                            )\n                        )\n                    }\n\n                    1 -> { // info\n                        viewModel.click(\n                            SearchClickCallback(\n                                SEARCH_ACTION_LOAD,\n                                callback.view,\n                                -1,\n                                callback.card\n                            )\n                        )\n                    }\n\n                    2 -> { // remove\n                        DataStoreHelper.setResultWatchState(\n                            callback.card.id,\n                            WatchType.NONE.internalId\n                        )\n                        viewModel.reloadStored()\n                    }\n                }\n            }\n            */\n        }\n\n        private val previewViewpager: ViewPager2 =\n            itemView.findViewById(R.id.home_preview_viewpager)\n\n        private val previewViewpagerText: ViewGroup =\n            itemView.findViewById(R.id.home_preview_viewpager_text)\n\n        // private val previewHeader: FrameLayout = itemView.findViewById(R.id.home_preview)\n        private val resumeHolder: View = itemView.findViewById(R.id.home_watch_holder)\n        private val resumeRecyclerView: RecyclerView =\n            itemView.findViewById(R.id.home_watch_child_recyclerview)\n        private val bookmarkHolder: View = itemView.findViewById(R.id.home_bookmarked_holder)\n        private val bookmarkRecyclerView: RecyclerView =\n            itemView.findViewById(R.id.home_bookmarked_child_recyclerview)\n\n        private val headProfilePic: ImageView? = itemView.findViewById(R.id.home_head_profile_pic)\n        private val headProfilePicCard: View? =\n            itemView.findViewById(R.id.home_head_profile_padding)\n\n        private val alternateHeadProfilePic: ImageView? =\n            itemView.findViewById(R.id.alternate_home_head_profile_pic)\n        private val alternateHeadProfilePicCard: View? =\n            itemView.findViewById(R.id.alternate_home_head_profile_padding)\n\n        private val topPadding: View? = itemView.findViewById(R.id.home_padding)\n\n        private val alternativeAccountPadding: View? =\n            itemView.findViewById(R.id.alternative_account_padding)\n\n        private val homeNonePadding: View = itemView.findViewById(R.id.home_none_padding)\n\n        fun onSelect(item: LoadResponse, position: Int) {\n            (binding as? FragmentHomeHeadTvBinding)?.apply {\n                homePreviewDescription.isGone = item.plot.isNullOrBlank()\n                homePreviewDescription.text = item.plot?.html() ?: \"\"\n\n                val scoreText = item.score?.toStringNull(0.1, 10, 1, false)\n\n                scoreText?.let { score ->\n                    homePreviewScore.text =\n                        homePreviewScore.context.getString(R.string.extension_rating, score)\n\n                    // while it should never fail, we do this just in case\n                    val rating = score.toDoubleOrNull() ?: item.score?.toDouble() ?: 0.0\n\n                    val color = when {\n                        rating < 5.0 -> \"#eb2f2f\".toColorInt() // Red\n                        rating < 8.0 -> \"#eda009\".toColorInt() // Yellow\n                        else -> \"#3bb33b\".toColorInt() // Green\n                    }\n                    homePreviewScore.backgroundTintList =\n                        android.content.res.ColorStateList.valueOf(color)\n                }\n                homePreviewScore.isGone = scoreText == null\n\n                item.year?.let { year ->\n                    homePreviewYear.text = year.toString()\n                }\n                homePreviewYear.isGone = item.year == null\n\n                val duration = item.duration\n                duration?.let { min ->\n                    homePreviewDuration.text =\n                        homePreviewDuration.context.getString(R.string.duration_format, min)\n                }\n                homePreviewDuration.isGone = duration == null || duration <= 0\n\n                val castText = item.actors?.take(3)?.joinToString(\", \") { it.actor.name }\n                if (!castText.isNullOrBlank()) {\n                    homePreviewCast.text =\n                        homePreviewCast.context.getString(R.string.cast_format, castText)\n                    homePreviewCast.isVisible = true\n                } else {\n                    homePreviewCast.isVisible = false\n                }\n\n                homePreviewText.text = item.name.html()\n                populateChips(\n                    homePreviewTags,\n                    item.tags?.take(6) ?: emptyList(),\n                    R.style.ChipFilledSemiTransparent,\n                    null\n                )\n\n\n                bindLogo(\n                    url = item.logoUrl,\n                    headers = item.posterHeaders,\n                    titleView = homePreviewText,\n                    logoView = homeBackgroundPosterWatermarkBadgeHolder\n                )\n\n                homePreviewTags.isGone =\n                    item.tags.isNullOrEmpty()\n\n                homePreviewInfoBtt.setOnClickListener { view ->\n                    viewModel.click(\n                        LoadClickCallback(0, view, position, item)\n                    )\n                }\n            }\n            (binding as? FragmentHomeHeadBinding)?.apply {\n                //homePreviewImage.setImage(item.posterUrl, item.posterHeaders)\n\n                homePreviewPlay.setOnClickListener { view ->\n                    viewModel.click(\n                        LoadClickCallback(\n                            START_ACTION_RESUME_LATEST,\n                            view,\n                            position,\n                            item\n                        )\n                    )\n                }\n\n                homePreviewInfo.setOnClickListener { view ->\n                    viewModel.click(\n                        LoadClickCallback(0, view, position, item)\n                    )\n                }\n\n                // very ugly code, but I don't care\n                val id = item.getId()\n                val watchType =\n                    DataStoreHelper.getResultWatchState(id)\n                homePreviewBookmark.setText(watchType.stringRes)\n                homePreviewBookmark.setCompoundDrawablesWithIntrinsicBounds(\n                    null,\n                    ContextCompat.getDrawable(\n                        homePreviewBookmark.context,\n                        watchType.iconRes\n                    ),\n                    null,\n                    null\n                )\n\n                homePreviewBookmark.setOnClickListener { fab ->\n                    fab.context.getActivity()?.showBottomDialog(\n                        WatchType.entries\n                            .map { fab.context.getString(it.stringRes) }\n                            .toList(),\n                        DataStoreHelper.getResultWatchState(id).ordinal,\n                        fab.context.getString(R.string.action_add_to_bookmarks),\n                        showApply = false,\n                        {}) {\n                        val newValue = WatchType.entries[it]\n\n                        ResultViewModel2().updateWatchStatus(\n                            newValue,\n                            fab.context,\n                            item\n                        ) { statusChanged: Boolean ->\n                            if (!statusChanged) return@updateWatchStatus\n\n                            homePreviewBookmark.setCompoundDrawablesWithIntrinsicBounds(\n                                null,\n                                ContextCompat.getDrawable(\n                                    homePreviewBookmark.context,\n                                    newValue.iconRes\n                                ),\n                                null,\n                                null\n                            )\n                            homePreviewBookmark.setText(newValue.stringRes)\n                        }\n                    }\n                }\n            }\n        }\n\n        private val previewCallback: ViewPager2.OnPageChangeCallback =\n            object : ViewPager2.OnPageChangeCallback() {\n                override fun onPageSelected(position: Int) {\n                    previewAdapter.apply {\n                        if (position >= itemCount - 1 && hasMoreItems) {\n                            hasMoreItems = false // don't make two requests\n                            viewModel.loadMoreHomeScrollResponses()\n                        }\n                    }\n                    val item = previewAdapter.getItemOrNull(position) ?: return\n                    onSelect(item, position)\n                }\n            }\n\n        fun onViewDetachedFromWindow() {\n            previewViewpager.unregisterOnPageChangeCallback(previewCallback)\n        }\n\n        private val toggleList = listOf<Pair<Chip, WatchType>>(\n            Pair(itemView.findViewById(R.id.home_type_watching_btt), WatchType.WATCHING),\n            Pair(itemView.findViewById(R.id.home_type_completed_btt), WatchType.COMPLETED),\n            Pair(itemView.findViewById(R.id.home_type_dropped_btt), WatchType.DROPPED),\n            Pair(itemView.findViewById(R.id.home_type_on_hold_btt), WatchType.ONHOLD),\n            Pair(itemView.findViewById(R.id.home_plan_to_watch_btt), WatchType.PLANTOWATCH),\n        )\n\n        private val toggleListHolder: ChipGroup? = itemView.findViewById(R.id.home_type_holder)\n\n        fun bind() = Unit\n\n        init {\n            previewViewpager.setPageTransformer(HomeScrollTransformer())\n\n            previewViewpager.adapter = previewAdapter\n            resumeRecyclerView.adapter = resumeAdapter\n            bookmarkRecyclerView.setRecycledViewPool(HomeChildItemAdapter.sharedPool)\n            bookmarkRecyclerView.adapter = bookmarkAdapter\n\n            resumeRecyclerView.setLinearListLayout(\n                nextLeft = R.id.nav_rail_view,\n                nextRight = FOCUS_SELF\n            )\n\n            bookmarkRecyclerView.setLinearListLayout(\n                nextLeft = R.id.nav_rail_view,\n                nextRight = FOCUS_SELF\n            )\n\n            fixPaddingStatusbarMargin(topPadding)\n\n            for ((chip, watch) in toggleList) {\n                chip.isChecked = false\n                chip.setOnCheckedChangeListener { _, isChecked ->\n                    if (isChecked) {\n                        viewModel.loadStoredData(setOf(watch))\n                    }\n                    // Else if all are unchecked -> Do not load data\n                    else if (toggleList.all { !it.first.isChecked }) {\n                        viewModel.loadStoredData(emptySet())\n                    }\n                }\n            }\n\n            headProfilePicCard?.isGone = isLayout(TV or EMULATOR)\n            alternateHeadProfilePicCard?.isGone = isLayout(TV or EMULATOR)\n\n            fragment.observe(viewModel.currentAccount) { currentAccount ->\n                headProfilePic?.loadImage(currentAccount?.image)\n                alternateHeadProfilePic?.loadImage(currentAccount?.image)\n            }\n\n            headProfilePicCard?.setOnClickListener {\n                activity?.showAccountSelectLinear()\n            }\n\n            fun showAccountEditBox(context: Context): Boolean {\n                val currentAccount = DataStoreHelper.getCurrentAccount()\n                return if (currentAccount != null) {\n                    showAccountEditDialog(\n                        context = context,\n                        account = currentAccount,\n                        isNewAccount = false,\n                        accountEditCallback = { accountViewModel.handleAccountUpdate(it, context) },\n                        accountDeleteCallback = {\n                            accountViewModel.handleAccountDelete(\n                                it,\n                                context\n                            )\n                        }\n                    )\n                    true\n                } else false\n            }\n\n            alternateHeadProfilePicCard?.setOnLongClickListener {\n                showAccountEditBox(it.context)\n            }\n            headProfilePicCard?.setOnLongClickListener {\n                showAccountEditBox(it.context)\n            }\n\n            alternateHeadProfilePicCard?.setOnClickListener {\n                activity?.showAccountSelectLinear()\n            }\n\n            (binding as? FragmentHomeHeadTvBinding)?.apply {\n                /*homePreviewChangeApi.setOnClickListener { view ->\n                    view.context.selectHomepage(viewModel.repo?.name) { api ->\n                        viewModel.loadAndCancel(api, forceReload = true, fromUI = true)\n                    }\n                }\n                homePreviewReloadProvider.setOnClickListener {\n                    viewModel.loadAndCancel(\n                        viewModel.apiName.value ?: noneApi.name,\n                        forceReload = true,\n                        fromUI = true\n                    )\n                    showToast(R.string.action_reload, Toast.LENGTH_SHORT)\n                    true\n                }\n                homePreviewSearchButton.setOnClickListener { _ ->\n                    // Open blank screen.\n                    viewModel.queryTextSubmit(\"\")\n                }*/\n\n                // A workaround to the focus problem of always centering the view on focus\n                // as that causes higher android versions to stretch the ui when switching between shows\n                var lastFocusTimeoutMs = 0L\n                homePreviewInfoBtt.setOnFocusChangeListener { view, hasFocus ->\n                    val lastFocusMs = lastFocusTimeoutMs\n                    // Always reset timer, as we only want to update\n                    // it if we have not interacted in half a second\n                    lastFocusTimeoutMs = System.currentTimeMillis()\n                    if (!hasFocus) return@setOnFocusChangeListener\n                    if (lastFocusMs + 500L < System.currentTimeMillis()) {\n                        MainActivity.centerView(view)\n                    }\n                }\n\n                homePreviewHiddenNextFocus.setOnFocusChangeListener { _, hasFocus ->\n                    if (!hasFocus) return@setOnFocusChangeListener\n                    previewViewpager.setCurrentItem(previewViewpager.currentItem + 1, true)\n                    homePreviewInfoBtt.requestFocus()\n                }\n\n                homePreviewHiddenPrevFocus.setOnFocusChangeListener { _, hasFocus ->\n                    if (!hasFocus) return@setOnFocusChangeListener\n                    if (previewViewpager.currentItem <= 0) {\n                        //Focus the Home item as the default focus will be the header item\n                        (activity as? MainActivity)?.binding?.navRailView?.findViewById<NavigationBarItemView>(\n                            R.id.navigation_home\n                        )?.requestFocus()\n                    } else {\n                        previewViewpager.setCurrentItem(previewViewpager.currentItem - 1, true)\n                        binding.homePreviewInfoBtt.requestFocus()\n                        //binding.homePreviewPlayBtt.requestFocus()\n                    }\n                }\n            }\n\n            (binding as? FragmentHomeHeadBinding)?.apply {\n                homeSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener {\n                    override fun onQueryTextSubmit(query: String): Boolean {\n                        viewModel.queryTextSubmit(query)\n                        return true\n                    }\n\n                    override fun onQueryTextChange(newText: String): Boolean {\n                        viewModel.queryTextChange(newText)\n                        return true\n                    }\n                })\n            }\n        }\n\n        private fun updatePreview(preview: Resource<Pair<Boolean, List<LoadResponse>>>) {\n            if (preview is Resource.Success) {\n                homeNonePadding.apply {\n                    val params = layoutParams\n                    params.height = 0\n                    layoutParams = params\n                }\n            } else fixPaddingStatusbarView(homeNonePadding)\n\n            when (preview) {\n                is Resource.Success -> {\n                    previewAdapter.submitList(preview.value.second)\n                    previewAdapter.hasMoreItems = preview.value.first\n                    /*if (!.setItems(\n                            preview.value.second,\n                            preview.value.first\n                        )\n                    ) {\n                        // this might seam weird and useless, however this prevents a very weird andrid bug were the viewpager is not rendered properly\n                        // I have no idea why that happens, but this is my ducktape solution\n                        previewViewpager.setCurrentItem(0, false)\n                        previewViewpager.beginFakeDrag()\n                        previewViewpager.fakeDragBy(1f)\n                        previewViewpager.endFakeDrag()\n                        previewCallback.onPageSelected(0)\n                        //previewHeader.isVisible = true\n                    }*/\n\n                    previewViewpager.isVisible = true\n                    previewViewpagerText.isVisible = true\n                    alternativeAccountPadding?.isVisible = false\n                    (binding as? FragmentHomeHeadTvBinding)?.apply {\n                        homePreviewInfoBtt.isVisible = true\n                    }\n                    // Explicitly bind the current item to ensure instant loading\n                    val currentPos = previewViewpager.currentItem\n                    val item = preview.value.second.getOrNull(currentPos)\n                    if (item != null) {\n                        onSelect(item, currentPos)\n                    }\n                }\n\n                else -> {\n                    previewAdapter.submitList(listOf())\n                    previewViewpager.setCurrentItem(0, false)\n                    previewViewpager.isVisible = false\n                    previewViewpagerText.isVisible = false\n                    alternativeAccountPadding?.isVisible = true\n                    (binding as? FragmentHomeHeadTvBinding)?.apply {\n                        homePreviewInfoBtt.isVisible = false\n                    }\n                    //previewHeader.isVisible = false\n                }\n            }\n        }\n\n        private fun updateResume(resumeWatching: List<SearchResponse>) {\n            resumeHolder.isVisible = resumeWatching.isNotEmpty()\n            resumeAdapter.submitList(resumeWatching)\n\n            if (\n                binding is FragmentHomeHeadBinding ||\n                binding is FragmentHomeHeadTvBinding &&\n                isLayout(EMULATOR)\n            ) {\n                val title = (binding as? FragmentHomeHeadBinding)?.homeWatchParentItemTitle\n                    ?: (binding as? FragmentHomeHeadTvBinding)?.homeWatchParentItemTitle\n\n                title?.setOnClickListener {\n                    viewModel.popup(\n                        HomeViewModel.ExpandableHomepageList(\n                            HomePageList(\n                                title.text.toString(),\n                                resumeWatching,\n                                false\n                            ), 1, false\n                        ),\n                        deleteCallback = {\n                            viewModel.deleteResumeWatching()\n                        }\n                    )\n                }\n            }\n        }\n\n        private fun updateBookmarks(data: Pair<Boolean, List<SearchResponse>>) {\n            val (visible, list) = data\n            bookmarkHolder.isVisible = visible\n            bookmarkAdapter.submitList(list)\n\n            if (\n                binding is FragmentHomeHeadBinding ||\n                binding is FragmentHomeHeadTvBinding &&\n                isLayout(EMULATOR)\n            ) {\n                val title = (binding as? FragmentHomeHeadBinding)?.homeBookmarkParentItemTitle\n                    ?: (binding as? FragmentHomeHeadTvBinding)?.homeBookmarkParentItemTitle\n\n                title?.setOnClickListener {\n                    val items = toggleList.map { it.first }.filter { it.isChecked }\n                    if (items.isEmpty()) return@setOnClickListener // we don't want to show an empty dialog\n                    val textSum = items\n                        .mapNotNull { it.text }.joinToString()\n\n                    viewModel.popup(\n                        HomeViewModel.ExpandableHomepageList(\n                            HomePageList(\n                                textSum,\n                                list,\n                                false\n                            ), 1, false\n                        ), deleteCallback = {\n                            viewModel.deleteBookmarks(list)\n                        }\n                    )\n                }\n            }\n        }\n\n        fun onViewAttachedToWindow() {\n            previewViewpager.registerOnPageChangeCallback(previewCallback)\n\n            binding.root.findViewTreeLifecycleOwner()?.apply {\n                observe(viewModel.preview) {\n                    updatePreview(it)\n                }\n                /*if (binding is FragmentHomeHeadTvBinding) {\n                    observe(viewModel.apiName) { name ->\n                        binding.homePreviewChangeApi.text = name\n                        binding.homePreviewReloadProvider.isGone = (name == noneApi.name)\n                    }\n                }*/\n                observe(viewModel.resumeWatching) {\n                    updateResume(it)\n                }\n                observe(viewModel.bookmarks) {\n                    updateBookmarks(it)\n                }\n                observe(viewModel.availableWatchStatusTypes) { (checked, visible) ->\n                    for ((chip, watch) in toggleList) {\n                        chip.apply {\n                            isVisible = visible.contains(watch)\n                            isChecked = checked.contains(watch)\n                        }\n                    }\n                    toggleListHolder?.isGone = visible.isEmpty()\n                }\n            } ?: debugException { \"Expected findViewTreeLifecycleOwner\" }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeScrollAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.home\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.core.view.isGone\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.databinding.HomeScrollViewBinding\nimport com.lagradost.cloudstream3.databinding.HomeScrollViewTvBinding\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.result.ResultFragment.bindLogo\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\n\nclass HomeScrollAdapter(\n    val callback: ((View, Int, LoadResponse) -> Unit)\n) : NoStateAdapter<LoadResponse>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n    a.uniqueUrl == b.uniqueUrl && a.name == b.name\n})) {\n    var hasMoreItems: Boolean = false\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        val inflater = LayoutInflater.from(parent.context)\n        val binding = if (isLayout(TV or EMULATOR)) {\n            HomeScrollViewTvBinding.inflate(inflater, parent, false)\n        } else {\n            HomeScrollViewBinding.inflate(inflater, parent, false)\n        }\n\n        return ViewHolderState(binding)\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        when (val binding = holder.view) {\n            is HomeScrollViewBinding -> {\n                clearImage(binding.homeScrollPreview)\n            }\n\n            is HomeScrollViewTvBinding -> {\n                clearImage(binding.homeScrollPreview)\n            }\n        }\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Any>,\n        item: LoadResponse,\n        position: Int,\n    ) {\n        val binding = holder.view\n\n        val posterUrl = item.backgroundPosterUrl ?: item.posterUrl\n\n        when (binding) {\n            is HomeScrollViewBinding -> {\n                binding.homeScrollPreview.loadImage(posterUrl)\n                binding.homeScrollPreviewTags.apply {\n                    text = item.tags?.joinToString(\" • \") ?: \"\"\n                    isGone = item.tags.isNullOrEmpty()\n                    maxLines = 2\n                }\n                binding.homeScrollPreviewTitle.text = item.name.html()\n\n                bindLogo(\n                    url = item.logoUrl,\n                    headers = item.posterHeaders,\n                    titleView = binding.homeScrollPreviewTitle,\n                    logoView = binding.homePreviewLogo\n                )\n            }\n\n            is HomeScrollViewTvBinding -> {\n                binding.homeScrollPreview.isFocusable = false\n                binding.homeScrollPreview.setOnClickListener { view ->\n                    callback.invoke(view ?: return@setOnClickListener, position, item)\n                }\n                binding.homeScrollPreview.loadImage(posterUrl)\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeScrollTransformer.kt",
    "content": "package com.lagradost.cloudstream3.ui.home\n\nimport android.view.View\nimport androidx.viewpager2.widget.ViewPager2\n\nclass HomeScrollTransformer : ViewPager2.PageTransformer {\n    override fun transformPage(page: View, position: Float) {\n        //page.translationX = -position * page.width / 2.0f\n\n        //val params = RecyclerView.LayoutParams(\n        //    RecyclerView.LayoutParams.MATCH_PARENT,\n        //    0\n        //)\n        //page.layoutParams = params\n        //progressBar?.layoutParams = params\n\n        val padding = (-position * page.width / 2).toInt()\n        page.setPadding(\n            padding, 0,\n            -padding, 0\n        )\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.home\n\nimport android.os.Build\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport com.lagradost.cloudstream3.APIHolder.apis\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.context\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.HomePageList\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.debugAssert\nimport com.lagradost.cloudstream3.mvvm.debugWarning\nimport com.lagradost.cloudstream3.mvvm.launchSafe\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.ui.APIRepository\nimport com.lagradost.cloudstream3.ui.APIRepository.Companion.noneApi\nimport com.lagradost.cloudstream3.ui.APIRepository.Companion.randomApi\nimport com.lagradost.cloudstream3.ui.WatchType\nimport com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment\nimport com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_FOCUSED\nimport com.lagradost.cloudstream3.ui.search.SearchClickCallback\nimport com.lagradost.cloudstream3.ui.search.SearchHelper\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.addProgramsToContinueWatching\nimport com.lagradost.cloudstream3.utils.AppContextUtils.filterHomePageListByFilmQuality\nimport com.lagradost.cloudstream3.utils.AppContextUtils.filterProviderByPreferredMedia\nimport com.lagradost.cloudstream3.utils.AppContextUtils.filterSearchResultByFilmQuality\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadResult\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE_BACKUP\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.deleteAllResumeStateIds\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllWatchStateIds\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getCurrentAccount\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getLastWatched\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.withContext\nimport java.util.EnumSet\nimport java.util.concurrent.CopyOnWriteArrayList\n\nclass HomeViewModel : ViewModel() {\n    companion object {\n        suspend fun getResumeWatching(): List<DataStoreHelper.ResumeWatchingResult>? {\n            val resumeWatching = withContext(Dispatchers.IO) {\n                getAllResumeStateIds()?.mapNotNull { id ->\n                    getLastWatched(id)\n                }?.sortedBy { -it.updateTime }\n            }\n            val resumeWatchingResult = withContext(Dispatchers.IO) {\n                resumeWatching?.mapNotNull { resume ->\n                    val headerCache = getKey<DownloadObjects.DownloadHeaderCached>(\n                        DOWNLOAD_HEADER_CACHE,\n                        resume.parentId.toString()\n                    )\n\n                    val data = if (headerCache == null) {\n                        // We store resume watching data in download header cache\n                        // Because downloads automatically pruned outdated download headers we\n                        // removed resume watching data. We should restore the data for affected users.\n                        val oldData = getKey<DownloadObjects.DownloadHeaderCached>(\n                            DOWNLOAD_HEADER_CACHE_BACKUP,\n                            resume.parentId.toString()\n                        ) ?: return@mapNotNull null\n\n                        // Restore data\n                        setKey(DOWNLOAD_HEADER_CACHE, resume.parentId.toString(), oldData)\n                        oldData\n                    } else {\n                        headerCache\n                    }\n\n                    val watchPos = getViewPos(resume.episodeId)\n\n                    DataStoreHelper.ResumeWatchingResult(\n                        data.name,\n                        data.url,\n                        data.apiName,\n                        data.type,\n                        data.poster,\n                        watchPos,\n                        resume.episodeId,\n                        resume.parentId,\n                        resume.episode,\n                        resume.season,\n                        resume.isFromDownload\n                    )\n                }\n            }\n            return resumeWatchingResult\n        }\n    }\n\n    fun deleteResumeWatching() {\n        deleteAllResumeStateIds()\n        loadResumeWatching()\n    }\n\n    fun deleteBookmarks(list: List<SearchResponse>) {\n        list.forEach { DataStoreHelper.deleteBookmarkedData(it.id) }\n        loadStoredData()\n    }\n\n    var repo: APIRepository? = null\n\n    private val _apiName = MutableLiveData<String>()\n    val apiName: LiveData<String> = _apiName\n\n    private val _currentAccount = MutableLiveData<DataStoreHelper.Account?>()\n    val currentAccount: MutableLiveData<DataStoreHelper.Account?> = _currentAccount\n\n    private val _randomItems = MutableLiveData<List<SearchResponse>?>(null)\n    val randomItems: LiveData<List<SearchResponse>?> = _randomItems\n\n    private var currentShuffledList: List<SearchResponse> = listOf()\n\n    private fun autoloadRepo(): APIRepository {\n        return APIRepository(synchronized(apis) { apis.first { it.hasMainPage } })\n    }\n\n    private val _availableWatchStatusTypes =\n        MutableLiveData<Pair<Set<WatchType>, Set<WatchType>>>()\n    val availableWatchStatusTypes: LiveData<Pair<Set<WatchType>, Set<WatchType>>> =\n        _availableWatchStatusTypes\n    private val _bookmarks = MutableLiveData<Pair<Boolean, List<SearchResponse>>>()\n    val bookmarks: LiveData<Pair<Boolean, List<SearchResponse>>> = _bookmarks\n\n    private val _resumeWatching = MutableLiveData<List<SearchResponse>>()\n    private val _preview = MutableLiveData<Resource<Pair<Boolean, List<LoadResponse>>>>()\n    private val previewResponses = CopyOnWriteArrayList<LoadResponse>()\n    private val previewResponsesAdded = mutableSetOf<String>()\n\n    val resumeWatching: LiveData<List<SearchResponse>> = _resumeWatching\n    val preview: LiveData<Resource<Pair<Boolean, List<LoadResponse>>>> = _preview\n\n    private fun loadResumeWatching() = viewModelScope.launchSafe {\n        val resumeWatchingResult = getResumeWatching()\n        if (isLayout(TV) && resumeWatchingResult != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            ioSafe {\n                // this WILL crash on non tvs, so keep this inside a try catch\n                activity?.addProgramsToContinueWatching(resumeWatchingResult)\n            }\n        }\n        resumeWatchingResult?.let {\n            _resumeWatching.postValue(it)\n        }\n    }\n\n    fun loadStoredData(preferredWatchStatus: Set<WatchType>?) = viewModelScope.launchSafe {\n        val watchStatusIds = withContext(Dispatchers.IO) {\n            getAllWatchStateIds()?.map { id ->\n                Pair(id, getResultWatchState(id))\n            }\n        }?.distinctBy { it.first } ?: return@launchSafe\n\n        val length = WatchType.entries.size\n        val currentWatchTypes = mutableSetOf<WatchType>()\n\n        for (watch in watchStatusIds) {\n            currentWatchTypes.add(watch.second)\n            if (currentWatchTypes.size >= length) {\n                break\n            }\n        }\n\n        currentWatchTypes.remove(WatchType.NONE)\n\n        if (currentWatchTypes.size <= 0) {\n            DataStoreHelper.homeBookmarkedList = intArrayOf()\n            _availableWatchStatusTypes.postValue(setOf<WatchType>() to setOf())\n            _bookmarks.postValue(Pair(false, ArrayList()))\n            return@launchSafe\n        }\n\n        val watchPrefNotNull = preferredWatchStatus ?: EnumSet.of(currentWatchTypes.first())\n        //if (currentWatchTypes.any { watchPrefNotNull.contains(it) }) watchPrefNotNull else listOf(currentWatchTypes.first())\n\n        DataStoreHelper.homeBookmarkedList = watchPrefNotNull.map { it.internalId }.toIntArray()\n        _availableWatchStatusTypes.postValue(\n\n            watchPrefNotNull to\n                    currentWatchTypes,\n\n            )\n\n        val list = withContext(Dispatchers.IO) {\n            watchStatusIds.filter { watchPrefNotNull.contains(it.second) }\n                .mapNotNull { getBookmarkedData(it.first) }\n                .sortedBy { -it.latestUpdatedTime }\n        }\n        _bookmarks.postValue(Pair(true, list))\n    }\n\n    private var onGoingLoad: Job? = null\n    private var isCurrentlyLoadingName: String? = null\n    private fun loadAndCancel(api: MainAPI) {\n        //println(\"loaded ${api.name}\")\n        onGoingLoad?.cancel()\n        isCurrentlyLoadingName = api.name\n        onGoingLoad = load(api)\n    }\n\n    data class ExpandableHomepageList(\n        var list: HomePageList,\n        var currentPage: Int,\n        var hasNext: Boolean,\n    )\n\n    private val expandable: MutableMap<String, ExpandableHomepageList> = mutableMapOf()\n    private val _page =\n        MutableLiveData<Resource<Map<String, ExpandableHomepageList>>>(Resource.Loading())\n    val page: LiveData<Resource<Map<String, ExpandableHomepageList>>> = _page\n\n    val lock: MutableSet<String> = mutableSetOf()\n\n    suspend fun expandAndReturn(name: String): ExpandableHomepageList? {\n        if (lock.contains(name)) return null\n        lock += name\n\n        repo?.apply {\n            waitForHomeDelay()\n\n            expandable[name]?.let { current ->\n                debugAssert({ !current.hasNext }) {\n                    \"Expand called when not needed\"\n                }\n\n                val nextPage = current.currentPage + 1\n                val next = getMainPage(nextPage, mainPage.indexOfFirst { it.name == name })\n                if (next is Resource.Success) {\n                    next.value.filterNotNull().forEach { main ->\n                        main.items.forEach { newList ->\n                            val key = newList.name\n                            expandable[key]?.apply {\n                                hasNext = main.hasNext\n                                currentPage = nextPage\n\n                                debugWarning({ newList.list.any { outer -> this.list.list.any { it.url == outer.url } } }) {\n                                    \"Expanded contained an item that was previously already in the list\\n${list.name} = ${this.list.list}\\n${newList.name} = ${newList.list}\"\n                                }\n\n                                this.list.list += newList.list\n                                this.list.list.distinctBy { it.url } // just to be sure we are not adding the same shit for some reason\n                            } ?: debugWarning {\n                                \"Expanded an item not in main load named $key, current list is ${expandable.keys}\"\n                            }\n                        }\n                    }\n                } else {\n                    current.hasNext = false\n                }\n            }\n            _page.postValue(Resource.Success(expandable))\n        }\n\n        lock -= name\n\n        return expandable[name]\n    }\n\n    // this is soo over engineered, but idk how I can make it clean without making the main api harder to use :pensive:\n    fun expand(name: String) = viewModelScope.launchSafe {\n        expandAndReturn(name)\n    }\n\n    // returns the amount of items added and modifies current\n    private suspend fun updatePreviewResponses(\n        current: MutableList<LoadResponse>,\n        alreadyAdded: MutableSet<String>,\n        shuffledList: List<SearchResponse>,\n        size: Int\n    ): Int {\n        var count = 0\n\n        val addItems = arrayListOf<SearchResponse>()\n        for (searchResponse in shuffledList) {\n            if (!alreadyAdded.contains(searchResponse.url)) {\n                addItems.add(searchResponse)\n                previewResponsesAdded.add(searchResponse.url)\n                if (++count >= size) {\n                    break\n                }\n            }\n        }\n\n        val add = addItems.amap { searchResponse ->\n            repo?.load(searchResponse.url)\n        }.mapNotNull { if (it != null && it is Resource.Success) it.value else null }\n        current.addAll(add)\n        return add.size\n    }\n\n    private var addJob: Job? = null\n    fun loadMoreHomeScrollResponses() {\n        addJob = ioSafe {\n            updatePreviewResponses(previewResponses, previewResponsesAdded, currentShuffledList, 1)\n            _preview.postValue(Resource.Success((previewResponsesAdded.size < currentShuffledList.size) to previewResponses))\n        }\n    }\n\n    private fun load(api: MainAPI): Job = ioSafe {\n        repo = //if (api != null) {\n            APIRepository(api)\n        //} else {\n        //    autoloadRepo()\n        //}\n\n        _apiName.postValue(repo?.name)\n        _randomItems.postValue(listOf())\n\n        if (repo?.hasMainPage != true) {\n            _page.postValue(Resource.Success(emptyMap()))\n            _preview.postValue(Resource.Failure(false, \"No homepage\"))\n            return@ioSafe\n        }\n\n\n        _page.postValue(Resource.Loading())\n        _preview.postValue(Resource.Loading())\n        // cancel the current preview expand as that is no longer relevant\n        addJob?.cancel()\n\n        when (val data = repo?.getMainPage(1, null)) {\n            is Resource.Success -> {\n                try {\n                    expandable.clear()\n                    data.value.forEach { home ->\n                        home?.items?.forEach { list ->\n                            val filteredList =\n                                context?.filterHomePageListByFilmQuality(list) ?: list\n                            expandable[list.name] =\n                                ExpandableHomepageList(\n                                    filteredList.copy(\n                                        list = CopyOnWriteArrayList(\n                                            filteredList.list\n                                        )\n                                    ), 1, home.hasNext\n                                )\n                        }\n                    }\n\n                    val items = data.value.mapNotNull { it?.items }.flatten()\n\n\n                    previewResponses.clear()\n                    previewResponsesAdded.clear()\n\n                    //val home = data.value\n                    if (items.isNotEmpty()) {\n                        val currentList =\n                            items.shuffled().filter { it.list.isNotEmpty() }\n                                .flatMap { it.list }\n                                .distinctBy { it.url }.toList()\n\n                        if (currentList.isNotEmpty()) {\n                            val randomItems =\n                                context?.filterSearchResultByFilmQuality(currentList.shuffled())\n                                    ?: currentList.shuffled()\n\n                            updatePreviewResponses(\n                                previewResponses,\n                                previewResponsesAdded,\n                                randomItems,\n                                3\n                            )\n\n                            _randomItems.postValue(randomItems)\n                            currentShuffledList = randomItems\n                        }\n                    }\n                    if (previewResponses.isEmpty()) {\n                        _preview.postValue(\n                            Resource.Failure(\n                                false,\n                                \"No homepage responses\"\n                            )\n                        )\n                    } else {\n                        _preview.postValue(Resource.Success((previewResponsesAdded.size < currentShuffledList.size) to previewResponses))\n                    }\n                    _page.postValue(Resource.Success(expandable))\n                } catch (e: Exception) {\n                    _randomItems.postValue(emptyList())\n                    logError(e)\n                }\n            }\n\n            is Resource.Failure -> {\n                @Suppress(\"UNNECESSARY_NOT_NULL_ASSERTION\")\n                _page.postValue(data!!)\n                @Suppress(\"UNNECESSARY_NOT_NULL_ASSERTION\")\n                _preview.postValue(data!!)\n            }\n\n            else -> Unit\n        }\n        isCurrentlyLoadingName = null\n    }\n\n    fun click(callback: SearchClickCallback) {\n        if (callback.action != SEARCH_ACTION_FOCUSED) {\n            SearchHelper.handleSearchClickCallback(callback)\n        }\n    }\n\n    private val _popup = MutableLiveData<Pair<ExpandableHomepageList, (() -> Unit)?>?>(null)\n    val popup: LiveData<Pair<ExpandableHomepageList, (() -> Unit)?>?> = _popup\n\n    fun popup(list: ExpandableHomepageList?, deleteCallback: (() -> Unit)? = null) {\n        if (list == null)\n            _popup.postValue(null)\n        else\n            _popup.postValue(list to deleteCallback)\n    }\n\n    private fun bookmarksUpdated(unused: Boolean) {\n        reloadStored()\n    }\n\n    private fun afterPluginsLoaded(forceReload: Boolean) {\n        loadAndCancel(DataStoreHelper.currentHomePage, forceReload)\n    }\n\n    private fun afterMainPluginsLoaded(unused: Boolean = false) {\n        loadAndCancel(DataStoreHelper.currentHomePage, false)\n    }\n\n    private fun reloadHome(unused: Boolean = false) {\n        loadAndCancel(DataStoreHelper.currentHomePage, true)\n    }\n\n    private fun reloadAccount(unused: Boolean = false) {\n        _currentAccount.postValue(\n            getCurrentAccount()\n        )\n    }\n\n    init {\n        MainActivity.bookmarksUpdatedEvent += ::bookmarksUpdated\n        MainActivity.afterPluginsLoadedEvent += ::afterPluginsLoaded\n        MainActivity.mainPluginsLoadedEvent += ::afterMainPluginsLoaded\n        MainActivity.reloadHomeEvent += ::reloadHome\n        MainActivity.reloadAccountEvent += ::reloadAccount\n    }\n\n    override fun onCleared() {\n        MainActivity.bookmarksUpdatedEvent -= ::bookmarksUpdated\n        MainActivity.afterPluginsLoadedEvent -= ::afterPluginsLoaded\n        MainActivity.mainPluginsLoadedEvent -= ::afterMainPluginsLoaded\n        MainActivity.reloadHomeEvent -= ::reloadHome\n        MainActivity.reloadAccountEvent -= ::reloadAccount\n        super.onCleared()\n    }\n\n    fun queryTextSubmit(query: String) {\n        QuickSearchFragment.pushSearch(\n            query,\n            repo?.name?.let { arrayOf(it) })\n    }\n\n    fun queryTextChange(newText: String) {\n        // do nothing\n    }\n\n    fun loadStoredData() {\n        val list = EnumSet.noneOf(WatchType::class.java)\n        DataStoreHelper.homeBookmarkedList.map { WatchType.fromInternalId(it) }.let {\n            list.addAll(it)\n        }\n        loadStoredData(list)\n    }\n\n    fun reloadStored() {\n        loadResumeWatching()\n        loadStoredData()\n    }\n\n    fun click(load: LoadClickCallback) {\n        loadResult(load.response.url, load.response.apiName, load.response.name, load.action)\n    }\n\n    // only save the key if it is from UI, as we don't want internal functions changing the setting\n    fun loadAndCancel(\n        preferredApiName: String?,\n        forceReload: Boolean = true,\n        fromUI: Boolean = false\n    ) =\n        ioSafe {\n            //println(\"trying to load $preferredApiName\")\n            // Since plugins are loaded in stages this function can get called multiple times.\n            // The issue with this is that the homepage may be fetched multiple times while the first request is loading\n            // api?.let { expandable[it.name]?.list?.list?.isNotEmpty() } == true\n            val currentPage = page.value\n\n            // if we don't need to reload and we have a valid homepage or currently loading the same thing then return\n            val currentLoading = isCurrentlyLoadingName\n            if (!forceReload && (currentPage is Resource.Success && currentPage.value.isNotEmpty() || (currentLoading != null && currentLoading == preferredApiName))) {\n                return@ioSafe\n            }\n\n            val api = getApiFromNameNull(preferredApiName)\n            if (preferredApiName == noneApi.name) {\n                // just set to random\n                if (fromUI) DataStoreHelper.currentHomePage = noneApi.name\n                loadAndCancel(noneApi)\n            } else if (preferredApiName == randomApi.name) {\n                // randomize the api, if none exist like if not loaded or not installed\n                // then use nothing\n                val validAPIs = context?.filterProviderByPreferredMedia()\n                if (validAPIs.isNullOrEmpty()) {\n                    loadAndCancel(noneApi)\n                } else {\n                    val apiRandom = validAPIs.random()\n                    loadAndCancel(apiRandom)\n                    if (fromUI) DataStoreHelper.currentHomePage = apiRandom.name\n                }\n            } else if (api == null) {\n                // API is not found aka not loaded or removed, post the loading\n                // progress if waiting for plugins, otherwise nothing\n                if (PluginManager.loadedOnlinePlugins || PluginManager.isSafeMode()) {\n                    loadAndCancel(noneApi)\n                } else {\n                    _page.postValue(Resource.Loading())\n                    if (preferredApiName != null)\n                        _apiName.postValue(preferredApiName)\n                }\n            } else {\n                // if the api is found, then set it to it and save key\n                if (fromUI) DataStoreHelper.currentHomePage = api.name\n                loadAndCancel(api)\n            }\n            reloadAccount()\n        }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.library\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.content.Context\nimport android.content.res.Configuration\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.Looper\nimport android.view.View\nimport android.view.ViewGroup.FOCUS_AFTER_DESCENDANTS\nimport android.view.ViewGroup.FOCUS_BLOCK_DESCENDANTS\nimport android.view.animation.AlphaAnimation\nimport android.widget.TextView\nimport androidx.annotation.StringRes\nimport androidx.appcompat.widget.SearchView\nimport androidx.core.view.allViews\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.fragment.app.activityViewModels\nimport androidx.preference.PreferenceManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.tabs.TabLayout\nimport com.google.android.material.tabs.TabLayoutMediator\nimport com.lagradost.cloudstream3.APIHolder\nimport com.lagradost.cloudstream3.APIHolder.allProviders\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.databinding.FragmentLibraryBinding\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.debugAssert\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.syncproviders.SyncIdName\nimport com.lagradost.cloudstream3.ui.AutofitRecyclerView\nimport com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_LOAD\nimport com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_SHOW_METADATA\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadResult\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadSearchResult\nimport com.lagradost.cloudstream3.utils.AppContextUtils.reduceDragSensitivity\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.getSpanCount\nimport java.util.concurrent.CopyOnWriteArrayList\nimport kotlin.math.abs\n\nconst val LIBRARY_FOLDER = \"library_folder\"\n\n\nenum class LibraryOpenerType(@StringRes val stringRes: Int) {\n    Default(R.string.action_default),\n    Provider(R.string.none),\n    Browser(R.string.browser),\n    Search(R.string.search),\n    None(R.string.none),\n}\n\n/** Used to store how the user wants to open said poster */\ndata class LibraryOpener(\n    val openType: LibraryOpenerType,\n    val providerData: ProviderLibraryData?,\n)\n\ndata class ProviderLibraryData(\n    val apiName: String\n)\n\nclass LibraryFragment : BaseFragment<FragmentLibraryBinding>(\n    BaseFragment.BindingCreator.Bind(FragmentLibraryBinding::bind)\n) {\n    companion object {\n        fun newInstance() = LibraryFragment()\n\n        /**\n         * Store which page was last seen when exiting the fragment and returning\n         **/\n        const val VIEWPAGER_ITEM_KEY = \"viewpager_item\"\n    }\n\n    private val libraryViewModel: LibraryViewModel by activityViewModels()\n\n    private var toggleRandomButton = false\n\n    override fun pickLayout(): Int? =\n        if (isLayout(PHONE)) R.layout.fragment_library else R.layout.fragment_library_tv\n\n    override fun onSaveInstanceState(outState: Bundle) {\n        binding?.viewpager?.currentItem?.let { currentItem ->\n            outState.putInt(VIEWPAGER_ITEM_KEY, currentItem)\n        }\n        super.onSaveInstanceState(outState)\n    }\n\n    private fun updateRandomVisibility(binding: FragmentLibraryBinding) {\n        if (!toggleRandomButton) {\n            binding.libraryRandom.isGone = true\n            binding.libraryRandomButtonTv.isGone = true\n            return\n        }\n        val position = libraryViewModel.currentPage.value ?: 0\n        val pages = (libraryViewModel.pages.value as? Resource.Success)?.value ?: return\n        val hasItems = pages[position].items.isNotEmpty()\n        val isPhone = isLayout(PHONE)\n\n        binding.libraryRandom.isVisible = isPhone && hasItems\n        binding.libraryRandomButtonTv.isVisible = !isPhone && hasItems\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padBottom = isLandscape(),\n            padLeft = !isLayout(PHONE)\n        )\n    }\n\n    @SuppressLint(\"ResourceType\", \"CutPasteId\")\n    override fun onBindingCreated(\n        binding: FragmentLibraryBinding,\n        savedInstanceState: Bundle?\n    ) {\n        binding.sortFab.setOnClickListener(sortChangeClickListener)\n        binding.librarySort.setOnClickListener(sortChangeClickListener)\n\n        binding.libraryRoot.findViewById<TextView>(androidx.appcompat.R.id.search_src_text)\n            ?.apply {\n                tag = \"tv_no_focus_tag\"\n                // Expand the Appbar when search bar is focused, fixing scroll up issue\n                setOnFocusChangeListener { _, _ ->\n                    binding.searchBar.setExpanded(true)\n                }\n            }\n\n        val searchCallback = Runnable {\n            val newText = binding.mainSearch.query.toString()\n            libraryViewModel.sort(ListSorting.Query, newText)\n        }\n\n        binding.mainSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener {\n            override fun onQueryTextSubmit(query: String?): Boolean {\n                libraryViewModel.sort(ListSorting.Query, query)\n                return true\n            }\n\n            // This is required to prevent the first text change\n            // When this is attached it'll immediately send a onQueryTextChange(\"\")\n            // Which we do not want\n            var hasInitialized = false\n            override fun onQueryTextChange(newText: String?): Boolean {\n                if (!hasInitialized) {\n                    hasInitialized = true\n                    return true\n                }\n\n                binding.mainSearch.removeCallbacks(searchCallback)\n\n                // Delay the execution of the search operation by 1 second (adjust as needed)\n                // this prevents running search when the user is typing\n                binding.mainSearch.postDelayed(searchCallback, 1000)\n\n                return true\n            }\n        })\n\n        libraryViewModel.reloadPages(false)\n\n        binding.listSelector.setOnClickListener {\n            val items = libraryViewModel.availableApiNames\n            val currentItem = libraryViewModel.currentApiName.value\n\n            activity?.showBottomDialog(\n                items,\n                items.indexOf(currentItem),\n                txt(R.string.select_library).asString(it.context),\n                false,\n                {}) { index ->\n                val selectedItem = items.getOrNull(index) ?: return@showBottomDialog\n                libraryViewModel.switchList(selectedItem)\n            }\n        }\n\n        //Load value for toggling Random button. Hide at startup\n        context?.let {\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)\n            toggleRandomButton =\n                settingsManager.getBoolean(\n                    getString(R.string.random_button_key),\n                    false\n                )\n            binding.libraryRandom.visibility = View.GONE\n            binding.libraryRandomButtonTv.visibility = View.GONE\n        }\n\n        /**\n         * Shows a plugin selection dialogue and saves the response\n         **/\n        fun Activity.showPluginSelectionDialog(\n            key: String,\n            syncId: SyncIdName,\n            apiName: String? = null,\n        ) {\n            val availableProviders = synchronized(allProviders) {\n                allProviders.filter {\n                    it.supportedSyncNames.contains(syncId)\n                }.map { it.name } +\n                        // Add the api if it exists\n                        (APIHolder.getApiFromNameNull(apiName)?.let { listOf(it.name) }\n                            ?: emptyList())\n            }\n            val baseOptions = listOf(\n                LibraryOpenerType.Default,\n                LibraryOpenerType.None,\n                LibraryOpenerType.Browser,\n                LibraryOpenerType.Search\n            )\n\n            val items = baseOptions.map { txt(it.stringRes).asString(this) } + availableProviders\n\n            val savedSelection = getKey<LibraryOpener>(\"$currentAccount/$LIBRARY_FOLDER\", key)\n            val selectedIndex =\n                when {\n                    savedSelection == null -> 0\n                    // If provider\n                    savedSelection.openType == LibraryOpenerType.Provider\n                            && savedSelection.providerData?.apiName != null -> {\n                        availableProviders.indexOf(savedSelection.providerData.apiName)\n                            .takeIf { it != -1 }\n                            ?.plus(baseOptions.size) ?: 0\n                    }\n                    // Else base option\n                    else -> baseOptions.indexOf(savedSelection.openType)\n                }\n\n            this.showBottomDialog(\n                items,\n                selectedIndex,\n                txt(R.string.open_with).asString(this),\n                false,\n                {},\n            ) {\n                val savedData = if (it < baseOptions.size) {\n                    LibraryOpener(\n                        baseOptions[it],\n                        null\n                    )\n                } else {\n                    LibraryOpener(\n                        LibraryOpenerType.Provider,\n                        ProviderLibraryData(items[it])\n                    )\n                }\n\n                setKey(\n                    \"$currentAccount/$LIBRARY_FOLDER\",\n                    key,\n                    savedData,\n                )\n            }\n        }\n\n        binding.providerSelector.setOnClickListener {\n            val syncName = libraryViewModel.currentSyncApi?.syncIdName ?: return@setOnClickListener\n            activity?.showPluginSelectionDialog(syncName.name, syncName)\n        }\n\n        binding.viewpager.setPageTransformer(LibraryScrollTransformer())\n\n        binding.viewpager.adapter = ViewpagerAdapter(\n            { isScrollingDown: Boolean ->\n                if (isScrollingDown) {\n                    binding.sortFab.shrink()\n                    binding.libraryRandom.shrink()\n                } else {\n                    binding.sortFab.extend()\n                    binding.libraryRandom.extend()\n                }\n            }) callback@{ searchClickCallback ->\n            // To prevent future accidents\n            debugAssert({\n                searchClickCallback.card !is SyncAPI.LibraryItem\n            }, {\n                \"searchClickCallback ${searchClickCallback.card} is not a LibraryItem\"\n            })\n\n            val syncId = (searchClickCallback.card as SyncAPI.LibraryItem).syncId\n            val syncName =\n                libraryViewModel.currentSyncApi?.syncIdName ?: return@callback\n\n            when (searchClickCallback.action) {\n                SEARCH_ACTION_SHOW_METADATA -> {\n                    (activity as? MainActivity)?.loadPopup(\n                        searchClickCallback.card,\n                        load = false\n                    )\n                    /*activity?.showPluginSelectionDialog(\n                            syncId,\n                            syncName,\n                            searchClickCallback.card.apiName\n                        )*/\n                }\n\n                SEARCH_ACTION_LOAD -> {\n                    loadLibraryItem(syncName, syncId, searchClickCallback.card)\n                }\n            }\n        }\n\n        binding.apply {\n            viewpager.offscreenPageLimit = 2\n            viewpager.reduceDragSensitivity()\n            searchBar.setExpanded(true)\n        }\n\n        val startLoading = Runnable {\n            binding.apply {\n                gridview.numColumns = root.context.getSpanCount()\n                gridview.adapter =\n                    context?.let { LoadingPosterAdapter(it, 6 * 3) }\n                libraryLoadingOverlay.isVisible = true\n                libraryLoadingShimmer.startShimmer()\n                emptyListTextview.isVisible = false\n            }\n        }\n\n        val stopLoading = Runnable {\n            binding.apply {\n                gridview.adapter = null\n                libraryLoadingOverlay.isVisible = false\n                libraryLoadingShimmer.stopShimmer()\n            }\n        }\n\n        val handler = Handler(Looper.getMainLooper())\n\n        observe(libraryViewModel.pages) { resource ->\n            when (resource) {\n                is Resource.Success -> {\n                    handler.removeCallbacks(startLoading)\n                    val pages = resource.value\n                    val showNotice = pages.all { it.items.isEmpty() }\n\n                    binding.apply {\n                        emptyListTextview.isVisible = showNotice\n                        if (showNotice) {\n                            if (libraryViewModel.availableApiNames.size > 1) {\n                                emptyListTextview.setText(R.string.empty_library_logged_in_message)\n                            } else {\n                                emptyListTextview.setText(R.string.empty_library_no_accounts_message)\n                            }\n                        }\n\n                        (viewpager.adapter as? ViewpagerAdapter)?.submitList(pages.map {\n                            it.copy(\n                                items = CopyOnWriteArrayList(it.items)\n                            )\n                        })\n                        //fix focus on the viewpager itself\n                        (viewpager.getChildAt(0) as RecyclerView).apply {\n                            tag = \"tv_no_focus_tag\"\n                            //isFocusable = false\n                        }\n\n                        // Using notifyItemRangeChanged keeps the animations when sorting\n                        /*viewpager.adapter?.notifyItemRangeChanged(\n                            0,\n                            viewpager.adapter?.itemCount ?: 0\n                        )*/\n\n                        libraryViewModel.currentPage.value?.let { page ->\n                            binding.viewpager.setCurrentItem(page, false)\n                            binding.searchBar.setExpanded(true)\n                        }\n\n                        // Set up random button click listener\n                        if (toggleRandomButton) {\n                            val randomClickListener = View.OnClickListener {\n                                val position = libraryViewModel.currentPage.value ?: 0\n                                val syncIdName = libraryViewModel.currentSyncApi?.syncIdName ?: return@OnClickListener\n                                pages[position].items.randomOrNull()?.let { item ->\n                                    loadLibraryItem(syncIdName, item.syncId, item)\n                                }\n                            }\n                            libraryRandom.setOnClickListener(randomClickListener)\n                            libraryRandomButtonTv.setOnClickListener(randomClickListener)\n                        }\n                        updateRandomVisibility(binding)\n\n                        // Only stop loading after 300ms to hide the fade effect the viewpager produces when updating\n                        // Without this there would be a flashing effect:\n                        // loading -> show old viewpager -> black screen -> show new viewpager\n                        handler.postDelayed(stopLoading, 300)\n\n                        savedInstanceState?.getInt(VIEWPAGER_ITEM_KEY)?.let { currentPos ->\n                            if (currentPos < 0) return@let\n                            viewpager.setCurrentItem(currentPos, false)\n                            // Using remove() sets the key to 0 instead of removing it\n                            savedInstanceState.putInt(VIEWPAGER_ITEM_KEY, -1)\n                        }\n\n                        // Since the animation to scroll multiple items is so much its better to just hide\n                        // the viewpager a bit while the fastest animation is running\n                        fun hideViewpager(distance: Int) {\n                            if (distance < 3) return\n\n                            val hideAnimation = AlphaAnimation(1f, 0f).apply {\n                                duration = distance * 50L\n                                fillAfter = true\n                            }\n                            val showAnimation = AlphaAnimation(0f, 1f).apply {\n                                duration = distance * 50L\n                                startOffset = distance * 100L\n                                fillAfter = true\n                            }\n                            viewpager.startAnimation(hideAnimation)\n                            viewpager.startAnimation(showAnimation)\n                        }\n\n                        TabLayoutMediator(\n                            libraryTabLayout,\n                            viewpager,\n                        ) { tab, position ->\n                            tab.text = pages.getOrNull(position)?.title?.asStringNull(context)\n                            tab.view.tag = \"tv_no_focus_tag\"\n                            tab.view.nextFocusDownId = R.id.search_result_root\n\n                            tab.view.setOnClickListener {\n                                val currentItem = binding.viewpager.currentItem\n                                val distance = abs(position - currentItem)\n                                hideViewpager(distance)\n                            }\n                            //Expand the appBar on tab focus\n                            tab.view.setOnFocusChangeListener { _, _ ->\n                                binding.searchBar.setExpanded(true)\n                            }\n                        }.attach()\n\n                        binding.libraryTabLayout.addOnTabSelectedListener(object :\n                            TabLayout.OnTabSelectedListener {\n                            override fun onTabSelected(tab: TabLayout.Tab?) {\n                                binding.libraryTabLayout.selectedTabPosition.let { page ->\n                                    libraryViewModel.switchPage(page)\n                                }\n                            }\n\n                            override fun onTabUnselected(tab: TabLayout.Tab?) = Unit\n                            override fun onTabReselected(tab: TabLayout.Tab?) = Unit\n                        })\n                    }\n                }\n\n                is Resource.Loading -> {\n                    // Only start loading after 200ms to prevent loading cached lists\n                    handler.postDelayed(startLoading, 200)\n                }\n\n                is Resource.Failure -> {\n                    stopLoading.run()\n                    // No user indication it failed :(\n                    // TODO\n                }\n            }\n        }\n\n        observe(libraryViewModel.currentPage) { position ->\n            updateRandomVisibility(binding)\n            val all = binding.viewpager.allViews.toList()\n                .filterIsInstance<AutofitRecyclerView>()\n\n            all.forEach { view ->\n                view.isVisible = view.tag == position\n                view.isFocusable = view.tag == position\n\n                if (view.tag == position)\n                    view.descendantFocusability = FOCUS_AFTER_DESCENDANTS\n                else\n                    view.descendantFocusability = FOCUS_BLOCK_DESCENDANTS\n            }\n        }\n    }\n\n    private fun loadLibraryItem(\n        syncName: SyncIdName,\n        syncId: String,\n        card: SearchResponse\n    ) {\n        // This basically first selects the individual opener and if that is default then\n        // selects the whole list opener\n        val savedListSelection =\n            getKey<LibraryOpener>(\"$currentAccount/$LIBRARY_FOLDER\", syncName.name)\n\n        val savedSelection = getKey<LibraryOpener>(\n            \"$currentAccount/$LIBRARY_FOLDER\",\n            syncId\n        ).takeIf {\n            it?.openType != LibraryOpenerType.Default\n        } ?: savedListSelection\n\n        when (savedSelection?.openType) {\n            null, LibraryOpenerType.Default -> {\n                // Prevents opening MAL/AniList as a provider\n                if (APIHolder.getApiFromNameNull(card.apiName) != null) {\n                    activity?.loadSearchResult(\n                        card\n                    )\n                } else {\n                    // Search when no provider can open\n                    QuickSearchFragment.pushSearch(\n                        activity,\n                        card.name\n                    )\n                }\n            }\n\n            LibraryOpenerType.None -> {}\n            LibraryOpenerType.Provider ->\n                savedSelection.providerData?.apiName?.let { apiName ->\n                    activity?.loadResult(\n                        card.url,\n                        apiName,\n                        card.name\n                    )\n                }\n\n            LibraryOpenerType.Browser ->\n                openBrowser(card.url)\n\n            LibraryOpenerType.Search -> {\n                QuickSearchFragment.pushSearch(\n                    activity,\n                    card.name\n                )\n            }\n        }\n\n    }\n\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n        val adapter = binding?.viewpager?.adapter ?: return\n        adapter.notifyItemRangeChanged(0, adapter.itemCount)\n    }\n\n    private val sortChangeClickListener = View.OnClickListener { view ->\n        val methods = libraryViewModel.sortingMethods.map {\n            txt(it.stringRes).asString(view.context)\n        }\n\n        activity?.showBottomDialog(\n            methods,\n            libraryViewModel.sortingMethods.indexOf(libraryViewModel.currentSortingMethod),\n            txt(R.string.sort_by).asString(view.context),\n            false,\n            {},\n            {\n                val method = libraryViewModel.sortingMethods[it]\n                libraryViewModel.sort(method)\n            })\n    }\n}\n\nclass MenuSearchView(context: Context) : SearchView(context)"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryScrollTransformer.kt",
    "content": "package com.lagradost.cloudstream3.ui.library\n\nimport android.view.View\nimport androidx.viewpager2.widget.ViewPager2\nimport com.lagradost.cloudstream3.R\nimport kotlin.math.roundToInt\n\nclass LibraryScrollTransformer : ViewPager2.PageTransformer {\n    override fun transformPage(page: View, position: Float) {\n        val padding = (-position * page.width).roundToInt()\n        page.findViewById<View>(R.id.page_recyclerview).setPadding(\n            padding, 0,\n            -padding, 0\n        )\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.library\n\nimport androidx.annotation.StringRes\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.throwAbleToResource\nimport com.lagradost.cloudstream3.syncproviders.AccountManager\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount\n\nenum class ListSorting(@StringRes val stringRes: Int) {\n    Query(R.string.none),\n    RatingHigh(R.string.sort_rating_desc),\n    RatingLow(R.string.sort_rating_asc),\n    UpdatedNew(R.string.sort_updated_new),\n    UpdatedOld(R.string.sort_updated_old),\n    AlphabeticalA(R.string.sort_alphabetical_a),\n    AlphabeticalZ(R.string.sort_alphabetical_z),\n    ReleaseDateNew(R.string.sort_release_date_new),\n    ReleaseDateOld(R.string.sort_release_date_old),\n}\n\nconst val LAST_SYNC_API_KEY = \"last_sync_api\"\n\nclass LibraryViewModel : ViewModel() {\n    fun switchPage(page: Int) {\n        _currentPage.postValue(page)\n    }\n\n    private val _currentPage: MutableLiveData<Int> = MutableLiveData(0)\n    val currentPage: LiveData<Int> = _currentPage\n\n    private val _pages: MutableLiveData<Resource<List<SyncAPI.Page>>> = MutableLiveData(null)\n    val pages: LiveData<Resource<List<SyncAPI.Page>>> = _pages\n\n    private val _currentApiName: MutableLiveData<String> = MutableLiveData(\"\")\n    val currentApiName: LiveData<String> = _currentApiName\n\n    private val availableSyncApis\n        get() = AccountManager.syncApis.filter { it.isAvailable }\n\n    var currentSyncApi = availableSyncApis.let { allApis ->\n        val lastSelection = getKey<String>(\"$currentAccount/$LAST_SYNC_API_KEY\")\n        availableSyncApis.firstOrNull { it.name == lastSelection } ?: allApis.firstOrNull()\n    }\n        private set(value) {\n            field = value\n            setKey(\"$currentAccount/$LAST_SYNC_API_KEY\", field?.name)\n        }\n\n    val availableApiNames: List<String>\n        get() = availableSyncApis.map { it.name }\n\n    var sortingMethods = emptyList<ListSorting>()\n        private set\n\n    var currentSortingMethod: ListSorting? = sortingMethods.firstOrNull()\n        private set\n\n    fun switchList(name: String) {\n        currentSyncApi = availableSyncApis[availableApiNames.indexOf(name)]\n        _currentApiName.postValue(currentSyncApi?.name)\n        reloadPages(true)\n    }\n\n    fun sort(method: ListSorting, query: String? = null) = ioSafe {\n        val value = _pages.value ?: return@ioSafe\n        if (value is Resource.Success) {\n            sort(method, query, value.value)\n        }\n    }\n\n    private fun sort(method: ListSorting, query: String? = null, items: List<SyncAPI.Page>) {\n        currentSortingMethod = method\n        DataStoreHelper.librarySortingMode = method.ordinal\n\n        items.forEach { page ->\n            page.sort(method, query)\n        }\n        _pages.postValue(Resource.Success(items))\n    }\n\n    fun reloadPages(forceReload: Boolean) {\n        // Only skip loading if its not forced and pages is not empty\n        if (!forceReload && (pages.value as? Resource.Success)?.value?.isNotEmpty() == true &&\n            currentSyncApi?.requireLibraryRefresh != true\n        ) return\n\n        ioSafe {\n            currentSyncApi?.let { repo ->\n                _currentApiName.postValue(repo.name)\n                _pages.postValue(Resource.Loading())\n                val libraryResource = repo.library()\n                val err = libraryResource.exceptionOrNull()\n                if (err != null) {\n                    _pages.postValue(throwAbleToResource(err))\n                    return@let\n                }\n                val library = libraryResource.getOrNull()\n                if (library == null) {\n                    _pages.postValue(Resource.Failure(false, \"Unable to fetch library\"))\n                    return@let\n                }\n\n                sortingMethods = library.supportedListSorting.toList()\n                repo.requireLibraryRefresh = false\n\n                val pages = library.allLibraryLists.map {\n                    SyncAPI.Page(\n                        it.name,\n                        it.items\n                    )\n                }\n\n                val desiredSortingMethod =\n                    ListSorting.entries.getOrNull(DataStoreHelper.librarySortingMode)\n                if (desiredSortingMethod != null && library.supportedListSorting.contains(\n                        desiredSortingMethod\n                    )\n                ) {\n                    sort(desiredSortingMethod, null, pages)\n                } else {\n                    // null query = no sorting\n                    sort(ListSorting.Query, null, pages)\n                }\n            }\n        }\n    }\n\n    init {\n        MainActivity.reloadLibraryEvent += ::reloadPages\n    }\n\n    override fun onCleared() {\n        MainActivity.reloadLibraryEvent -= ::reloadPages\n        super.onCleared()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/library/LoadingPosterAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.library\n\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.BaseAdapter\nimport com.lagradost.cloudstream3.R\n\nclass LoadingPosterAdapter(context: Context, private val itemCount: Int) :\n    BaseAdapter() {\n    private val inflater: LayoutInflater = LayoutInflater.from(context)\n\n    override fun getCount(): Int {\n        return itemCount\n    }\n\n    override fun getItem(position: Int): Any? {\n        return null\n    }\n\n    override fun getItemId(position: Int): Long {\n        return position.toLong()\n    }\n\n    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {\n        return convertView ?: inflater.inflate(R.layout.loading_poster_dynamic, parent, false)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/library/PageAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.library\n\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport android.widget.FrameLayout\nimport androidx.core.view.isVisible\nimport com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.ui.AutofitRecyclerView\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.search.SearchClickCallback\nimport com.lagradost.cloudstream3.ui.search.SearchResultBuilder\nimport kotlin.math.roundToInt\n\nclass PageAdapter(\n    private val resView: AutofitRecyclerView,\n    val clickCallback: (SearchClickCallback) -> Unit\n) :\n    NoStateAdapter<SyncAPI.LibraryItem>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n        if (a.id != null || b.id != null) {\n            a.id == b.id\n        } else {\n            a.name == b.name && a.url == b.url\n        }\n    })) {\n    private val coverHeight: Int get() = (resView.itemWidth / 0.68).roundToInt()\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            SearchResultGridExpandedBinding.inflate(\n                LayoutInflater.from(parent.context),\n                parent,\n                false\n            )\n        )\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        when (val binding = holder.view) {\n            is SearchResultGridExpandedBinding -> {\n                clearImage(binding.imageView)\n            }\n        }\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Any>,\n        item: SyncAPI.LibraryItem,\n        position: Int\n    ) {\n        val binding = holder.view as? SearchResultGridExpandedBinding ?: return\n\n        /** https://stackoverflow.com/questions/8817522/how-to-get-color-code-of-image-view */\n        SearchResultBuilder.bind(\n            this@PageAdapter.clickCallback,\n            item,\n            position,\n            holder.itemView,\n        )\n\n        // See searchAdaptor for this, it basically fixes the height\n        val params = FrameLayout.LayoutParams(\n            ViewGroup.LayoutParams.MATCH_PARENT,\n            coverHeight\n        )\n        if (params.height != binding.imageView.layoutParams.height || params.width != binding.imageView.layoutParams.width) {\n            binding.imageView.layoutParams = params\n        }\n\n        val showProgress = item.episodesCompleted?.let{ it>0 } ?: false && item.episodesTotal != null\n        binding.watchProgress.isVisible = showProgress\n        if (showProgress) {\n            binding.watchProgress.max = item.episodesTotal\n            binding.watchProgress.progress = item.episodesCompleted\n        }\n\n        binding.imageText.text = item.name\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/library/ViewpagerAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.library\n\nimport android.os.Build\nimport android.os.Bundle\nimport android.os.Parcelable\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.core.view.doOnAttach\nimport androidx.fragment.app.Fragment\nimport androidx.recyclerview.widget.RecyclerView.OnFlingListener\nimport com.google.android.material.appbar.AppBarLayout\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.LibraryViewpagerPageBinding\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.ui.BaseAdapter\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.home.getSafeParcelable\nimport com.lagradost.cloudstream3.ui.search.SearchClickCallback\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.UIHelper.getSpanCount\n\nclass ViewpagerAdapterViewHolderState(val binding: LibraryViewpagerPageBinding) :\n    ViewHolderState<Bundle>(binding) {\n    override fun save(): Bundle =\n        Bundle().apply {\n            putParcelable(\n                \"pageRecyclerview\",\n                binding.pageRecyclerview.layoutManager?.onSaveInstanceState()\n            )\n        }\n\n    override fun restore(state: Bundle) {\n        state.getSafeParcelable<Parcelable>(\"pageRecyclerview\")?.let { recycle ->\n            binding.pageRecyclerview.layoutManager?.onRestoreInstanceState(recycle)\n        }\n    }\n}\n\nclass ViewpagerAdapter(\n    val scrollCallback: (isScrollingDown: Boolean) -> Unit,\n    val clickCallback: (SearchClickCallback) -> Unit\n) : BaseAdapter<SyncAPI.Page, Bundle>(\n    id = \"ViewpagerAdapter\".hashCode(),\n    diffCallback = BaseDiffCallback(\n        itemSame = { a, b ->\n            a.title == b.title\n        },\n        contentSame = { a, b ->\n            a.items == b.items && a.title == b.title\n        }\n    )) {\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Bundle> {\n        return ViewpagerAdapterViewHolderState(\n            LibraryViewpagerPageBinding.inflate(LayoutInflater.from(parent.context), parent, false)\n        )\n    }\n\n    override fun onUpdateContent(\n        holder: ViewHolderState<Bundle>,\n        item: SyncAPI.Page,\n        position: Int\n    ) {\n        val binding = holder.view\n        if (binding !is LibraryViewpagerPageBinding) return\n        (binding.pageRecyclerview.adapter as? PageAdapter)?.submitList(item.items)\n        binding.pageRecyclerview.scrollToPosition(0)\n    }\n\n    override fun onBindContent(holder: ViewHolderState<Bundle>, item: SyncAPI.Page, position: Int) {\n        val binding = holder.view\n        if (binding !is LibraryViewpagerPageBinding) return\n\n        binding.pageRecyclerview.tag = position\n        binding.pageRecyclerview.apply {\n            spanCount = binding.root.context.getSpanCount()\n            if (adapter == null) { //  || rebind\n                // Only add the items after it has been attached since the items rely on ItemWidth\n                // Which is only determined after the recyclerview is attached.\n                // If this fails then item height becomes 0 when there is only one item\n                doOnAttach {\n                    adapter = PageAdapter(\n                        this,\n                        clickCallback\n                    ).apply {\n                        submitList(item.items)\n                    }\n                }\n            } else {\n                (adapter as? PageAdapter)?.submitList(item.items)\n                // scrollToPosition(0)\n            }\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->\n                    val diff = scrollY - oldScrollY\n\n                    //Expand the top Appbar based on scroll direction up/down, simulate phone behavior\n                    if (isLayout(TV or EMULATOR)) {\n                        binding.root.rootView.findViewById<AppBarLayout>(R.id.search_bar)\n                            ?.apply {\n                                if (diff <= 0)\n                                    setExpanded(true)\n                                else\n                                    setExpanded(false)\n                            }\n                    }\n                    if (diff == 0) return@setOnScrollChangeListener\n\n                    scrollCallback.invoke(diff > 0)\n                }\n            } else {\n                onFlingListener = object : OnFlingListener() {\n                    override fun onFling(velocityX: Int, velocityY: Int): Boolean {\n                        scrollCallback.invoke(velocityY > 0)\n                        return false\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.annotation.SuppressLint\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.graphics.drawable.AnimatedImageDrawable\nimport android.graphics.drawable.AnimatedVectorDrawable\nimport android.media.metrics.PlaybackErrorEvent\nimport android.os.Build\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.WindowManager\nimport android.widget.FrameLayout\nimport android.widget.ImageView\nimport android.widget.ProgressBar\nimport android.widget.Toast\nimport androidx.annotation.LayoutRes\nimport androidx.annotation.OptIn\nimport androidx.annotation.StringRes\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.fragment.app.Fragment\nimport androidx.media3.common.PlaybackException\nimport androidx.media3.common.util.UnstableApi\nimport androidx.media3.exoplayer.ExoPlayer\nimport androidx.media3.session.MediaSession\nimport androidx.media3.ui.AspectRatioFrameLayout\nimport androidx.media3.ui.DefaultTimeBar\nimport androidx.media3.ui.PlayerView\nimport androidx.media3.ui.SubtitleView\nimport androidx.media3.ui.TimeBar\nimport androidx.preference.PreferenceManager\nimport androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat\nimport com.github.rubensousa.previewseekbar.PreviewBar\nimport com.github.rubensousa.previewseekbar.media3.PreviewTimeBar\nimport com.lagradost.cloudstream3.CommonActivity.isInPIPMode\nimport com.lagradost.cloudstream3.CommonActivity.keyEventListener\nimport com.lagradost.cloudstream3.CommonActivity.playerEventListener\nimport com.lagradost.cloudstream3.CommonActivity.screenWidth\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle\nimport com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment\nimport com.lagradost.cloudstream3.utils.AppContextUtils\nimport com.lagradost.cloudstream3.utils.AppContextUtils.requestLocalAudioFocus\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.EpisodeSkip\nimport com.lagradost.cloudstream3.utils.UIHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI\nimport com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage\nimport java.net.SocketTimeoutException\n\nenum class PlayerResize(@StringRes val nameRes: Int) {\n    Fit(R.string.resize_fit),\n    Fill(R.string.resize_fill),\n    Zoom(R.string.resize_zoom),\n}\n\n// when the player should switch skip op to next episode\nconst val SKIP_OP_VIDEO_PERCENTAGE = 50\n\n// when the player should preload the next episode for faster loading\nconst val PRELOAD_NEXT_EPISODE_PERCENTAGE = 80\n\n// when the player should mark the episode as watched and resume watching the next\nconst val NEXT_WATCH_EPISODE_PERCENTAGE = 90\n\n// when the player should sync the progress of \"watched\", TODO MAKE SETTING\nconst val UPDATE_SYNC_PROGRESS_PERCENTAGE = 80\n\n@OptIn(UnstableApi::class)\nabstract class AbstractPlayerFragment(\n    var player: IPlayer = CS3IPlayer()\n) : Fragment() {\n    var resizeMode: Int = 0\n    var subView: SubtitleView? = null\n    protected open var hasPipModeSupport = true\n\n    var playerPausePlayHolderHolder: FrameLayout? = null\n    var playerPausePlay: ImageView? = null\n    var playerBuffering: ProgressBar? = null\n    var playerView: PlayerView? = null\n    var piphide: FrameLayout? = null\n    var subtitleHolder: FrameLayout? = null\n    var currentPlayerStatus = CSPlayerLoading.IsBuffering\n\n    @LayoutRes\n    protected open var layout: Int = R.layout.fragment_player\n\n    open fun nextEpisode() {\n        throw NotImplementedError()\n    }\n\n    open fun prevEpisode() {\n        throw NotImplementedError()\n    }\n\n    open fun playerPositionChanged(position: Long, duration: Long) {\n        throw NotImplementedError()\n    }\n\n    open fun playerStatusChanged() {}\n\n    open fun playerDimensionsLoaded(width: Int, height: Int) {\n        throw NotImplementedError()\n    }\n\n    open fun subtitlesChanged() {\n        throw NotImplementedError()\n    }\n\n    open fun embeddedSubtitlesFetched(subtitles: List<SubtitleData>) {\n        throw NotImplementedError()\n    }\n\n    open fun onTracksInfoChanged() {\n        throw NotImplementedError()\n    }\n\n    open fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) {\n\n    }\n\n    open fun onTimestampSkipped(timestamp: EpisodeSkip.SkipStamp) {\n\n    }\n\n    open fun exitedPipMode() {\n        throw NotImplementedError()\n    }\n\n    private fun keepScreenOn(on: Boolean) {\n        if (on) {\n            activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)\n        } else {\n            activity?.window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)\n        }\n    }\n\n    private fun updateIsPlaying(\n        wasPlaying: CSPlayerLoading,\n        isPlaying: CSPlayerLoading\n    ) {\n        val isPlayingRightNow = CSPlayerLoading.IsPlaying == isPlaying\n        val isPausedRightNow = CSPlayerLoading.IsPaused == isPlaying\n        currentPlayerStatus = isPlaying\n\n        keepScreenOn(!isPausedRightNow)\n\n        val isBuffering = CSPlayerLoading.IsBuffering == isPlaying\n        if (isBuffering) {\n            playerPausePlayHolderHolder?.isVisible = false\n            playerBuffering?.isVisible = true\n        } else {\n            playerPausePlayHolderHolder?.isVisible = true\n            playerBuffering?.isVisible = false\n\n            if(isPlaying == CSPlayerLoading.IsEnded && isLayout(PHONE)){\n                playerPausePlay?.setImageResource(R.drawable.ic_baseline_replay_24)\n            } else if (wasPlaying != isPlaying) {\n                playerPausePlay?.setImageResource(if (isPlayingRightNow) R.drawable.play_to_pause else R.drawable.pause_to_play)\n                val drawable = playerPausePlay?.drawable\n\n                var startedAnimation = false\n                if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {\n                    if (drawable is AnimatedImageDrawable) {\n                        drawable.start()\n                        startedAnimation = true\n                    }\n                }\n\n                if (drawable is AnimatedVectorDrawable) {\n                    drawable.start()\n                    startedAnimation = true\n                }\n\n                if (drawable is AnimatedVectorDrawableCompat) {\n                    drawable.start()\n                    startedAnimation = true\n                }\n\n                // somehow the phone is wacked\n                if (!startedAnimation) {\n                    playerPausePlay?.setImageResource(if (isPlayingRightNow) R.drawable.netflix_pause else R.drawable.netflix_play)\n                }\n            } else {\n                playerPausePlay?.setImageResource(if (isPlayingRightNow) R.drawable.netflix_pause else R.drawable.netflix_play)\n            }\n        }\n\n        PlayerPipHelper.updatePIPModeActions(\n            activity,\n            isPlaying,\n            hasPipModeSupport,\n            player.getAspectRatio()\n        )\n    }\n\n    private var pipReceiver: BroadcastReceiver? = null\n    override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {\n        super.onPictureInPictureModeChanged(isInPictureInPictureMode)\n        try {\n            isInPIPMode = isInPictureInPictureMode\n            if (isInPictureInPictureMode) {\n                // Hide the full-screen UI (controls, etc.) while in picture-in-picture mode.\n                piphide?.isVisible = false\n                pipReceiver = object : BroadcastReceiver() {\n                    override fun onReceive(\n                        context: Context,\n                        intent: Intent,\n                    ) {\n                        if (ACTION_MEDIA_CONTROL != intent.action) {\n                            return\n                        }\n                        player.handleEvent(\n                            CSPlayerEvent.entries[intent.getIntExtra(\n                                EXTRA_CONTROL_TYPE,\n                                0\n                            )], source = PlayerEventSource.UI\n                        )\n                    }\n                }\n\n                val filter = IntentFilter()\n                filter.addAction(ACTION_MEDIA_CONTROL)\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n                    activity?.registerReceiver(pipReceiver, filter, Context.RECEIVER_EXPORTED)\n                } else {\n                    @SuppressLint(\"UnspecifiedRegisterReceiverFlag\")\n                    activity?.registerReceiver(pipReceiver, filter)\n                }\n\n                val isPlaying = player.getIsPlaying()\n                val isPlayingValue =\n                    if (isPlaying) CSPlayerLoading.IsPlaying else CSPlayerLoading.IsPaused\n                updateIsPlaying(isPlayingValue, isPlayingValue)\n            } else {\n                // Restore the full-screen UI.\n                piphide?.isVisible = true\n                exitedPipMode()\n                pipReceiver?.let {\n                    // Prevents java.lang.IllegalArgumentException: Receiver not registered\n                    safe {\n                        activity?.unregisterReceiver(it)\n                    }\n                }\n                activity?.hideSystemUI()\n                this.view?.let { UIHelper.hideKeyboard(it) }\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    open fun hasNextMirror(): Boolean {\n        throw NotImplementedError()\n    }\n\n    open fun nextMirror() {\n        throw NotImplementedError()\n    }\n\n    private fun requestAudioFocus() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            activity?.requestLocalAudioFocus(AppContextUtils.getFocusRequest())\n        }\n    }\n\n    open fun playerError(exception: Throwable) {\n        fun showToast(message: String, gotoNext: Boolean = false) {\n            if (gotoNext && hasNextMirror()) {\n                showToast(\n                    message,\n                    Toast.LENGTH_SHORT\n                )\n                nextMirror()\n            } else {\n                showToast(\n                    context?.getString(R.string.no_links_found_toast) + \"\\n\" + message,\n                    Toast.LENGTH_LONG\n                )\n                activity?.popCurrentPage()\n            }\n        }\n\n        val ctx = context ?: return\n        when (exception) {\n            is PlaybackException -> {\n                val msg = exception.message ?: \"\"\n                val errorName = exception.errorCodeName\n                when (val code = exception.errorCode) {\n                    PlaybackException.ERROR_CODE_IO_FILE_NOT_FOUND,\n                    PlaybackException.ERROR_CODE_IO_NO_PERMISSION,\n                    PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE,\n                    PlaybackException.ERROR_CODE_IO_UNSPECIFIED,\n                    PlaybackException.ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED -> {\n                        showToast(\n                            \"${ctx.getString(R.string.source_error)}\\n$errorName ($code)\\n$msg\",\n                            gotoNext = true\n                        )\n                    }\n\n                    PlaybackException.ERROR_CODE_REMOTE_ERROR,\n                    PlaybackException.ERROR_CODE_IO_BAD_HTTP_STATUS,\n                    PlaybackException.ERROR_CODE_TIMEOUT,\n                    PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED,\n                    PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_TIMEOUT,\n                    PlaybackException.ERROR_CODE_IO_INVALID_HTTP_CONTENT_TYPE -> {\n                        showToast(\n                            \"${ctx.getString(R.string.remote_error)}\\n$errorName ($code)\\n$msg\",\n                            gotoNext = true\n                        )\n                    }\n\n                    PlaybackErrorEvent.ERROR_AUDIO_TRACK_INIT_FAILED,\n                    PlaybackErrorEvent.ERROR_AUDIO_TRACK_OTHER,\n                    PlaybackException.ERROR_CODE_DECODING_FAILED,\n                    PlaybackException.ERROR_CODE_AUDIO_TRACK_WRITE_FAILED,\n                    PlaybackException.ERROR_CODE_DECODER_INIT_FAILED,\n                    PlaybackException.ERROR_CODE_DECODER_QUERY_FAILED -> {\n                        showToast(\n                            \"${ctx.getString(R.string.render_error)}\\n$errorName ($code)\\n$msg\",\n                            gotoNext = true\n                        )\n                    }\n\n                    PlaybackException.ERROR_CODE_DECODING_FORMAT_UNSUPPORTED,\n                    PlaybackException.ERROR_CODE_DECODING_FORMAT_EXCEEDS_CAPABILITIES -> {\n                        showToast(\n                            \"${ctx.getString(R.string.unsupported_error)}\\n$errorName ($code)\\n$msg\",\n                            gotoNext = true\n                        )\n                    }\n\n                    PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED,\n                    PlaybackException.ERROR_CODE_PARSING_MANIFEST_MALFORMED -> {\n                        showToast(\n                            \"${ctx.getString(R.string.encoding_error)}\\n$errorName ($code)\\n$msg\",\n                            gotoNext = true\n                        )\n                    }\n\n                    else -> {\n                        showToast(\n                            \"${ctx.getString(R.string.unexpected_error)}\\n$errorName ($code)\\n$msg\",\n                            gotoNext = false\n                        )\n                    }\n                }\n            }\n\n            is InvalidFileException -> {\n                showToast(\n                    \"${ctx.getString(R.string.source_error)}\\n${exception.message}\",\n                    gotoNext = true\n                )\n            }\n\n            is SocketTimeoutException -> {\n                /**\n                 * Ensures this is run on the UI thread to prevent issues\n                 * caused by SocketTimeoutException in torrents. Running\n                 * on another thread can break player interactions or\n                 * prevent switching to the next source.\n                 */\n                activity?.runOnUiThread {\n                    showToast(\n                        \"${ctx.getString(R.string.remote_error)}\\n${exception.message}\",\n                        gotoNext = true\n                    )\n                }\n            }\n\n            is ErrorLoadingException -> {\n                exception.message?.let {\n                    showToast(\n                        it,\n                        gotoNext = true\n                    )\n                } ?: showToast(\n                    exception.toString(),\n                    gotoNext = true\n                )\n            }\n\n            else -> {\n                exception.message?.let {\n                    showToast(\n                        it,\n                        gotoNext = false\n                    )\n                } ?: showToast(\n                    exception.toString(),\n                    gotoNext = false\n                )\n            }\n        }\n    }\n\n    private fun onSubStyleChanged(style: SaveCaptionStyle) {\n        player.updateSubtitleStyle(style)\n        // Forcefully update the subtitle encoding in case the edge size is changed\n        player.seekTime(-1)\n    }\n\n\n    @SuppressLint(\"UnsafeOptInUsageError\")\n    open fun playerUpdated(player: Any?) {\n        if (player is ExoPlayer) {\n            context?.let { ctx ->\n                mMediaSession?.release()\n                mMediaSession = MediaSession.Builder(ctx, player)\n                    // Ensure unique ID for concurrent players\n                    .setId(System.currentTimeMillis().toString())\n                    .build()\n            }\n\n            // Necessary for multiple combined videos\n            @Suppress(\"DEPRECATION\")\n            playerView?.setShowMultiWindowTimeBar(true)\n            playerView?.player = player\n            playerView?.performClick()\n        }\n    }\n\n    protected var mMediaSession: MediaSession? = null\n\n    // this can be used in the future for players other than exoplayer\n    //private val mMediaSessionCallback: MediaSessionCompat.Callback = object : MediaSessionCompat.Callback() {\n    //    override fun onMediaButtonEvent(mediaButtonEvent: Intent): Boolean {\n    //        val keyEvent = mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT) as KeyEvent?\n    //        if (keyEvent != null) {\n    //            if (keyEvent.action == KeyEvent.ACTION_DOWN) { // NO DOUBLE SKIP\n    //                val consumed = when (keyEvent.keyCode) {\n    //                    KeyEvent.KEYCODE_MEDIA_PAUSE -> callOnPause()\n    //                    KeyEvent.KEYCODE_MEDIA_PLAY -> callOnPlay()\n    //                    KeyEvent.KEYCODE_MEDIA_STOP -> callOnStop()\n    //                    KeyEvent.KEYCODE_MEDIA_NEXT -> callOnNext()\n    //                    else -> false\n    //                }\n    //                if (consumed) return true\n    //            }\n    //        }\n    //\n    //        return super.onMediaButtonEvent(mediaButtonEvent)\n    //    }\n    //}\n\n    open fun onDownload(event: DownloadEvent) = Unit\n\n    /** This receives the events from the player, if you want to append functionality you do it here,\n     * do note that this only receives events for UI changes,\n     * and returning early WONT stop it from changing in eg the player time or pause status */\n    open fun mainCallback(event: PlayerEvent) {\n        // we don't want to spam DownloadEvent\n        if (event !is DownloadEvent) {\n            Log.i(TAG, \"Handle event: $event\")\n        }\n        when (event) {\n            is DownloadEvent -> {\n                onDownload(event)\n            }\n\n            is ResizedEvent -> {\n                playerDimensionsLoaded(event.width, event.height)\n            }\n\n            is PlayerAttachedEvent -> {\n                playerUpdated(event.player)\n            }\n\n            is SubtitlesUpdatedEvent -> {\n                subtitlesChanged()\n            }\n\n            is TimestampSkippedEvent -> {\n                onTimestampSkipped(event.timestamp)\n            }\n\n            is TimestampInvokedEvent -> {\n                onTimestamp(event.timestamp)\n            }\n\n            is TracksChangedEvent -> {\n                onTracksInfoChanged()\n            }\n\n            is EmbeddedSubtitlesFetchedEvent -> {\n                embeddedSubtitlesFetched(event.tracks)\n            }\n\n            is ErrorEvent -> {\n                playerError(event.error)\n            }\n\n            is RequestAudioFocusEvent -> {\n                requestAudioFocus()\n            }\n\n            is EpisodeSeekEvent -> {\n                when (event.offset) {\n                    -1 -> prevEpisode()\n                    1 -> nextEpisode()\n                    else -> {}\n                }\n            }\n\n            is StatusEvent -> {\n                updateIsPlaying(wasPlaying = event.wasPlaying, isPlaying = event.isPlaying)\n                playerStatusChanged()\n            }\n\n            is PositionEvent -> {\n                playerPositionChanged(position = event.toMs, duration = event.durationMs)\n            }\n\n            is VideoEndedEvent -> {\n                context?.let { ctx ->\n                    // Only play next episode if autoplay is on (default)\n                    if (PreferenceManager.getDefaultSharedPreferences(ctx)\n                            ?.getBoolean(\n                                ctx.getString(R.string.autoplay_next_key),\n                                true\n                            ) == true\n                    ) {\n                        player.handleEvent(\n                            CSPlayerEvent.NextEpisode,\n                            source = PlayerEventSource.Player\n                        )\n                    }\n                }\n            }\n\n            is PauseEvent -> Unit\n            is PlayEvent -> Unit\n        }\n    }\n\n    @SuppressLint(\"SetTextI18n\", \"UnsafeOptInUsageError\")\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        resizeMode = DataStoreHelper.resizeMode\n        resize(resizeMode, false)\n\n        player.releaseCallbacks()\n        player.initCallbacks(\n            eventHandler = ::mainCallback,\n            requestedListeningPercentages = listOf(\n                SKIP_OP_VIDEO_PERCENTAGE,\n                PRELOAD_NEXT_EPISODE_PERCENTAGE,\n                NEXT_WATCH_EPISODE_PERCENTAGE,\n                UPDATE_SYNC_PROGRESS_PERCENTAGE,\n            ),\n        )\n\n        val player = player\n        if (player is CS3IPlayer) {\n            // preview bar\n            val progressBar: PreviewTimeBar? = playerView?.findViewById(R.id.exo_progress)\n            val previewImageView: ImageView? = playerView?.findViewById(R.id.previewImageView)\n            val previewFrameLayout: FrameLayout? = playerView?.findViewById(R.id.previewFrameLayout)\n            if (progressBar != null && previewImageView != null && previewFrameLayout != null) {\n                var resume = false\n                progressBar.addOnScrubListener(object : PreviewBar.OnScrubListener {\n                    override fun onScrubStart(previewBar: PreviewBar?) {\n                        val hasPreview = player.hasPreview()\n                        progressBar.isPreviewEnabled = hasPreview\n                        resume = player.getIsPlaying()\n                        if (resume) player.handleEvent(\n                            CSPlayerEvent.Pause,\n                            PlayerEventSource.Player\n                        )\n\n                        // No clashing UI\n                        if (hasPreview) {\n                            subView?.isVisible = false\n                        }\n                    }\n\n                    override fun onScrubMove(\n                        previewBar: PreviewBar?,\n                        progress: Int,\n                        fromUser: Boolean\n                    ) {\n                    }\n\n                    override fun onScrubStop(previewBar: PreviewBar?) {\n                        if (resume) player.handleEvent(CSPlayerEvent.Play, PlayerEventSource.Player)\n                        // Delay to prevent the small flicker of subtitle before seeking\n                        subView?.postDelayed({\n                            // If we are not scrubbing then show subtitles again\n                            if (previewBar == null || !previewBar.isPreviewEnabled || !previewBar.isShowingPreview) {\n                                subView?.isVisible = true\n                            }\n                        }, 200)\n                    }\n                })\n                progressBar.attachPreviewView(previewFrameLayout)\n                progressBar.setPreviewLoader { currentPosition, max ->\n                    val bitmap = player.getPreview(currentPosition.toFloat().div(max.toFloat()))\n                    previewImageView.isGone = bitmap == null\n                    previewImageView.setImageBitmap(bitmap)\n                }\n            }\n\n            subView = playerView?.findViewById(androidx.media3.ui.R.id.exo_subtitles)\n            player.initSubtitles(subView, subtitleHolder, CustomDecoder.style)\n            (player.imageGenerator as? PreviewGenerator)?.params = ImageParams.new16by9(screenWidth)\n\n            /*previewImageView?.doOnLayout {\n                (player.imageGenerator as? PreviewGenerator)?.params = ImageParams(\n                    it.measuredWidth,\n                    it.measuredHeight\n                )\n            }*/\n            /** this might seam a bit fucky and that is because it is, the seek event is captured twice, once by the player\n             * and once by the UI even if it should only be registered once by the UI */\n            playerView?.findViewById<DefaultTimeBar>(R.id.exo_progress)\n                ?.addListener(object : TimeBar.OnScrubListener {\n                    override fun onScrubStart(timeBar: TimeBar, position: Long) = Unit\n                    override fun onScrubMove(timeBar: TimeBar, position: Long) = Unit\n                    override fun onScrubStop(timeBar: TimeBar, position: Long, canceled: Boolean) {\n                        if (canceled) return\n                        val playerDuration = player.getDuration() ?: return\n                        val playerPosition = player.getPosition() ?: return\n                        mainCallback(\n                            PositionEvent(\n                                source = PlayerEventSource.UI,\n                                durationMs = playerDuration,\n                                fromMs = playerPosition,\n                                toMs = position\n                            )\n                        )\n                    }\n                })\n\n            SubtitlesFragment.applyStyleEvent += ::onSubStyleChanged\n\n            try {\n                context?.let { ctx ->\n                    val settingsManager = PreferenceManager.getDefaultSharedPreferences(\n                        ctx\n                    )\n\n                    val currentPrefCacheSize =\n                        settingsManager.getInt(getString(R.string.video_buffer_size_key), 0)\n                    val currentPrefDiskSize =\n                        settingsManager.getInt(getString(R.string.video_buffer_disk_key), 0)\n                    val currentPrefBufferSec =\n                        settingsManager.getInt(getString(R.string.video_buffer_length_key), 0)\n\n                    player.cacheSize = currentPrefCacheSize * 1024L * 1024L\n                    player.simpleCacheSize = currentPrefDiskSize * 1024L * 1024L\n                    player.videoBufferMs = currentPrefBufferSec * 1000L\n                }\n            } catch (e: Exception) {\n                logError(e)\n            }\n        }\n\n        /*context?.let { ctx ->\n            player.loadPlayer(\n                ctx,\n                false,\n                ExtractorLink(\n                    \"idk\",\n                    \"bunny\",\n                    \"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\",\n                    \"\",\n                    Qualities.P720.value,\n                    false\n                ),\n            )\n        }*/\n    }\n\n    override fun onDestroy() {\n        player.release()\n        player.releaseCallbacks()\n        player = CS3IPlayer()\n\n        playerEventListener = null\n        keyEventListener = null\n\n        PlayerPipHelper.updatePIPModeActions(activity, CSPlayerLoading.IsPaused, false, null)\n\n        mMediaSession?.release()\n        mMediaSession = null\n        playerView?.player = null\n        SubtitlesFragment.applyStyleEvent -= ::onSubStyleChanged\n\n        keepScreenOn(false)\n        super.onDestroy()\n    }\n\n    fun nextResize() {\n        resizeMode = (resizeMode + 1) % PlayerResize.entries.size\n        resize(resizeMode, true)\n    }\n\n    fun resize(resize: Int, showToast: Boolean) {\n        resize(PlayerResize.entries[resize], showToast)\n    }\n\n    @SuppressLint(\"UnsafeOptInUsageError\")\n    open fun resize(resize: PlayerResize, showToast: Boolean) {\n        DataStoreHelper.resizeMode = resize.ordinal\n        val type = when (resize) {\n            PlayerResize.Fill -> AspectRatioFrameLayout.RESIZE_MODE_FILL\n            PlayerResize.Fit -> AspectRatioFrameLayout.RESIZE_MODE_FIT\n            PlayerResize.Zoom -> AspectRatioFrameLayout.RESIZE_MODE_ZOOM\n        }\n        playerView?.resizeMode = type\n\n        if (showToast)\n            showToast(resize.nameRes, Toast.LENGTH_SHORT)\n    }\n\n    override fun onStop() {\n        player.onStop()\n        super.onStop()\n    }\n\n    override fun onResume() {\n        context?.let { ctx ->\n            player.onResume(ctx)\n        }\n\n        super.onResume()\n    }\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? {\n        val root = inflater.inflate(layout, container, false)\n        playerPausePlayHolderHolder = root.findViewById(R.id.player_pause_play_holder_holder)\n        playerPausePlay = root.findViewById(R.id.player_pause_play)\n        playerBuffering = root.findViewById(R.id.player_buffering)\n        playerView = root.findViewById(R.id.player_view)\n        piphide = root.findViewById(R.id.piphide)\n        subtitleHolder = root.findViewById(R.id.subtitle_holder)\n        return root\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt",
    "content": "@file:Suppress(\"DEPRECATION\")\n\npackage com.lagradost.cloudstream3.ui.player\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.graphics.Bitmap\nimport android.net.Uri\nimport android.os.Handler\nimport android.os.Looper\nimport android.util.Log\nimport android.util.Rational\nimport android.widget.FrameLayout\nimport androidx.annotation.MainThread\nimport androidx.annotation.OptIn\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.net.toUri\nimport androidx.media3.common.C.TIME_UNSET\nimport androidx.media3.common.C.TRACK_TYPE_AUDIO\nimport androidx.media3.common.C.TRACK_TYPE_TEXT\nimport androidx.media3.common.C.TRACK_TYPE_VIDEO\nimport androidx.media3.common.Format\nimport androidx.media3.common.MediaItem\nimport androidx.media3.common.MimeTypes\nimport androidx.media3.common.PlaybackException\nimport androidx.media3.common.Player\nimport androidx.media3.common.TrackGroup\nimport androidx.media3.common.TrackSelectionOverride\nimport androidx.media3.common.Tracks\nimport androidx.media3.common.VideoSize\nimport androidx.media3.common.util.UnstableApi\nimport androidx.media3.database.StandaloneDatabaseProvider\nimport androidx.media3.datasource.DataSource\nimport androidx.media3.datasource.DefaultDataSource\nimport androidx.media3.datasource.DefaultHttpDataSource\nimport androidx.media3.datasource.HttpDataSource\nimport androidx.media3.datasource.cache.CacheDataSource\nimport androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor\nimport androidx.media3.datasource.cache.SimpleCache\nimport androidx.media3.datasource.cronet.CronetDataSource\nimport androidx.media3.datasource.okhttp.OkHttpDataSource\nimport androidx.media3.exoplayer.DecoderCounters\nimport androidx.media3.exoplayer.DecoderReuseEvaluation\nimport androidx.media3.exoplayer.DefaultLoadControl\nimport androidx.media3.exoplayer.DefaultRenderersFactory\nimport androidx.media3.exoplayer.ExoPlayer\nimport androidx.media3.exoplayer.Renderer.STATE_ENABLED\nimport androidx.media3.exoplayer.Renderer.STATE_STARTED\nimport androidx.media3.exoplayer.SeekParameters\nimport androidx.media3.exoplayer.analytics.AnalyticsListener\nimport androidx.media3.exoplayer.dash.DashMediaSource\nimport androidx.media3.exoplayer.drm.DefaultDrmSessionManager\nimport androidx.media3.exoplayer.drm.FrameworkMediaDrm\nimport androidx.media3.exoplayer.drm.HttpMediaDrmCallback\nimport androidx.media3.exoplayer.drm.LocalMediaDrmCallback\nimport androidx.media3.exoplayer.source.ClippingMediaSource\nimport androidx.media3.exoplayer.source.ConcatenatingMediaSource\nimport androidx.media3.exoplayer.source.ConcatenatingMediaSource2\nimport androidx.media3.exoplayer.source.DefaultMediaSourceFactory\nimport androidx.media3.exoplayer.source.MediaSource\nimport androidx.media3.exoplayer.source.MergingMediaSource\nimport androidx.media3.exoplayer.source.SingleSampleMediaSource\nimport androidx.media3.exoplayer.text.TextOutput\nimport androidx.media3.exoplayer.text.TextRenderer\nimport androidx.media3.exoplayer.trackselection.DefaultTrackSelector\nimport androidx.media3.exoplayer.trackselection.TrackSelector\nimport androidx.media3.extractor.mp4.FragmentedMp4Extractor\nimport androidx.media3.ui.SubtitleView\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.AudioFile\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.MainActivity.Companion.deleteFileOnExit\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.debugAssert\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.fixSubtitleAlignment\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle\nimport com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.applyStyle\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isUsingMobileData\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.CLEARKEY_UUID\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount\nimport com.lagradost.cloudstream3.utils.DrmExtractorLink\nimport com.lagradost.cloudstream3.utils.EpisodeSkip\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkPlayList\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.PLAYREADY_UUID\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromTagToLanguageName\nimport com.lagradost.cloudstream3.utils.WIDEVINE_UUID\nimport io.github.anilbeesetti.nextlib.media3ext.ffdecoder.NextRenderersFactory\nimport kotlinx.coroutines.delay\nimport okhttp3.Interceptor\nimport org.chromium.net.CronetEngine\nimport java.io.File\nimport java.security.SecureRandom\nimport java.util.UUID\nimport java.util.concurrent.Executors\nimport javax.net.ssl.HttpsURLConnection\nimport javax.net.ssl.SSLContext\nimport javax.net.ssl.SSLSession\n\nconst val TAG = \"CS3ExoPlayer\"\nconst val PREFERRED_AUDIO_LANGUAGE_KEY = \"preferred_audio_language\"\n\n/** toleranceBeforeUs – The maximum time that the actual position seeked to may precede the\n * requested seek position, in microseconds. Must be non-negative. */\nconst val toleranceBeforeUs = 300_000L\n\n/**\n * toleranceAfterUs – The maximum time that the actual position seeked to may exceed the requested\n * seek position, in microseconds. Must be non-negative.\n */\nconst val toleranceAfterUs = 300_000L\n\n@OptIn(UnstableApi::class)\nclass CS3IPlayer : IPlayer {\n    private var playerListener: Player.Listener? = null\n    private var isPlaying = false\n    private var exoPlayer: ExoPlayer? = null\n        set(value) {\n            // If the old value is not null then the player has not been properly released.\n            debugAssert(\n                { field != null && value != null },\n                { \"Previous player instance should be released!\" })\n            field = value\n        }\n\n    var cacheSize = 0L\n    var simpleCacheSize = 0L\n    var videoBufferMs = 0L\n\n    val imageGenerator = IPreviewGenerator.new()\n\n    private val seekActionTime = 30000L\n    private val isMediaSeekable\n        get() = exoPlayer?.let {\n            it.isCommandAvailable(Player.COMMAND_GET_CURRENT_MEDIA_ITEM) && it.isCurrentMediaItemSeekable\n        } ?: false\n\n    private var ignoreSSL: Boolean = true\n    private var playBackSpeed: Float = 1.0f\n\n    private var lastMuteVolume: Float = 1.0f\n\n    private var currentLink: ExtractorLink? = null\n    private var currentDownloadedFile: ExtractorUri? = null\n    private var hasUsedFirstRender = false\n\n    private var currentWindow: Int = 0\n    private var playbackPosition: Long = 0\n\n    private val subtitleHelper = PlayerSubtitleHelper()\n\n    /** If we want to play the audio only in the background when the app is not open */\n    private var isAudioOnlyBackground = false\n\n    /**\n     * This is a way to combine the MediaItem and its duration for the concatenating MediaSource.\n     * @param durationUs does not matter if only one slice is present, since it will not concatenate\n     * */\n    data class MediaItemSlice(\n        val mediaItem: MediaItem,\n        val durationUs: Long,\n        val drm: DrmMetadata? = null\n    )\n\n    data class DrmMetadata(\n        val kid: String? = null,\n        val key: String? = null,\n        val uuid: UUID,\n        val kty: String? = null,\n        val licenseUrl: String? = null,\n        val keyRequestParameters: HashMap<String, String>,\n    )\n\n    override fun getDuration(): Long? = exoPlayer?.duration\n    override fun getPosition(): Long? = exoPlayer?.currentPosition\n    override fun getIsPlaying(): Boolean = isPlaying\n    override fun getPlaybackSpeed(): Float = playBackSpeed\n\n    /**\n     * Tracks reported to be used by exoplayer, since sometimes it has a mind of it's own when selecting subs.\n     * String = id (without exoplayer track number)\n     * Boolean = if it's active\n     * */\n    private var playerSelectedSubtitleTracks = listOf<Pair<String, Boolean>>()\n    private var requestedListeningPercentages: List<Int>? = null\n\n    private var eventHandler: ((PlayerEvent) -> Unit)? = null\n    private val mainHandler = Handler(Looper.getMainLooper())\n\n    fun event(event: PlayerEvent) {\n        // Ensure that all work is done on the main looper, aka main thread\n        if (Looper.myLooper() == mainHandler.looper) {\n            eventHandler?.invoke(event)\n        } else {\n            mainHandler.post {\n                eventHandler?.invoke(event)\n            }\n        }\n    }\n\n    /**\n     * As initCallbacks and releaseCallbacks must always be done,\n     * we use this to say that the player is in use.\n     * */\n    @Volatile\n    var isPlayerActive: Boolean = false\n\n    override fun releaseCallbacks() {\n        eventHandler = null\n        if (isPlayerActive) {\n            isPlayerActive = false\n            activePlayers -= 1\n            releaseCronetEngine()\n        }\n    }\n\n    override fun initCallbacks(\n        eventHandler: ((PlayerEvent) -> Unit),\n        requestedListeningPercentages: List<Int>?,\n    ) {\n        this.requestedListeningPercentages = requestedListeningPercentages\n        this.eventHandler = eventHandler\n        if (!isPlayerActive) {\n            isPlayerActive = true\n            activePlayers += 1\n        }\n    }\n\n    // I know, this is not a perfect solution, however it works for fixing subs\n    private fun reloadSubs() {\n        exoPlayer?.applicationLooper?.let {\n            try {\n                Handler(it).post {\n                    try {\n                        seekTime(1L, source = PlayerEventSource.Player)\n                    } catch (e: Exception) {\n                        logError(e)\n                    }\n                }\n            } catch (e: Exception) {\n                logError(e)\n            }\n        }\n    }\n\n    fun String.stripTrackId(): String {\n        return this.replace(Regex(\"\"\"^\\d+:\"\"\"), \"\")\n    }\n\n    fun initSubtitles(subView: SubtitleView?, subHolder: FrameLayout?, style: SaveCaptionStyle?) {\n        subtitleHelper.initSubtitles(subView, subHolder, style)\n    }\n\n    override fun getPreview(fraction: Float): Bitmap? {\n        return imageGenerator.getPreviewImage(fraction)\n    }\n\n    override fun hasPreview(): Boolean {\n        return imageGenerator.hasPreview()\n    }\n\n    override fun loadPlayer(\n        context: Context,\n        sameEpisode: Boolean,\n        link: ExtractorLink?,\n        data: ExtractorUri?,\n        startPosition: Long?,\n        subtitles: Set<SubtitleData>,\n        subtitle: SubtitleData?,\n        autoPlay: Boolean?,\n        preview: Boolean,\n    ) {\n        Log.i(TAG, \"loadPlayer\")\n        if (sameEpisode) {\n            saveData()\n        } else {\n            currentSubtitles = subtitle\n            playbackPosition = 0\n        }\n\n        startPosition?.let {\n            playbackPosition = it\n        }\n\n        // we want autoplay because of TV and UX\n        isPlaying = autoPlay ?: isPlaying\n\n        // release the current exoplayer and cache\n        releasePlayer()\n\n        if (link != null) {\n            // only video support atm\n            (imageGenerator as? PreviewGenerator)?.let { gen ->\n                if (preview) {\n                    gen.load(link, sameEpisode)\n                } else {\n                    gen.clear(sameEpisode)\n                }\n            }\n\n            loadOnlinePlayer(context, link)\n        } else if (data != null) {\n            (imageGenerator as? PreviewGenerator)?.let { gen ->\n                if (preview) {\n                    gen.load(context, data, sameEpisode)\n                } else {\n                    gen.clear(sameEpisode)\n                }\n            }\n            loadOfflinePlayer(context, data)\n        } else {\n            throw IllegalArgumentException(\"Requires link or uri\")\n        }\n\n    }\n\n    override fun setActiveSubtitles(subtitles: Set<SubtitleData>) {\n        Log.i(TAG, \"setActiveSubtitles ${subtitles.size}\")\n        subtitleHelper.setAllSubtitles(subtitles)\n    }\n\n    private var currentSubtitles: SubtitleData? = null\n\n    private fun List<Tracks.Group>.getTrack(id: String?): Pair<TrackGroup, Int>? {\n        if (id == null) return null\n        // This beast of an expression does:\n        // 1. Filter all audio tracks\n        // 2. Get all formats in said audio tacks\n        // 3. Gets all ids of the formats\n        // 4. Filters to find the first audio track with the same id as the audio track we are looking for\n        // 5. Returns the media group and the index of the audio track in the group\n        return this.firstNotNullOfOrNull { group ->\n            (0 until group.mediaTrackGroup.length).map {\n                group.getTrackFormat(it) to it\n            }.firstOrNull {\n                // The format id system is \"trackNumber:trackID\"\n                // The track number is not generated by us so we filter it out\n                it.first.id?.stripTrackId() == id\n            }\n                ?.let { group.mediaTrackGroup to it.second }\n        }\n    }\n\n    override fun setMaxVideoSize(width: Int, height: Int, id: String?) {\n        if (id != null) {\n            val videoTrack =\n                exoPlayer?.currentTracks?.groups?.filter { it.type == TRACK_TYPE_VIDEO }\n                    ?.getTrack(id)\n\n            if (videoTrack != null) {\n                exoPlayer?.trackSelectionParameters = exoPlayer?.trackSelectionParameters\n                    ?.buildUpon()\n                    ?.setOverrideForType(\n                        TrackSelectionOverride(\n                            videoTrack.first,\n                            videoTrack.second\n                        )\n                    )\n                    ?.build()\n                    ?: return\n                return\n            }\n        }\n\n        exoPlayer?.trackSelectionParameters = exoPlayer?.trackSelectionParameters\n            ?.buildUpon()\n            ?.setMaxVideoSize(width, height)\n            ?.build()\n            ?: return\n    }\n\n    override fun setPreferredAudioTrack(trackLanguage: String?, id: String?, formatIndex: Int?) {\n        preferredAudioTrackLanguage = trackLanguage\n        id?.let { trackId ->\n            val trackFormatIndex = formatIndex ?: 0\n            exoPlayer?.currentTracks?.groups\n                ?.filter { it.type == TRACK_TYPE_AUDIO }\n                ?.find { group ->\n                    group.getFormats().any { (format, _) ->\n                        format.id == trackId\n                    }\n                }\n                ?.let { group ->\n                    exoPlayer?.trackSelectionParameters\n                        ?.buildUpon()\n                        ?.setOverrideForType(TrackSelectionOverride(group.mediaTrackGroup, trackFormatIndex))\n                        ?.build()\n                }\n                ?.let { newParams ->\n                    exoPlayer?.trackSelectionParameters = newParams\n                    return\n                }\n        }\n        // Fallback to language-based selection\n        exoPlayer?.trackSelectionParameters = exoPlayer?.trackSelectionParameters\n            ?.buildUpon()\n            ?.setPreferredAudioLanguage(trackLanguage)\n            ?.build() ?: return\n    }\n\n    /**\n     * Gets all supported formats in a list\n     * */\n    private fun List<Tracks.Group>.getFormats(): List<Pair<Format, Int>> {\n        return this.map {\n            it.getFormats()\n        }.flatten()\n    }\n\n    private fun Tracks.Group.getFormats(): List<Pair<Format, Int>> {\n        return (0 until this.mediaTrackGroup.length).mapNotNull { i ->\n            if (this.isSupported)\n                this.mediaTrackGroup.getFormat(i) to i\n            else null\n        }\n    }\n\n    private fun Format.toAudioTrack(formatIndex: Int?): AudioTrack {\n        return AudioTrack(\n            this.id,\n            this.label,\n            this.language,\n            this.sampleMimeType,\n            this.channelCount,\n            formatIndex ?: 0,\n        )\n    }\n\n    private fun Format.toSubtitleTrack(): TextTrack {\n        return TextTrack(\n            this.id?.stripTrackId(),\n            this.label,\n            this.language,\n            this.sampleMimeType,\n        )\n    }\n\n    private fun Format.toVideoTrack(): VideoTrack {\n        return VideoTrack(\n            this.id?.stripTrackId(),\n            this.label,\n            this.language,\n            this.width,\n            this.height,\n            this.sampleMimeType\n        )\n    }\n\n    override fun getVideoTracks(): CurrentTracks {\n        val allTrackGroups = exoPlayer?.currentTracks?.groups ?: emptyList()\n        val videoTracks = allTrackGroups.filter { it.type == TRACK_TYPE_VIDEO }\n            .getFormats()\n            .map { it.first.toVideoTrack() }\n        var currentAudioTrack: AudioTrack? = null\n        val audioTracks = allTrackGroups.filter { it.type == TRACK_TYPE_AUDIO }\n            .flatMap { group ->\n                group.getFormats().map { (format, formatIndex) ->\n                    val audioTrack = format.toAudioTrack(formatIndex)\n                    if (group.isTrackSelected(formatIndex)) {\n                        currentAudioTrack = audioTrack\n                    }\n                    audioTrack\n                }\n            }\n        val textTracks = allTrackGroups.filter { it.type == TRACK_TYPE_TEXT }\n            .getFormats()\n            .map { it.first.toSubtitleTrack() }\n        val currentTextTracks = textTracks.filter { track ->\n            playerSelectedSubtitleTracks.any { it.second && it.first == track.id }\n        }\n        return CurrentTracks(\n            exoPlayer?.videoFormat?.toVideoTrack(),\n            currentAudioTrack,\n            currentTextTracks,\n            videoTracks,\n            audioTracks,\n            textTracks\n        )\n    }\n\n    /**\n     * @return True if the player should be reloaded\n     * */\n    override fun setPreferredSubtitles(subtitle: SubtitleData?): Boolean {\n        Log.i(TAG, \"setPreferredSubtitles init $subtitle\")\n        currentSubtitles = subtitle\n        val trackSelector = exoPlayer?.trackSelector as? DefaultTrackSelector ?: return false\n        // Disable subtitles if null\n        if (subtitle == null) {\n            trackSelector.setParameters(\n                trackSelector.buildUponParameters()\n                    .setTrackTypeDisabled(TRACK_TYPE_TEXT, true)\n                    .clearOverridesOfType(TRACK_TYPE_TEXT)\n            )\n            return false\n        }\n        // Handle subtitle based on status\n        when (subtitleHelper.subtitleStatus(subtitle)) {\n            SubtitleStatus.REQUIRES_RELOAD -> {\n                Log.i(TAG, \"setPreferredSubtitles REQUIRES_RELOAD\")\n                return true\n            }\n            SubtitleStatus.NOT_FOUND -> {\n                Log.i(TAG, \"setPreferredSubtitles NOT_FOUND\")\n                return true\n            }\n            SubtitleStatus.IS_ACTIVE -> {\n                Log.i(TAG, \"setPreferredSubtitles IS_ACTIVE\")\n                exoPlayer?.currentTracks?.groups\n                    ?.filter { it.type == TRACK_TYPE_TEXT }\n                    ?.getTrack(subtitle.getId())\n                    ?.let { (trackGroup, trackIndex) ->\n                        trackSelector.setParameters(\n                            trackSelector.buildUponParameters()\n                                .setTrackTypeDisabled(TRACK_TYPE_TEXT, false)\n                                .setOverrideForType(TrackSelectionOverride(trackGroup, trackIndex))\n                        )\n                    }\n                return false\n            }\n        }\n    }\n\n    private var currentSubtitleOffset: Long = 0\n\n    override fun setSubtitleOffset(offset: Long) {\n        currentSubtitleOffset = offset\n        CustomDecoder.subtitleOffset = offset\n        if (currentTextRenderer?.state == STATE_ENABLED || currentTextRenderer?.state == STATE_STARTED) {\n            exoPlayer?.currentPosition?.also { pos ->\n                // This seems to properly refresh all subtitles\n                // It needs to be done as all subtitle cues with timings are pre-processed\n                currentTextRenderer?.resetPosition(pos, false)\n            }\n        }\n    }\n\n    override fun getSubtitleOffset(): Long {\n        return currentSubtitleOffset\n    }\n\n    override fun getSubtitleCues(): List<SubtitleCue> {\n        return currentSubtitleDecoder?.getSubtitleCues() ?: emptyList()\n    }\n\n    override fun getCurrentPreferredSubtitle(): SubtitleData? {\n        return subtitleHelper.getAllSubtitles().firstOrNull { sub ->\n            playerSelectedSubtitleTracks.any { (id, isSelected) ->\n                isSelected && sub.getId() == id\n            }\n        }\n    }\n\n    override fun getAspectRatio(): Rational? {\n        return exoPlayer?.videoFormat?.let { format ->\n            Rational(format.width, format.height)\n        }\n    }\n\n    override fun updateSubtitleStyle(style: SaveCaptionStyle) {\n        subtitleHelper.setSubStyle(style)\n    }\n\n    override fun saveData() {\n        Log.i(TAG, \"saveData\")\n        updatedTime()\n\n        exoPlayer?.let { exo ->\n            playbackPosition = exo.currentPosition\n            currentWindow = exo.currentMediaItemIndex\n            isPlaying = exo.isPlaying\n        }\n    }\n\n    private fun releasePlayer(saveTime: Boolean = true) {\n        Log.i(TAG, \"releasePlayer\")\n        eventLooperIndex += 1\n        if (saveTime)\n            updatedTime()\n\n        currentTextRenderer = null\n        currentSubtitleDecoder = null\n\n        exoPlayer?.apply {\n            playWhenReady = false\n\n            // This may look weird, however on some TV devices the audio does not stop playing\n            // so this may fix it?\n            try {\n                pause()\n            } catch (t: Throwable) {\n                // No documented exception, but just to be extra safe\n                logError(t)\n            }\n            playerListener?.let {\n                removeListener(it)\n                playerListener = null\n            }\n            stop()\n            release()\n        }\n        //simpleCache?.release()\n\n        exoPlayer = null\n        event(PlayerAttachedEvent(null))\n        //simpleCache = null\n    }\n\n    override fun onStop() {\n        Log.i(TAG, \"onStop\")\n\n        saveData()\n        if (!isAudioOnlyBackground) {\n            handleEvent(CSPlayerEvent.Pause, PlayerEventSource.Player)\n        }\n        //releasePlayer()\n    }\n\n    override fun onPause() {\n        Log.i(TAG, \"onPause\")\n        saveData()\n        if (!isAudioOnlyBackground) {\n            handleEvent(CSPlayerEvent.Pause, PlayerEventSource.Player)\n        }\n        //releasePlayer()\n    }\n\n    override fun onResume(context: Context) {\n        isAudioOnlyBackground = false\n        if (exoPlayer == null)\n            reloadPlayer(context)\n    }\n\n    override fun release() {\n        imageGenerator.release()\n        releasePlayer()\n    }\n\n    override fun setPlaybackSpeed(speed: Float) {\n        exoPlayer?.setPlaybackSpeed(speed)\n        playBackSpeed = speed\n    }\n\n    companion object {\n        private const val CRONET_TIMEOUT_MS = 15_000\n\n        /**\n         * Single shared engine, to minimize the overhead of maintaining many as:\n         * 1. Cpu time/Startup time\n         * 2. Mem consumption/GC\n         * 3. Disk usage, as we simply use the same folder\n         * */\n        private var cronetEngine: CronetEngine? = null\n\n        /**\n         * How many active sessions we have.\n         *\n         * However in reality it should never go negative or be more than 1,\n         * but this makes more sense architecturally.\n         * */\n        @Volatile\n        private var activePlayers = 0\n\n        /** Unique monotonically increasing id to keep track of the last release call */\n        @Volatile\n        private var cronetReleasedId = 0\n\n        fun releaseCronetEngine() {\n            if (cronetEngine == null) return\n\n            // Delayed release, as we do not want to restart it when opening trailers ect\n            val id = ++cronetReleasedId\n            val posted = Handler(Looper.getMainLooper()).postDelayed({\n                // This might get dropped, but that should be very rare\n                // and should not affect it.\n                releaseCronetEngineInstantly(id)\n            }, 60_000) // 1min timeout before release\n\n            // If not posted, then run instantly\n            if (!posted) {\n                releaseCronetEngineInstantly(id)\n            }\n        }\n\n        private fun releaseCronetEngineInstantly(id: Int) {\n            // We should release if and only if this was the last call, and\n            // there is no active players\n            if (activePlayers == 0 && id == cronetReleasedId) {\n                try {\n                    cronetEngine?.shutdown()\n                } catch (t: Throwable) {\n                    logError(t)\n                } finally {\n                    Log.d(TAG, \"CronetEngine shutdown\")\n                    // Even if it fails to shutdown, the GC should take care of it\n                    cronetEngine = null\n                }\n            }\n        }\n\n        /**\n         * Setting this variable is permanent across app sessions.\n         **/\n        var preferredAudioTrackLanguage: String? = null\n            get() {\n                return field ?: getKey(\n                    \"$currentAccount/$PREFERRED_AUDIO_LANGUAGE_KEY\",\n                    field\n                )?.also {\n                    field = it\n                }\n            }\n            set(value) {\n                setKey(\"$currentAccount/$PREFERRED_AUDIO_LANGUAGE_KEY\", value)\n                field = value\n            }\n\n        private var simpleCache: SimpleCache? = null\n\n        /// Create a small factory for small things, no cache, no cronet\n        private fun createOnlineSource(\n            headers: Map<String, String>?,\n            interceptor: Interceptor?\n        ): HttpDataSource.Factory {\n            val client = if (interceptor == null) {\n                app.baseClient\n            } else {\n                app.baseClient.newBuilder()\n                    .addInterceptor(interceptor)\n                    .build()\n            }\n            val source = OkHttpDataSource.Factory(client).setUserAgent(USER_AGENT)\n\n            if (!headers.isNullOrEmpty()) {\n                source.setDefaultRequestProperties(headers)\n            }\n            return source\n        }\n\n        fun tryCreateEngine(context: Context, diskCacheSize: Long): CronetEngine? {\n            // Fast case, no need to recreate it\n            cronetEngine?.let {\n                return it\n            }\n\n            // https://gist.github.com/ShivamKumarJha/3c8398b47053ae05112d2a8f8b5de531\n            return try {\n                val cacheDirectory = File(context.cacheDir, \"CronetEngine\")\n                cacheDirectory.deleteRecursively()\n                if (!cacheDirectory.exists()) {\n                    cacheDirectory.mkdirs()\n                }\n                CronetEngine.Builder(context)\n                    .enableBrotli(true)\n                    .enableHttp2(true)\n                    .enableQuic(true)\n                    .setStoragePath(cacheDirectory.absolutePath)\n                    .setLibraryLoader(null)\n                    .enableHttpCache(CronetEngine.Builder.HTTP_CACHE_DISK, diskCacheSize)\n                    .build().also { buildEngine ->\n                        Log.d(\n                            TAG,\n                            \"Created CronetEngine with cache at ${cacheDirectory.absolutePath}\"\n                        )\n                        cronetEngine = buildEngine\n                    }\n            } catch (t: Throwable) {\n                logError(t)\n                // Something went wrong, so we use the backup okhttp\n                null\n            }\n        }\n\n        private fun createVideoSource(\n            link: ExtractorLink,\n            engine: CronetEngine?,\n            interceptor: Interceptor?,\n        ): HttpDataSource.Factory {\n            val userAgent = link.headers.entries.find {\n                it.key.equals(\"User-Agent\", ignoreCase = true)\n            }?.value ?: USER_AGENT\n\n            val source = if (interceptor == null) {\n                if (engine == null) {\n                    Log.d(TAG, \"Using DefaultHttpDataSource for $link\")\n                    OkHttpDataSource.Factory(app.baseClient).setUserAgent(userAgent)\n                } else {\n                    Log.d(TAG, \"Using CronetDataSource for $link\")\n                    CronetDataSource.Factory(engine, Executors.newSingleThreadExecutor())\n                        .setUserAgent(userAgent)\n                        .setConnectionTimeoutMs(CRONET_TIMEOUT_MS)\n                        .setReadTimeoutMs(CRONET_TIMEOUT_MS)\n                        .setResetTimeoutOnRedirects(true)\n                        .setHandleSetCookieRequests(true)\n                }\n            } else {\n                Log.d(TAG, \"Using OkHttpDataSource for $link\")\n                val client = app.baseClient.newBuilder()\n                    .addInterceptor(interceptor)\n                    .build()\n                OkHttpDataSource.Factory(client).setUserAgent(userAgent)\n            }\n\n            // Do no include empty referer, if the provider wants those they can use the header map.\n            val refererMap =\n                if (link.referer.isBlank()) emptyMap() else mapOf(\"referer\" to link.referer)\n\n            // These are extra headers the browser like to insert, not sure if we want to include them\n            // for WIDEVINE/drm as well? Do that if someone gets 404 and creates an issue.\n            val headers = refererMap + link.headers // Adds the headers from the provider, e.g Authorization\n\n            return source.apply {\n                setDefaultRequestProperties(headers)\n            }\n        }\n\n        private fun Context.createOfflineSource(): DataSource.Factory {\n            return DefaultDataSource.Factory(\n                this,\n                DefaultHttpDataSource.Factory().setUserAgent(USER_AGENT)\n            )\n        }\n\n        private fun getCache(context: Context, cacheSize: Long): SimpleCache? {\n            return try {\n                val databaseProvider = StandaloneDatabaseProvider(context)\n                SimpleCache(\n                    File(\n                        context.cacheDir, \"exoplayer\"\n                    ).also { deleteFileOnExit(it) }, // Ensures always fresh file\n                    LeastRecentlyUsedCacheEvictor(cacheSize),\n                    databaseProvider\n                )\n            } catch (e: Exception) {\n                logError(e)\n                null\n            }\n        }\n\n        private fun getMediaItemBuilder(mimeType: String):\n                MediaItem.Builder {\n            return MediaItem.Builder()\n                //Replace needed for android 6.0.0  https://github.com/google/ExoPlayer/issues/5983\n                .setMimeType(mimeType)\n        }\n\n        private fun getMediaItem(mimeType: String, uri: Uri): MediaItem {\n            return getMediaItemBuilder(mimeType).setUri(uri).build()\n        }\n\n        private fun getMediaItem(mimeType: String, url: String): MediaItem {\n            return getMediaItemBuilder(mimeType).setUri(url).build()\n        }\n\n        private fun getTrackSelector(context: Context, maxVideoHeight: Int?): TrackSelector {\n            val trackSelector = DefaultTrackSelector(context)\n            trackSelector.parameters = trackSelector.buildUponParameters()\n                // This will not force higher quality videos to fail\n                // but will make the m3u8 pick the correct preferred\n                .setMaxVideoSize(Int.MAX_VALUE, maxVideoHeight ?: Int.MAX_VALUE)\n                .setPreferredAudioLanguage(null)\n                .build()\n            return trackSelector\n        }\n\n        private var currentSubtitleDecoder: CustomSubtitleDecoderFactory? = null\n        private var currentTextRenderer: TextRenderer? = null\n    }\n\n    private fun getCurrentTimestamp(writePosition: Long? = null): EpisodeSkip.SkipStamp? {\n        val position = writePosition ?: this@CS3IPlayer.getPosition() ?: return null\n        for (lastTimeStamp in lastTimeStamps) {\n            if (lastTimeStamp.startMs <= position && (position + (toleranceBeforeUs / 1000L) + 1) < lastTimeStamp.endMs) {\n                return lastTimeStamp\n            }\n        }\n        return null\n    }\n\n    fun updatedTime(\n        writePosition: Long? = null,\n        source: PlayerEventSource = PlayerEventSource.Player\n    ) {\n        val position = writePosition ?: exoPlayer?.currentPosition\n\n        getCurrentTimestamp(position)?.let { timestamp ->\n            event(TimestampInvokedEvent(timestamp, source))\n        }\n\n        val duration = exoPlayer?.contentDuration\n        if (duration != null && position != null) {\n            event(\n                PositionEvent(\n                    source,\n                    fromMs = exoPlayer?.currentPosition ?: 0,\n                    position,\n                    duration\n                )\n            )\n        }\n    }\n\n    override fun seekTime(time: Long, source: PlayerEventSource) {\n        exoPlayer?.seekTime(time, source)\n    }\n\n    override fun seekTo(time: Long, source: PlayerEventSource) {\n        if (isMediaSeekable) {\n            updatedTime(time, source)\n            exoPlayer?.seekTo(time)\n        } else {\n            Log.i(TAG, \"Media is not seekable, we can not seek to $time\")\n        }\n    }\n\n    private fun ExoPlayer.seekTime(time: Long, source: PlayerEventSource) {\n        if (isMediaSeekable) {\n            updatedTime(currentPosition + time, source)\n            seekTo(currentPosition + time)\n        } else {\n            Log.i(TAG, \"Media is not seekable, we can not seek to $time\")\n        }\n    }\n\n    override fun handleEvent(event: CSPlayerEvent, source: PlayerEventSource) {\n        Log.i(TAG, \"handleEvent ${event.name}\")\n        try {\n            exoPlayer?.apply {\n                when (event) {\n                    CSPlayerEvent.Play -> {\n                        event(PlayEvent(source))\n                        play()\n                    }\n\n                    CSPlayerEvent.Pause -> {\n                        event(PauseEvent(source))\n                        pause()\n                    }\n\n                    CSPlayerEvent.ToggleMute -> {\n                        if (volume <= 0) {\n                            //is muted\n                            volume = lastMuteVolume\n                        } else {\n                            // is not muted\n                            lastMuteVolume = volume\n                            volume = 0f\n                        }\n                    }\n\n                    CSPlayerEvent.PlayPauseToggle -> {\n                        if (isPlaying) {\n                            handleEvent(CSPlayerEvent.Pause, source)\n                        } else {\n                            handleEvent(CSPlayerEvent.Play, source)\n                        }\n                    }\n\n                    CSPlayerEvent.SeekForward -> seekTime(seekActionTime, source)\n\n                    CSPlayerEvent.SeekBack -> seekTime(-seekActionTime, source)\n\n                    CSPlayerEvent.Restart -> seekTo(0, source)\n\n                    CSPlayerEvent.NextEpisode -> event(\n                        EpisodeSeekEvent(\n                            offset = 1,\n                            source = source\n                        )\n                    )\n\n                    CSPlayerEvent.PrevEpisode -> event(\n                        EpisodeSeekEvent(\n                            offset = -1,\n                            source = source\n                        )\n                    )\n\n                    CSPlayerEvent.SkipCurrentChapter -> {\n                        //val dur = this@CS3IPlayer.getDuration() ?: return@apply\n                        getCurrentTimestamp()?.let { lastTimeStamp ->\n                            if (lastTimeStamp.skipToNextEpisode) {\n                                handleEvent(CSPlayerEvent.NextEpisode, source)\n                            } else {\n                                seekTo(lastTimeStamp.endMs + 1L)\n                            }\n                            event(TimestampSkippedEvent(timestamp = lastTimeStamp, source = source))\n                        }\n                    }\n\n                    CSPlayerEvent.PlayAsAudio -> {\n                        isAudioOnlyBackground = true\n                        activity?.moveTaskToBack(false)\n                    }\n                }\n            }\n        } catch (t: Throwable) {\n            Log.e(TAG, \"handleEvent error\", t)\n            event(ErrorEvent(t))\n        }\n    }\n\n    // we want to push metadata when loading torrents, so we just set up a looper that loops until\n    // the index changes, this way only 1 looper is active at a time, and modifying eventLooperIndex\n    // will kill any active loopers\n    private var eventLooperIndex = 0\n    private fun torrentEventLooper(hash: String) = ioSafe {\n        eventLooperIndex += 2\n        // very shitty, but should work fine\n        // release player is called once for the new link\n        val currentIndex = eventLooperIndex + 1\n        while (eventLooperIndex <= currentIndex && eventHandler != null) {\n            try {\n                val status = Torrent.get(hash)\n                event(\n                    DownloadEvent(\n                        connections = status.activePeers,\n                        downloadSpeed = status.downloadSpeed?.toLong()!!,\n                        totalBytes = status.torrentSize!!,\n                        downloadedBytes = status.bytesRead!!,\n                    )\n                )\n            } catch (_: NullPointerException) {\n            } catch (t: Throwable) {\n                logError(t)\n            }\n            delay(1000)\n        }\n    }\n\n    private fun buildExoPlayer(\n        context: Context,\n        mediaItemSlices: List<MediaItemSlice>,\n        subSources: List<SingleSampleMediaSource>,\n        currentWindow: Int,\n        playbackPosition: Long,\n        playBackSpeed: Float,\n        subtitleOffset: Long,\n        cacheSize: Long,\n        videoBufferMs: Long,\n        onlineSource: HttpDataSource.Factory? = null,\n        playWhenReady: Boolean = true,\n        trackSelector: TrackSelector? = null,\n        /**\n         * Sets the m3u8 preferred video quality, will not force stop anything with higher quality.\n         * Does not work if trackSelector is defined.\n         **/\n        maxVideoHeight: Int? = null,\n        /** External audio tracks to merge with the video */\n        audioSources: List<MediaSource> = emptyList()\n    ): ExoPlayer {\n        val exoPlayerBuilder =\n            ExoPlayer.Builder(context)\n                .setRenderersFactory { eventHandler, videoRendererEventListener, audioRendererEventListener, textRendererOutput, metadataRendererOutput ->\n                    val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)\n                    val current = settingsManager.getInt(\n                        context.getString(R.string.software_decoding_key),\n                        -1\n                    )\n                    val (isSoftwareDecodingEnabled, isSoftwareDecodingPreferred) = when (current) {\n                        0 -> true to false // HW+SW, aka on but prefer hw\n                        2 -> true to true // SW+HW, aka on but prefer sw\n                        1 -> false to false // HW, aka off\n                        // -1 = automatic\n                        // We do not want tv to have software decoding, because of crashes\n                        else -> isLayout(PHONE or EMULATOR) to false\n                    }\n\n                    val factory = if (isSoftwareDecodingEnabled) {\n                        FixedNextRenderersFactory(context).apply {\n                            setEnableDecoderFallback(true)\n                            setExtensionRendererMode(\n                                if (isSoftwareDecodingPreferred)\n                                    DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER\n                                else\n                                    DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON\n                            )\n                        }\n                    } else {\n                        // no nextlib = EXTENSION_RENDERER_MODE_OFF\n                        DefaultRenderersFactory(context)\n                    }\n\n                    val style = CustomDecoder.style\n                    // Custom TextOutput to apply cue styling and rules to all subtitles\n                    val customTextOutput = TextOutput { cue ->\n                        // Do not remove filterNotNull as Java typesystem is fucked\n                        val (bitmapCues, textCues) = cue.cues.filterNotNull()\n                            .partition { it.bitmap != null }\n\n                        val styledBitmapCues = bitmapCues.map { bitmapCue ->\n                            bitmapCue\n                                .buildUpon()\n                                .fixSubtitleAlignment()\n                                .applyStyle(style)\n                                .build()\n                        }\n\n                        // Reuse memory, to avoid many allocations\n                        val set = HashSet<CharSequence>()\n                        val buffer = StringBuilder()\n\n                        // Move cues into one single one\n                        // This is to prevent text overlap in vtt (and potentially other) subtitle files\n                        val styledTextCues = textCues.groupBy {\n                            // Groups cues which share the same positon\n                            it.lineAnchor to it.position.times(1000.0f).toInt()\n                        }.mapNotNull { (_, entries) ->\n                            set.clear()\n                            buffer.clear()\n                            var count = 0\n                            for (x in entries) {\n                                // Only allow non null text, otherwise we might have \"a\\n\\nb\"\n                                val text = x.text ?: continue\n\n                                // Prevent duplicate entries, this often happens when the subtitle file\n                                // uses multiple text lines as outlines. Most commonly found in fansubs\n                                // with fancy subtitle styling.\n                                if (!set.add(text)) {\n                                    continue\n                                }\n                                if (++count > 1) buffer.append('\\n')\n\n                                // Trim to avoid weird formatting if the last line ends with a newline\n                                buffer.append(text.trim())\n                            }\n\n                            val combinedCueText = buffer.toString()\n\n                            // Use the style of the first entry as the base\n                            entries\n                                .firstOrNull()\n                                ?.buildUpon()\n                                ?.setText(combinedCueText)\n                                ?.fixSubtitleAlignment()\n                                ?.applyStyle(style)\n                                ?.build()\n                        }\n\n                        val combinedCues = styledBitmapCues + styledTextCues\n\n                        subtitleHelper.subtitleView?.setCues(combinedCues)\n                    }\n\n                    factory.createRenderers(\n                        eventHandler,\n                        videoRendererEventListener,\n                        audioRendererEventListener,\n                        customTextOutput,\n                        metadataRendererOutput\n                    ).map {\n                        if (it is TextRenderer) {\n                            CustomDecoder.subtitleOffset = subtitleOffset\n                            val decoder = CustomSubtitleDecoderFactory()\n\n                            val currentTextRenderer = TextRenderer(\n                                customTextOutput,\n                                eventHandler.looper,\n                                decoder\n                            ).apply {\n                                // Required to make the decoder work with old subtitles\n                                // Upgrade CustomSubtitleDecoderFactory when media3 supports it\n                                @Suppress(\"DEPRECATION\")\n                                experimentalSetLegacyDecodingEnabled(true)\n                            }.also { renderer ->\n                                currentTextRenderer = renderer\n                                currentSubtitleDecoder = decoder\n                            }\n                            currentTextRenderer\n                        } else\n                            it\n                    }.toTypedArray()\n                }\n                .setTrackSelector(\n                    trackSelector ?: getTrackSelector(\n                        context,\n                        maxVideoHeight\n                    )\n                )\n                // Allows any seeking to be +- 0.3s to allow for faster seeking\n                .setSeekParameters(SeekParameters(toleranceBeforeUs, toleranceAfterUs))\n                .setLoadControl(\n                    DefaultLoadControl.Builder()\n                        .setTargetBufferBytes(\n                            if (cacheSize <= 0) {\n                                DefaultLoadControl.DEFAULT_TARGET_BUFFER_BYTES\n                            } else {\n                                if (cacheSize > Int.MAX_VALUE) Int.MAX_VALUE else cacheSize.toInt()\n                            }\n                        )\n                        .setBackBuffer(\n                            30000,\n                            true\n                        )\n                        .setBufferDurationsMs(\n                            DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,\n                            if (videoBufferMs <= 0) {\n                                DefaultLoadControl.DEFAULT_MAX_BUFFER_MS\n                            } else {\n                                videoBufferMs.toInt()\n                            },\n                            DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,\n                            DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS\n                        ).build()\n                )\n\n        // Because \"Java rules\" the media3 team hates to do open classes so we have to copy paste the entire thing to add a custom extractor\n        // This includes the updated MKV extractor that enabled seeking in formats where the seek information is at the back of the file\n        val extractorFactor = UpdatedDefaultExtractorsFactory()\n            .setFragmentedMp4ExtractorFlags(FragmentedMp4Extractor.FLAG_MERGE_FRAGMENTED_SIDX)\n\n        // Create an online connection with cache for all online sources\n        val dataSourceFactory = if (onlineSource == null) {\n            null\n        } else {\n            if (simpleCache == null)\n                simpleCache = getCache(context, simpleCacheSize)\n\n            val cacheFactory = CacheDataSource.Factory().apply {\n                simpleCache?.let { setCache(it) }\n                setUpstreamDataSourceFactory(onlineSource)\n            }\n            cacheFactory\n        }\n\n        val defaultMediaSourceFactory = if (dataSourceFactory != null) {\n            DefaultMediaSourceFactory(dataSourceFactory, extractorFactor)\n        } else {\n            DefaultMediaSourceFactory(context, extractorFactor)\n        }\n\n        // If there is only one item then treat it as normal, if multiple: concatenate the items.\n        val videoMediaSource = if (mediaItemSlices.size == 1) {\n            val item = mediaItemSlices.first()\n\n            item.drm?.let { drm ->\n                when (drm.uuid) {\n                    CLEARKEY_UUID -> {\n                        // Use headers from DrmMetadata for media requests\n                        val client = dataSourceFactory\n                            ?: throw IllegalArgumentException(\"Must supply onlineSource\")\n                        val drmCallback =\n                            LocalMediaDrmCallback(\"{\\\"keys\\\":[{\\\"kty\\\":\\\"${drm.kty}\\\",\\\"k\\\":\\\"${drm.key}\\\",\\\"kid\\\":\\\"${drm.kid}\\\"}],\\\"type\\\":\\\"temporary\\\"}\".toByteArray())\n                        val manager = DefaultDrmSessionManager.Builder()\n                            .setPlayClearSamplesWithoutKeys(true)\n                            .setMultiSession(false)\n                            .setKeyRequestParameters(drm.keyRequestParameters)\n                            .setUuidAndExoMediaDrmProvider(\n                                drm.uuid,\n                                FrameworkMediaDrm.DEFAULT_PROVIDER\n                            )\n                            .build(drmCallback)\n\n                        DashMediaSource.Factory(client)\n                            .setDrmSessionManagerProvider { manager }\n                            .createMediaSource(item.mediaItem)\n                    }\n\n                    WIDEVINE_UUID,\n                    PLAYREADY_UUID -> {\n                        // Use headers from DrmMetadata for media requests\n                        val client = dataSourceFactory\n                            ?: throw IllegalArgumentException(\"Must supply onlineSource\")\n                        val drmCallback = HttpMediaDrmCallback(drm.licenseUrl, client)\n                        val manager = DefaultDrmSessionManager.Builder()\n                            .setPlayClearSamplesWithoutKeys(true)\n                            .setMultiSession(true)\n                            .setKeyRequestParameters(drm.keyRequestParameters)\n                            .setUuidAndExoMediaDrmProvider(\n                                drm.uuid,\n                                FrameworkMediaDrm.DEFAULT_PROVIDER\n                            )\n                            .build(drmCallback)\n\n                        DashMediaSource.Factory(client)\n                            .setDrmSessionManagerProvider { manager }\n                            .createMediaSource(item.mediaItem)\n                    }\n\n                    else -> {\n                        Log.e(\n                            TAG,\n                            \"DRM Metadata class is not supported: ${drm::class.simpleName}\"\n                        )\n                        null\n                    }\n                }\n            } ?: run {\n                defaultMediaSourceFactory.createMediaSource(item.mediaItem)\n            }\n        } else {\n            try {\n                val source = ConcatenatingMediaSource2.Builder()\n                mediaItemSlices.map { item ->\n                    source.add(\n                        // The duration MUST be known for it to work properly, see https://github.com/google/ExoPlayer/issues/4727\n                        ClippingMediaSource(\n                            defaultMediaSourceFactory.createMediaSource(item.mediaItem),\n                            item.durationUs\n                        )\n                    )\n                }\n                source.build()\n            } catch (_: IllegalArgumentException) {\n                @Suppress(\"DEPRECATION\")\n                val source =\n                    ConcatenatingMediaSource() // FIXME figure out why ConcatenatingMediaSource2 seems to fail with Torrents only\n                mediaItemSlices.map { item ->\n                    source.addMediaSource(\n                        // The duration MUST be known for it to work properly, see https://github.com/google/ExoPlayer/issues/4727\n                        ClippingMediaSource(\n                            defaultMediaSourceFactory.createMediaSource(item.mediaItem),\n                            item.durationUs\n                        )\n                    )\n                }\n                source\n            }\n        }\n        return exoPlayerBuilder.build().apply {\n            setPlayWhenReady(playWhenReady)\n            seekTo(currentWindow, playbackPosition)\n            // Merge video, subtitles and external audio tracks\n            val allSources = listOf(videoMediaSource) + subSources + audioSources\n            setMediaSource(\n                MergingMediaSource(*allSources.toTypedArray()),\n                playbackPosition\n            )\n            setHandleAudioBecomingNoisy(true)\n            setPlaybackSpeed(playBackSpeed)\n            this.addAnalyticsListener(tracksAnalyticsListener)\n        }\n    }\n\n    private fun loadExo(\n        context: Context,\n        mediaSlices: List<MediaItemSlice>,\n        subSources: List<SingleSampleMediaSource>,\n        audioSources: List<MediaSource> = emptyList(),\n        onlineSource: HttpDataSource.Factory? = null,\n    ) {\n        Log.i(TAG, \"loadExo\")\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)\n        val maxVideoHeight = settingsManager.getInt(\n            context.getString(if (context.isUsingMobileData()) R.string.quality_pref_mobile_data_key else R.string.quality_pref_key),\n            Int.MAX_VALUE\n        )\n\n        try {\n            hasUsedFirstRender = false\n\n            // ye this has to be a val for whatever reason\n            // this makes no sense\n            exoPlayer = buildExoPlayer(\n                context,\n                mediaSlices,\n                subSources,\n                currentWindow,\n                playbackPosition,\n                playBackSpeed,\n                cacheSize = cacheSize,\n                videoBufferMs = videoBufferMs,\n                playWhenReady = isPlaying, // this keep the current state of the player\n                subtitleOffset = currentSubtitleOffset,\n                maxVideoHeight = maxVideoHeight,\n                audioSources = audioSources,\n                onlineSource = onlineSource,\n            )\n\n            event(PlayerAttachedEvent(exoPlayer))\n            exoPlayer?.prepare()\n\n            exoPlayer?.let { exo ->\n                event(StatusEvent(CSPlayerLoading.IsBuffering, CSPlayerLoading.IsBuffering))\n                isPlaying = exo.isPlaying\n            }\n\n            // we want to avoid an empty exoplayer from sending events\n            // this is because we need PlayerAttachedEvent to be called to render the UI\n            // but don't really want the rest like Player.STATE_ENDED calling next episode\n            if (mediaSlices.isEmpty() && subSources.isEmpty()) {\n                return\n            }\n\n            exoPlayer?.addListener(object : Player.Listener {\n                override fun onTracksChanged(tracks: Tracks) {\n                    safe {\n                        val textTracks = tracks.groups.filter { it.type == TRACK_TYPE_TEXT }\n\n                        playerSelectedSubtitleTracks =\n                            textTracks.map { group ->\n                                group.getFormats().mapNotNull { (format, _) ->\n                                    (format.id?.stripTrackId()\n                                        ?: return@mapNotNull null) to group.isSelected\n                                }\n                            }.flatten()\n\n                        val exoPlayerReportedTracks =\n                            tracks.groups.filter { it.type == TRACK_TYPE_TEXT }.getFormats()\n                                .mapNotNull { (format, _) ->\n                                    // Filter out non subs, already used subs and subs without languages\n                                    if (format.id == null ||\n                                        format.language == null ||\n                                        format.language?.startsWith(\"-\") == true\n                                    ) return@mapNotNull null\n\n                                    return@mapNotNull SubtitleData(\n                                        // Nicer looking displayed names\n                                        fromTagToLanguageName(format.language)\n                                            ?: format.language!!,\n                                        format.label ?: \"\",\n                                        // See setPreferredTextLanguage\n                                        format.id!!.stripTrackId(),\n                                        SubtitleOrigin.EMBEDDED_IN_VIDEO,\n                                        format.sampleMimeType ?: MimeTypes.APPLICATION_SUBRIP,\n                                        emptyMap(),\n                                        format.language,\n                                    )\n                                }\n\n                        event(EmbeddedSubtitlesFetchedEvent(tracks = exoPlayerReportedTracks))\n                        event(TracksChangedEvent())\n                        event(SubtitlesUpdatedEvent())\n                    }\n                }\n\n                // fixme: Use onPlaybackStateChanged(int) and onPlayWhenReadyChanged(boolean, int) instead.\n                @Suppress(\"OVERRIDE_DEPRECATION\")\n                override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {\n                    exoPlayer?.let { exo ->\n                        event(\n                            StatusEvent(\n                                wasPlaying = if (isPlaying) CSPlayerLoading.IsPlaying else CSPlayerLoading.IsPaused,\n                                isPlaying =\n                                    when (playbackState) {\n                                        Player.STATE_ENDED -> CSPlayerLoading.IsEnded\n                                        Player.STATE_BUFFERING -> CSPlayerLoading.IsBuffering\n                                        else -> if (exo.isPlaying) CSPlayerLoading.IsPlaying else CSPlayerLoading.IsPaused\n                                    }\n                            )\n                        )\n                        isPlaying = exo.isPlaying\n                    }\n\n                    when (playbackState) {\n                        Player.STATE_READY -> {\n                            onRenderFirst()\n                        }\n\n                        else -> {}\n                    }\n\n\n                    if (playWhenReady) {\n                        when (playbackState) {\n                            Player.STATE_READY -> {\n\n                            }\n\n                            Player.STATE_ENDED -> {\n                                event(VideoEndedEvent())\n                            }\n\n                            Player.STATE_BUFFERING -> {\n                                updatedTime(source = PlayerEventSource.Player)\n                            }\n\n                            Player.STATE_IDLE -> {\n\n                            }\n\n                            else -> Unit\n                        }\n                    }\n                }\n\n                override fun onPlayerError(error: PlaybackException) {\n                    // If the Network fails then ignore the exception if the duration is set.\n                    // This is to switch mirrors automatically if the stream has not been fetched, but\n                    // allow playing the buffer without internet as then the duration is fetched.\n                    when {\n                        error.errorCode == PlaybackException.ERROR_CODE_IO_NETWORK_CONNECTION_FAILED\n                                && exoPlayer?.duration != TIME_UNSET -> {\n                            exoPlayer?.prepare()\n                        }\n\n                        error.errorCode == PlaybackException.ERROR_CODE_BEHIND_LIVE_WINDOW -> {\n                            // Re-initialize player at the current live window default position.\n                            exoPlayer?.seekToDefaultPosition()\n                            exoPlayer?.prepare()\n                        }\n\n                        else -> {\n                            event(ErrorEvent(error))\n                        }\n                    }\n\n                    super.onPlayerError(error)\n                }\n\n                //override fun onCues(cues: MutableList<Cue>) {\n                //    super.onCues(cues.map { cue -> cue.buildUpon().setText(\"Hello world\").setSize(Cue.DIMEN_UNSET).build() })\n                //}\n\n                override fun onIsPlayingChanged(isPlaying: Boolean) {\n                    super.onIsPlayingChanged(isPlaying)\n                    if (isPlaying) {\n                        event(RequestAudioFocusEvent())\n                        onRenderFirst()\n                    }\n                }\n\n                override fun onPlaybackStateChanged(playbackState: Int) {\n                    super.onPlaybackStateChanged(playbackState)\n                    when (playbackState) {\n                        Player.STATE_READY -> {\n\n                        }\n\n                        Player.STATE_ENDED -> {\n                            // Only play next episode if autoplay is on (default)\n                            if (PreferenceManager.getDefaultSharedPreferences(context)\n                                    ?.getBoolean(\n                                        context.getString(R.string.autoplay_next_key),\n                                        true\n                                    ) == true\n                            ) {\n                                handleEvent(\n                                    CSPlayerEvent.NextEpisode,\n                                    source = PlayerEventSource.Player\n                                )\n                            }\n                        }\n\n                        Player.STATE_BUFFERING -> {\n                            updatedTime(source = PlayerEventSource.Player)\n                        }\n\n                        Player.STATE_IDLE -> {\n                            // IDLE\n                        }\n\n                        else -> Unit\n                    }\n                }\n\n                override fun onVideoSizeChanged(videoSize: VideoSize) {\n                    super.onVideoSizeChanged(videoSize)\n                    event(ResizedEvent(height = videoSize.height, width = videoSize.width))\n                }\n\n                override fun onRenderedFirstFrame() {\n                    super.onRenderedFirstFrame()\n                    onRenderFirst()\n                    updatedTime(source = PlayerEventSource.Player)\n                }\n            }.also { playerListener = it })\n        } catch (t: Throwable) {\n            Log.e(TAG, \"loadExo error\", t)\n            event(ErrorEvent(t))\n        }\n    }\n\n    private var lastTimeStamps: List<EpisodeSkip.SkipStamp> = emptyList()\n\n    override fun addTimeStamps(timeStamps: List<EpisodeSkip.SkipStamp>) {\n        lastTimeStamps = timeStamps\n        timeStamps.forEach { timestamp ->\n            exoPlayer?.createMessage { _, _ ->\n                updatedTime(source = PlayerEventSource.Player)\n                //if (payload is EpisodeSkip.SkipStamp) // this should always be true\n                //    onTimestampInvoked?.invoke(payload)\n            }\n                ?.setLooper(Looper.getMainLooper())\n                ?.setPosition(timestamp.startMs)\n                //?.setPayload(timestamp)\n                ?.setDeleteAfterDelivery(false)\n                ?.send()\n        }\n        updatedTime(source = PlayerEventSource.Player)\n    }\n\n    fun onRenderFirst() {\n        if (hasUsedFirstRender) { // this insures that we only call this once per player load\n            return\n        }\n        Log.i(TAG, \"Rendered first frame\")\n        hasUsedFirstRender = true\n\n        setPreferredSubtitles(currentSubtitles)\n        val format = exoPlayer?.videoFormat\n        val width = format?.width\n        val height = format?.height\n        if (height != null && width != null) {\n            event(ResizedEvent(width = width, height = height))\n            updatedTime()\n            exoPlayer?.apply {\n                requestedListeningPercentages?.forEach { percentage ->\n                    createMessage { _, _ ->\n                        updatedTime()\n                    }\n                        .setLooper(Looper.getMainLooper())\n                        .setPosition(contentDuration * percentage / 100)\n                        //   .setPayload(customPayloadData)\n                        .setDeleteAfterDelivery(false)\n                        .send()\n                }\n            }\n        }\n    }\n\n    private fun loadOfflinePlayer(context: Context, data: ExtractorUri) {\n        Log.i(TAG, \"loadOfflinePlayer\")\n        try {\n            currentDownloadedFile = data\n\n            val mediaItem = getMediaItem(MimeTypes.VIDEO_MP4, data.uri)\n            val offlineSourceFactory = context.createOfflineSource()\n\n            val (subSources, activeSubtitles) = getSubSources(\n                offlineSourceFactory = offlineSourceFactory,\n                subHelper = subtitleHelper,\n                interceptor = null,\n            )\n\n            subtitleHelper.setActiveSubtitles(activeSubtitles.toSet())\n            loadExo(context, listOf(MediaItemSlice(mediaItem, Long.MIN_VALUE)), subSources)\n        } catch (t: Throwable) {\n            Log.e(TAG, \"loadOfflinePlayer error\", t)\n            event(ErrorEvent(t))\n        }\n    }\n\n    private fun getSubSources(\n        offlineSourceFactory: DataSource.Factory?,\n        subHelper: PlayerSubtitleHelper,\n        interceptor: Interceptor?,\n    ): Pair<List<SingleSampleMediaSource>, List<SubtitleData>> {\n        val activeSubtitles = ArrayList<SubtitleData>()\n        val subSources = subHelper.getAllSubtitles().mapNotNull { sub ->\n            val subConfig = MediaItem.SubtitleConfiguration.Builder(sub.getFixedUrl().toUri())\n                .setMimeType(sub.mimeType)\n                .setLanguage(\"_${sub.name}\")\n                .setId(sub.getId())\n                .setSelectionFlags(0)\n                .build()\n            when (sub.origin) {\n                SubtitleOrigin.DOWNLOADED_FILE, SubtitleOrigin.EMBEDDED_IN_VIDEO -> {\n                    if (offlineSourceFactory != null) {\n                        activeSubtitles.add(sub)\n                        SingleSampleMediaSource.Factory(offlineSourceFactory)\n                            .createMediaSource(subConfig, TIME_UNSET)\n                    } else {\n                        null\n                    }\n                }\n\n                SubtitleOrigin.URL -> {\n                    val dataSourceFactory = createOnlineSource(sub.headers, interceptor)\n                    activeSubtitles.add(sub)\n                    SingleSampleMediaSource.Factory(dataSourceFactory)\n                        .createMediaSource(subConfig, TIME_UNSET)\n                }\n            }\n        }\n        return Pair(subSources, activeSubtitles)\n    }\n\n    /**\n     * Creates audio media sources from ExtractorLink's audioTracks\n     * @param audioTracks List of audio tracks from ExtractorLink\n     * @return List of MediaSource for audio tracks\n     */\n    private fun getAudioSources(\n        audioTracks: List<AudioFile>,\n        interceptor: Interceptor?,\n    ): List<MediaSource> {\n        return audioTracks.mapNotNull { audio ->\n            try {\n                val mediaItem = getMediaItem(MimeTypes.AUDIO_UNKNOWN, audio.url)\n                val dataSourceFactory = createOnlineSource(audio.headers, interceptor)\n                DefaultMediaSourceFactory(dataSourceFactory).createMediaSource(mediaItem)\n            } catch (e: Exception) {\n                Log.e(TAG, \"Failed to create audio source for ${audio.url}: ${e.message}\")\n                null\n            }\n        }\n    }\n\n    override fun isActive(): Boolean {\n        return exoPlayer != null\n    }\n\n\n    @MainThread\n    private fun loadTorrent(context: Context, link: ExtractorLink) {\n        ioSafe {\n            // we check exoPlayer a lot here, and that is because we don't want to load exo after\n            // the user has left the player, in the case that the user click back when this is\n            // happening\n            try {\n                if (exoPlayer == null) return@ioSafe\n                val (newLink, status) = Torrent.transformLink(link)\n                val hash = status.hash\n                if (exoPlayer == null) return@ioSafe\n                runOnMainThread {\n                    if (exoPlayer == null) return@runOnMainThread\n                    releasePlayer()\n                    if (hash != null) {\n                        torrentEventLooper(hash)\n                    }\n                    loadOnlinePlayer(context, newLink)\n                }\n            } catch (t: Throwable) {\n                event(ErrorEvent(t))\n            }\n        }\n    }\n\n    @SuppressLint(\"UnsafeOptInUsageError\")\n    @MainThread\n    private fun loadOnlinePlayer(context: Context, link: ExtractorLink, retry: Boolean = false) {\n        Log.i(TAG, \"loadOnlinePlayer $link\")\n        try {\n            val mime = when (link.type) {\n                ExtractorLinkType.M3U8 -> MimeTypes.APPLICATION_M3U8\n                ExtractorLinkType.DASH -> MimeTypes.APPLICATION_MPD\n                ExtractorLinkType.VIDEO -> MimeTypes.VIDEO_MP4\n                ExtractorLinkType.TORRENT, ExtractorLinkType.MAGNET -> {\n                    // we check settings first, todo cleanup\n                    val default = TvType.entries.toTypedArray()\n                        .sorted()\n                        .filter { it != TvType.NSFW }\n                        .map { it.ordinal }\n\n                    val defaultSet = default.map { it.toString() }.toSet()\n                    val currentPrefMedia = try {\n                        PreferenceManager.getDefaultSharedPreferences(context)\n                            .getStringSet(\n                                context.getString(R.string.prefer_media_type_key),\n                                defaultSet\n                            )\n                            ?.mapNotNull { it.toIntOrNull() ?: return@mapNotNull null }\n                    } catch (e: Throwable) {\n                        null\n                    } ?: default\n\n                    if (!currentPrefMedia.contains(TvType.Torrent.ordinal)) {\n                        val errorMessage = context.getString(R.string.torrent_preferred_media)\n                        event(ErrorEvent(ErrorLoadingException(errorMessage)))\n                        return\n                    }\n\n                    if (Torrent.hasAcceptedTorrentForThisSession == false) {\n                        val errorMessage = context.getString(R.string.torrent_not_accepted)\n                        event(ErrorEvent(ErrorLoadingException(errorMessage)))\n                        return\n                    }\n                    // load the initial UI, we require an exoPlayer to be alive\n                    if (!retry) {\n                        // this causes a *bug* that restarts all torrents from 0\n                        // but I would call this a feature\n                        releasePlayer()\n                        loadExo(context, listOf(), listOf())\n                    }\n                    event(\n                        StatusEvent(\n                            wasPlaying = CSPlayerLoading.IsPlaying,\n                            isPlaying = CSPlayerLoading.IsBuffering\n                        )\n                    )\n\n                    if (Torrent.hasAcceptedTorrentForThisSession == true) {\n                        loadTorrent(context, link)\n                        return\n                    }\n\n                    val builder: AlertDialog.Builder = AlertDialog.Builder(context)\n\n                    val dialogClickListener =\n                        DialogInterface.OnClickListener { _, which ->\n                            when (which) {\n                                DialogInterface.BUTTON_POSITIVE -> {\n                                    Torrent.hasAcceptedTorrentForThisSession = true\n                                    loadTorrent(context, link)\n                                }\n\n                                DialogInterface.BUTTON_NEGATIVE -> {\n                                    Torrent.hasAcceptedTorrentForThisSession = false\n                                    val errorMessage =\n                                        context.getString(R.string.torrent_not_accepted)\n                                    event(ErrorEvent(ErrorLoadingException(errorMessage)))\n                                }\n                            }\n                        }\n\n                    builder.setTitle(R.string.play_torrent_button)\n                        .setMessage(R.string.torrent_info)\n                        // Ensure that the user will not accidentally start a torrent session.\n                        .setCancelable(false).setOnCancelListener {\n                            val errorMessage = context.getString(R.string.torrent_not_accepted)\n                            event(ErrorEvent(ErrorLoadingException(errorMessage)))\n                        }\n                        .setPositiveButton(R.string.ok, dialogClickListener)\n                        .setNegativeButton(R.string.go_back, dialogClickListener)\n                        .show().setDefaultFocus()\n\n                    return\n                }\n            }\n\n            currentLink = link\n\n            if (ignoreSSL) {\n                // Disables ssl check\n                val sslContext: SSLContext = SSLContext.getInstance(\"TLS\")\n                sslContext.init(null, arrayOf(SSLTrustManager()), SecureRandom())\n                sslContext.createSSLEngine()\n                HttpsURLConnection.setDefaultHostnameVerifier { _: String, _: SSLSession ->\n                    true\n                }\n                HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.socketFactory)\n            }\n\n\n            val mediaItems = when (link) {\n                is ExtractorLinkPlayList -> link.playlist.map {\n                    MediaItemSlice(getMediaItem(mime, it.url), it.durationUs)\n                }\n\n                is DrmExtractorLink -> {\n                    listOf(\n                        // Single sliced list with unset length\n                        MediaItemSlice(\n                            getMediaItem(mime, link.url), Long.MIN_VALUE,\n                            drm = DrmMetadata(\n                                kid = link.kid,\n                                key = link.key,\n                                uuid = link.uuid,\n                                kty = link.kty,\n                                licenseUrl = link.licenseUrl,\n                                keyRequestParameters = link.keyRequestParameters,\n                            )\n                        )\n                    )\n                }\n\n                else -> listOf(\n                    // Single sliced list with unset length\n                    MediaItemSlice(getMediaItem(mime, link.url), Long.MIN_VALUE)\n                )\n            }\n\n            // For DASH or HLS single streams (non-playlist), prefer the player's default\n            // live position instead of starting at 0. Use TIME_UNSET to let ExoPlayer pick\n            // the live/default position when no explicit start position was provided.\n            if (playbackPosition == 0L && (link.type == ExtractorLinkType.M3U8 || link.type == ExtractorLinkType.DASH)) {\n                playbackPosition = TIME_UNSET\n            }\n\n            val provider = getApiFromNameNull(link.source)\n            val interceptor: Interceptor? = provider?.getVideoInterceptor(link)\n\n            val onlineSourceFactory =\n                createVideoSource(\n                    link = link,\n                    engine = tryCreateEngine(context, simpleCacheSize),\n                    interceptor = interceptor\n                )\n\n            val offlineSourceFactory = context.createOfflineSource()\n\n            val (subSources, activeSubtitles) = getSubSources(\n                offlineSourceFactory = offlineSourceFactory,\n                subHelper = subtitleHelper,\n                interceptor = interceptor, // Backwards compatibility, needs a new api to work properly\n            )\n\n            // Create audio sources from ExtractorLink's audioTracks\n            val audioSources = getAudioSources(\n                audioTracks = link.audioTracks,\n                interceptor = interceptor, // Backwards compatibility, needs a new api to work properly\n            )\n\n            subtitleHelper.setActiveSubtitles(activeSubtitles.toSet())\n\n            loadExo(\n                context = context,\n                mediaSlices = mediaItems,\n                subSources = subSources,\n                audioSources = audioSources,\n                onlineSource = onlineSourceFactory\n            )\n        } catch (t: Throwable) {\n            Log.e(TAG, \"loadOnlinePlayer error\", t)\n            event(ErrorEvent(t))\n        }\n    }\n\n    override fun reloadPlayer(context: Context) {\n        Log.i(TAG, \"reloadPlayer\")\n\n        releasePlayer(false)\n        currentLink?.let {\n            loadOnlinePlayer(context, it)\n        } ?: currentDownloadedFile?.let {\n            loadOfflinePlayer(context, it)\n        }\n    }\n\n    private val tracksAnalyticsListener = object : AnalyticsListener {\n\n        override fun onVideoInputFormatChanged(\n            eventTime: AnalyticsListener.EventTime,\n            format: Format,\n            decoderReuseEvaluation: DecoderReuseEvaluation?\n        ) {\n            event(TracksChangedEvent())\n        }\n\n        override fun onAudioInputFormatChanged(\n            eventTime: AnalyticsListener.EventTime,\n            format: Format,\n            decoderReuseEvaluation: DecoderReuseEvaluation?\n        ) {\n            event(TracksChangedEvent())\n        }\n\n        override fun onVideoDisabled(\n            eventTime: AnalyticsListener.EventTime,\n            decoderCounters: DecoderCounters\n        ) {\n            event(TracksChangedEvent())\n        }\n\n        override fun onAudioDisabled(\n            eventTime: AnalyticsListener.EventTime,\n            decoderCounters: DecoderCounters\n        ) {\n            event(TracksChangedEvent())\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubripParser.kt",
    "content": "/*\r\n * Copyright (C) 2016 The Android Open Source Project\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\n\r\n\r\n/*\r\n* This is a fork of media3 subrip parses as the developers fear a flexible player, and open classes.\r\n*/\r\npackage com.lagradost.cloudstream3.ui.player\r\n\r\nimport android.text.Html\r\nimport android.text.Spanned\r\nimport android.text.TextUtils\r\nimport androidx.annotation.VisibleForTesting\r\nimport androidx.media3.common.C\r\nimport androidx.media3.common.Format\r\nimport androidx.media3.common.Format.CueReplacementBehavior\r\nimport androidx.media3.common.text.Cue\r\nimport androidx.media3.common.text.Cue.AnchorType\r\nimport androidx.media3.common.util.Assertions\r\nimport androidx.media3.common.util.Consumer\r\nimport androidx.media3.common.util.Log\r\nimport androidx.media3.common.util.ParsableByteArray\r\nimport androidx.media3.common.util.UnstableApi\r\nimport androidx.media3.extractor.text.CuesWithTiming\r\nimport androidx.media3.extractor.text.SubtitleParser\r\nimport androidx.media3.extractor.text.SubtitleParser.OutputOptions\r\nimport com.google.common.collect.ImmutableList\r\nimport java.nio.charset.Charset\r\nimport java.nio.charset.StandardCharsets\r\nimport java.util.regex.Matcher\r\nimport java.util.regex.Pattern\r\n\r\n/** A [SubtitleParser] for SubRip.  */\r\n@UnstableApi\r\nclass CustomSubripParser : SubtitleParser {\r\n    private val textBuilder: StringBuilder = StringBuilder()\r\n    private val tags: ArrayList<String> = ArrayList()\r\n    private val parsableByteArray: ParsableByteArray = ParsableByteArray()\r\n\r\n    override fun getCueReplacementBehavior(): @CueReplacementBehavior Int {\r\n        return CUE_REPLACEMENT_BEHAVIOR\r\n    }\r\n\r\n    override fun parse(\r\n        data: ByteArray,\r\n        offset: Int,\r\n        length: Int,\r\n        outputOptions: OutputOptions,\r\n        output: Consumer<CuesWithTiming>\r\n    ) {\r\n        parsableByteArray.reset(data,  /* limit= */offset + length)\r\n        parsableByteArray.setPosition(offset)\r\n        val charset = detectUtfCharset(parsableByteArray)\r\n\r\n        val cuesWithTimingBeforeRequestedStartTimeUs: MutableList<CuesWithTiming>? =\r\n            if (outputOptions.startTimeUs != C.TIME_UNSET && outputOptions.outputAllCues)\r\n                ArrayList<CuesWithTiming>()\r\n            else\r\n                null\r\n        var currentLine: String?\r\n        while ((parsableByteArray.readLine(charset).also { currentLine = it }) != null) {\r\n            if (currentLine!!.isEmpty()) {\r\n                // Skip blank lines.\r\n                continue\r\n            }\r\n\r\n            // Parse and check the index line.\r\n            try {\r\n                currentLine.toInt()\r\n            } catch (_: NumberFormatException) {\r\n                Log.w(TAG, \"Skipping invalid index: $currentLine\")\r\n                continue\r\n            }\r\n\r\n            // Read and parse the timing line.\r\n            currentLine = parsableByteArray.readLine(charset)\r\n            if (currentLine == null) {\r\n                Log.w(TAG, \"Unexpected end\")\r\n                break\r\n            }\r\n\r\n            val startTimeUs: Long\r\n            val endTimeUs: Long\r\n            val matcher = SUBRIP_TIMING_LINE.matcher(currentLine)\r\n            if (matcher.matches()) {\r\n                startTimeUs = parseTimecode(matcher,  /* groupOffset= */1)\r\n                endTimeUs = parseTimecode(matcher,  /* groupOffset= */6)\r\n            } else {\r\n                Log.w(TAG, \"Skipping invalid timing: $currentLine\")\r\n                continue\r\n            }\r\n\r\n            // Read and parse the text and tags.\r\n            textBuilder.setLength(0)\r\n            tags.clear()\r\n            currentLine = parsableByteArray.readLine(charset)\r\n            while (!TextUtils.isEmpty(currentLine)) {\r\n                if (textBuilder.isNotEmpty()) {\r\n                    textBuilder.append(\"<br>\")\r\n                }\r\n                textBuilder.append(processLine(currentLine!!, tags))\r\n                currentLine = parsableByteArray.readLine(charset)\r\n            }\r\n\r\n            val text = Html.fromHtml(textBuilder.toString())\r\n\r\n            var alignmentTag: String? = null\r\n            for (i in tags.indices) {\r\n                val tag = tags[i]\r\n                if (tag.matches(SUBRIP_ALIGNMENT_TAG.toRegex())) {\r\n                    alignmentTag = tag\r\n                    // Subsequent alignment tags should be ignored.\r\n                    break\r\n                }\r\n            }\r\n            if (outputOptions.startTimeUs == C.TIME_UNSET || endTimeUs >= outputOptions.startTimeUs) {\r\n                output.accept(\r\n                    CuesWithTiming(\r\n                        ImmutableList.of<Cue>(buildCue(text, alignmentTag)),\r\n                        startTimeUs,  /* durationUs= */\r\n                        endTimeUs - startTimeUs\r\n                    )\r\n                )\r\n            } else cuesWithTimingBeforeRequestedStartTimeUs?.add(\r\n                CuesWithTiming(\r\n                    ImmutableList.of<Cue>(buildCue(text, alignmentTag)),\r\n                    startTimeUs,  /* durationUs= */\r\n                    endTimeUs - startTimeUs\r\n                )\r\n            )\r\n        }\r\n        if (cuesWithTimingBeforeRequestedStartTimeUs != null) {\r\n            for (cuesWithTiming in cuesWithTimingBeforeRequestedStartTimeUs) {\r\n                output.accept(cuesWithTiming)\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Determine UTF encoding of the byte array from a byte order mark (BOM), defaulting to UTF-8 if\r\n     * no BOM is found.\r\n     */\r\n    private fun detectUtfCharset(data: ParsableByteArray): Charset {\r\n        val charset = data.readUtfCharsetFromBom()\r\n        return charset ?: StandardCharsets.UTF_8\r\n    }\r\n\r\n    /**\r\n     * Trims and removes tags from the given line. The removed tags are added to `tags`.\r\n     *\r\n     * @param line The line to process.\r\n     * @param tags A list to which removed tags will be added.\r\n     * @return The processed line.\r\n     */\r\n    private fun processLine(line: String, tags: ArrayList<String>): String {\r\n        var line = line\r\n        line = line.trim { it <= ' ' }\r\n\r\n        var removedCharacterCount = 0\r\n        val processedLine = StringBuilder(line)\r\n        val matcher = SUBRIP_TAG_PATTERN.matcher(line)\r\n        while (matcher.find()) {\r\n            val tag = matcher.group()\r\n            tags.add(tag)\r\n            val start = matcher.start() - removedCharacterCount\r\n            val tagLength = tag.length\r\n            processedLine.replace(start,  /* end= */start + tagLength,  /* str= */\"\")\r\n            removedCharacterCount += tagLength\r\n        }\r\n\r\n        return processedLine.toString()\r\n    }\r\n\r\n    /**\r\n     * Build a [Cue] based on the given text and alignment tag.\r\n     *\r\n     * @param text The text.\r\n     * @param alignmentTag The alignment tag, or `null` if no alignment tag is available.\r\n     * @return Built cue\r\n     */\r\n    private fun buildCue(text: Spanned, alignmentTag: String?): Cue {\r\n        val cue = Cue.Builder().setText(text)\r\n        if (alignmentTag == null) {\r\n            return cue.build()\r\n        }\r\n\r\n        // Horizontal alignment.\r\n        when (alignmentTag) {\r\n            ALIGN_BOTTOM_LEFT, ALIGN_MID_LEFT, ALIGN_TOP_LEFT -> cue.setPositionAnchor(Cue.ANCHOR_TYPE_START)\r\n            ALIGN_BOTTOM_RIGHT, ALIGN_MID_RIGHT, ALIGN_TOP_RIGHT -> cue.setPositionAnchor(Cue.ANCHOR_TYPE_END)\r\n            ALIGN_BOTTOM_MID, ALIGN_MID_MID, ALIGN_TOP_MID -> cue.setPositionAnchor(Cue.ANCHOR_TYPE_MIDDLE)\r\n            else -> cue.setPositionAnchor(Cue.ANCHOR_TYPE_MIDDLE)\r\n        }\r\n\r\n        // Vertical alignment.\r\n        when (alignmentTag) {\r\n            ALIGN_BOTTOM_LEFT, ALIGN_BOTTOM_MID, ALIGN_BOTTOM_RIGHT -> cue.setLineAnchor(Cue.ANCHOR_TYPE_END)\r\n            ALIGN_TOP_LEFT, ALIGN_TOP_MID, ALIGN_TOP_RIGHT -> cue.setLineAnchor(Cue.ANCHOR_TYPE_START)\r\n            ALIGN_MID_LEFT, ALIGN_MID_MID, ALIGN_MID_RIGHT -> cue.setLineAnchor(Cue.ANCHOR_TYPE_MIDDLE)\r\n            else -> cue.setLineAnchor(Cue.ANCHOR_TYPE_MIDDLE)\r\n        }\r\n\r\n        return cue.setPosition(getFractionalPositionForAnchorType(cue.getPositionAnchor()))\r\n            .setLine(\r\n                getFractionalPositionForAnchorType(cue.getLineAnchor()),\r\n                Cue.LINE_TYPE_FRACTION\r\n            )\r\n            .build()\r\n    }\r\n\r\n    companion object {\r\n        /**\r\n         * The [CueReplacementBehavior] for consecutive [CuesWithTiming] emitted by this\r\n         * implementation.\r\n         */\r\n        const val CUE_REPLACEMENT_BEHAVIOR: @CueReplacementBehavior Int =\r\n            Format.CUE_REPLACEMENT_BEHAVIOR_MERGE\r\n\r\n        // Fractional positions for use when alignment tags are present.\r\n        private const val START_FRACTION = 0.08f\r\n        private const val END_FRACTION = 1 - START_FRACTION\r\n        private const val MID_FRACTION = 0.5f\r\n\r\n        private const val TAG = \"SubripParser\"\r\n\r\n        // The google devs are useless, this entire class is just to override this\r\n        private const val SUBRIP_TIMECODE = \"(?:(\\\\d+):)?(\\\\d+):(\\\\d+)(?:[,.](\\\\d+))?\"\r\n        private val SUBRIP_TIMING_LINE: Pattern =\r\n            Pattern.compile(\"\\\\s*($SUBRIP_TIMECODE)\\\\s*-->\\\\s*($SUBRIP_TIMECODE)\\\\s*\")\r\n\r\n        // NOTE: Android Studio's suggestion to simplify '\\\\}' is incorrect [internal: b/144480183].\r\n        private val SUBRIP_TAG_PATTERN: Pattern = Pattern.compile(\"\\\\{\\\\\\\\.*?\\\\}\")\r\n        private const val SUBRIP_ALIGNMENT_TAG = \"\\\\{\\\\\\\\an[1-9]\\\\}\"\r\n\r\n        // Alignment tags for SSA V4+.\r\n        private const val ALIGN_BOTTOM_LEFT = \"{\\\\an1}\"\r\n        private const val ALIGN_BOTTOM_MID = \"{\\\\an2}\"\r\n        private const val ALIGN_BOTTOM_RIGHT = \"{\\\\an3}\"\r\n        private const val ALIGN_MID_LEFT = \"{\\\\an4}\"\r\n        private const val ALIGN_MID_MID = \"{\\\\an5}\"\r\n        private const val ALIGN_MID_RIGHT = \"{\\\\an6}\"\r\n        private const val ALIGN_TOP_LEFT = \"{\\\\an7}\"\r\n        private const val ALIGN_TOP_MID = \"{\\\\an8}\"\r\n        private const val ALIGN_TOP_RIGHT = \"{\\\\an9}\"\r\n\r\n        private fun parseTimecode(matcher: Matcher, groupOffset: Int): Long {\r\n            val hours = matcher.group(groupOffset + 1)\r\n            var timestampMs = if (hours != null) hours.toLong() * 60 * 60 * 1000 else 0\r\n            timestampMs +=\r\n                Assertions.checkNotNull<String?>(matcher.group(groupOffset + 2))\r\n                    .toLong() * 60 * 1000\r\n            timestampMs += Assertions.checkNotNull<String?>(matcher.group(groupOffset + 3))\r\n                .toLong() * 1000\r\n            val millis = matcher.group(groupOffset + 4)\r\n\r\n            timestampMs += when (millis?.length) {\r\n                null -> 0L\r\n                1 -> millis.toLong() * 100L\r\n                2 -> millis.toLong() * 10L\r\n                3 -> millis.toLong() * 1L\r\n                else -> millis.substring(0, 3).toLong()\r\n            }\r\n\r\n            return timestampMs * 1000\r\n        }\r\n\r\n        // TODO(b/289983417): Make package-private again, once it is no longer needed in\r\n        // DelegatingSubtitleDecoderWithSubripParserTest.java (i.e. legacy subtitle flow is removed)\r\n        @VisibleForTesting(otherwise = VisibleForTesting.Companion.PRIVATE)\r\n        fun getFractionalPositionForAnchorType(anchorType: @AnchorType Int): Float {\r\n            return when (anchorType) {\r\n                Cue.ANCHOR_TYPE_START -> START_FRACTION\r\n                Cue.ANCHOR_TYPE_MIDDLE -> MID_FRACTION\r\n                Cue.ANCHOR_TYPE_END -> END_FRACTION\r\n                Cue.TYPE_UNSET ->         // Should never happen.\r\n                    throw IllegalArgumentException()\r\n\r\n                else ->\r\n                    throw IllegalArgumentException()\r\n            }\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.content.Context\nimport android.text.Layout\nimport android.util.Log\nimport androidx.annotation.OptIn\nimport androidx.media3.common.Format\nimport androidx.media3.common.MimeTypes\nimport androidx.media3.common.text.Cue\nimport androidx.media3.common.util.Consumer\nimport androidx.media3.common.util.UnstableApi\nimport androidx.media3.exoplayer.text.SubtitleDecoderFactory\nimport androidx.media3.extractor.text.CuesWithTiming\nimport androidx.media3.extractor.text.SimpleSubtitleDecoder\nimport androidx.media3.extractor.text.Subtitle\nimport androidx.media3.extractor.text.SubtitleDecoder\nimport androidx.media3.extractor.text.SubtitleParser\nimport androidx.media3.extractor.text.dvb.DvbParser\nimport androidx.media3.extractor.text.pgs.PgsParser\nimport androidx.media3.extractor.text.ssa.SsaParser\nimport androidx.media3.extractor.text.ttml.TtmlParser\nimport androidx.media3.extractor.text.tx3g.Tx3gParser\nimport androidx.media3.extractor.text.webvtt.Mp4WebvttParser\nimport androidx.media3.extractor.text.webvtt.WebvttParser\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle\nimport com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment\nimport org.mozilla.universalchardet.UniversalDetector\nimport java.lang.ref.WeakReference\nimport java.nio.charset.Charset\n\n/**\n * @param fallbackFormat used to create a decoder based on mimetype if the subtitle string is not\n * enough to identify the subtitle format.\n */\n@OptIn(UnstableApi::class)\nclass CustomDecoder(private val fallbackFormat: Format?) : SubtitleParser {\n    companion object {\n        fun updateForcedEncoding(context: Context) {\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)\n            val value = settingsManager.getString(\n                context.getString(R.string.subtitles_encoding_key),\n                null\n            )\n            overrideEncoding = if (value.isNullOrBlank()) {\n                null\n            } else {\n                value\n            }\n        }\n\n        private const val DEFAULT_MARGIN: Float = 0.05f\n        const val SSA_ALIGNMENT_BOTTOM_LEFT = 1\n        const val SSA_ALIGNMENT_BOTTOM_CENTER = 2\n        const val SSA_ALIGNMENT_BOTTOM_RIGHT = 3\n        const val SSA_ALIGNMENT_MIDDLE_LEFT = 4\n        const val SSA_ALIGNMENT_MIDDLE_CENTER = 5\n        const val SSA_ALIGNMENT_MIDDLE_RIGHT = 6\n        const val SSA_ALIGNMENT_TOP_LEFT = 7\n        const val SSA_ALIGNMENT_TOP_CENTER = 8\n        const val SSA_ALIGNMENT_TOP_RIGHT = 9\n\n        /** Subtitle offset in milliseconds */\n        var subtitleOffset: Long = 0\n        private const val UTF_8 = \"UTF-8\"\n        private const val TAG = \"CustomDecoder\"\n        private var overrideEncoding: String? = null\n        val style: SaveCaptionStyle get() = SubtitlesFragment.getCurrentSavedStyle()\n        private val locationRegex = Regex(\"\"\"\\{\\\\an(\\d+)\\}\"\"\", RegexOption.IGNORE_CASE)\n        val bloatRegex =\n            listOf(\n                Regex(\n                    \"\"\"Support\\s+us\\s+and\\s+become\\s+VIP\\s+member\\s+to\\s+remove\\s+all\\s+ads\\s+from\\s+(www\\.|)OpenSubtitles(\\.org|)\"\"\",\n                    RegexOption.IGNORE_CASE\n                ),\n                Regex(\n                    \"\"\"Please\\s+rate\\s+this\\s+subtitle\\s+at\\s+.*\\s+Help\\s+other\\s+users\\s+to\\s+choose\\s+the\\s+best\\s+subtitles\"\"\",\n                    RegexOption.IGNORE_CASE\n                ),\n                Regex(\n                    \"\"\"Contact\\s(www\\.|)OpenSubtitles(\\.org|)\\s+today\"\"\",\n                    RegexOption.IGNORE_CASE\n                ),\n                Regex(\n                    \"\"\"Advertise\\s+your\\s+product\\s+or\\s+brand\\s+here\"\"\",\n                    RegexOption.IGNORE_CASE\n                ),\n            )\n\n        //https://emptycharacter.com/\n        //https://www.fileformat.info/info/unicode/char/200b/index.htm\n        fun trimStr(string: String): String {\n            return string.trimStart().trim('\\uFEFF', '\\u200B').replace(\n                Regex(\"[\\u00A0\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u205F]\"),\n                \" \"\n            )\n        }\n\n        private fun computeDefaultLineOrPosition(@Cue.AnchorType anchor: Int) = when (anchor) {\n            Cue.ANCHOR_TYPE_START -> DEFAULT_MARGIN\n            Cue.ANCHOR_TYPE_MIDDLE -> 0.5f\n            Cue.ANCHOR_TYPE_END -> 1.0f - DEFAULT_MARGIN\n            Cue.TYPE_UNSET -> Cue.DIMEN_UNSET\n            else -> Cue.DIMEN_UNSET\n        }\n\n        /**\n         * Fixes alignment for cues with {\\anX},\n         * this is common for .vtt that should be parsed as .srt\n         *\n         * ```\n         * WEBVTT\n         *\n         * 00:00.000 --> 00:01.000\n         * {\\an1}Label 1\n         *\n         * 00:01.000 --> 00:02.000\n         * {\\an2}Label 2\n         *\n         * 00:02.000 --> 00:03.000\n         * {\\an3}Label 3\n         *\n         * 00:03.000 --> 00:04.000\n         * {\\an4}Label 4\n         *\n         * 00:04.000 --> 00:05.000\n         * {\\an5}Label 5\n         *\n         * 00:05.000 --> 00:06.000\n         * {\\an6}Label 6\n         *\n         * 00:06.000 --> 00:07.000\n         * {\\an7}Label 7\n         *\n         * 00:07.000 --> 00:08.000\n         * {\\an8}Label 8\n         *\n         * 00:08.000 --> 00:09.000\n         * {\\an9}Label 9\n         * ```\n         */\n        fun Cue.Builder.fixSubtitleAlignment(): Cue.Builder {\n            var trimmed = text?.trim() ?: return this\n            // https://github.com/androidx/media/blob/main/libraries/extractor/src/main/java/androidx/media3/extractor/text/ssa/SsaStyle.java\n            // exoplayer can already parse this, however for eg webvtt it fails\n            locationRegex.find(trimmed)?.groupValues?.get(1)?.toIntOrNull()?.let { alignment ->\n                // toLineAnchor\n                this.setSubtitleAlignment(alignment)\n            }\n\n            // remove all matches, so we do not display \\anx\n            trimmed = trimmed.replace(locationRegex, \"\")\n            setText(trimmed)\n            return this\n        }\n\n        fun Cue.Builder.setSubtitleAlignment(alignment: Int?): Cue.Builder {\n            if (alignment == null) return this\n            when (alignment) {\n                SSA_ALIGNMENT_BOTTOM_LEFT, SSA_ALIGNMENT_BOTTOM_CENTER, SSA_ALIGNMENT_BOTTOM_RIGHT -> Cue.ANCHOR_TYPE_END\n                SSA_ALIGNMENT_MIDDLE_LEFT, SSA_ALIGNMENT_MIDDLE_CENTER, SSA_ALIGNMENT_MIDDLE_RIGHT -> Cue.ANCHOR_TYPE_MIDDLE\n                SSA_ALIGNMENT_TOP_LEFT, SSA_ALIGNMENT_TOP_CENTER, SSA_ALIGNMENT_TOP_RIGHT -> Cue.ANCHOR_TYPE_START\n                else -> null\n            }?.let { anchor ->\n                setLineAnchor(anchor)\n                setLine(\n                    computeDefaultLineOrPosition(anchor), Cue.LINE_TYPE_FRACTION\n                )\n            }\n            // toPositionAnchor\n            when (alignment) {\n                SSA_ALIGNMENT_BOTTOM_LEFT, SSA_ALIGNMENT_MIDDLE_LEFT, SSA_ALIGNMENT_TOP_LEFT -> Cue.ANCHOR_TYPE_START\n                SSA_ALIGNMENT_BOTTOM_CENTER, SSA_ALIGNMENT_MIDDLE_CENTER, SSA_ALIGNMENT_TOP_CENTER -> Cue.ANCHOR_TYPE_MIDDLE\n                SSA_ALIGNMENT_BOTTOM_RIGHT, SSA_ALIGNMENT_MIDDLE_RIGHT, SSA_ALIGNMENT_TOP_RIGHT -> Cue.ANCHOR_TYPE_END\n                else -> null\n            }?.let { anchor ->\n                setPositionAnchor(anchor)\n                setPosition(computeDefaultLineOrPosition(anchor))\n            }\n\n            // toTextAlignment\n            when (alignment) {\n                SSA_ALIGNMENT_BOTTOM_LEFT, SSA_ALIGNMENT_MIDDLE_LEFT, SSA_ALIGNMENT_TOP_LEFT -> Layout.Alignment.ALIGN_NORMAL\n                SSA_ALIGNMENT_BOTTOM_CENTER, SSA_ALIGNMENT_MIDDLE_CENTER, SSA_ALIGNMENT_TOP_CENTER -> Layout.Alignment.ALIGN_CENTER\n                SSA_ALIGNMENT_BOTTOM_RIGHT, SSA_ALIGNMENT_MIDDLE_RIGHT, SSA_ALIGNMENT_TOP_RIGHT -> Layout.Alignment.ALIGN_OPPOSITE\n                else -> null\n            }?.let { anchor ->\n                setTextAlignment(anchor)\n            }\n            return this\n        }\n    }\n\n    private var realDecoder: SubtitleParser? = null\n\n    private fun getStr(byteArray: ByteArray): Pair<String, Charset> {\n        val encoding = try {\n            val encoding = overrideEncoding ?: run {\n                val detector = UniversalDetector()\n\n                detector.handleData(byteArray, 0, byteArray.size)\n                detector.dataEnd()\n\n                detector.detectedCharset // \"windows-1256\"\n            }\n\n            Log.i(\n                TAG,\n                \"Detected encoding with charset $encoding and override = $overrideEncoding\"\n            )\n            encoding ?: UTF_8\n        } catch (e: Exception) {\n            Log.e(TAG, \"Failed to detect encoding throwing error\")\n            logError(e)\n            UTF_8\n        }\n\n        return try {\n            val set = charset(encoding)\n            Pair(String(byteArray, set), set)\n        } catch (e: Exception) {\n            Log.e(TAG, \"Failed to parse using encoding $encoding\")\n            logError(e)\n            Pair(byteArray.decodeToString(), charset(UTF_8))\n        }\n    }\n\n    private fun getSubtitleParser(data: String): SubtitleParser? {\n        // This way we read the subtitle file and decide what decoder to use instead of relying fully on mimetype\n\n        // First we remove all invisible characters at the start, this is an issue in some subtitle files\n        // Cntrl is control characters: https://en.wikipedia.org/wiki/Unicode_control_characters\n        // Cf is formatting characters: https://www.compart.com/en/unicode/category/Cf\n        val controlCharsRegex = Regex(\"\"\"[\\p{Cntrl}\\p{Cf}]\"\"\")\n        val trimmedText =\n            data.trimStart { it.isWhitespace() || controlCharsRegex.matches(it.toString()) }\n\n        //https://github.com/LagradOst/CloudStream-2/blob/ddd774ee66810137ff7bd65dae70bcf3ba2d2489/CloudStreamForms/CloudStreamForms/Script/MainChrome.cs#L388\n        val subtitleParser = when {\n            // \"WEBVTT\" can be hidden behind invisible characters not filtered by trim\n            trimmedText.substring(0, 10).contains(\"WEBVTT\", ignoreCase = true) -> WebvttParser()\n            trimmedText.startsWith(\"<?xml version=\\\"\", ignoreCase = true) -> TtmlParser()\n            (trimmedText.startsWith(\n                \"[Script Info]\",\n                ignoreCase = true\n            ) || trimmedText.startsWith(\n                \"Title:\",\n                ignoreCase = true\n            )) -> SsaParser(fallbackFormat?.initializationData)\n\n            trimmedText.startsWith(\"1\", ignoreCase = true) -> CustomSubripParser()\n            fallbackFormat != null -> {\n                when (fallbackFormat.sampleMimeType) {\n                    MimeTypes.TEXT_VTT -> WebvttParser()\n                    MimeTypes.TEXT_SSA -> SsaParser(fallbackFormat.initializationData)\n                    MimeTypes.APPLICATION_MP4VTT -> Mp4WebvttParser()\n                    MimeTypes.APPLICATION_TTML -> TtmlParser()\n                    MimeTypes.APPLICATION_SUBRIP -> CustomSubripParser()\n                    MimeTypes.APPLICATION_TX3G -> Tx3gParser(fallbackFormat.initializationData)\n                    // These decoders are not converted to parsers yet\n                    // TODO\n//                            MimeTypes.APPLICATION_CEA608, MimeTypes.APPLICATION_MP4CEA608 -> Cea608Decoder(\n//                                mimeType,\n//                                fallbackFormat.accessibilityChannel,\n//                                Cea608Decoder.MIN_DATA_CHANNEL_TIMEOUT_MS\n//                            )\n//                            MimeTypes.APPLICATION_CEA708 -> Cea708Decoder(\n//                                fallbackFormat.accessibilityChannel,\n//                                fallbackFormat.initializationData\n//                            )\n                    MimeTypes.APPLICATION_DVBSUBS -> DvbParser(fallbackFormat.initializationData)\n                    MimeTypes.APPLICATION_PGS -> PgsParser()\n                    else -> null\n                }\n            }\n\n            else -> null\n        }\n        return subtitleParser\n    }\n\n    val currentSubtitleCues = mutableListOf<SubtitleCue>()\n\n\n    override fun parse(\n        data: ByteArray,\n        offset: Int,\n        length: Int,\n        outputOptions: SubtitleParser.OutputOptions,\n        output: Consumer<CuesWithTiming>\n    ) {\n        val currentStyle = style\n        val customOutput = Consumer<CuesWithTiming> { cue ->\n            val newCue =\n                CuesWithTiming(cue.cues, cue.startTimeUs, cue.durationUs)\n\n            // Do not apply the offset to the currentSubtitleCues as those are then used for sync subs\n            currentSubtitleCues.add(\n                SubtitleCue(\n                    newCue.startTimeUs / 1000,\n                    newCue.durationUs / 1000,\n                    newCue.cues.map { it.text.toString() })\n            )\n\n            // offset timing for the final\n            val updatedCues =\n                CuesWithTiming(\n                    newCue.cues,\n                    newCue.startTimeUs - subtitleOffset.times(1000),\n                    newCue.durationUs\n                )\n\n            output.accept(updatedCues)\n        }\n        Log.i(TAG, \"Parse subtitle, current parser: $realDecoder\")\n        try {\n            val inputString = getStr(data).first\n            Log.i(TAG, \"Subtitle preview: ${inputString.substring(0, 30)}\")\n            if (inputString.isNotBlank()) {\n                var str: String = trimStr(inputString)\n                realDecoder = realDecoder ?: getSubtitleParser(inputString)\n                Log.i(\n                    TAG,\n                    \"Parser selected: $realDecoder\"\n                )\n                realDecoder?.let { decoder ->\n                    if (decoder !is SsaParser) {\n                        if (currentStyle.removeBloat)\n                            bloatRegex.forEach { rgx ->\n                                str = str.replace(rgx, \"\\n\")\n                            }\n                        if (currentStyle.upperCase) {\n                            str = str.uppercase()\n                        }\n                    }\n                }\n                val array = str.toByteArray()\n                realDecoder?.parse(\n                    array,\n                    minOf(array.size, offset),\n                    minOf(array.size, length),\n                    outputOptions,\n                    customOutput\n                )\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    override fun getCueReplacementBehavior(): Int {\n        // CUE_REPLACEMENT_BEHAVIOR_REPLACE seems most compatible, change if required\n        return realDecoder?.cueReplacementBehavior ?: Format.CUE_REPLACEMENT_BEHAVIOR_REPLACE\n    }\n\n    override fun reset() {\n        currentSubtitleCues.clear()\n        super.reset()\n    }\n}\n\n/** See https://github.com/google/ExoPlayer/blob/release-v2/library/core/src/main/java/com/google/android/exoplayer2/text/SubtitleDecoderFactory.java */\n@OptIn(UnstableApi::class)\nclass CustomSubtitleDecoderFactory : SubtitleDecoderFactory {\n\n    override fun supportsFormat(format: Format): Boolean {\n        return listOf(\n            MimeTypes.TEXT_VTT,\n            MimeTypes.TEXT_SSA,\n            MimeTypes.APPLICATION_TTML,\n            MimeTypes.APPLICATION_MP4VTT,\n            MimeTypes.APPLICATION_SUBRIP,\n            MimeTypes.APPLICATION_TX3G,\n            //MimeTypes.APPLICATION_CEA608,\n            //MimeTypes.APPLICATION_MP4CEA608,\n            //MimeTypes.APPLICATION_CEA708,\n            MimeTypes.APPLICATION_DVBSUBS,\n            MimeTypes.APPLICATION_PGS,\n            //MimeTypes.TEXT_EXOPLAYER_CUES\n        ).contains(format.sampleMimeType)\n    }\n\n    private var latestDecoder: WeakReference<CustomDecoder>? = null\n\n    fun getSubtitleCues(): List<SubtitleCue>? {\n        return latestDecoder?.get()?.currentSubtitleCues\n    }\n\n    /**\n     * Decoders created here persists across reset()\n     * Do not save state in the decoder which you want to reset (e.g subtitle offset)\n     */\n    override fun createDecoder(format: Format): SubtitleDecoder {\n        val parser = CustomDecoder(format)\n        // Allow garbage collection if player releases the decoder\n        latestDecoder = WeakReference(parser)\n\n        return DelegatingSubtitleDecoder(\n            parser::class.simpleName + \"Decoder\", parser\n        )\n    }\n}\n\n/** We need to convert the newer SubtitleParser to an older SubtitleDecoder */\n@OptIn(UnstableApi::class)\nclass DelegatingSubtitleDecoder(name: String, private val parser: SubtitleParser) :\n    SimpleSubtitleDecoder(name) {\n\n    override fun decode(data: ByteArray, length: Int, reset: Boolean): Subtitle {\n        if (reset) {\n            parser.reset()\n        }\n        return parser.parseToLegacySubtitle(data, 0, length);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadFileGenerator.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.net.Uri\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.context\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromLanguageToTagIETF\nimport com.lagradost.cloudstream3.utils.SubtitleUtils.cleanDisplayName\nimport com.lagradost.cloudstream3.utils.SubtitleUtils.isMatchingSubtitle\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getFolder\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getDownloadFileInfo\n\nclass DownloadFileGenerator(\n    episodes: List<ExtractorUri>,\n    currentIndex: Int = 0\n) : VideoGenerator<ExtractorUri>(episodes, currentIndex) {\n    override val hasCache = false\n    override val canSkipLoading = false\n\n    override suspend fun generateLinks(\n        clearCache: Boolean,\n        sourceTypes: Set<ExtractorLinkType>,\n        callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,\n        subtitleCallback: (SubtitleData) -> Unit,\n        offset: Int,\n        isCasting: Boolean\n    ): Boolean {\n        val meta = getCurrent(offset) ?: return false\n\n        if (meta.uri == Uri.EMPTY) {\n            // We do this here so that we only load it when\n            // we actually need it as it can be more expensive.\n            val info = meta.id?.let { id ->\n                activity?.let { act ->\n                    getDownloadFileInfo(act, id)\n                }\n            }\n\n            if (info != null) {\n                val newMeta = meta.copy(uri = info.path)\n                callback(null to newMeta)\n            } else callback(null to meta)\n        } else callback(null to meta)\n\n        val ctx = context ?: return true\n        val relative = meta.relativePath ?: return true\n        val display = meta.displayName ?: return true\n\n        val cleanDisplay = cleanDisplayName(display)\n\n        getFolder(ctx, relative, meta.basePath)?.forEach { (name, uri) ->\n            if (isMatchingSubtitle(name, display, cleanDisplay)) {\n                val cleanName = cleanDisplayName(name)\n                val lastNum = Regex(\" ([0-9]+)$\")\n                val nameSuffix = lastNum.find(cleanName)?.groupValues?.get(1) ?: \"\"\n                val originalName = cleanName.removePrefix(cleanDisplay).replace(lastNum, \"\").trim()\n\n                subtitleCallback(\n                    SubtitleData(\n                        originalName.ifBlank { ctx.getString(R.string.default_subtitles) },\n                        nameSuffix,\n                        uri.toString(),\n                        SubtitleOrigin.DOWNLOADED_FILE,\n                        name.toSubtitleMimeType(),\n                        emptyMap(),\n                        fromLanguageToTagIETF(originalName, true)\n                    )\n                )\n            }\n        }\n\n        return true\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadedPlayerActivity.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.KeyEvent\nimport androidx.appcompat.app.AppCompatActivity\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.ui.player.OfflinePlaybackHelper.playLink\nimport com.lagradost.cloudstream3.ui.player.OfflinePlaybackHelper.playUri\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.UIHelper.enableEdgeToEdgeCompat\n\nclass DownloadedPlayerActivity : AppCompatActivity() {\n    private val dTAG = \"DownloadedPlayerAct\"\n\n    override fun dispatchKeyEvent(event: KeyEvent): Boolean =\n        CommonActivity.dispatchKeyEvent(this, event) ?: super.dispatchKeyEvent(event)\n\n    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean =\n        CommonActivity.onKeyDown(this, keyCode, event) ?: super.onKeyDown(keyCode, event)\n\n    override fun onUserLeaveHint() {\n        super.onUserLeaveHint()\n        CommonActivity.onUserLeaveHint(this)\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        CommonActivity.loadThemes(this)\n        CommonActivity.init(this)\n        enableEdgeToEdgeCompat()\n        setContentView(R.layout.empty_layout)\n        Log.i(dTAG, \"onCreate\")\n\n        val data = intent.data\n\n        if (OfflinePlaybackHelper.playIntent(activity = this, intent = intent)) {\n            return\n        }\n\n        if (intent?.action == Intent.ACTION_SEND || intent?.action == Intent.ACTION_OPEN_DOCUMENT || intent?.action == Intent.ACTION_VIEW) {\n            val extraText = safe { // I dont trust android\n                intent.getStringExtra(Intent.EXTRA_TEXT)\n            }\n            val cd = intent.clipData\n            val item = if (cd != null && cd.itemCount > 0) cd.getItemAt(0) else null\n            val url = item?.text?.toString()\n\n            // idk what I am doing, just hope any of these work\n            if (item?.uri != null)\n                playUri(this, item.uri)\n            else if (url != null)\n                playLink(this, url)\n            else if (data != null)\n                playUri(this, data)\n            else if (extraText != null)\n                playLink(this, extraText)\n            else {\n                finish()\n                return\n            }\n        } else if (data?.scheme == \"content\") {\n            playUri(this, data)\n        } else {\n            finish()\n            return\n        }\n\n        attachBackPressedCallback(\"DownloadedPlayerActivity\") { finish() }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        CommonActivity.setActivityInstance(this)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/ExtractorLinkGenerator.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\n\nclass ExtractorLinkGenerator(\n    private val links: List<ExtractorLink>,\n    private val subtitles: List<SubtitleData>,\n) : NoVideoGenerator() {\n    override suspend fun generateLinks(\n        clearCache: Boolean,\n        sourceTypes: Set<ExtractorLinkType>,\n        callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,\n        subtitleCallback: (SubtitleData) -> Unit,\n        offset: Int,\n        isCasting: Boolean\n    ): Boolean {\n        subtitles.forEach(subtitleCallback)\n        links.forEach {\n            if(sourceTypes.contains(it.type)) {\n                callback.invoke(it to null)\n            }\n        }\n\n        return true\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/FixedNextRenderersFactory.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\r\n\r\nimport android.content.Context\r\nimport android.os.Looper\r\nimport androidx.media3.common.util.UnstableApi\r\nimport androidx.media3.exoplayer.Renderer\r\nimport androidx.media3.exoplayer.text.TextOutput\r\nimport androidx.media3.exoplayer.text.TextRenderer\r\nimport io.github.anilbeesetti.nextlib.media3ext.ffdecoder.NextRenderersFactory\r\n\r\n@UnstableApi\r\nclass FixedNextRenderersFactory(context: Context) : NextRenderersFactory(context) {\r\n    /** Somehow the nextlib authors decided that we need a text renderer that causes\r\n     * \"ERROR_CODE_FAILED_RUNTIME_CHECK\".\r\n     *\r\n     * Core issue: https://github.com/anilbeesetti/nextlib/pull/158\r\n     * Comment: https://github.com/recloudstream/cloudstream/pull/2342#issuecomment-3917751718\r\n     * */\r\n    override fun buildTextRenderers(\r\n        context: Context,\r\n        output: TextOutput,\r\n        outputLooper: Looper,\r\n        extensionRendererMode: Int,\r\n        out: ArrayList<Renderer>\r\n    ) {\r\n        out.add(TextRenderer(output, outputLooper))\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.animation.ObjectAnimator\nimport android.animation.ValueAnimator\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.app.Dialog\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.content.pm.ActivityInfo\nimport android.content.res.ColorStateList\nimport android.content.res.Configuration\nimport android.graphics.Color\nimport android.graphics.Matrix\nimport android.media.AudioManager\nimport android.media.audiofx.LoudnessEnhancer\nimport android.os.Build\nimport android.os.Bundle\nimport android.os.Handler\nimport android.os.Looper\nimport android.provider.Settings\nimport android.text.Editable\nimport android.text.format.DateUtils\nimport android.view.KeyEvent\nimport android.view.LayoutInflater\nimport android.view.MotionEvent\nimport android.view.ScaleGestureDetector\nimport android.view.Surface\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.WindowInsets\nimport android.view.WindowManager\nimport android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES\nimport android.view.animation.AccelerateDecelerateInterpolator\nimport android.view.animation.AlphaAnimation\nimport android.view.animation.Animation\nimport android.view.animation.AnimationUtils\nimport android.widget.LinearLayout\nimport androidx.annotation.OptIn\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.ContextCompat\nimport androidx.core.graphics.blue\nimport androidx.core.graphics.green\nimport androidx.core.graphics.red\nimport androidx.core.view.children\nimport androidx.core.view.isGone\nimport androidx.core.view.isInvisible\nimport androidx.core.view.isVisible\nimport androidx.core.widget.doOnTextChanged\nimport androidx.media3.common.MimeTypes\nimport androidx.media3.common.util.UnstableApi\nimport androidx.media3.exoplayer.ExoPlayer\nimport androidx.media3.ui.AspectRatioFrameLayout\nimport androidx.preference.PreferenceManager\nimport androidx.recyclerview.widget.SimpleItemAnimator\nimport com.google.android.material.button.MaterialButton\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.CommonActivity.keyEventListener\nimport com.lagradost.cloudstream3.CommonActivity.playerEventListener\nimport com.lagradost.cloudstream3.CommonActivity.screenHeightWithOrientation\nimport com.lagradost.cloudstream3.CommonActivity.screenWidthWithOrientation\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.PlayerCustomLayoutBinding\nimport com.lagradost.cloudstream3.databinding.SpeedDialogBinding\nimport com.lagradost.cloudstream3.databinding.SubtitleOffsetBinding\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.ui.player.GeneratorPlayer.Companion.subsProvidersIsActive\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isUsingMobileData\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.getNavigationBarHeight\nimport com.lagradost.cloudstream3.utils.UIHelper.getStatusBarHeight\nimport com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI\nimport com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage\nimport com.lagradost.cloudstream3.utils.UIHelper.showSystemUI\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\nimport com.lagradost.cloudstream3.utils.UserPreferenceDelegate\nimport com.lagradost.cloudstream3.utils.Vector2\nimport com.lagradost.cloudstream3.utils.setText\nimport com.lagradost.cloudstream3.utils.txt\nimport kotlin.math.abs\nimport kotlin.math.absoluteValue\nimport kotlin.math.ceil\nimport kotlin.math.max\nimport kotlin.math.min\nimport kotlin.math.round\nimport kotlin.math.roundToInt\n\n// You can zoom out more than 100%, but it will zoom back into 100%\nconst val MINIMUM_ZOOM = 0.95f\n\n// How sensitive the auto zoom is to center at the min zoom\nconst val ZOOM_SNAP_SENSITIVITY = 0.07f\n\n// Maximum zoom to avoid getting lost\nconst val MAXIMUM_ZOOM = 4.0f\n\nconst val MINIMUM_SEEK_TIME = 7000L         // when swipe seeking\nconst val MINIMUM_VERTICAL_SWIPE = 2.0f     // in percentage\nconst val MINIMUM_HORIZONTAL_SWIPE = 2.0f   // in percentage\nconst val VERTICAL_MULTIPLIER = 2.0f\nconst val HORIZONTAL_MULTIPLIER = 2.0f\nconst val DOUBLE_TAB_MAXIMUM_HOLD_TIME = 200L\nconst val DOUBLE_TAB_MINIMUM_TIME_BETWEEN = 200L    // this also affects the UI show response time\nconst val DOUBLE_TAB_PAUSE_PERCENTAGE = 0.15        // in both directions\nprivate const val SUBTITLE_DELAY_BUNDLE_KEY = \"subtitle_delay\"\n\n// All the UI Logic for the player\n@OptIn(UnstableApi::class)\nopen class FullScreenPlayer : AbstractPlayerFragment() {\n    private var isVerticalOrientation: Boolean = false\n    protected open var lockRotation = true\n    protected open var isFullScreenPlayer = true\n    protected var playerBinding: PlayerCustomLayoutBinding? = null\n    protected var brightnessOverlay: View? = null\n\n    private var durationMode: Boolean by UserPreferenceDelegate(\"duration_mode\", false)\n\n    // state of player UI\n    protected var isShowing = false\n    private var uiShowingBeforeGesture = false\n    protected var isLocked = false\n    protected var timestampShowState = false\n\n    protected var hasEpisodes = false\n        private set\n    // protected val hasEpisodes\n    //    get() = episodes.isNotEmpty()\n\n    // options for player\n\n    /**\n     * Default profile 1\n     * Decides how links should be sorted based on a priority system.\n     * This will be set in runtime based on settings.\n     **/\n    protected var currentQualityProfile = 1\n\n    //    protected var currentPrefQuality =\n//        Qualities.P2160.value // preferred maximum quality, used for ppl w bad internet or on cell\n    protected var extraBrightnessEnabled = false\n    protected var fastForwardTime = 10000L\n    protected var androidTVInterfaceOffSeekTime = 10000L\n    protected var androidTVInterfaceOnSeekTime = 30000L\n    protected var swipeHorizontalEnabled = false\n    protected var swipeVerticalEnabled = false\n    protected var playBackSpeedEnabled = false\n    protected var playerResizeEnabled = false\n    protected var doubleTapEnabled = false\n    protected var doubleTapPauseEnabled = true\n    protected var playerRotateEnabled = false\n    protected var rotatedManually = false\n    protected var autoPlayerRotateEnabled = false\n    private var hideControlsNames = false\n    protected var speedupEnabled = false\n    protected var subtitleDelay\n        set(value) = try {\n            player.setSubtitleOffset(-value)\n        } catch (e: Exception) {\n            logError(e)\n        }\n        get() = try {\n            -player.getSubtitleOffset()\n        } catch (e: Exception) {\n            logError(e)\n            0L\n        }\n\n    // private var useSystemBrightness = false\n    protected var useTrueSystemBrightness = true\n    private val fullscreenNotch = true // TODO SETTING\n\n    private var statusBarHeight: Int? = null\n    private var navigationBarHeight: Int? = null\n\n    private val brightnessIcons = listOf(\n        R.drawable.sun_1,\n        R.drawable.sun_2,\n        R.drawable.sun_3,\n        R.drawable.sun_4,\n        R.drawable.sun_5,\n        R.drawable.sun_6,\n        R.drawable.sun_7,\n        // R.drawable.ic_baseline_brightness_1_24,\n        // R.drawable.ic_baseline_brightness_2_24,\n        // R.drawable.ic_baseline_brightness_3_24,\n        // R.drawable.ic_baseline_brightness_4_24,\n        // R.drawable.ic_baseline_brightness_5_24,\n        // R.drawable.ic_baseline_brightness_6_24,\n        // R.drawable.ic_baseline_brightness_7_24,\n    )\n\n    private val volumeIcons = listOf(\n        R.drawable.ic_baseline_volume_mute_24,\n        R.drawable.ic_baseline_volume_down_24,\n        R.drawable.ic_baseline_volume_up_24,\n    )\n\n    private var isShowingEpisodeOverlay: Boolean = false\n    private var previousPlayStatus: Boolean = false\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? {\n        val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null\n        playerBinding = PlayerCustomLayoutBinding.bind(root.findViewById(R.id.player_holder))\n\n        // Inject the overlay from a separate XML into the PlayerView content frame\n        safe {\n            val pv = root.findViewById<androidx.media3.ui.PlayerView>(R.id.player_view)\n            val packageName = context?.packageName ?: return@safe\n            val contentId = resources.getIdentifier(\"exo_content_frame\", \"id\", packageName)\n            val contentFrame = pv?.findViewById<ViewGroup>(contentId)\n            if (contentFrame != null) {\n                brightnessOverlay = contentFrame.findViewById<View>(R.id.extra_brightness_overlay)\n                brightnessOverlay = LayoutInflater.from(context).inflate(\n                    R.layout.extra_brightness_overlay,\n                    contentFrame,\n                    false\n                )\n                contentFrame.addView(brightnessOverlay)\n                requestUpdateBrightnessOverlayOnNextLayout()\n            }\n        }\n\n        return root\n    }\n\n    @SuppressLint(\"UnsafeOptInUsageError\")\n    override fun playerUpdated(player: Any?) {\n        super.playerUpdated(player)\n    }\n\n    override fun onDestroyView() {\n        // Clean up brightness overlay if created\n        safe {\n            // remove overlay if present\n            brightnessOverlay?.let { overlay ->\n                val oParent = overlay.parent as? ViewGroup\n                oParent?.removeView(overlay)\n            }\n        }\n        brightnessOverlay = null\n        playerBinding = null\n        super.onDestroyView()\n    }\n\n    /**\n     * Resize/position the brightness overlay to exactly match the visible video surface.\n     * This copies the video surface size, scale and translation so the overlay won't cover\n     * letterbox/pillarbox areas when zooming or panning.\n     */\n    private fun updateBrightnessOverlayBounds() {\n        val overlay = brightnessOverlay ?: return\n        val pv = playerView ?: return\n        val video = pv.videoSurfaceView ?: return\n\n        // Compute accurate transformed bounding box of the video view after scale+translation\n        val vw = video.width.toFloat()\n        val vh = video.height.toFloat()\n        val sx = video.scaleX\n        val sy = video.scaleY\n        if (vw > 0f && vh > 0f) {\n            // pivot defaults to center if not set\n            val pivotX = if (video.pivotX != 0f) video.pivotX else vw * 0.5f\n            val pivotY = if (video.pivotY != 0f) video.pivotY else vh * 0.5f\n            // Use view position (includes translation) as base; avoid double-counting translation\n            val tx = video.x\n            val ty = video.y\n\n            // transform function for a local point (lx,ly)\n            fun transform(lx: Float, ly: Float): Pair<Float, Float> {\n                val gx = tx + pivotX + (lx - pivotX) * sx\n                val gy = ty + pivotY + (ly - pivotY) * sy\n                return Pair(gx, gy)\n            }\n\n            val p0 = transform(0f, 0f)\n            val p1 = transform(vw, 0f)\n            val p2 = transform(0f, vh)\n            val p3 = transform(vw, vh)\n\n            val minX = min(min(p0.first, p1.first), min(p2.first, p3.first))\n            val maxX = max(max(p0.first, p1.first), max(p2.first, p3.first))\n            val minY = min(min(p0.second, p1.second), min(p2.second, p3.second))\n            val maxY = max(max(p0.second, p1.second), max(p2.second, p3.second))\n\n            val newW = ceil(maxX - minX).toInt().coerceAtLeast(0)\n            val newH = ceil(maxY - minY).toInt().coerceAtLeast(0)\n\n            val lp = overlay.layoutParams\n            if (lp == null) {\n                overlay.layoutParams = ViewGroup.LayoutParams(newW, newH)\n            } else {\n                if (lp.width != newW || lp.height != newH) {\n                    lp.width = newW\n                    lp.height = newH\n                    overlay.layoutParams = lp\n                }\n            }\n\n            overlay.scaleX = 1.0f\n            overlay.scaleY = 1.0f\n            overlay.x = minX\n            overlay.y = minY\n        }\n    }\n\n    /**\n     * Ensure the overlay is updated once the next layout pass completes.\n     * Adds a one-time global layout listener (PiP/resizing/rotation frames).\n     */\n    private fun requestUpdateBrightnessOverlayOnNextLayout() {\n        val pv = playerView ?: return\n        safe {\n            val obs = pv.viewTreeObserver\n            val listener = object : android.view.ViewTreeObserver.OnGlobalLayoutListener {\n                override fun onGlobalLayout() {\n                    safe {\n                        updateBrightnessOverlayBounds()\n                    }\n                    if (obs.isAlive) {\n                        obs.removeOnGlobalLayoutListener(this)\n                    }\n                }\n            }\n            if (obs.isAlive) obs.addOnGlobalLayoutListener(listener)\n        }\n    }\n\n    open fun showMirrorsDialogue() {\n        throw NotImplementedError()\n    }\n\n    open fun showTracksDialogue() {\n        throw NotImplementedError()\n    }\n\n    open fun openOnlineSubPicker(\n        context: Context,\n        loadResponse: LoadResponse?,\n        dismissCallback: (() -> Unit)\n    ) {\n        throw NotImplementedError()\n    }\n\n    open fun showEpisodesOverlay() {\n        throw NotImplementedError()\n    }\n\n    open fun isThereEpisodes(): Boolean {\n        return false\n    }\n\n    /**\n     * [isValidTouch] should be called on a [View] spanning across the screen for reliable results.\n     *\n     * Android has supported gesture navigation properly since API-30. We get the absolute screen dimens using\n     * [WindowManager.getCurrentWindowMetrics] and remove the stable insets\n     * {[WindowInsets.getInsetsIgnoringVisibility]} to get a safe perimeter.\n     * This approach supports any and all types of necessary system insets.\n     *\n     * @return false if the touch is on the status bar or navigation bar\n     * */\n    private fun View.isValidTouch(rawX: Float, rawY: Float): Boolean {\n        // NOTE: screenWidth is without the navbar width when 3button nav is turned on.\n        if (Build.VERSION.SDK_INT >= 30) {\n            // real = absolute dimen without any default deductions like navbar width\n            val windowMetrics =\n                (context?.getSystemService(Context.WINDOW_SERVICE) as? WindowManager)?.currentWindowMetrics\n            val realScreenHeight =\n                windowMetrics?.let { windowMetrics.bounds.bottom - windowMetrics.bounds.top }\n                    ?: screenHeightWithOrientation\n            val realScreenWidth =\n                windowMetrics?.let { windowMetrics.bounds.right - windowMetrics.bounds.left }\n                    ?: screenWidthWithOrientation\n\n            val insets =\n                rootWindowInsets.getInsetsIgnoringVisibility(WindowInsets.Type.systemBars())\n            val isOutsideHeight = rawY < insets.top || rawY > (realScreenHeight - insets.bottom)\n            val isOutsideWidth = if (windowMetrics == null) {\n                rawX < screenWidthWithOrientation\n            } else rawX < insets.left || rawX > realScreenWidth - insets.right\n\n            return !(isOutsideWidth || isOutsideHeight)\n        } else {\n            val statusHeight = statusBarHeight ?: 0\n            return rawY > statusHeight && rawX < screenWidthWithOrientation\n        }\n    }\n\n    override fun exitedPipMode() {\n        animateLayoutChanges()\n    }\n\n    private fun animateLayoutChangesForSubtitles() =\n        // Post here as bottomPlayerBar is gone the first frame => bottomPlayerBar.height = 0\n        playerBinding?.bottomPlayerBar?.post {\n            val sView = subView ?: return@post\n            val sStyle = CustomDecoder.style\n            val binding = playerBinding ?: return@post\n\n            val move = if (isShowing) minOf(\n                // We do not want to drag down subtitles if the subtitle elevation is large\n                -sStyle.elevation.toPx,\n                // The lib uses Invisible instead of Gone for no reason\n                binding.previewFrameLayout.height - binding.bottomPlayerBar.height\n            ) else -sStyle.elevation.toPx\n            ObjectAnimator.ofFloat(sView, \"translationY\", move.toFloat()).apply {\n                duration = 200\n                start()\n            }\n        }\n\n    protected fun animateLayoutChanges() {\n        if (isLayout(PHONE)) { // isEnabled also disables the onKeyDown\n            playerBinding?.exoProgress?.isEnabled = isShowing // Prevent accidental clicks/drags\n        }\n\n        if (isShowing) {\n            updateUIVisibility()\n        } else {\n            toggleEpisodesOverlay(false)\n            playerBinding?.playerHolder?.postDelayed({ updateUIVisibility() }, 200)\n        }\n\n        val titleMove = if (isShowing) 0f else -50.toPx.toFloat()\n        playerBinding?.playerVideoTitleHolder?.let {\n            ObjectAnimator.ofFloat(it, \"translationY\", titleMove).apply {\n                duration = 200\n                start()\n            }\n        }\n        playerBinding?.playerVideoTitleRez?.let {\n            ObjectAnimator.ofFloat(it, \"translationY\", titleMove).apply {\n                duration = 200\n                start()\n            }\n        }\n        playerBinding?.playerVideoInfo?.let {\n            ObjectAnimator.ofFloat(it, \"translationY\", titleMove).apply {\n                duration = 200\n                start()\n            }\n        }\n\n        val playerBarMove = if (isShowing) 0f else 50.toPx.toFloat()\n        playerBinding?.bottomPlayerBar?.let {\n            ObjectAnimator.ofFloat(it, \"translationY\", playerBarMove).apply {\n                duration = 200\n                start()\n            }\n        }\n        if (isLayout(PHONE)) {\n            playerBinding?.playerEpisodesButton?.let {\n                ObjectAnimator.ofFloat(it, \"translationX\", if (isShowing) 0f else 50.toPx.toFloat())\n                    .apply {\n                        duration = 200\n                        start()\n                    }\n            }\n        }\n        val fadeTo = if (isShowing) 1f else 0f\n        val fadeAnimation = AlphaAnimation(1f - fadeTo, fadeTo)\n\n        fadeAnimation.duration = 100\n        fadeAnimation.fillAfter = true\n\n        animateLayoutChangesForSubtitles()\n\n        val playerSourceMove = if (isShowing) 0f else -50.toPx.toFloat()\n\n        playerBinding?.apply {\n            playerOpenSource.let {\n                ObjectAnimator.ofFloat(it, \"translationY\", playerSourceMove).apply {\n                    duration = 200\n                    start()\n                }\n            }\n\n            if (!isLocked) {\n                playerFfwdHolder.alpha = 1f\n                playerRewHolder.alpha = 1f\n                // player_pause_play_holder?.alpha = 1f\n                shadowOverlay.isVisible = true\n                shadowOverlay.startAnimation(fadeAnimation)\n                playerFfwdHolder.startAnimation(fadeAnimation)\n                playerRewHolder.startAnimation(fadeAnimation)\n                playerPausePlay.startAnimation(fadeAnimation)\n                downloadBothHeader.startAnimation(fadeAnimation)\n\n                /*if (isBuffering) {\n                        player_pause_play?.isVisible = false\n                        player_pause_play_holder?.isVisible = false\n                    } else {\n                        player_pause_play?.isVisible = true\n                        player_pause_play_holder?.startAnimation(fadeAnimation)\n                        player_pause_play?.startAnimation(fadeAnimation)\n                    }*/\n                // player_buffering?.startAnimation(fadeAnimation)\n            }\n\n            bottomPlayerBar.startAnimation(fadeAnimation)\n            playerOpenSource.startAnimation(fadeAnimation)\n            playerTopHolder.startAnimation(fadeAnimation)\n        }\n    }\n\n    override fun subtitlesChanged() {\n        val tracks = player.getVideoTracks()\n        val isBuiltinSubtitles = tracks.currentTextTracks.all { track ->\n            track.sampleMimeType == MimeTypes.APPLICATION_MEDIA3_CUES\n        }\n        // Subtitle offset is not possible on built-in media3 tracks\n        playerBinding?.playerSubtitleOffsetBtt?.isGone =\n            isBuiltinSubtitles || tracks.currentTextTracks.isEmpty()\n    }\n\n    private fun restoreOrientationWithSensor(activity: Activity) {\n        val currentOrientation = activity.resources.configuration.orientation\n        val orientation = when (currentOrientation) {\n            Configuration.ORIENTATION_LANDSCAPE ->\n                ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE\n\n            Configuration.ORIENTATION_PORTRAIT ->\n                ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT\n\n            else -> dynamicOrientation()\n        }\n        activity.requestedOrientation = orientation\n    }\n\n    private fun toggleOrientationWithSensor(activity: Activity) {\n        val currentOrientation = activity.resources.configuration.orientation\n        val orientation: Int = when (currentOrientation) {\n            Configuration.ORIENTATION_LANDSCAPE ->\n                ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT\n\n            Configuration.ORIENTATION_PORTRAIT ->\n                ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE\n\n            else -> dynamicOrientation()\n        }\n        activity.requestedOrientation = orientation\n    }\n\n    open fun lockOrientation(activity: Activity) {\n        @Suppress(\"DEPRECATION\")\n        val display = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)\n            (activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay\n        else activity.display!!\n        val rotation = display.rotation\n        val currentOrientation = activity.resources.configuration.orientation\n        val orientation: Int\n        when (currentOrientation) {\n            Configuration.ORIENTATION_LANDSCAPE ->\n                orientation =\n                    if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90)\n                        ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE\n                    else\n                        ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE\n\n            Configuration.ORIENTATION_PORTRAIT ->\n                orientation =\n                    if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_270)\n                        ActivityInfo.SCREEN_ORIENTATION_PORTRAIT\n                    else\n                        ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT\n\n            else -> orientation = dynamicOrientation()\n        }\n        activity.requestedOrientation = orientation\n    }\n\n    private fun updateOrientation(ignoreDynamicOrientation: Boolean = false) {\n        activity?.apply {\n            if (lockRotation) {\n                if (isLocked) {\n                    lockOrientation(this)\n                } else {\n                    if (ignoreDynamicOrientation || rotatedManually) {\n                        // restore when lock is disabled\n                        restoreOrientationWithSensor(this)\n                    } else {\n                        this.requestedOrientation = dynamicOrientation()\n                    }\n                }\n            }\n        }\n    }\n\n    protected fun enterFullscreen() {\n        if (isFullScreenPlayer) {\n            activity?.hideSystemUI()\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && fullscreenNotch) {\n                val params = activity?.window?.attributes\n                params?.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES\n                activity?.window?.attributes = params\n            }\n        }\n        updateOrientation()\n    }\n\n    protected fun exitFullscreen() {\n        resetZoomToDefault()\n        // if (lockRotation)\n        activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER\n\n        // simply resets brightness and notch settings that might have been overridden\n        val lp = activity?.window?.attributes\n        lp?.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            lp?.layoutInDisplayCutoutMode =\n                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT\n        }\n        activity?.window?.attributes = lp\n        activity?.showSystemUI()\n    }\n    private fun resetZoomToDefault() {\n        if (zoomMatrix != null) resize(PlayerResize.Fit, false)\n    }\n\n    override fun onResume() {\n        enterFullscreen()\n        verifyVolume()\n        activity?.attachBackPressedCallback(\"FullScreenPlayer\") {\n            if (isShowingEpisodeOverlay) {\n                // isShowingEpisodeOverlay pauses, so this makes it easier to unpause\n                if (isLayout(TV or EMULATOR)) {\n                    playerPausePlay?.requestFocus()\n                }\n                toggleEpisodesOverlay(show = false)\n                return@attachBackPressedCallback\n            } else if (isShowing && isLayout(TV or EMULATOR)) {\n                // netflix capture back and hide ~monke\n                onClickChange()\n            } else {\n                activity?.popCurrentPage(\"FullScreenPlayer\")\n            }\n        }\n        requestUpdateBrightnessOverlayOnNextLayout()\n        super.onResume()\n    }\n\n    override fun onStop() {\n        activity?.detachBackPressedCallback(\"FullScreenPlayer\")\n        super.onStop()\n    }\n\n    override fun onDestroy() {\n        exitFullscreen()\n        super.onDestroy()\n    }\n\n    private fun setPlayBackSpeed(speed: Float) {\n        try {\n            DataStoreHelper.playBackSpeed = speed\n            playerBinding?.playerSpeedBtt?.text =\n                getString(R.string.player_speed_text_format).format(speed)\n                    .replace(\".0x\", \"x\")\n        } catch (e: Exception) {\n            // the format string was wrong\n            logError(e)\n        }\n\n        player.setPlaybackSpeed(speed)\n    }\n\n    private fun skipOp() {\n        player.seekTime(85000) // skip 85s\n    }\n\n    private fun showSubtitleOffsetDialog() {\n        val ctx = context ?: return\n        // Pause player because the subtitles cannot be continuously updated to follow playback.\n        player.handleEvent(\n            CSPlayerEvent.Pause,\n            PlayerEventSource.UI\n        )\n\n        val binding = SubtitleOffsetBinding.inflate(LayoutInflater.from(ctx), null, false)\n\n        // Use dialog as opposed to alertdialog to get fullscreen\n        val dialog = Dialog(ctx, R.style.DialogFullscreenPlayer).apply {\n            setContentView(binding.root)\n        }\n        dialog.show()\n\n        val isPortrait =\n            ctx.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT\n        fixSystemBarsPadding(binding.root, fixIme = isPortrait)\n\n        var currentOffset = subtitleDelay\n        binding.apply {\n            var subtitleAdapter: SubtitleOffsetItemAdapter? = null\n\n            subtitleOffsetInput.doOnTextChanged { text, _, _, _ ->\n                text?.toString()?.toLongOrNull()?.let { time ->\n                    currentOffset = time\n\n                    // Scroll to the first active subtitle\n                    val playerPosition = player.getPosition() ?: 0\n                    val totalPosition = playerPosition - currentOffset\n                    subtitleAdapter?.updateTime(totalPosition)\n\n                    subtitleAdapter?.getLatestActiveItem(totalPosition)\n                        ?.let { subtitlePos ->\n                            subtitleOffsetRecyclerview.scrollToPosition(subtitlePos)\n                        }\n\n                    val str = when {\n                        time > 0L -> {\n                            txt(R.string.subtitle_offset_extra_hint_later_format, time)\n                        }\n\n                        time < 0L -> {\n                            txt(R.string.subtitle_offset_extra_hint_before_format, -time)\n                        }\n\n                        else -> {\n                            txt(R.string.subtitle_offset_extra_hint_none_format)\n                        }\n                    }\n                    subtitleOffsetSubTitle.setText(str)\n                }\n            }\n            subtitleOffsetInput.text =\n                Editable.Factory.getInstance()?.newEditable(currentOffset.toString())\n\n            val subtitles = player.getSubtitleCues().toMutableList()\n\n            subtitleOffsetRecyclerview.isVisible = subtitles.isNotEmpty()\n            noSubtitlesLoadedNotice.isVisible = subtitles.isEmpty()\n\n            val initialSubtitlePosition = (player.getPosition() ?: 0) - currentOffset\n            subtitleAdapter =\n                SubtitleOffsetItemAdapter(initialSubtitlePosition) { subtitleCue ->\n                    val playerPosition = player.getPosition() ?: 0\n                    subtitleOffsetInput.text = Editable.Factory.getInstance()\n                        ?.newEditable((playerPosition - subtitleCue.startTimeMs).toString())\n                }.apply {\n                    submitList(subtitles)\n                }\n\n            subtitleOffsetRecyclerview.adapter = subtitleAdapter\n            // Prevent flashing changes when changing items\n            (subtitleOffsetRecyclerview.itemAnimator as? SimpleItemAnimator)?.supportsChangeAnimations =\n                false\n\n            val firstSubtitle = subtitleAdapter.getLatestActiveItem(initialSubtitlePosition)\n            subtitleOffsetRecyclerview.scrollToPosition(firstSubtitle)\n\n            val buttonChange = 100L\n            val buttonChangeMore = 1000L\n\n            fun changeBy(by: Long) {\n                val current = (subtitleOffsetInput.text?.toString()?.toLongOrNull() ?: 0) + by\n                subtitleOffsetInput.text =\n                    Editable.Factory.getInstance()?.newEditable(current.toString())\n            }\n\n            subtitleOffsetAdd.setOnClickListener {\n                changeBy(buttonChange)\n            }\n            subtitleOffsetAddMore.setOnClickListener {\n                changeBy(buttonChangeMore)\n            }\n            subtitleOffsetSubtract.setOnClickListener {\n                changeBy(-buttonChange)\n            }\n            subtitleOffsetSubtractMore.setOnClickListener {\n                changeBy(-buttonChangeMore)\n            }\n\n            dialog.setOnDismissListener {\n                if (isFullScreenPlayer)\n                    activity?.hideSystemUI()\n            }\n            applyBtt.setOnClickListener {\n                subtitleDelay = currentOffset\n                dialog.dismissSafe(activity)\n                player.seekTime(1L)\n            }\n            resetBtt.setOnClickListener {\n                subtitleDelay = 0\n                dialog.dismissSafe(activity)\n                player.seekTime(1L)\n            }\n            cancelBtt.setOnClickListener {\n                dialog.dismissSafe(activity)\n            }\n        }\n    }\n\n\n    @SuppressLint(\"SetTextI18n\")\n    fun updateSpeedDialogBinding(binding: SpeedDialogBinding) {\n        val speed = player.getPlaybackSpeed()\n        binding.speedText.text = \"%.2fx\".format(speed).replace(\".0x\", \"x\")\n        // Android crashes if you don't round to an exact step size\n        binding.speedBar.value =\n            (speed.coerceIn(0.1f, 2.0f) / binding.speedBar.stepSize).roundToInt()\n                .toFloat() * binding.speedBar.stepSize\n    }\n\n    private fun showSpeedDialog() {\n        val act = activity ?: return\n        val isPlaying = player.getIsPlaying()\n        player.handleEvent(CSPlayerEvent.Pause, PlayerEventSource.UI)\n\n        val binding: SpeedDialogBinding = SpeedDialogBinding.inflate(\n            LayoutInflater.from(act)\n        )\n\n        updateSpeedDialogBinding(binding)\n        for ((view, speed) in arrayOf(\n            binding.speed25 to 0.25f,\n            binding.speed100 to 1.0f,\n            binding.speed125 to 1.25f,\n            binding.speed150 to 1.5f,\n            binding.speed200 to 2.0f,\n        )) {\n            view.setOnClickListener {\n                setPlayBackSpeed(speed)\n                updateSpeedDialogBinding(binding)\n            }\n        }\n\n        binding.speedMinus.setOnClickListener {\n            setPlayBackSpeed(maxOf((player.getPlaybackSpeed() - 0.1f), 0.1f))\n            updateSpeedDialogBinding(binding)\n        }\n\n        binding.speedPlus.setOnClickListener {\n            setPlayBackSpeed(minOf((player.getPlaybackSpeed() + 0.1f), 2.0f))\n            updateSpeedDialogBinding(binding)\n        }\n\n        binding.speedBar.addOnChangeListener { slider, value, fromUser ->\n            if (fromUser) {\n                setPlayBackSpeed(value)\n                updateSpeedDialogBinding(binding)\n            }\n        }\n\n        val dismiss = DialogInterface.OnDismissListener {\n            if (isFullScreenPlayer)\n                activity?.hideSystemUI()\n            if (isPlaying) {\n                player.handleEvent(CSPlayerEvent.Play, PlayerEventSource.UI)\n            }\n        }\n\n        // if (isLayout(PHONE)) {\n        //    val builder =\n        //        BottomSheetDialog(act, R.style.AlertDialogCustom)\n        //    builder.setContentView(binding.root)\n        //    builder.setOnDismissListener(dismiss)\n        //    builder.show()\n        //} else {\n        val builder =\n            AlertDialog.Builder(act, R.style.AlertDialogCustom)\n                .setView(binding.root)\n        builder.setOnDismissListener(dismiss)\n        val dialog = builder.create()\n        dialog.show()\n        //}\n    }\n\n    fun resetRewindText() {\n        playerBinding?.exoRewText?.text =\n            getString(R.string.rew_text_regular_format).format(fastForwardTime / 1000)\n    }\n\n    fun resetFastForwardText() {\n        playerBinding?.exoFfwdText?.text =\n            getString(R.string.ffw_text_regular_format).format(fastForwardTime / 1000)\n    }\n\n    private fun rewind() {\n        try {\n            playerBinding?.apply {\n                playerCenterMenu.isGone = false\n                playerRewHolder.alpha = 1f\n\n                val rotateLeft = AnimationUtils.loadAnimation(context, R.anim.rotate_left)\n                playerRew.startAnimation(rotateLeft)\n\n                val goLeft = AnimationUtils.loadAnimation(context, R.anim.go_left)\n                goLeft.setAnimationListener(object : Animation.AnimationListener {\n                    override fun onAnimationStart(animation: Animation?) {}\n\n                    override fun onAnimationRepeat(animation: Animation?) {}\n\n                    override fun onAnimationEnd(animation: Animation?) {\n                        exoRewText.post {\n                            resetRewindText()\n                            playerCenterMenu.isGone = !isShowing\n                            playerRewHolder.alpha = if (isShowing) 1f else 0f\n                        }\n                    }\n                })\n                exoRewText.startAnimation(goLeft)\n                exoRewText.text =\n                    getString(R.string.rew_text_format).format(fastForwardTime / 1000)\n            }\n            player.seekTime(-fastForwardTime)\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    private fun fastForward() {\n        try {\n            playerBinding?.apply {\n                playerCenterMenu.isGone = false\n                playerFfwdHolder.alpha = 1f\n\n                val rotateRight = AnimationUtils.loadAnimation(context, R.anim.rotate_right)\n                playerFfwd.startAnimation(rotateRight)\n\n                val goRight = AnimationUtils.loadAnimation(context, R.anim.go_right)\n                goRight.setAnimationListener(object : Animation.AnimationListener {\n                    override fun onAnimationStart(animation: Animation?) {}\n\n                    override fun onAnimationRepeat(animation: Animation?) {}\n\n                    override fun onAnimationEnd(animation: Animation?) {\n                        exoFfwdText.post {\n                            resetFastForwardText()\n                            playerCenterMenu.isGone = !isShowing\n                            playerFfwdHolder.alpha = if (isShowing) 1f else 0f\n                        }\n                    }\n                })\n                exoFfwdText.startAnimation(goRight)\n                exoFfwdText.text =\n                    getString(R.string.ffw_text_format).format(fastForwardTime / 1000)\n            }\n            player.seekTime(fastForwardTime)\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    private fun onClickChange() {\n        isShowing = !isShowing\n        if (isShowing) {\n            playerBinding?.playerIntroPlay?.isGone = true\n            autoHide()\n        }\n        if (isFullScreenPlayer)\n            activity?.hideSystemUI()\n        animateLayoutChanges()\n        if (playerBinding?.playerEpisodeOverlay?.isGone == true) playerBinding?.playerPausePlay?.requestFocus()\n    }\n\n    private fun toggleLock() {\n        if (!isShowing) {\n            onClickChange()\n        }\n\n        isLocked = !isLocked\n        updateOrientation(true) // set true to ignore auto rotate to stay in current orientation\n\n        if (isLocked && isShowing) {\n            playerBinding?.playerHolder?.postDelayed({\n                if (isLocked && isShowing) {\n                    onClickChange()\n                }\n            }, 200)\n        }\n\n        val fadeTo = if (isLocked) 0f else 1f\n        playerBinding?.apply {\n            val fadeAnimation = AlphaAnimation(playerVideoTitleHolder.alpha, fadeTo).apply {\n                duration = 100\n                fillAfter = true\n            }\n\n            updateUIVisibility()\n            // MENUS\n            // centerMenu.startAnimation(fadeAnimation)\n            playerPausePlay.startAnimation(fadeAnimation)\n            playerFfwdHolder.startAnimation(fadeAnimation)\n            playerRewHolder.startAnimation(fadeAnimation)\n            downloadBothHeader.startAnimation(fadeAnimation)\n\n            if (hasEpisodes)\n                playerEpisodesButton.startAnimation(fadeAnimation)\n            // player_media_route_button?.startAnimation(fadeAnimation)\n            // video_bar.startAnimation(fadeAnimation)\n\n            // TITLE\n            playerVideoTitleRez.startAnimation(fadeAnimation)\n            playerVideoInfo.startAnimation(fadeAnimation)\n            playerEpisodeFiller.startAnimation(fadeAnimation)\n            playerVideoTitleHolder.startAnimation(fadeAnimation)\n            playerTopHolder.startAnimation(fadeAnimation)\n            // BOTTOM\n            playerLockHolder.startAnimation(fadeAnimation)\n            // player_go_back_holder?.startAnimation(fadeAnimation)\n\n            shadowOverlay.isVisible = true\n            shadowOverlay.startAnimation(fadeAnimation)\n        }\n        updateLockUI()\n    }\n\n    open fun updateUIVisibility() {\n        val isGone = isLocked || !isShowing\n        var togglePlayerTitleGone = isGone\n        context?.let {\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)\n            val limitTitle = settingsManager.getInt(getString(R.string.prefer_limit_title_key), 0)\n            if (limitTitle < 0) {\n                togglePlayerTitleGone = true\n            }\n        }\n        playerBinding?.apply {\n\n            playerLockHolder.isGone = isGone\n            playerVideoBar.isGone = isGone\n\n            playerPausePlay.isGone = isGone\n            // player_buffering?.isGone = isGone\n            playerTopHolder.isGone = isGone\n            val showPlayerEpisodes = !isGone && isThereEpisodes()\n            playerEpisodesButtonRoot.isVisible = showPlayerEpisodes\n            playerEpisodesButton.isVisible = showPlayerEpisodes\n            playerVideoTitleHolder.isGone = togglePlayerTitleGone\n//        player_video_title_rez?.isGone = isGone\n            playerEpisodeFiller.isGone = isGone\n            playerCenterMenu.isGone = isGone\n            playerLock.isGone = !isShowing\n            // player_media_route_button?.isClickable = !isGone\n            playerGoBackHolder.isGone = isGone\n            playerSourcesBtt.isGone = isGone\n            playerSkipEpisode.isClickable = !isGone\n        }\n    }\n\n    private fun updateLockUI() {\n        playerBinding?.apply {\n            playerLock.setIconResource(if (isLocked) R.drawable.video_locked else R.drawable.video_unlocked)\n            if (layout == R.layout.fragment_player) {\n                val color = if (isLocked) context?.colorFromAttribute(R.attr.colorPrimary)\n                else Color.WHITE\n                if (color != null) {\n                    playerLock.setTextColor(color)\n                    playerLock.iconTint = ColorStateList.valueOf(color)\n                    playerLock.rippleColor =\n                        ColorStateList.valueOf(Color.argb(50, color.red, color.green, color.blue))\n                }\n            }\n        }\n    }\n\n    private var currentTapIndex = 0\n    protected fun autoHide() {\n        currentTapIndex++\n        delayHide()\n    }\n\n    protected fun hidePlayerUI() {\n        if (isShowing) {\n            isShowing = false\n            animateLayoutChanges()\n        }\n    }\n\n    override fun playerStatusChanged() {\n        super.playerStatusChanged()\n        delayHide()\n    }\n\n    private fun delayHide() {\n        val index = currentTapIndex\n        playerBinding?.playerHolder?.postDelayed({\n            if (!isCurrentTouchValid && isShowing && index == currentTapIndex && player.getIsPlaying()) {\n                onClickChange()\n            }\n        }, 3000)\n    }\n\n    // this is used because you don't want to hide UI when double tap seeking\n    private var currentDoubleTapIndex = 0\n    private fun toggleShowDelayed() {\n        if (doubleTapEnabled || doubleTapPauseEnabled) {\n            val index = currentDoubleTapIndex\n            playerBinding?.playerHolder?.postDelayed({\n                if (index == currentDoubleTapIndex) {\n                    onClickChange()\n                }\n            }, DOUBLE_TAB_MINIMUM_TIME_BETWEEN)\n        } else {\n            onClickChange()\n        }\n    }\n\n    private var isCurrentTouchValid = false\n    private var currentTouchStart: Vector2? = null\n    private var currentTouchLast: Vector2? = null\n    private var currentTouchAction: TouchAction? = null\n    private var currentLastTouchAction: TouchAction? = null\n    private var currentTouchStartPlayerTime: Long? =\n        null // the time in the player when you first click\n    private var currentTouchStartTime: Long? = null // the system time when you first click\n    private var currentLastTouchEndTime: Long = 0 // the system time when you released your finger\n    private var currentClickCount: Int =\n        0 // amount of times you have double clicked, will reset when other action is taken\n\n    // requested volume and brightness is used to make swiping smoother\n    // to make it not jump between values,\n    // this value is within the range [0,2] where 1+ is loudness\n    private var currentRequestedVolume: Float = 0.0f\n\n    // from [0.0f, 1.0f] where 1.0f is max extra brightness, used only to track extra brightness\n    private var currentExtraBrightness: Float = 0.0f\n\n    // this value is within the range [0,2] where 1+ is extra brightness\n    private var currentRequestedBrightness: Float = 1.0f\n\n    enum class TouchAction {\n        Brightness,\n        Volume,\n        Time,\n    }\n\n    companion object {\n        /**\n         * Gets the translationXY + scale form a matrix with no rotation.\n         *\n         * @return (translationX, translationY, scale)\n         * */\n        fun matrixToTranslationAndScale(matrix: Matrix): Triple<Float, Float, Float> {\n            val points = floatArrayOf(0.0f, 0.0f, 1.0f, 1.0f)\n            matrix.mapPoints(points)\n\n            // A linear matrix will map (0,0) to the translation\n            val translationX = points[0]\n            val translationY = points[1]\n\n            // The unit vectors (1,0) and (0,1) will map to the scale if you remove the translation\n            // As this assumes a uniform scaling, only a single vector is needed\n            val scaleX = points[2] - translationX\n            val scaleY = points[3] - translationY\n\n            // The matrix should have the same scaleX and scaleY\n            if (BuildConfig.DEBUG) {\n                assert((scaleX - scaleY).absoluteValue < 0.1f) {\n                    \"$scaleY != $scaleX\"\n                }\n            }\n\n            return Triple(translationX, translationY, scaleX)\n        }\n\n        private fun forceLetters(inp: Long, letters: Int = 2): String {\n            val added: Int = letters - inp.toString().length\n            return if (added > 0) {\n                \"0\".repeat(added) + inp.toString()\n            } else {\n                inp.toString()\n            }\n        }\n\n        private fun convertTimeToString(sec: Long): String {\n            val rsec = sec % 60L\n            val min = ceil((sec - rsec) / 60.0).toInt()\n            val rmin = min % 60L\n            val h = ceil((min - rmin) / 60.0).toLong()\n            // int rh = h;// h % 24;\n            return (if (h > 0) forceLetters(h) + \":\" else \"\") + (if (rmin >= 0 || h >= 0) forceLetters(\n                rmin\n            ) + \":\" else \"\") + forceLetters(\n                rsec\n            )\n        }\n    }\n\n    private fun calculateNewTime(\n        startTime: Long?,\n        touchStart: Vector2?,\n        touchEnd: Vector2?\n    ): Long? {\n        if (touchStart == null || touchEnd == null || startTime == null) return null\n        val diffX =\n            (touchEnd.x - touchStart.x) * HORIZONTAL_MULTIPLIER / screenWidthWithOrientation.toFloat()\n        val duration = player.getDuration() ?: return null\n        return max(\n            min(\n                startTime + ((duration * (diffX * diffX)) * (if (diffX < 0) -1 else 1)).toLong(),\n                duration\n            ), 0\n        )\n    }\n\n    /**\n     * Returns screen brightness in <0.0f, 1.0f> range\n     */\n    private fun getBrightness(): Float? {\n        return if (useTrueSystemBrightness) {\n            try {\n                Settings.System.getInt(\n                    context?.contentResolver,\n                    Settings.System.SCREEN_BRIGHTNESS\n                ) / 255f\n            } catch (e: Exception) {\n                // because true system brightness requires\n                // permission, this is a lazy way to check\n                // as it will throw an error if we do not have it\n                useTrueSystemBrightness = false\n                return getBrightness()\n            }\n        } else {\n            try {\n                activity?.window?.attributes?.screenBrightness\n            } catch (e: Exception) {\n                logError(e)\n                null\n            }\n        }\n    }\n\n    /**\n     * Sets the screen brightness in the range <0.0f, 1.0f>. Values outside this range\n     * will be clamped to the minimum (0.0f) or maximum (1.0f).\n     *\n     * @param brightness desired brightness (values outside the range will be clamped)\n     */\n    private fun setBrightness(brightness: Float) {\n        if (useTrueSystemBrightness) {\n            try {\n                Settings.System.putInt(\n                    context?.contentResolver,\n                    Settings.System.SCREEN_BRIGHTNESS_MODE,\n                    Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL\n                )\n\n                Settings.System.putInt(\n                    context?.contentResolver,\n                    Settings.System.SCREEN_BRIGHTNESS,\n                    min(1, (brightness.coerceIn(0.0f, 1.0f) * 255).toInt())\n                )\n            } catch (e: Exception) {\n                useTrueSystemBrightness = false\n                setBrightness(brightness)\n            }\n        } else {\n            try {\n                val lp = activity?.window?.attributes\n                // use 0.004f instead of 0, because on some devices setting too small value\n                // causes system to override it and in turn system makes the screen apply system brightness level instead\n                // which can be too bright, and it is very hard to fine tune very low brightness, because of it.\n                // Without this clamp, it can jump from almost 0% to 100% brightness when this threshold is crossed.\n                lp?.screenBrightness = brightness.coerceIn(0.004f, 1.0f)\n                // Log.i(\"Brightness\", \"clamped brightness: ${lp?.screenBrightness}\")\n                activity?.window?.attributes = lp\n            } catch (e: Exception) {\n                logError(e)\n            }\n        }\n    }\n\n    private var isVolumeLocked: Boolean = false\n    private var hasShownVolumeToast: Boolean = false\n\n    private var isBrightnessLocked: Boolean = false\n    private var hasShownBrightnessToast: Boolean = false\n\n    private var progressBarLeftHideRunnable: Runnable? = null\n    private var progressBarRightHideRunnable: Runnable? = null\n\n    // Verifies that the currentRequestedVolume matches the system volume\n    // if not, then it removes changes currentRequestedVolume and removes the loudnessEnhancer\n    // if the real volume is less than 100%\n    //\n    // This is here to make returning to the player less jarring, if we change the volume outside\n    // the app. Note that this will make it a bit wierd when using loudness in PiP, then returning\n    // however that is the cost of correctness.\n    private fun verifyVolume() {\n        (activity?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager)?.let { audioManager ->\n            val currentVolumeStep =\n                audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)\n            val maxVolumeStep =\n                audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)\n\n            // if we can set the volume directly then do it\n            if (currentVolumeStep < maxVolumeStep || currentRequestedVolume <= 1.0f) {\n                currentRequestedVolume =\n                    currentVolumeStep.toFloat() / maxVolumeStep.toFloat()\n\n                loudnessEnhancer?.release()\n                loudnessEnhancer = null\n            }\n        }\n    }\n\n    val holdhandler = Handler(Looper.getMainLooper())\n    var hasTriggeredSpeedUp = false\n    val holdRunnable = Runnable {\n        if (isShowing) {\n            onClickChange()\n        }\n        player.setPlaybackSpeed(2.0f)\n        showOrHideSpeedUp(true)\n        hasTriggeredSpeedUp = true\n    }\n\n    private fun showOrHideSpeedUp(show: Boolean) {\n        playerBinding?.playerSpeedupButton?.let { button ->\n            button.clearAnimation()\n            button.alpha = if (show) 0f else 1f\n            button.isVisible = show\n            button.animate()\n                .alpha(if (show) 1f else 0f)\n                .setDuration(200L)\n                .start()\n        }\n    }\n\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n\n        // If we rotate the device we need to recalculate the zoom\n        val matrix = zoomMatrix\n        val animation = matrixAnimation\n        if ((animation == null || !animation.isRunning) && matrix != null) {\n            // Ignore if we have no zoom or mid animation\n            playerView?.post {\n                applyZoomMatrix(matrix, true)\n                requestUpdateBrightnessOverlayOnNextLayout()\n            }\n        }\n    }\n\n    private var scaleGestureDetector: ScaleGestureDetector? = null\n    private var lastPan: Vector2? = null\n\n    /**\n     * Gets the non-null zoom matrix,\n     * this is different from `zoomMatrix ?: Matrix()`\n     * because it allows used to start zooming at different resizeModes.\n     *\n     * The main issue is that RESIZE_MODE_FIT = 100% zoom, but if you are in RESIZE_MODE_ZOOM\n     * 100% will make the zoom snap to less zoomed in then you already are.\n     * */\n    fun currentZoomMatrix(): Matrix {\n        val current = zoomMatrix\n        if (current != null) {\n            // Already assigned\n            return current\n        }\n\n        val playerView = playerView\n        val videoView = playerView?.videoSurfaceView\n\n        if (playerView == null || videoView == null || playerView.resizeMode != AspectRatioFrameLayout.RESIZE_MODE_ZOOM) {\n            // This is a fit or fill resize mode so start at 100% zoom\n            return Matrix()\n        }\n\n        val videoWidth = videoView.width.toFloat()\n        val videoHeight = videoView.height.toFloat()\n        val playerWidth = screenWidthWithOrientation\n        val playerHeight = screenHeightWithOrientation\n\n        // Sanity check\n        if (videoWidth <= 1.0f || videoHeight <= 1.0f || playerWidth <= 1.0f || playerHeight <= 1.0f) {\n            // Something is wrong with the video, return the default 100% zoom\n            return Matrix()\n        }\n\n        val initAspect =\n            (playerHeight * videoWidth) / (playerWidth * videoHeight)\n        val aspect = max(initAspect, 1.0f / initAspect)\n\n        // Return the matrix with the correct zoom, as it is already zoomed in\n        return Matrix().apply { postScale(aspect, aspect) }\n    }\n\n    /** A Matrix encoding the translation and scale of the current zoom */\n    private var zoomMatrix: Matrix? = null\n\n    /** A Matrix encoding the translation and scale of the desired zoom,\n     * aka after you release the zoom */\n    private var desiredMatrix: Matrix? = null\n\n    /** The animation of zooming to the desiredMatrix */\n    private var matrixAnimation: ValueAnimator? = null\n\n    @SuppressLint(\"UnsafeOptInUsageError\")\n    override fun resize(resize: PlayerResize, showToast: Boolean) {\n        // Clear all zoom stuff if we resize\n        matrixAnimation?.cancel()\n        matrixAnimation = null\n        zoomMatrix = null\n        desiredMatrix = null\n        playerView?.videoSurfaceView?.apply {\n            scaleX = 1.0f\n            scaleY = 1.0f\n            translationX = 0.0f\n            translationY = 0.0f\n        }\n\n        super.resize(resize, showToast)\n        requestUpdateBrightnessOverlayOnNextLayout()\n    }\n\n    /**\n     * Applies a new zoom matrix to the screen. Matrix should only contain a scale + translation.\n     *\n     * @param newMatrix The new zoom matrix\n     * @param animation If this zoom is part of an animation,\n     * as then it will not auto zoom after we are done\n     */\n    @OptIn(UnstableApi::class)\n    fun applyZoomMatrix(newMatrix: Matrix, animation: Boolean) {\n        if (!animation) {\n            matrixAnimation?.cancel()\n            matrixAnimation = null\n        }\n        val (translationX, translationY, scale) = matrixToTranslationAndScale(newMatrix)\n\n        playerView?.let { player ->\n            if (player.resizeMode == AspectRatioFrameLayout.RESIZE_MODE_FIT) {\n                player.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM\n            }\n\n            val videoView = player.videoSurfaceView ?: return@let\n\n            val videoWidth = videoView.width.toFloat()\n            val videoHeight = videoView.height.toFloat()\n            val playerWidth = screenWidthWithOrientation\n            val playerHeight = screenHeightWithOrientation\n\n            // Sanity check\n            if (videoWidth <= 1.0f || videoHeight <= 1.0f || playerWidth <= 1.0f || playerHeight <= 1.0f || scale <= 0.01f) {\n                return\n            }\n\n            // Calculate the scaled aspect ratio as the view height is not real, check the debugger\n            // and you will see videoView.height > screen.heigh\n            val initAspect =\n                (playerHeight * videoWidth) / (playerWidth * videoHeight)\n            val aspect = min(initAspect, 1.0f / initAspect)\n            val scaledAspect = scale * aspect\n\n            // Calculate clamp, this is very weird because we need to use aspect here as videoHeight > playerHeight\n            val maxTransX = max(0.0f, videoWidth * scaledAspect - playerWidth) * 0.5f\n            val maxTransY = max(0.0f, videoHeight * scaledAspect - playerHeight) * 0.5f\n\n            // Correct the translation to clamp within the viewing area\n            val expectedTranslationX = translationX.coerceIn(-maxTransX, maxTransX)\n            val expectedTranslationY = translationY.coerceIn(-maxTransY, maxTransY)\n\n            // Set the transform to the correct x and y\n            newMatrix.postTranslate(\n                expectedTranslationX - translationX,\n                expectedTranslationY - translationY\n            )\n            zoomMatrix = newMatrix\n\n            if (!animation) {\n                // If we are not in an animation, set up the values for the animation\n                if ((scaledAspect - 1.0f).absoluteValue < ZOOM_SNAP_SENSITIVITY) {\n                    // We are within the correct scaling, so center and fit it\n                    playerBinding?.videoOutline?.isVisible = true\n                    val desired = Matrix()\n                    desired.setScale(1.0f / aspect, 1.0f / aspect)\n                    desiredMatrix = desired\n                } else if (scale < 1.0f) {\n                    // We have zoomed too far, zoom to 100%\n                    playerBinding?.videoOutline?.isVisible = false\n                    desiredMatrix = Matrix()\n                } else {\n                    // Keep the same scaling after zoom\n                    playerBinding?.videoOutline?.isVisible = false\n                    desiredMatrix = null\n                }\n            }\n\n            // Finally set the actual scale + translation\n            videoView.scaleX = scaledAspect\n            videoView.scaleY = scaledAspect\n            videoView.translationX = expectedTranslationX\n            videoView.translationY = expectedTranslationY\n            updateBrightnessOverlayBounds()\n        }\n    }\n\n    fun createScaleGestureDetector(context: Context) {\n        scaleGestureDetector = ScaleGestureDetector(\n            context,\n            object : ScaleGestureDetector.SimpleOnScaleGestureListener() {\n                override fun onScale(detector: ScaleGestureDetector): Boolean {\n                    val matrix = currentZoomMatrix()\n                    val (_, _, scale) = matrixToTranslationAndScale(matrix)\n                    // Clamp scale of the zoom, do it here as it is easier then doing it within applyZoomMatrix\n                    val newScale = (scale * detector.scaleFactor).coerceIn(\n                        MINIMUM_ZOOM,\n                        MAXIMUM_ZOOM\n                    )\n                    // How much we should scale it with to prevent inf scaling\n                    val actualScaleFactor = newScale / scale\n\n                    // Scale around the focus point, this is more natural than just zoom\n                    val pivotX = detector.focusX - screenWidthWithOrientation.toFloat() * 0.5f\n                    val pivotY = detector.focusY - screenHeightWithOrientation.toFloat() * 0.5f\n                    matrix.postScale(\n                        actualScaleFactor,\n                        actualScaleFactor,\n                        pivotX,\n                        pivotY\n                    )\n                    applyZoomMatrix(matrix, false)\n                    return true\n                }\n            })\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    private fun handleMotionEvent(view: View?, event: MotionEvent?): Boolean {\n        if (event == null || view == null) return false\n        val currentTouch = Vector2(event.x, event.y)\n        val startTouch = currentTouchStart\n\n        playerBinding?.playerIntroPlay?.isGone = true\n\n        // Handle pan with two fingers\n        if (event.pointerCount == 2 && !isLocked && isFullScreenPlayer && !hasTriggeredSpeedUp && currentTouchAction == null) {\n            holdhandler.removeCallbacks(holdRunnable) // remove 2x speed\n\n            // Gesture detectors for zoom & pan\n            if (scaleGestureDetector == null) {\n                createScaleGestureDetector(view.context)\n            }\n\n            isCurrentTouchValid = false // Prevent other touches\n            scaleGestureDetector?.onTouchEvent(event)\n\n            when (event.actionMasked) {\n                MotionEvent.ACTION_POINTER_DOWN -> {\n                    // Hide UI\n                    if (isShowing) {\n                        onClickChange()\n                    }\n                }\n\n                MotionEvent.ACTION_MOVE -> {\n                    val newPan = Vector2(\n                        (event.getX(0) + event.getX(1)) / 2f,\n                        (event.getY(0) + event.getY(1)) / 2f\n                    )\n                    val oldPan = lastPan\n                    if (oldPan != null) {\n                        val matrix = currentZoomMatrix()\n                        // Delta move\n                        matrix.postTranslate(newPan.x - oldPan.x, newPan.y - oldPan.y)\n                        applyZoomMatrix(matrix, false)\n                        updateBrightnessOverlayBounds()\n                    }\n                    lastPan = newPan\n                }\n\n                MotionEvent.ACTION_POINTER_UP, MotionEvent.ACTION_UP -> {\n                    // Reset touch\n                    lastPan = null\n                    currentTouchStart = null\n                    currentLastTouchAction = null\n                    currentTouchAction = null\n                    currentTouchStartPlayerTime = null\n                    currentTouchLast = null\n                    currentTouchStartTime = null\n\n                    // Reset views\n                    playerBinding?.videoOutline?.isVisible = false\n                    matrixAnimation?.cancel()\n                    matrixAnimation = null\n\n                    // After we have zoomed in, snap to\n                    matrixAnimation = ValueAnimator.ofFloat(0.0f, 1.0f).apply {\n                        startDelay = 0\n                        duration = 200\n\n                        val startMatrix = currentZoomMatrix()\n                        val endMatrix = desiredMatrix ?: return@apply\n\n                        val (startX, startY, startScale) = matrixToTranslationAndScale(startMatrix)\n                        val (endX, endY, endScale) = matrixToTranslationAndScale(endMatrix)\n\n                        addUpdateListener { animation ->\n                            val value = animation.animatedValue as Float // ValueAnimator.ofFloat\n\n                            // Linear interpolation of scale and translation between startMatrix and endMatrix\n                            val valueInv = 1.0f - value\n                            val x = startX * valueInv + endX * value\n                            val y = startY * valueInv + endY * value\n                            val s = startScale * valueInv + endScale * value\n                            val m = Matrix()\n                            m.setScale(s, s)\n                            m.postTranslate(x, y)\n                            applyZoomMatrix(m, true)\n                        }\n                        start()\n                    }\n                }\n            }\n            return true\n        }\n\n        playerBinding?.apply {\n            when (event.action) {\n                MotionEvent.ACTION_DOWN -> {\n                    // validates if the touch is inside of the player area\n                    isCurrentTouchValid = view.isValidTouch(currentTouch.x, currentTouch.y)\n                    if (isCurrentTouchValid && isShowingEpisodeOverlay) {\n                        toggleEpisodesOverlay(show = false)\n                    } else if (isCurrentTouchValid) {\n                        if (speedupEnabled) {\n                            hasTriggeredSpeedUp = false\n                            if (player.getIsPlaying() && !isLocked && isFullScreenPlayer) {\n                                holdhandler.postDelayed(holdRunnable, 500)\n                            }\n                        }\n                        isVolumeLocked = currentRequestedVolume < 1.0f\n                        if (currentRequestedVolume <= 1.0f) {\n                            hasShownVolumeToast = false\n                        }\n\n                        isBrightnessLocked = currentRequestedBrightness < 1.0f\n                        if (currentRequestedBrightness <= 1.0f) {\n                            hasShownBrightnessToast = false\n                        }\n\n                        currentTouchStartTime = System.currentTimeMillis()\n                        currentTouchStart = currentTouch\n                        currentTouchLast = currentTouch\n                        currentTouchStartPlayerTime = player.getPosition()\n\n                        getBrightness()?.let {\n                            currentRequestedBrightness = it + currentExtraBrightness\n                        }\n                        verifyVolume()\n                    }\n                }\n\n                MotionEvent.ACTION_UP -> {\n                    holdhandler.removeCallbacks(holdRunnable)\n                    if (hasTriggeredSpeedUp) {\n                        player.setPlaybackSpeed(DataStoreHelper.playBackSpeed)\n                        showOrHideSpeedUp(false)\n                    }\n                    if (isCurrentTouchValid && !isLocked && isFullScreenPlayer) {\n                        // seek time\n                        if (swipeHorizontalEnabled && currentTouchAction == TouchAction.Time) {\n                            val startTime = currentTouchStartPlayerTime\n                            if (startTime != null) {\n                                calculateNewTime(\n                                    startTime,\n                                    startTouch,\n                                    currentTouch\n                                )?.let { seekTo ->\n                                    if (abs(seekTo - startTime) > MINIMUM_SEEK_TIME) {\n                                        player.seekTo(seekTo, PlayerEventSource.UI)\n                                    }\n                                }\n                            }\n                        }\n                    }\n\n                    // see if click is eligible for seek 10s\n                    val holdTime = currentTouchStartTime?.minus(System.currentTimeMillis())\n                    if (isCurrentTouchValid // is valid\n                        && currentTouchAction == null // no other action like swiping is taking place\n                        && currentLastTouchAction == null // last action was none, this prevents mis input random seek\n                        && holdTime != null\n                        && holdTime < DOUBLE_TAB_MAXIMUM_HOLD_TIME // it is a click not a long hold\n                    ) {\n                        if (!isLocked\n                            && (System.currentTimeMillis() - currentLastTouchEndTime) < DOUBLE_TAB_MINIMUM_TIME_BETWEEN // the time since the last action is short\n                        ) {\n                            currentClickCount++\n\n                            if (currentClickCount >= 1) { // have double clicked\n                                currentDoubleTapIndex++\n                                if (doubleTapPauseEnabled && isFullScreenPlayer) { // you can pause if your tap is in the middle of the screen\n                                    when {\n                                        currentTouch.x < screenWidthWithOrientation / 2 - (DOUBLE_TAB_PAUSE_PERCENTAGE * screenWidthWithOrientation) -> {\n                                            if (doubleTapEnabled)\n                                                rewind()\n                                        }\n\n                                        currentTouch.x > screenWidthWithOrientation / 2 + (DOUBLE_TAB_PAUSE_PERCENTAGE * screenWidthWithOrientation) -> {\n                                            if (doubleTapEnabled)\n                                                fastForward()\n                                        }\n\n                                        else -> {\n                                            player.handleEvent(\n                                                CSPlayerEvent.PlayPauseToggle,\n                                                PlayerEventSource.UI\n                                            )\n                                        }\n                                    }\n                                } else if (doubleTapEnabled && isFullScreenPlayer) {\n                                    if (currentTouch.x < screenWidthWithOrientation / 2) {\n                                        rewind()\n                                    } else {\n                                        fastForward()\n                                    }\n                                }\n                            }\n                        } else {\n                            // is a valid click but not fast enough for seek\n                            currentClickCount = 0\n                            if (!hasTriggeredSpeedUp) {\n                                toggleShowDelayed()\n                            }\n                            // onClickChange()\n                        }\n                    } else {\n                        currentClickCount = 0\n                    }\n\n                    // If we hid the UI for a gesture and playback is paused, show it again\n                    if (!player.getIsPlaying()) {\n                        val didGesture =\n                            currentTouchAction != null || currentLastTouchAction != null\n                        if (didGesture && uiShowingBeforeGesture && !isShowing) {\n                            isShowing = true\n                            animateLayoutChanges()\n                        }\n                    }\n\n                    // call auto hide as it wont hide when you have your finger down\n                    autoHide()\n\n                    // reset variables\n                    isCurrentTouchValid = false\n                    currentTouchStart = null\n                    currentLastTouchAction = currentTouchAction\n                    currentTouchAction = null\n                    currentTouchStartPlayerTime = null\n                    currentTouchLast = null\n                    currentTouchStartTime = null\n                    uiShowingBeforeGesture = false\n\n                    // resets UI\n                    playerTimeText.isVisible = false\n\n                    currentLastTouchEndTime = System.currentTimeMillis()\n                }\n\n                MotionEvent.ACTION_MOVE -> {\n                    // if current touch is valid\n\n                    if (hasTriggeredSpeedUp) {\n                        return true\n                    }\n                    if (startTouch != null && isCurrentTouchValid && !isLocked && isFullScreenPlayer) {\n                        // action is unassigned and can therefore be assigned\n\n                        if (currentTouchAction == null) {\n                            val diffFromStart = startTouch - currentTouch\n                            if (swipeVerticalEnabled) {\n                                if (abs(diffFromStart.y * 100 / screenHeightWithOrientation) > MINIMUM_VERTICAL_SWIPE) {\n                                    // left = Brightness, right = Volume, but the UI is reversed to show the UI better\n                                    uiShowingBeforeGesture = isShowing\n                                    currentTouchAction =\n                                        if (startTouch.x < screenWidthWithOrientation / 2) {\n                                            // hide the UI if you hold brightness to show screen better, better UX\n                                            hidePlayerUI()\n                                            TouchAction.Brightness\n                                        } else {\n                                            // hide the UI if you hold volume to show screen better, better UX\n                                            hidePlayerUI()\n                                            TouchAction.Volume\n                                        }\n                                }\n                            }\n                            if (swipeHorizontalEnabled) {\n                                if (abs(diffFromStart.x * 100 / screenHeightWithOrientation) > MINIMUM_HORIZONTAL_SWIPE) {\n                                    currentTouchAction = TouchAction.Time\n                                }\n                            }\n                        }\n\n                        // display action\n                        val lastTouch = currentTouchLast\n                        if (lastTouch != null) {\n                            val diffFromLast = lastTouch - currentTouch\n                            val verticalAddition =\n                                diffFromLast.y * VERTICAL_MULTIPLIER / screenHeightWithOrientation.toFloat()\n\n                            // update UI\n                            playerTimeText.isVisible = false\n\n                            when (currentTouchAction) {\n                                TouchAction.Time -> {\n                                    holdhandler.removeCallbacks(holdRunnable)\n                                    // this simply updates UI as the seek logic happens on release\n                                    // startTime is rounded to make the UI sync in a nice way\n                                    val startTime =\n                                        currentTouchStartPlayerTime?.div(1000L)?.times(1000L)\n                                    if (startTime != null) {\n                                        calculateNewTime(\n                                            startTime,\n                                            startTouch,\n                                            currentTouch\n                                        )?.let { newMs ->\n                                            val skipMs = newMs - startTime\n                                            playerTimeText.apply {\n                                                text =\n                                                    \"${convertTimeToString(newMs / 1000)} [${\n                                                        (if (abs(skipMs) < 1000) \"\" else (if (skipMs > 0) \"+\" else \"-\"))\n                                                    }${convertTimeToString(abs(skipMs / 1000))}]\"\n                                                isVisible = true\n                                            }\n                                        }\n                                    }\n                                }\n\n                                TouchAction.Brightness -> {\n                                    holdhandler.removeCallbacks(holdRunnable)\n                                    playerBinding?.playerProgressbarRightHolder?.apply {\n                                        if (!isVisible || alpha < 1f) {\n                                            alpha = 1f\n                                            isVisible = true\n                                        }\n\n                                        progressBarRightHideRunnable?.let { removeCallbacks(it) }\n                                        progressBarRightHideRunnable = Runnable {\n                                            // Fade out the progress bar\n                                            animate().cancel()\n                                            animate()\n                                                .alpha(0f)\n                                                .setDuration(300)\n                                                .withEndAction { isVisible = false }\n                                                .start()\n                                        }\n                                        // Show the progress bar for 1.5 seconds\n                                        postDelayed(progressBarRightHideRunnable, 1500)\n                                    }\n\n                                    val lastRequested = currentRequestedBrightness\n                                    val nextBrightness = if (extraBrightnessEnabled) {\n                                        currentRequestedBrightness + verticalAddition\n                                    } else {\n                                        (currentRequestedBrightness + verticalAddition).coerceIn(\n                                            0.0f,\n                                            1.0f\n                                        )\n                                    }\n                                    // Log.e(\"Brightness\", \"Current: $currentRequestedBrightness, Next: $nextBrightness\")\n                                    // show toast\n                                    if (extraBrightnessEnabled && nextBrightness > 1.0f && isBrightnessLocked && !hasShownBrightnessToast) {\n                                        showToast(R.string.slide_up_again_to_exceed_100)\n                                        hasShownBrightnessToast = true\n                                    }\n                                    currentRequestedBrightness = nextBrightness\n\n                                    // this is to not spam request it, just in case it fucks over someone\n                                    if (lastRequested != currentRequestedBrightness)\n                                        setBrightness(currentRequestedBrightness)\n\n                                    val level1ProgressBar = playerProgressbarRightLevel1\n\n                                    // max is set high to make it smooth\n                                    level1ProgressBar.max = 100_000\n                                    level1ProgressBar.progress =\n                                        max(\n                                            2_000,\n                                            (min(\n                                                1.0f,\n                                                currentRequestedBrightness\n                                            ) * 100_000f).toInt()\n                                        )\n\n                                    if (extraBrightnessEnabled && !isBrightnessLocked) {\n                                        val level2ProgressBar = playerProgressbarRightLevel2\n\n                                        currentExtraBrightness = if (currentRequestedBrightness > 1.0f) min(2.0f, currentRequestedBrightness) - 1.0f else 0.0f\n                                        level2ProgressBar.max = 100_000\n                                        level2ProgressBar.progress =\n                                            (currentExtraBrightness * 100_000f).toInt().coerceIn(2_000, 100_000)\n                                        level2ProgressBar.isVisible = currentRequestedBrightness > 1.0f\n                                        brightnessOverlay?.let {\n                                            it.alpha = currentExtraBrightness\n                                        }\n                                    }\n\n                                    // Log.i(\"Brightness\", \"current: $currentRequestedBrightness, ce: $currentExtraBrightness L1: ${level1ProgressBar.progress}, L2: ${level2ProgressBar.progress}\")\n                                    playerProgressbarRightIcon.setImageResource(\n                                        brightnessIcons[min( // clamp the value in case of extra brightness\n                                            brightnessIcons.size - 1,\n                                            max(\n                                                0,\n                                                round(currentRequestedBrightness * (brightnessIcons.size - 1)).toInt()\n                                            )\n                                        )]\n                                    )\n                                }\n\n                                TouchAction.Volume -> {\n                                    holdhandler.removeCallbacks(holdRunnable)\n                                    handleVolumeAdjustment(\n                                        verticalAddition,\n                                        false\n                                    )\n                                }\n\n                                else -> Unit\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        currentTouchLast = currentTouch\n        return true\n    }\n\n    @SuppressLint(\"GestureBackNavigation\")\n    private fun handleKeyEvent(event: KeyEvent, hasNavigated: Boolean): Boolean {\n        if (hasNavigated) {\n            autoHide()\n            return false\n        }\n        val keyCode = event.keyCode\n\n        if (event.action == KeyEvent.ACTION_DOWN) {\n            when (keyCode) {\n                KeyEvent.KEYCODE_DPAD_CENTER -> {\n                    if (!isShowing) {\n                        // If UI is not shown make click instantly skip to next chapter even if locked\n                        if (timestampShowState) {\n                            player.handleEvent(CSPlayerEvent.SkipCurrentChapter)\n                        } else if (!isLocked) {\n                            player.handleEvent(CSPlayerEvent.PlayPauseToggle)\n                        }\n                        onClickChange()\n                        return true\n                    }\n                }\n\n                KeyEvent.KEYCODE_DPAD_DOWN,\n                KeyEvent.KEYCODE_DPAD_UP -> {\n                    if (!isShowing && !isShowingEpisodeOverlay) {\n                        onClickChange()\n                        return true\n                    }\n                }\n\n                KeyEvent.KEYCODE_DPAD_LEFT -> {\n                    if (!isShowing && !isLocked && !isShowingEpisodeOverlay) {\n                        player.seekTime(-androidTVInterfaceOffSeekTime)\n                        return true\n                    } else if (playerBinding?.playerPausePlay?.isFocused == true) {\n                        player.seekTime(-androidTVInterfaceOnSeekTime)\n                        return true\n                    }\n                }\n\n                KeyEvent.KEYCODE_DPAD_RIGHT -> {\n                    if (!isShowing && !isLocked && !isShowingEpisodeOverlay) {\n                        player.seekTime(androidTVInterfaceOffSeekTime)\n                        return true\n                    } else if (playerBinding?.playerPausePlay?.isFocused == true) {\n                        player.seekTime(androidTVInterfaceOnSeekTime)\n                        return true\n                    }\n                }\n\n                KeyEvent.KEYCODE_VOLUME_DOWN,\n                KeyEvent.KEYCODE_VOLUME_UP -> {\n                    if (isLayout(PHONE or EMULATOR) && isFullScreenPlayer) {\n                        /**\n                         * Some TVs do not support volume boosting, and overriding\n                         * the volume buttons can be inconvenient for TV users.\n                         * Since boosting volume is mainly useful on phones and emulators,\n                         * we limit this feature to those devices.\n                         */\n                        verifyVolume()\n                        if (currentRequestedVolume <= 1.0f) {\n                            hasShownVolumeToast = false\n                        }\n                        isVolumeLocked = currentRequestedVolume < 1.0f\n                        handleVolumeAdjustment(\n                            // +- 5%\n                            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {\n                                0.05f\n                            } else {\n                                -0.05f\n                            },\n                            true\n                        )\n                        return true\n                    }\n                }\n            }\n        }\n\n        when (keyCode) {\n            // don't allow dpad move when hidden\n\n            KeyEvent.KEYCODE_DPAD_DOWN,\n            KeyEvent.KEYCODE_DPAD_UP,\n            KeyEvent.KEYCODE_DPAD_DOWN_LEFT,\n            KeyEvent.KEYCODE_DPAD_DOWN_RIGHT,\n            KeyEvent.KEYCODE_DPAD_UP_LEFT,\n            KeyEvent.KEYCODE_DPAD_UP_RIGHT -> {\n                if (!isShowing) {\n                    return true\n                } else {\n                    autoHide()\n                }\n            }\n\n            // netflix capture back and hide ~monke\n            // This is removed due to inconsistent behavior on A36 vs A22, see https://github.com/recloudstream/cloudstream/issues/1804\n            /*KeyEvent.KEYCODE_BACK -> {\n                if (isShowing && isLayout(TV or EMULATOR)) {\n                    onClickChange()\n                    return true\n                }\n            }*/\n        }\n\n        return false\n    }\n\n    private var loudnessEnhancer: LoudnessEnhancer? = null\n\n    private fun handleVolumeAdjustment(\n        delta: Float,\n        fromButton: Boolean,\n    ) {\n        val audioManager =\n            activity?.getSystemService(Context.AUDIO_SERVICE) as? AudioManager ?: return\n        val currentVolumeStep = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)\n        val maxVolumeStep = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)\n\n        val currentVolume = currentRequestedVolume\n        val isCurrentVolumeLocked = isVolumeLocked\n\n        val nextVolume =\n            (currentVolume + delta).coerceIn(0.0f, if (isCurrentVolumeLocked) 1.0f else 2.0f)\n\n        val nextVolumeStep =\n            (nextVolume * maxVolumeStep.toFloat()).roundToInt().coerceIn(0, maxVolumeStep)\n\n        // show toast\n        if (fromButton) {\n            // for button related request we only show a toast when we exceeded the volume\n            if (currentVolume <= 1.0f && nextVolume > 1.0f && !hasShownVolumeToast) {\n                showToast(R.string.volume_exceeded_100)\n                hasShownVolumeToast = true\n            }\n        } else {\n            val nextRequestedVolume = currentVolume + delta\n\n            // for swipes, we show toast that we need to swipe again\n            if (nextRequestedVolume > 1.0 && isCurrentVolumeLocked && !hasShownVolumeToast) {\n                showToast(R.string.slide_up_again_to_exceed_100)\n                hasShownVolumeToast = true\n            }\n        }\n\n        // set the current volume step\n        if (nextVolumeStep != currentVolumeStep) {\n            audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, nextVolumeStep, 0)\n        }\n\n        var hasBoostError = false\n\n        // Apply loudness enhancer for volumes > 100%, removes it if less\n        if (nextVolume > 1.0f) {\n            val boostFactor = ((nextVolume - 1.0f) * 1000).toInt()\n            val currentEnhancer = loudnessEnhancer\n\n            if (currentEnhancer != null) {\n                currentEnhancer.setTargetGain(boostFactor)\n            } else {\n                val audioSessionId = (playerView?.player as? ExoPlayer)?.audioSessionId\n                if (audioSessionId != null && audioSessionId != AudioManager.ERROR) {\n                    try {\n                        loudnessEnhancer = LoudnessEnhancer(audioSessionId).apply {\n                            setTargetGain(boostFactor)\n                            enabled = true\n                        }\n                    } catch (t: Throwable) {\n                        logError(t)\n                        hasBoostError = true\n                    }\n                }\n            }\n        } else {\n            loudnessEnhancer?.release()\n            loudnessEnhancer = null\n        }\n\n        currentRequestedVolume = nextVolume\n\n        // Update the progress bar\n        playerBinding?.apply {\n            val level1ProgressBar = playerProgressbarLeftLevel1\n            val level2ProgressBar = playerProgressbarLeftLevel2\n\n            // Change color to show that LoudnessEnhancer broke\n            // this is not a real fix, but solves the crash issue\n            if (nextVolume > 1.0f) {\n                level2ProgressBar.progressTintList = ColorStateList.valueOf(\n                    ContextCompat.getColor(\n                        level2ProgressBar.context, if (hasBoostError) {\n                            R.color.colorPrimaryRed\n                        } else {\n                            R.color.colorPrimaryOrange\n                        }\n                    )\n                )\n            }\n\n            level1ProgressBar.max = 100_000\n            level1ProgressBar.progress =\n                (nextVolume * 100_000f).toInt().coerceIn(2_000, 100_000)\n\n            level2ProgressBar.max = 100_000\n            level2ProgressBar.progress =\n                if (nextVolume > 1.0f) ((nextVolume - 1.0) * 100_000f).toInt()\n                    .coerceIn(2_000, 100_000) else 0\n            level2ProgressBar.isVisible = nextVolume > 1.0f\n\n            // Calculate the clamped index for the volume icon based on the requested volume\n            val iconIndex = (nextVolume * (volumeIcons.lastIndex))\n                .roundToInt()\n                .coerceIn(0, volumeIcons.lastIndex)\n\n            // Update icon\n            playerProgressbarLeftIcon.setImageResource(volumeIcons[iconIndex])\n        }\n\n        // alpha fade\n        playerBinding?.playerProgressbarLeftHolder?.apply {\n            if (!isVisible || alpha < 1f) {\n                alpha = 1f\n                isVisible = true\n            }\n\n            progressBarLeftHideRunnable?.let { removeCallbacks(it) }\n            progressBarLeftHideRunnable = Runnable {\n                // Fade out the progress bar\n                animate().cancel()\n                animate()\n                    .alpha(0f)\n                    .setDuration(300)\n                    .withEndAction { isVisible = false }\n                    .start()\n            }\n            // Show the progress bar for 1.5 seconds\n            postDelayed(progressBarLeftHideRunnable, 1500)\n        }\n    }\n\n    protected fun uiReset() {\n        isShowing = false\n        toggleEpisodesOverlay(false)\n        // if nothing has loaded these buttons should not be visible\n        playerBinding?.apply {\n            playerSkipEpisode.isVisible = false\n            playerGoForwardRoot.isVisible = false\n            playerTracksBtt.isVisible = false\n            playerSkipOp.isVisible = false\n            shadowOverlay.isVisible = false\n        }\n        updateLockUI()\n        updateUIVisibility()\n        animateLayoutChanges()\n        resetFastForwardText()\n        resetRewindText()\n    }\n\n    override fun onSaveInstanceState(outState: Bundle) {\n        // As this is video specific it is better to not do any setKey/getKey\n        outState.putLong(SUBTITLE_DELAY_BUNDLE_KEY, subtitleDelay)\n        super.onSaveInstanceState(outState)\n    }\n\n    @SuppressLint(\"ClickableViewAccessibility\")\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        // init variables\n        setPlayBackSpeed(DataStoreHelper.playBackSpeed)\n        savedInstanceState?.getLong(SUBTITLE_DELAY_BUNDLE_KEY)?.let {\n            subtitleDelay = it\n        }\n\n        // handle tv controls\n        playerEventListener = { eventType ->\n            when (eventType) {\n                PlayerEventType.Lock -> {\n                    toggleLock()\n                }\n\n                PlayerEventType.NextEpisode -> {\n                    player.handleEvent(CSPlayerEvent.NextEpisode)\n                }\n\n                PlayerEventType.Pause -> {\n                    player.handleEvent(CSPlayerEvent.Pause)\n                }\n\n                PlayerEventType.PlayPauseToggle -> {\n                    player.handleEvent(CSPlayerEvent.PlayPauseToggle)\n                }\n\n                PlayerEventType.Play -> {\n                    player.handleEvent(CSPlayerEvent.Play)\n                }\n\n                PlayerEventType.SkipCurrentChapter -> {\n                    player.handleEvent(CSPlayerEvent.SkipCurrentChapter)\n                }\n\n                PlayerEventType.Resize -> {\n                    nextResize()\n                }\n\n                PlayerEventType.PrevEpisode -> {\n                    player.handleEvent(CSPlayerEvent.PrevEpisode)\n                }\n\n                PlayerEventType.SeekForward -> {\n                    player.handleEvent(CSPlayerEvent.SeekForward)\n                }\n\n                PlayerEventType.ShowSpeed -> {\n                    showSpeedDialog()\n                }\n\n                PlayerEventType.SeekBack -> {\n                    player.handleEvent(CSPlayerEvent.SeekBack)\n                }\n\n                PlayerEventType.Restart -> {\n                    player.handleEvent(CSPlayerEvent.Restart)\n                }\n\n                PlayerEventType.ToggleMute -> {\n                    player.handleEvent(CSPlayerEvent.ToggleMute)\n                }\n\n                PlayerEventType.ToggleHide -> {\n                    onClickChange()\n                }\n\n                PlayerEventType.ShowMirrors -> {\n                    showMirrorsDialogue()\n                }\n\n                PlayerEventType.SearchSubtitlesOnline -> {\n                    if (subsProvidersIsActive) {\n                        openOnlineSubPicker(view.context, null) {}\n                    }\n                }\n\n                PlayerEventType.SkipOp -> {\n                    skipOp()\n                }\n            }\n        }\n\n        // handle tv controls directly based on player state\n        keyEventListener = { eventNav ->\n            // Don't hook player keys if player isn't active\n            if (player.isActive()) {\n                val (event, hasNavigated) = eventNav\n                if (event != null)\n                    handleKeyEvent(event, hasNavigated)\n                else false\n            } else false\n        }\n\n        try {\n            context?.let { ctx ->\n                val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n\n                fastForwardTime =\n                    settingsManager.getInt(ctx.getString(R.string.double_tap_seek_time_key), 10)\n                        .toLong() * 1000L\n\n                androidTVInterfaceOffSeekTime =\n                    settingsManager.getInt(\n                        ctx.getString(R.string.android_tv_interface_off_seek_key),\n                        10\n                    )\n                        .toLong() * 1000L\n                androidTVInterfaceOnSeekTime =\n                    settingsManager.getInt(\n                        ctx.getString(R.string.android_tv_interface_on_seek_key),\n                        10\n                    )\n                        .toLong() * 1000L\n\n                navigationBarHeight = ctx.getNavigationBarHeight()\n                statusBarHeight = ctx.getStatusBarHeight()\n\n                swipeHorizontalEnabled =\n                    settingsManager.getBoolean(ctx.getString(R.string.swipe_enabled_key), true)\n                swipeVerticalEnabled =\n                    settingsManager.getBoolean(\n                        ctx.getString(R.string.swipe_vertical_enabled_key),\n                        true\n                    )\n                playBackSpeedEnabled = settingsManager.getBoolean(\n                    ctx.getString(R.string.playback_speed_enabled_key),\n                    false\n                )\n                playerRotateEnabled = settingsManager.getBoolean(\n                    ctx.getString(R.string.rotate_video_key),\n                    false\n                )\n                autoPlayerRotateEnabled = settingsManager.getBoolean(\n                    ctx.getString(R.string.auto_rotate_video_key),\n                    true\n                )\n                playerResizeEnabled =\n                    settingsManager.getBoolean(\n                        ctx.getString(R.string.player_resize_enabled_key),\n                        true\n                    )\n                doubleTapEnabled =\n                    settingsManager.getBoolean(\n                        ctx.getString(R.string.double_tap_enabled_key),\n                        false\n                    )\n\n                doubleTapPauseEnabled =\n                    settingsManager.getBoolean(\n                        ctx.getString(R.string.double_tap_pause_enabled_key),\n                        false\n                    )\n\n                hideControlsNames = settingsManager.getBoolean(\n                    ctx.getString(R.string.hide_player_control_names_key),\n                    false\n                )\n\n                speedupEnabled = settingsManager.getBoolean(\n                    ctx.getString(R.string.speedup_key),\n                    false\n                )\n\n                extraBrightnessEnabled = settingsManager.getBoolean(\n                    ctx.getString(R.string.extra_brightness_key),\n                    false\n                )\n\n                val profiles = QualityDataHelper.getProfiles()\n                val type = if (ctx.isUsingMobileData())\n                    QualityDataHelper.QualityProfileType.Data\n                else QualityDataHelper.QualityProfileType.WiFi\n\n                currentQualityProfile =\n                    profiles.firstOrNull { it.types.contains(type) }?.id ?: profiles.firstOrNull()?.id\n                            ?: currentQualityProfile\n\n//                currentPrefQuality = settingsManager.getInt(\n//                    ctx.getString(if (ctx.isUsingMobileData()) R.string.quality_pref_mobile_data_key else R.string.quality_pref_key),\n//                    currentPrefQuality\n//                )\n                // useSystemBrightness =\n                //    settingsManager.getBoolean(ctx.getString(R.string.use_system_brightness_key), false)\n            }\n            playerBinding?.apply {\n                playerSpeedBtt.isVisible = playBackSpeedEnabled\n                playerResizeBtt.isVisible = playerResizeEnabled\n                playerRotateBtt.isVisible =\n                    if (isLayout(TV or EMULATOR)) false else playerRotateEnabled\n                if (hideControlsNames) {\n                    hideControlsNames()\n                }\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n\n        playerBinding?.apply {\n            if (isLayout(TV or EMULATOR)) {\n                mapOf(\n                    playerGoBack to playerGoBackText,\n                    playerRestart to playerRestartText,\n                    playerGoForward to playerGoForwardText,\n                    downloadHeaderToggle to downloadHeaderToggleText,\n                    playerEpisodesButton to playerEpisodesButtonText\n                ).forEach { (button, text) ->\n                    button.setOnFocusChangeListener { _, hasFocus ->\n                        if (!hasFocus) {\n                            text.isSelected = false\n                            text.isVisible = false\n                            return@setOnFocusChangeListener\n                        }\n                        if (button.id == R.id.player_episodes_button) {\n                            toggleEpisodesOverlay(show = true)\n                        } else {\n                            toggleEpisodesOverlay(show = false)\n                        }\n                        text.isSelected = true\n                        text.isVisible = true\n                    }\n                }\n            }\n\n            playerPausePlay.setOnClickListener {\n                autoHide()\n                if (currentPlayerStatus == CSPlayerLoading.IsEnded && isLayout(PHONE)) {\n                    player.handleEvent(CSPlayerEvent.Restart)\n                } else {\n                    player.handleEvent(CSPlayerEvent.PlayPauseToggle)\n                }\n            }\n\n            exoDuration.setOnClickListener {\n                setRemainingTimeCounter(true)\n            }\n\n            timeLeft.setOnClickListener {\n                setRemainingTimeCounter(false)\n            }\n\n            skipChapterButton.setOnClickListener {\n                player.handleEvent(CSPlayerEvent.SkipCurrentChapter)\n            }\n\n            playerRotateBtt.setOnClickListener {\n                autoHide()\n                toggleRotate()\n            }\n\n            // init clicks\n            playerResizeBtt.setOnClickListener {\n                autoHide()\n                nextResize()\n            }\n\n            playerSpeedBtt.setOnClickListener {\n                autoHide()\n                showSpeedDialog()\n            }\n\n            playerSkipOp.setOnClickListener {\n                autoHide()\n                skipOp()\n            }\n\n            playerSkipEpisode.setOnClickListener {\n                autoHide()\n                player.handleEvent(CSPlayerEvent.NextEpisode)\n            }\n\n            playerGoForward.setOnClickListener {\n                autoHide()\n                player.handleEvent(CSPlayerEvent.NextEpisode)\n            }\n\n            playerRestart.setOnClickListener {\n                autoHide()\n                player.handleEvent(CSPlayerEvent.Restart)\n            }\n\n            playerLock.setOnClickListener {\n                autoHide()\n                toggleLock()\n            }\n\n            playerSubtitleOffsetBtt.setOnClickListener {\n                showSubtitleOffsetDialog()\n            }\n\n            playerRew.setOnClickListener {\n                autoHide()\n                rewind()\n            }\n\n            playerFfwd.setOnClickListener {\n                autoHide()\n                fastForward()\n            }\n\n            playerGoBack.setOnClickListener {\n                activity?.popCurrentPage(\"FullScreenPlayer\")\n            }\n\n            playerSourcesBtt.setOnClickListener {\n                showMirrorsDialogue()\n            }\n\n            playerTracksBtt.setOnClickListener {\n                showTracksDialogue()\n            }\n\n            // it is !not! a bug that you cant touch the right side, it does not register inputs on navbar or status bar\n            playerHolder.setOnTouchListener { callView, event ->\n                return@setOnTouchListener handleMotionEvent(callView, event)\n            }\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                playerControlsScroll.setOnScrollChangeListener { _, _, _, _, _ ->\n                    autoHide()\n                }\n            }\n\n            exoProgress.setOnTouchListener { _, event ->\n                // this makes the bar not disappear when sliding\n                when (event.action) {\n                    MotionEvent.ACTION_DOWN -> {\n                        currentTapIndex++\n                    }\n\n                    MotionEvent.ACTION_MOVE -> {\n                        currentTapIndex++\n                    }\n\n                    MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_BUTTON_RELEASE -> {\n                        autoHide()\n                    }\n                }\n                return@setOnTouchListener false\n            }\n            playerEpisodesButton.setOnClickListener {\n                toggleEpisodesOverlay(show = true)\n            }\n        }\n        // cs3 is peak media center\n        setRemainingTimeCounter(durationMode || isLayout(TV))\n        playerBinding?.exoPosition?.doOnTextChanged { _, _, _, _ ->\n            updateRemainingTime()\n        }\n        // init UI\n        try {\n            uiReset()\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    @SuppressLint(\"SourceLockedOrientationActivity\")\n    private fun toggleRotate() {\n        activity?.let {\n            toggleOrientationWithSensor(it)\n            rotatedManually = true\n        }\n    }\n\n    private fun PlayerCustomLayoutBinding.hideControlsNames() {\n        fun iterate(layout: LinearLayout) {\n            layout.children.forEach {\n                if (it is MaterialButton) {\n                    it.textSize = 0f\n                    it.iconPadding = 0\n                    it.iconGravity = MaterialButton.ICON_GRAVITY_TEXT_START\n                    it.setPadding(0, 0, 0, 0)\n                } else if (it is LinearLayout) {\n                    iterate(it)\n                }\n            }\n        }\n        iterate(playerLockHolder.parent as LinearLayout)\n    }\n\n    override fun playerDimensionsLoaded(width: Int, height: Int) {\n        isVerticalOrientation = height > width\n        updateOrientation()\n    }\n\n    private fun updateRemainingTime() {\n        val duration = player.getDuration()\n        val position = player.getPosition()\n\n        if (duration != null && duration > 1 && position != null) {\n            val remainingTimeSeconds = (duration - position + 500) / 1000\n            val formattedTime = \"-${DateUtils.formatElapsedTime(remainingTimeSeconds)}\"\n\n            playerBinding?.timeLeft?.text = formattedTime\n        }\n    }\n\n    private fun setRemainingTimeCounter(showRemaining: Boolean) {\n        durationMode = showRemaining\n        playerBinding?.exoDuration?.isInvisible = showRemaining\n        playerBinding?.timeLeft?.isVisible = showRemaining\n    }\n\n    private fun dynamicOrientation(): Int {\n        return if (autoPlayerRotateEnabled) {\n            if (isVerticalOrientation) {\n                ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT\n            } else {\n                ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE\n            }\n        } else {\n            ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE // default orientation\n        }\n    }\n\n    private fun toggleEpisodesOverlay(show: Boolean) {\n        if (show && !isShowingEpisodeOverlay) {\n            previousPlayStatus = player.getIsPlaying()\n            player.handleEvent(CSPlayerEvent.Pause)\n            showEpisodesOverlay()\n            isShowingEpisodeOverlay = true\n            animateEpisodesOverlay(true)\n        } else if (isShowingEpisodeOverlay) {\n            if (previousPlayStatus) player.handleEvent(CSPlayerEvent.Play)\n            isShowingEpisodeOverlay = false\n            animateEpisodesOverlay(false)\n        }\n    }\n\n    private fun animateEpisodesOverlay(show: Boolean) {\n        playerBinding?.playerEpisodeOverlay?.let { overlay ->\n            overlay.animate().cancel()\n            (overlay.parent as? ViewGroup)?.layoutTransition = null // Disable layout transitions\n\n            val offset = 50 * overlay.resources.displayMetrics.density\n\n            overlay.translationX = if (show) offset else 0f\n            playerBinding?.playerEpisodeOverlay?.isVisible = true\n\n            overlay.animate()\n                .translationX(if (show) 0f else offset)\n                .alpha(if (show) 1f else 0f)\n                .setDuration(300)\n                .setInterpolator(AccelerateDecelerateInterpolator()).withEndAction {\n                    if (!show) {\n                        playerBinding?.playerEpisodeOverlay?.isGone = true\n                    }\n                }\n                .start()\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.animation.ValueAnimator\nimport android.annotation.SuppressLint\nimport android.app.Dialog\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.content.res.ColorStateList\nimport android.graphics.Bitmap\nimport android.os.Build\nimport android.os.Bundle\nimport android.text.Spanned\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport android.widget.ImageView\nimport android.widget.LinearLayout\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.annotation.MainThread\nimport androidx.annotation.OptIn\nimport androidx.core.animation.addListener\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.edit\nimport androidx.core.text.toSpanned\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.lifecycle.ViewModelProvider\nimport androidx.lifecycle.viewModelScope\nimport androidx.media3.common.Format.NO_VALUE\nimport androidx.media3.common.MimeTypes\nimport androidx.media3.common.Player\nimport androidx.media3.common.util.UnstableApi\nimport androidx.media3.exoplayer.ExoPlayer\nimport androidx.media3.ui.PlayerNotificationManager\nimport androidx.media3.ui.PlayerNotificationManager.EXTRA_INSTANCE_ID\nimport androidx.media3.ui.PlayerNotificationManager.MediaDescriptionAdapter\nimport androidx.preference.PreferenceManager\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.CloudStreamApp\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.LoadResponse.Companion.getAniListId\nimport com.lagradost.cloudstream3.LoadResponse.Companion.getImdbId\nimport com.lagradost.cloudstream3.LoadResponse.Companion.getMalId\nimport com.lagradost.cloudstream3.LoadResponse.Companion.getTMDbId\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.databinding.DialogOnlineSubtitlesBinding\nimport com.lagradost.cloudstream3.databinding.FragmentPlayerBinding\nimport com.lagradost.cloudstream3.databinding.PlayerSelectSourceAndSubsBinding\nimport com.lagradost.cloudstream3.databinding.PlayerSelectTracksBinding\nimport com.lagradost.cloudstream3.isAnimeOp\nimport com.lagradost.cloudstream3.isEpisodeBased\nimport com.lagradost.cloudstream3.isLiveStream\nimport com.lagradost.cloudstream3.isMovieType\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.mvvm.observeNullable\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities\nimport com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities.SubtitleSearch\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.subtitleProviders\nimport com.lagradost.cloudstream3.ui.download.DownloadButtonSetup\nimport com.lagradost.cloudstream3.ui.player.CS3IPlayer.Companion.preferredAudioTrackLanguage\nimport com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.updateForcedEncoding\nimport com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType\nimport com.lagradost.cloudstream3.ui.player.source_priority.LinkSource\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper.getLinkPriority\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityProfileDialog\nimport com.lagradost.cloudstream3.ui.result.ACTION_CLICK_DEFAULT\nimport com.lagradost.cloudstream3.ui.result.EpisodeAdapter\nimport com.lagradost.cloudstream3.ui.result.FOCUS_SELF\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.ui.result.ResultFragment\nimport com.lagradost.cloudstream3.ui.result.ResultViewModel2\nimport com.lagradost.cloudstream3.ui.result.SyncViewModel\nimport com.lagradost.cloudstream3.ui.result.setLinearListLayout\nimport com.lagradost.cloudstream3.ui.setRecycledViewPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.ui.subtitles.SUBTITLE_AUTO_SELECT_KEY\nimport com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment\nimport com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.getAutoSelectLanguageTagIETF\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\nimport com.lagradost.cloudstream3.utils.AppContextUtils.sortSubs\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\nimport com.lagradost.cloudstream3.utils.EpisodeSkip\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromTagToEnglishLanguageName\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromTagToLanguageName\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.languages\nimport com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI\nimport com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\nimport com.lagradost.cloudstream3.utils.downloader.DownloadUtils.getImageBitmapFromUrl\nimport com.lagradost.cloudstream3.utils.setText\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.safefile.SafeFile\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.isActive\nimport kotlinx.coroutines.launch\nimport java.io.Serializable\nimport java.util.Calendar\n\n@OptIn(UnstableApi::class)\nclass GeneratorPlayer : FullScreenPlayer() {\n    companion object {\n        const val NOTIFICATION_ID = 2326\n        const val CHANNEL_ID = 7340\n        const val STOP_ACTION = \"stopcs3\"\n\n        private var lastUsedGenerator: IGenerator? = null\n        fun newInstance(generator: IGenerator, syncData: HashMap<String, String>? = null): Bundle {\n            Log.i(TAG, \"newInstance = $syncData\")\n            lastUsedGenerator = generator\n            return Bundle().apply {\n                if (syncData != null) putSerializable(\"syncData\", syncData)\n            }\n        }\n\n        val subsProviders = subtitleProviders\n        val subsProvidersIsActive\n            get() = subsProviders.isNotEmpty()\n    }\n\n\n    private var limitTitle = 0\n    private var showTitle = false\n    private var showName = false\n    private var showResolution = false\n    private var showMediaInfo = false\n\n    private lateinit var viewModel: PlayerGeneratorViewModel //by activityViewModels()\n    private lateinit var sync: SyncViewModel\n    private var currentLinks: Set<Pair<ExtractorLink?, ExtractorUri?>> = setOf()\n    private var currentSubs: Set<SubtitleData> = setOf()\n\n    private var currentSelectedLink: Pair<ExtractorLink?, ExtractorUri?>? = null\n    private var currentSelectedSubtitles: SubtitleData? = null\n    private var currentMeta: Any? = null\n    private var nextMeta: Any? = null\n    private var isActive: Boolean = false\n    private var isNextEpisode: Boolean = false // this is used to reset the watch time\n\n    private var preferredAutoSelectSubtitles: String? = null // null means do nothing, \"\" means none\n\n    private var binding: FragmentPlayerBinding? = null\n    private var allMeta: List<ResultEpisode>? = null\n    private fun startLoading() {\n        player.release()\n        currentSelectedSubtitles = null\n        isActive = false\n        binding?.overlayLoadingSkipButton?.isVisible = false\n        binding?.playerLoadingOverlay?.isVisible = true\n    }\n\n    private fun setSubtitles(subtitle: SubtitleData?, userInitiated: Boolean): Boolean {\n        // If subtitle is changed and user initiated -> Save the language\n        if (subtitle != currentSelectedSubtitles && userInitiated) {\n            val subtitleLanguageTagIETF = if (subtitle == null) {\n                \"\" // -> No Subtitles\n            } else {\n                subtitle.getIETF_tag()\n            }\n\n            if (subtitleLanguageTagIETF != null) {\n                Log.i(TAG, \"Set SUBTITLE_AUTO_SELECT_KEY to '$subtitleLanguageTagIETF'\")\n                setKey(SUBTITLE_AUTO_SELECT_KEY, subtitleLanguageTagIETF)\n                preferredAutoSelectSubtitles = subtitleLanguageTagIETF\n            }\n        }\n\n        currentSelectedSubtitles = subtitle\n        //Log.i(TAG, \"setSubtitles = $subtitle\")\n        return player.setPreferredSubtitles(subtitle)\n    }\n\n    override fun embeddedSubtitlesFetched(subtitles: List<SubtitleData>) {\n        viewModel.addSubtitles(subtitles.toSet())\n    }\n\n    override fun onTracksInfoChanged() {\n        val tracks = player.getVideoTracks()\n        playerBinding?.playerTracksBtt?.isVisible =\n            tracks.allVideoTracks.size > 1 || tracks.allAudioTracks.size > 1\n        // Only set the preferred language if it is available.\n        // Otherwise it may give some users audio track init failed!\n        if (tracks.allAudioTracks.any { it.language == preferredAudioTrackLanguage }) {\n            player.setPreferredAudioTrack(preferredAudioTrackLanguage)\n        }\n        updatePlayerInfo()\n    }\n\n    override fun playerStatusChanged() {\n        super.playerStatusChanged()\n        if (player.getIsPlaying()) {\n            viewModel.forceClearCache = false\n        }\n    }\n\n    private fun noSubtitles(): Boolean {\n        return setSubtitles(null, true)\n    }\n\n    private fun getPos(): Long {\n        val durPos = getViewPos(viewModel.getId()) ?: return 0L\n        if (durPos.duration == 0L) return 0L\n        if (durPos.position * 100L / durPos.duration > 95L) {\n            return 0L\n        }\n        return durPos.position\n    }\n\n    private var currentVerifyLink: Job? = null\n\n    private fun loadExtractorJob(extractorLink: ExtractorLink?) {\n        currentVerifyLink?.cancel()\n\n        extractorLink?.let { link ->\n            currentVerifyLink = ioSafe {\n                if (link.extractorData != null) {\n                    getApiFromNameNull(link.source)?.extractorVerifierJob(link.extractorData)\n                }\n            }\n        }\n    }\n\n    // https://github.com/androidx/media/blob/main/libraries/ui/src/main/java/androidx/media3/ui/PlayerNotificationManager.java#L1517\n    private fun createBroadcastIntent(\n        action: String,\n        context: Context,\n        instanceId: Int\n    ): PendingIntent {\n        val intent: Intent = Intent(action).setPackage(context.packageName)\n        intent.putExtra(EXTRA_INSTANCE_ID, instanceId)\n        val pendingFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE\n        } else PendingIntent.FLAG_UPDATE_CURRENT\n\n        return PendingIntent.getBroadcast(context, instanceId, intent, pendingFlags)\n    }\n\n    private var cachedPlayerNotificationManager: PlayerNotificationManager? = null\n\n    private fun getMediaNotification(context: Context): PlayerNotificationManager {\n        val cache = cachedPlayerNotificationManager\n        if (cache != null) return cache\n        return PlayerNotificationManager.Builder(\n            context,\n            NOTIFICATION_ID,\n            CHANNEL_ID.toString()\n        )\n            .setChannelNameResourceId(R.string.player_notification_channel_name)\n            .setChannelDescriptionResourceId(R.string.player_notification_channel_description)\n            .setMediaDescriptionAdapter(object : MediaDescriptionAdapter {\n                override fun getCurrentContentTitle(player: Player): CharSequence {\n                    return when (val meta = currentMeta) {\n                        is ResultEpisode -> {\n                            meta.headerName\n                        }\n\n                        is ExtractorUri -> {\n                            meta.headerName ?: meta.name\n                        }\n\n                        else -> null\n                    } ?: \"Unknown\"\n                }\n\n                override fun createCurrentContentIntent(player: Player): PendingIntent? {\n                    // Open the app without creating a new task to resume playback seamlessly\n                    return PendingIntentCompat.getActivity(\n                        context,\n                        0,\n                        Intent(context, MainActivity::class.java),\n                        0,\n                        false\n                    )\n                }\n\n                override fun getCurrentContentText(player: Player): CharSequence? {\n                    return when (val meta = currentMeta) {\n                        is ResultEpisode -> {\n                            meta.name\n                        }\n\n                        is ExtractorUri -> {\n                            if (meta.headerName == null) {\n                                null\n                            } else {\n                                meta.name\n                            }\n                        }\n\n                        else -> null\n                    }\n                }\n\n                override fun getCurrentLargeIcon(\n                    player: Player,\n                    callback: PlayerNotificationManager.BitmapCallback\n                ): Bitmap? {\n                    ioSafe {\n                        val url = when (val meta = currentMeta) {\n                            is ResultEpisode -> {\n                                meta.poster\n                            }\n\n                            else -> null\n                        }\n                        // if we have a poster url try with it first\n                        if (url != null) {\n                            val urlBitmap = context.getImageBitmapFromUrl(url)\n                            if (urlBitmap != null) {\n                                callback.onBitmap(urlBitmap)\n                                return@ioSafe\n                            }\n                        }\n\n                        // retry several times with a preview in case the preview generator is slow\n                        for (i in 0..10) {\n                            val preview = this@GeneratorPlayer.player.getPreview(0.5f)\n                            if (preview == null) {\n                                delay(1000L)\n                                continue\n                            }\n                            callback.onBitmap(\n                                preview\n                            )\n                            break\n                        }\n                    }\n\n                    // return null as we want to use the callback\n                    return null\n                }\n            }).setCustomActionReceiver(object : PlayerNotificationManager.CustomActionReceiver {\n                // we have to use a custom action for stop if we want to exit the player instead of just stopping playback\n                override fun createCustomActions(\n                    context: Context,\n                    instanceId: Int\n                ): MutableMap<String, NotificationCompat.Action> {\n                    return mutableMapOf(\n                        STOP_ACTION to NotificationCompat.Action(\n                            R.drawable.baseline_stop_24,\n                            context.getString(androidx.media3.ui.R.string.exo_controls_stop_description),\n                            createBroadcastIntent(STOP_ACTION, context, instanceId)\n                        )\n                    )\n                }\n\n                override fun getCustomActions(player: Player): MutableList<String> {\n                    return mutableListOf(STOP_ACTION)\n                }\n\n                override fun onCustomAction(player: Player, action: String, intent: Intent) {\n                    when (action) {\n                        STOP_ACTION -> {\n                            exitFullscreen()\n                            this@GeneratorPlayer.player.release()\n                            activity?.popCurrentPage()\n                        }\n                    }\n                }\n            })\n            .setPlayActionIconResourceId(R.drawable.ic_baseline_play_arrow_24)\n            .setPauseActionIconResourceId(R.drawable.netflix_pause)\n            .setSmallIconResourceId(R.drawable.baseline_headphones_24)\n            .setStopActionIconResourceId(R.drawable.baseline_stop_24)\n            .setRewindActionIconResourceId(R.drawable.go_back_30)\n            .setFastForwardActionIconResourceId(R.drawable.go_forward_30)\n            .setNextActionIconResourceId(R.drawable.ic_baseline_skip_next_24)\n            .setPreviousActionIconResourceId(R.drawable.baseline_skip_previous_24)\n            .build().apply {\n                setColorized(true) // Color\n                setUseChronometer(true) // Seekbar\n\n                // Don't show the prev episode button\n                setUsePreviousAction(false)\n                setUsePreviousActionInCompactView(false)\n\n                // Don't show the next episode button\n                setUseNextAction(false)\n                setUseNextActionInCompactView(false)\n\n                // Show the skip 30s in both modes\n                setUseFastForwardAction(true)\n                setUseFastForwardActionInCompactView(true)\n\n                // Only show rewind in expanded\n                setUseRewindAction(true)\n                setUseFastForwardActionInCompactView(false)\n\n                // Use custom stop action\n                setUseStopAction(false)\n            }\n            .also { cachedPlayerNotificationManager = it }\n    }\n\n    override fun playerUpdated(player: Any?) {\n        super.playerUpdated(player)\n\n        // Cancel the notification when released\n        if (player == null) {\n            cachedPlayerNotificationManager?.setPlayer(null)\n            cachedPlayerNotificationManager = null\n            return\n        }\n\n        // setup the notification when starting the player\n        if (player is ExoPlayer) {\n            val ctx = context ?: return\n            getMediaNotification(ctx).apply {\n                setPlayer(player)\n                mMediaSession?.platformToken?.let {\n                    setMediaSessionToken(it)\n                }\n            }\n        }\n    }\n\n    override fun onDownload(event: DownloadEvent) {\n        super.onDownload(event)\n        showDownloadProgress(event)\n    }\n\n    private fun showDownloadProgress(event: DownloadEvent) {\n        activity?.runOnUiThread {\n            playerBinding?.downloadedProgress?.apply {\n                val indeterminate = event.totalBytes <= 0 || event.downloadedBytes <= 0\n                isIndeterminate = indeterminate\n                if (!indeterminate) {\n                    max = (event.totalBytes / 1000).toInt()\n                    progress = (event.downloadedBytes / 1000).toInt()\n                }\n            }\n            playerBinding?.downloadedProgressText.setText(\n                txt(\n                    R.string.download_size_format,\n                    android.text.format.Formatter.formatShortFileSize(\n                        context,\n                        event.downloadedBytes\n                    ),\n                    android.text.format.Formatter.formatShortFileSize(context, event.totalBytes)\n                )\n            )\n            val downloadSpeed =\n                android.text.format.Formatter.formatShortFileSize(context, event.downloadSpeed)\n            playerBinding?.downloadedProgressSpeedText?.text =\n                    // todo string fmt\n                event.connections?.let { connections ->\n                    \"%s/s - %d Connections\".format(downloadSpeed, connections)\n                } ?: downloadSpeed\n\n            // don't display when done\n            playerBinding?.downloadedProgressSpeedText?.isGone =\n                event.downloadedBytes != 0L && event.downloadedBytes - 1024 >= event.totalBytes\n        }\n    }\n\n    private fun loadLink(link: Pair<ExtractorLink?, ExtractorUri?>?, sameEpisode: Boolean) {\n        if (link == null) return\n\n        // manage UI\n        binding?.playerLoadingOverlay?.isVisible = false\n        val isTorrent =\n            link.first?.type == ExtractorLinkType.MAGNET || link.first?.type == ExtractorLinkType.TORRENT\n\n        playerBinding?.downloadHeader?.isVisible = false\n        playerBinding?.downloadHeaderToggle?.isVisible = isTorrent\n        if (!isLayout(PHONE)) {\n            playerBinding?.downloadBothHeader?.isVisible = isTorrent\n        }\n\n        showDownloadProgress(DownloadEvent(0, 0, 0, null))\n\n        uiReset()\n        currentSelectedLink = link\n        currentMeta = viewModel.getMeta()\n        nextMeta = viewModel.getNextMeta()\n        allMeta = viewModel.getAllMeta()?.filterIsInstance<ResultEpisode>()?.map { episode ->\n            // Refresh all the episodes watch duration\n            getViewPos(episode.id)?.let { data ->\n                episode.copy(position = data.position, duration = data.duration)\n            } ?: episode\n        }\n        //  setEpisodes(viewModel.getAllMeta() ?: emptyList())\n        isActive = true\n        setPlayerDimen(null)\n        setTitle()\n        if (!sameEpisode)\n            hasRequestedStamps = false\n\n        loadExtractorJob(link.first)\n        // load player\n        context?.let { ctx ->\n            val (url, uri) = link\n            player.loadPlayer(\n                ctx,\n                sameEpisode,\n                url,\n                uri,\n                startPosition = if (sameEpisode) null else {\n                    if (isNextEpisode) 0L else getPos()\n                },\n                currentSubs,\n                (if (sameEpisode) currentSelectedSubtitles else null) ?: getAutoSelectSubtitle(\n                    currentSubs, settings = true, downloads = true\n                ),\n                preview = isFullScreenPlayer\n            )\n        }\n\n        if (!sameEpisode) {\n            player.addTimeStamps(emptyList()) // clear stamps\n            // Resets subtitle delay, as we watch some other content\n            player.setSubtitleOffset(0)\n        }\n    }\n\n    private fun sortLinks(qualityProfile: Int): List<Pair<ExtractorLink?, ExtractorUri?>> {\n        return currentLinks.sortedBy {\n            // negative because we want to sort highest quality first\n            -getLinkPriority(qualityProfile, it.first)\n        }\n    }\n\n    data class TempMetaData(\n        var episode: Int? = null,\n        var season: Int? = null,\n        var name: String? = null,\n        var imdbId: String? = null,\n    )\n\n    private fun getMetaData(): TempMetaData {\n        val meta = TempMetaData()\n\n        when (val newMeta = currentMeta) {\n            is ResultEpisode -> {\n                if (!newMeta.tvType.isMovieType()) {\n                    meta.episode = newMeta.episode\n                    meta.season = newMeta.season\n                }\n                meta.name = newMeta.headerName\n            }\n\n            is ExtractorUri -> {\n                if (newMeta.tvType?.isMovieType() == false) {\n                    meta.episode = newMeta.episode\n                    meta.season = newMeta.season\n                }\n                meta.name = newMeta.headerName\n            }\n        }\n        return meta\n    }\n\n    fun getName(entry: AbstractSubtitleEntities.SubtitleEntity, withLanguage: Boolean): String {\n        if (entry.lang.isBlank() || !withLanguage) {\n            return entry.name\n        }\n        val language = fromTagToLanguageName(entry.lang.trim()) ?: entry.lang\n        return \"$language ${entry.name}\"\n    }\n\n    override fun openOnlineSubPicker(\n        context: Context, loadResponse: LoadResponse?, dismissCallback: (() -> Unit)\n    ) {\n        val providers = subsProviders.toList()\n        val isSingleProvider = subsProviders.size == 1\n\n        val dialog = Dialog(context, R.style.DialogFullscreenPlayer)\n        val binding =\n            DialogOnlineSubtitlesBinding.inflate(LayoutInflater.from(context), null, false)\n        dialog.setContentView(binding.root)\n        fixSystemBarsPadding(binding.root)\n\n        var currentSubtitles: List<AbstractSubtitleEntities.SubtitleEntity> = emptyList()\n        var currentSubtitle: AbstractSubtitleEntities.SubtitleEntity? = null\n\n        val layout = R.layout.sort_bottom_single_choice_double_text\n        val arrayAdapter =\n            object : ArrayAdapter<AbstractSubtitleEntities.SubtitleEntity>(dialog.context, layout) {\n                fun setHearingImpairedIcon(\n                    imageViewEnd: ImageView?, position: Int\n                ) {\n                    if (imageViewEnd == null) return\n                    val isHearingImpaired =\n                        currentSubtitles.getOrNull(position)?.isHearingImpaired ?: false\n\n                    val drawableEnd = if (isHearingImpaired) {\n                        ContextCompat.getDrawable(\n                            context, R.drawable.ic_baseline_hearing_24\n                        )?.apply {\n                            setTint(\n                                ContextCompat.getColor(\n                                    context, R.color.textColor\n                                )\n                            )\n                        }\n                    } else null\n\n                    imageViewEnd.setImageDrawable(drawableEnd)\n                }\n\n                @SuppressLint(\"SetTextI18n\")\n                override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {\n                    val view = convertView ?: LayoutInflater.from(context).inflate(layout, null)\n\n                    val item = getItem(position)\n\n                    val mainTextView = view.findViewById<TextView>(R.id.main_text)\n                    val secondaryTextView = view.findViewById<TextView>(R.id.secondary_text)\n                    val drawableEnd = view.findViewById<ImageView>(R.id.drawable_end)\n\n                    mainTextView?.text = item?.let { getName(it, false) }\n\n                    val language =\n                        item?.let { fromTagToLanguageName(it.lang) ?: it.lang } ?: \"\"\n                    val providerSuffix =\n                        if (isSingleProvider || item == null) \"\" else \" · ${item.source}\"\n                    secondaryTextView?.text = language + providerSuffix\n\n                    setHearingImpairedIcon(drawableEnd, position)\n                    return view\n                }\n            }\n\n        dialog.show()\n        binding.cancelBtt.setOnClickListener {\n            dialog.dismissSafe()\n        }\n\n        binding.subtitleAdapter.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n        binding.subtitleAdapter.adapter = arrayAdapter\n\n        binding.subtitleAdapter.setOnItemClickListener { _, _, position, _ ->\n            currentSubtitle = currentSubtitles.getOrNull(position) ?: return@setOnItemClickListener\n        }\n\n        var currentLanguageTagIETF: String = getAutoSelectLanguageTagIETF()\n\n\n        fun setSubtitlesList(list: List<AbstractSubtitleEntities.SubtitleEntity>) {\n            currentSubtitles = list\n            arrayAdapter.clear()\n            arrayAdapter.addAll(currentSubtitles)\n        }\n\n        val currentTempMeta = getMetaData()\n\n        // bruh idk why it is not correct\n        val color =\n            ColorStateList.valueOf(context.colorFromAttribute(androidx.appcompat.R.attr.colorAccent))\n        binding.searchLoadingBar.progressTintList = color\n        binding.searchLoadingBar.indeterminateTintList = color\n\n        observeNullable(viewModel.currentSubtitleYear) {\n            // When year is changed search again\n            binding.subtitlesSearch.setQuery(binding.subtitlesSearch.query, true)\n            binding.yearBtt.text = it?.toString() ?: txt(R.string.none).asString(context)\n        }\n\n        binding.yearBtt.setOnClickListener {\n            val none = txt(R.string.none).asString(context)\n            val currentYear = Calendar.getInstance().get(Calendar.YEAR)\n            val earliestYear = 1900\n\n            val years = (currentYear downTo earliestYear).toList()\n            val options = listOf(none) + years.map {\n                it.toString()\n            }\n\n            val selectedIndex = viewModel.currentSubtitleYear.value\n                ?.let {\n                    // + 1 since none also takes a space\n                    years.indexOf(it) + 1\n                }\n                ?.takeIf { it >= 0 } ?: 0\n\n            activity?.showDialog(\n                options,\n                selectedIndex,\n                txt(R.string.year).asString(context),\n                true, {\n                }, { index ->\n                    viewModel.setSubtitleYear(years.getOrNull(index - 1))\n                }\n            )\n        }\n\n        binding.subtitlesSearch.setOnQueryTextListener(object :\n            androidx.appcompat.widget.SearchView.OnQueryTextListener {\n            override fun onQueryTextSubmit(query: String?): Boolean {\n                binding.searchLoadingBar.show()\n                ioSafe {\n                    val search =\n                        SubtitleSearch(\n                            query = query ?: return@ioSafe,\n                            imdbId = loadResponse?.getImdbId(),\n                            tmdbId = loadResponse?.getTMDbId()?.toInt(),\n                            malId = loadResponse?.getMalId()?.toInt(),\n                            aniListId = loadResponse?.getAniListId()?.toInt(),\n                            epNumber = currentTempMeta.episode,\n                            seasonNumber = currentTempMeta.season,\n                            lang = currentLanguageTagIETF.ifBlank { null },\n                            year = viewModel.currentSubtitleYear.value\n                        )\n\n                    // TODO Make ui a lot better, like search with tabs\n                    val results = providers.amap {\n                        when (val response = Resource.fromResult(it.search(search))) {\n                            is Resource.Success -> {\n                                response.value\n                            }\n\n                            is Resource.Loading -> {\n                                emptyList()\n                            }\n\n                            is Resource.Failure -> {\n                                showToast(response.errorString)\n                                emptyList()\n                            }\n                        }\n                    }\n                    val max = results.maxOfOrNull { it.size } ?: return@ioSafe\n\n                    // very ugly\n                    val items = ArrayList<AbstractSubtitleEntities.SubtitleEntity>()\n                    val arrays = results.size\n                    for (index in 0 until max) {\n                        for (i in 0 until arrays) {\n                            items.add(results[i].getOrNull(index) ?: continue)\n                        }\n                    }\n\n                    // ugly ik\n                    activity?.runOnUiThread {\n                        setSubtitlesList(items)\n                        binding.searchLoadingBar.hide()\n                    }\n                }\n\n                return true\n            }\n\n            override fun onQueryTextChange(newText: String?): Boolean {\n                return true\n            }\n        })\n\n        binding.searchFilter.setOnClickListener { view ->\n            val languagesTagName =\n                languages\n                    .map { Pair(it.IETF_tag, it.nameNextToFlagEmoji()) }\n                    .sortedBy {\n                        it.second.substringAfter(\"\\u00a0\").lowercase()\n                    } // name ignoring flag emoji\n            val (langTagsIETF, langNames) = languagesTagName.unzip()\n\n            activity?.showDialog(\n                langNames,\n                langTagsIETF.indexOf(currentLanguageTagIETF),\n                view?.context?.getString(R.string.subs_subtitle_languages)\n                    ?: return@setOnClickListener,\n                true,\n                { }) { index ->\n                currentLanguageTagIETF = langTagsIETF[index]\n                binding.subtitlesSearch.setQuery(binding.subtitlesSearch.query, true)\n            }\n        }\n\n        binding.applyBtt.setOnClickListener {\n            currentSubtitle?.let { currentSubtitle ->\n                providers.firstOrNull { it.idPrefix == currentSubtitle.idPrefix }?.let { api ->\n                    ioSafe {\n                        when (val apiResource =\n                            Resource.fromResult(api.resource(currentSubtitle))) {\n                            is Resource.Success -> {\n                                val subtitles = apiResource.value.getSubtitles().map { resource ->\n                                    SubtitleData(\n                                        originalName = resource.name ?: getName(\n                                            currentSubtitle,\n                                            true\n                                        ),\n                                        nameSuffix = \"\",\n                                        url = resource.url,\n                                        origin = resource.origin,\n                                        mimeType = resource.url.toSubtitleMimeType(),\n                                        headers = currentSubtitle.headers,\n                                        languageCode = currentSubtitle.lang\n                                    )\n                                }\n                                if (subtitles.isEmpty()) {\n                                    showToast(R.string.no_subtitles)\n                                    return@ioSafe\n                                }\n                                runOnMainThread {\n                                    addAndSelectSubtitles(*subtitles.toTypedArray())\n                                }\n                            }\n\n                            is Resource.Failure -> {\n                                showToast(apiResource.errorString)\n                            }\n\n                            is Resource.Loading -> {\n                                // not possible\n                            }\n                        }\n                    }\n                }\n            }\n            dialog.dismissSafe()\n        }\n\n        dialog.setOnDismissListener {\n            dismissCallback.invoke()\n        }\n\n        dialog.show()\n        binding.subtitlesSearch.setQuery(currentTempMeta.name, true)\n        //TODO: Set year text from currently loaded movie on Player\n        //dialog.subtitles_search_year?.setText(currentTempMeta.year)\n    }\n\n    private fun openSubPicker() {\n        try {\n            subsPathPicker.launch(\n                arrayOf(\n                    \"text/plain\",\n                    \"text/str\",\n                    \"application/octet-stream\",\n                    MimeTypes.TEXT_UNKNOWN,\n                    MimeTypes.TEXT_VTT,\n                    MimeTypes.TEXT_SSA,\n                    MimeTypes.APPLICATION_TTML,\n                    MimeTypes.APPLICATION_MP4VTT,\n                    MimeTypes.APPLICATION_SUBRIP,\n                )\n            )\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    @MainThread\n    private fun addAndSelectSubtitles(\n        vararg subtitleData: SubtitleData\n    ) {\n        if (subtitleData.isEmpty()) return\n        val selectedSubtitle = subtitleData.first()\n        val ctx = context ?: return\n\n        val subs = currentSubs + subtitleData\n\n        // this is used instead of observe(viewModel._currentSubs), because observe is too slow\n        player.setActiveSubtitles(subs)\n\n        // Save current time as to not reset player to 00:00\n        player.saveData()\n        player.reloadPlayer(ctx)\n\n        setSubtitles(selectedSubtitle, false)\n        viewModel.addSubtitles(subtitleData.toSet())\n\n        selectSourceDialog?.dismissSafe()\n\n        showToast(\n            String.format(ctx.getString(R.string.player_loaded_subtitles), selectedSubtitle.name),\n            Toast.LENGTH_LONG\n        )\n    }\n\n    // Open file picker\n    private val subsPathPicker =\n        registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->\n            safe {\n                // It lies, it can be null if file manager quits.\n                if (uri == null) return@safe\n                val ctx = context ?: CloudStreamApp.context ?: return@safe\n                // RW perms for the path\n                ctx.contentResolver.takePersistableUriPermission(\n                    uri,\n                    Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION\n                )\n\n                val file = SafeFile.fromUri(ctx, uri)\n                val fileName = file?.name()\n                println(\"Loaded subtitle file. Selected URI path: $uri - Name: $fileName\")\n                // DO NOT REMOVE THE FILE EXTENSION FROM NAME, IT'S NEEDED FOR MIME TYPES\n                val name = fileName ?: uri.toString()\n\n                val subtitleData = SubtitleData(\n                    name,\n                    \"\",\n                    uri.toString(),\n                    SubtitleOrigin.DOWNLOADED_FILE,\n                    name.toSubtitleMimeType(),\n                    emptyMap(),\n                    null\n                )\n\n                addAndSelectSubtitles(subtitleData)\n            }\n        }\n\n    private var selectSourceDialog: Dialog? = null\n    // var selectTracksDialog: AlertDialog? = null\n\n\n    /** Will toast both when an error is found and when a subtitle is selected,\n     * so only use from a user click and not a background process */\n    private fun addFirstSub(query: SubtitleSearch) =\n        viewModel.viewModelScope.launch {\n            // async should not have a race condition if they are on the same group\n            var hasSelectASubtitle = false\n\n            // first come first served with these subtitles\n            // we might want to change it to prefer different sources when used multiple times,\n            // however caching might make this random after the first click too\n            subsProviders.toList().amap { provider ->\n                val success = when (val result = Resource.fromResult(\n                    provider.search(\n                        query = query\n                    )\n                )) {\n                    is Resource.Failure -> {\n                        // scope might cancel, so we do an extra check\n                        if (this.isActive) {\n                            showToast(\"${provider.idPrefix}${result.errorString}\")\n                        }\n                        return@amap\n                    }\n\n                    is Resource.Loading -> {\n                        // unreachable\n                        return@amap\n                    }\n\n                    is Resource.Success -> {\n                        result.value\n                    }\n                }\n\n                // try to add every subtitle until we have added a new subtitle file\n                for (subtitleEntry in success) {\n                    if (hasSelectASubtitle || !this.isActive) {\n                        break\n                    }\n\n                    val subtitleResources = provider.resource(subtitleEntry).getOrNull() ?: continue\n\n                    val subtitles = subtitleResources.getSubtitles().map { resource ->\n                        SubtitleData(\n                            originalName = resource.name ?: getName(subtitleEntry, true),\n                            nameSuffix = \"\",\n                            url = resource.url,\n                            origin = resource.origin,\n                            mimeType = resource.url.toSubtitleMimeType(),\n                            headers = subtitleEntry.headers,\n                            languageCode = subtitleEntry.lang,\n                        )\n                    }\n\n                    // checks for both a race condition and if any of the subs generated is new\n                    if (this.isActive && !currentSubs.containsAll(subtitles) && !hasSelectASubtitle) {\n                        hasSelectASubtitle = true\n                        runOnMainThread {\n                            addAndSelectSubtitles(*subtitles.toTypedArray())\n                        }\n                        break\n                    }\n                }\n            }\n            // maybe better error here?\n            if (!hasSelectASubtitle && this.isActive) {\n                showToast(R.string.no_subtitles)\n            }\n        }\n\n\n    override fun showMirrorsDialogue() {\n        try {\n            currentSelectedSubtitles = player.getCurrentPreferredSubtitle()\n            //println(\"CURRENT SELECTED :$currentSelectedSubtitles of $currentSubs\")\n            context?.let { ctx ->\n                val isPlaying = player.getIsPlaying()\n                player.handleEvent(CSPlayerEvent.Pause, PlayerEventSource.UI)\n                val currentSubtitles = sortSubs(currentSubs)\n\n                val sourceDialog = Dialog(ctx, R.style.DialogFullscreenPlayer)\n                val binding =\n                    PlayerSelectSourceAndSubsBinding.inflate(LayoutInflater.from(ctx), null, false)\n                sourceDialog.setContentView(binding.root)\n\n                fixSystemBarsPadding(binding.root)\n                selectSourceDialog = sourceDialog\n\n                sourceDialog.show()\n                val providerList = binding.sortProviders\n                val subtitleList = binding.sortSubtitles\n                val subtitleOptionList = binding.sortSubtitlesOptions\n\n                val loadFromFileFooter: TextView =\n                    layoutInflater.inflate(R.layout.sort_bottom_footer_add_choice, null) as TextView\n\n                loadFromFileFooter.text = ctx.getString(R.string.player_load_subtitles)\n                loadFromFileFooter.setOnClickListener {\n                    openSubPicker()\n                }\n                subtitleList.addFooterView(loadFromFileFooter)\n\n                var shouldDismiss = true\n\n                binding.subtitleSettingsBtt.setOnClickListener {\n                    safe {\n                        val subtitlesFragment = SubtitlesFragment()\n                        subtitlesFragment.systemBarsAddPadding = true\n                        subtitlesFragment.show(this.parentFragmentManager, \"SubtitleSettings\")\n                    }\n                }\n\n                fun dismiss() {\n                    if (isPlaying) {\n                        player.handleEvent(CSPlayerEvent.Play)\n                    }\n                    activity?.hideSystemUI()\n                }\n\n                if (subsProvidersIsActive) {\n                    val currentLoadResponse = viewModel.getLoadResponse()\n\n                    val loadFromOpenSubsFooter: TextView = layoutInflater.inflate(\n                        R.layout.sort_bottom_footer_add_choice, null\n                    ) as TextView\n\n                    loadFromOpenSubsFooter.text =\n                        ctx.getString(R.string.player_load_subtitles_online)\n\n                    loadFromOpenSubsFooter.setOnClickListener {\n                        shouldDismiss = false\n                        sourceDialog.dismissSafe(activity)\n                        openOnlineSubPicker(it.context, currentLoadResponse) {\n                            dismiss()\n                        }\n                    }\n                    subtitleList.addFooterView(loadFromOpenSubsFooter)\n\n                    // subs from 1 button here\n                    val metadata = getMetaData()\n                    val queryName = metadata.name ?: currentLoadResponse?.name\n                    if (queryName != null) {\n                        val currentLanguageTagIETF: String = getAutoSelectLanguageTagIETF()\n                        val loadFromFirstSubsFooter: TextView = layoutInflater.inflate(\n                            R.layout.sort_bottom_footer_add_choice, null\n                        ) as TextView\n\n                        loadFromFirstSubsFooter.text =\n                            ctx.getString(R.string.player_load_one_subtitle_online)\n\n                        loadFromFirstSubsFooter.setOnClickListener {\n                            sourceDialog.dismissSafe(activity)\n                            showToast(R.string.loading)\n                            addFirstSub(\n                                SubtitleSearch(\n                                    query = queryName,\n                                    imdbId = currentLoadResponse?.getImdbId(),\n                                    tmdbId = currentLoadResponse?.getTMDbId()?.toInt(),\n                                    malId = currentLoadResponse?.getMalId()?.toInt(),\n                                    aniListId = currentLoadResponse?.getAniListId()?.toInt(),\n                                    epNumber = metadata.episode,\n                                    seasonNumber = metadata.season,\n                                    lang = currentLanguageTagIETF.ifBlank { null },\n                                    year = viewModel.currentSubtitleYear.value\n                                )\n                            )\n                        }\n                        subtitleList.addFooterView(loadFromFirstSubsFooter)\n                    }\n                }\n\n                var sourceIndex = 0\n                var startSource = 0\n                var sortedUrls = emptyList<Pair<ExtractorLink?, ExtractorUri?>>()\n\n                fun refreshLinks(qualityProfile: Int) {\n                    sortedUrls = sortLinks(qualityProfile)\n                    if (sortedUrls.isEmpty()) {\n                        sourceDialog.findViewById<LinearLayout>(R.id.sort_sources_holder)?.isGone =\n                            true\n                    } else {\n                        startSource = sortedUrls.indexOf(currentSelectedLink)\n                        sourceIndex = startSource\n\n                        val sourcesArrayAdapter =\n                            ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)\n\n                        sourcesArrayAdapter.addAll(sortedUrls.map { (link, uri) ->\n                            val name = link?.name ?: uri?.name ?: \"NULL\"\n                            \"$name ${Qualities.getStringByInt(link?.quality)}\"\n                        })\n\n                        providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n                        providerList.adapter = sourcesArrayAdapter\n                        providerList.setSelection(sourceIndex)\n                        providerList.setItemChecked(sourceIndex, true)\n\n                        providerList.setOnItemClickListener { _, _, which, _ ->\n                            sourceIndex = which\n                            providerList.setItemChecked(which, true)\n                        }\n\n                        providerList.setOnItemLongClickListener { _, _, position, _ ->\n                            sortedUrls.getOrNull(position)?.first?.url?.let {\n                                clipboardHelper(\n                                    txt(R.string.video_source),\n                                    it\n                                )\n                            }\n                            true\n                        }\n                    }\n                }\n\n                refreshLinks(currentQualityProfile)\n\n                sourceDialog.setOnDismissListener {\n                    if (shouldDismiss) dismiss()\n                    selectSourceDialog = null\n                }\n\n\n                val subsArrayAdapter =\n                    ArrayAdapter<Spanned>(ctx, R.layout.sort_bottom_single_choice)\n                subsArrayAdapter.add(ctx.getString(R.string.no_subtitles).html())\n\n                val subtitlesGrouped =\n                    currentSubtitles.groupBy { it.originalName }.map { (key, value) ->\n                        key to value.sortedBy { it.nameSuffix.toIntOrNull() ?: 0 }\n                    }.toMap()\n                val subtitlesGroupedList = subtitlesGrouped.entries.toList()\n\n                val subtitles = subtitlesGrouped.map { it.key.html() }\n\n                val subtitleGroupIndexStart =\n                    subtitlesGrouped.keys.indexOf(currentSelectedSubtitles?.originalName) + 1\n                var subtitleGroupIndex = subtitleGroupIndexStart\n\n                val subtitleOptionIndexStart =\n                    subtitlesGrouped[currentSelectedSubtitles?.originalName]?.indexOfFirst { it.nameSuffix == currentSelectedSubtitles?.nameSuffix }\n                        ?: 0\n                var subtitleOptionIndex = subtitleOptionIndexStart\n\n                subsArrayAdapter.addAll(subtitles)\n\n                subtitleList.adapter = subsArrayAdapter\n                subtitleList.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n\n                subtitleList.setSelection(subtitleGroupIndex)\n                subtitleList.setItemChecked(subtitleGroupIndex, true)\n\n                val subsOptionsArrayAdapter =\n                    ArrayAdapter<Spanned>(ctx, R.layout.sort_bottom_single_choice)\n\n                subtitleOptionList.adapter = subsOptionsArrayAdapter\n                subtitleOptionList.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n\n                fun updateSubtitleOptionList() {\n                    subsOptionsArrayAdapter.clear()\n\n                    val subtitleOptions =\n                        subtitlesGroupedList\n                            .getOrNull(subtitleGroupIndex - 1)?.value?.map { subtitle ->\n                                val nameSuffix = subtitle.nameSuffix.html()\n                                nameSuffix.ifBlank {\n                                    when (subtitle.origin) {\n                                        SubtitleOrigin.URL -> txt(R.string.subtitles_from_online)\n                                        SubtitleOrigin.DOWNLOADED_FILE -> txt(R.string.downloaded)\n                                        SubtitleOrigin.EMBEDDED_IN_VIDEO -> txt(R.string.subtitles_from_embedded)\n                                    }.asString(ctx).toSpanned()\n                                }\n                            }\n                            ?: emptyList()\n\n                    // Show nothing if there is nothing to select\n                    val shouldHide = subtitleOptions.size < 2\n                    subtitleOptionList.isGone = shouldHide // Make it easier to click\n                    if (shouldHide) return\n\n                    subsOptionsArrayAdapter.addAll(subtitleOptions)\n\n                    subtitleOptionList.setSelection(subtitleOptionIndex)\n                    subtitleOptionList.setItemChecked(subtitleOptionIndex, true)\n                }\n\n                updateSubtitleOptionList()\n\n                subtitleList.setOnItemClickListener { _, _, which, _ ->\n                    if (which > subtitlesGrouped.size) {\n                        // Since android TV is funky the setOnItemClickListener will be triggered\n                        // instead of setOnClickListener when selecting. To override this we programmatically\n                        // click the view when selecting an item outside the list.\n\n                        // Cheeky way of getting the view at that position to click it\n                        // to avoid keeping track of the various footers.\n                        // getChildAt() gives null :(\n                        val child = subtitleList.adapter.getView(which, null, subtitleList)\n                        child?.performClick()\n                    } else {\n                        if (subtitleGroupIndex != which) {\n                            subtitleGroupIndex = which\n                            subtitleOptionIndex =\n                                if (subtitleGroupIndex == subtitleGroupIndexStart) {\n                                    subtitleOptionIndexStart\n                                } else {\n                                    0\n                                }\n                        }\n                        subtitleList.setItemChecked(which, true)\n                        updateSubtitleOptionList()\n                    }\n                }\n\n                subtitleOptionList.setOnItemClickListener { _, _, which, _ ->\n                    if (which >= (subtitlesGroupedList.getOrNull(subtitleGroupIndex - 1)?.value?.size\n                            ?: -1)\n                    ) {\n                        val child = subtitleOptionList.adapter.getView(which, null, subtitleList)\n                        child?.performClick()\n                    } else {\n                        subtitleOptionIndex = which\n                        subtitleOptionList.setItemChecked(which, true)\n                    }\n                }\n\n                binding.cancelBtt.setOnClickListener {\n                    sourceDialog.dismissSafe(activity)\n                }\n\n                fun setProfileName(profile: Int) {\n                    binding.sourceSettingsBtt.setText(\n                        QualityDataHelper.getProfileName(\n                            profile\n                        )\n                    )\n                }\n                setProfileName(currentQualityProfile)\n\n                binding.profilesClickSettings.setOnClickListener {\n                    val activity = activity ?: return@setOnClickListener\n                    QualityProfileDialog(\n                        activity,\n                        R.style.DialogFullscreenPlayer,\n                        currentLinks.mapNotNull { it.first?.let { extractorLink -> LinkSource(extractorLink) } },\n                        currentQualityProfile\n                    ) { profile ->\n                        currentQualityProfile = profile.id\n                        setProfileName(profile.id)\n                        refreshLinks(profile.id)\n                    }.show()\n                }\n\n                binding.subtitlesEncodingFormat.apply {\n                    val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n\n                    val prefNames = ctx.resources.getStringArray(R.array.subtitles_encoding_list)\n                    val prefValues = ctx.resources.getStringArray(R.array.subtitles_encoding_values)\n\n                    val value = settingsManager.getString(\n                        ctx.getString(R.string.subtitles_encoding_key), null\n                    )\n                    val index = prefValues.indexOf(value)\n                    text = prefNames[if (index == -1) 0 else index]\n                }\n\n                binding.subtitlesEncodingFormat.setOnClickListener {\n                    val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n\n                    val prefNames = ctx.resources.getStringArray(R.array.subtitles_encoding_list)\n                    val prefValues = ctx.resources.getStringArray(R.array.subtitles_encoding_values)\n\n                    val currentPrefMedia = settingsManager.getString(\n                        ctx.getString(R.string.subtitles_encoding_key), null\n                    )\n\n                    shouldDismiss = false\n                    sourceDialog.dismissSafe(activity)\n\n                    val index = prefValues.indexOf(currentPrefMedia)\n                    activity?.showDialog(\n                        prefNames.toList(),\n                        if (index == -1) 0 else index,\n                        ctx.getString(R.string.subtitles_encoding),\n                        true,\n                        {}) {\n                        settingsManager.edit {\n                            putString(\n                                ctx.getString(R.string.subtitles_encoding_key), prefValues[it]\n                            )\n                        }\n                        updateForcedEncoding(ctx)\n                        dismiss()\n                        player.seekTime(-1) // to update subtitles, a dirty trick\n                    }\n                }\n\n                binding.applyBtt.setOnClickListener {\n                    var init = sourceIndex != startSource\n                    if (subtitleGroupIndex != subtitleGroupIndexStart || subtitleOptionIndex != subtitleOptionIndexStart) {\n                        init = init or if (subtitleGroupIndex <= 0) {\n                            noSubtitles()\n                        } else {\n                            subtitlesGroupedList.getOrNull(subtitleGroupIndex - 1)?.value?.getOrNull(\n                                subtitleOptionIndex\n                            )?.let {\n                                setSubtitles(it, true)\n                            } ?: false\n                        }\n                    }\n                    if (init) {\n                        sortedUrls.getOrNull(sourceIndex)?.let {\n                            loadLink(it, true)\n                        }\n                    }\n                    sourceDialog.dismissSafe(activity)\n                }\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    override fun showTracksDialogue() {\n        try {\n            //println(\"CURRENT SELECTED :$currentSelectedSubtitles of $currentSubs\")\n            context?.let { ctx ->\n                val tracks = player.getVideoTracks()\n\n                val isPlaying = player.getIsPlaying()\n                player.handleEvent(CSPlayerEvent.Pause)\n\n                val currentVideoTracks = tracks.allVideoTracks.sortedBy {\n                    it.height?.times(-1)\n                }\n                val currentAudioTracks = tracks.allAudioTracks\n                val binding: PlayerSelectTracksBinding =\n                    PlayerSelectTracksBinding.inflate(LayoutInflater.from(ctx), null, false)\n                val trackDialog = Dialog(ctx, R.style.DialogFullscreenPlayer)\n                trackDialog.setContentView(binding.root)\n                trackDialog.show()\n\n                fixSystemBarsPadding(binding.root)\n\n                // selectTracksDialog = tracksDialog\n\n                val videosList = binding.videoTracksList\n                val audioList = binding.autoTracksList\n\n                binding.videoTracksHolder.isVisible = currentVideoTracks.size > 1\n                binding.audioTracksHolder.isVisible = currentAudioTracks.size > 1\n\n                fun dismiss() {\n                    if (isPlaying) {\n                        player.handleEvent(CSPlayerEvent.Play)\n                    }\n                    activity?.hideSystemUI()\n                }\n\n                val videosArrayAdapter =\n                    ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)\n\n                videosArrayAdapter.addAll(currentVideoTracks.mapIndexed { index, format ->\n                    format.label\n                        ?: (if (format.height == NO_VALUE || format.width == NO_VALUE) index else \"${format.width}x${format.height}\").toString()\n                })\n\n                videosList.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n                videosList.adapter = videosArrayAdapter\n\n                // Sometimes the data is not the same because some data gets resolved at different stages i think\n                var videoIndex = currentVideoTracks.indexOf(tracks.currentVideoTrack).takeIf {\n                    it != -1\n                } ?: currentVideoTracks.indexOfFirst {\n                    tracks.currentVideoTrack?.id == it.id\n                }\n\n                videosList.setSelection(videoIndex)\n                videosList.setItemChecked(videoIndex, true)\n\n                videosList.setOnItemClickListener { _, _, which, _ ->\n                    videoIndex = which\n                    videosList.setItemChecked(which, true)\n                }\n\n                trackDialog.setOnDismissListener {\n                    dismiss()\n                    // selectTracksDialog = null\n                }\n\n                var audioIndexStart = currentAudioTracks.indexOfFirst { track ->\n                    track.id == tracks.currentAudioTrack?.id && \n                    track.formatIndex == tracks.currentAudioTrack?.formatIndex\n                }.coerceAtLeast(0)\n\n                val audioArrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)\n\n                audioArrayAdapter.addAll(currentAudioTracks.mapIndexed { index, track ->\n                    val language = track.language?.let { fromTagToLanguageName(it) ?: it } \n                        ?: track.label \n                        ?: \"Audio\"\n                    \n                    val codec = track.sampleMimeType?.let { mimeType ->\n                    when {\n                            mimeType.contains(\"mp4a\") || mimeType.contains(\"aac\") -> \"aac\"\n                            mimeType.contains(\"ac-3\") || mimeType.contains(\"ac3\") -> \"ac3\"\n                            mimeType.contains(\"eac3-joc\") -> \"Dolby Atmos\"\n                            mimeType.contains(\"eac3\") -> \"eac3\"\n                            mimeType.contains(\"opus\") -> \"opus\"\n                            mimeType.contains(\"vorbis\") -> \"vorbis\"\n                            mimeType.contains(\"mp3\") || mimeType.contains(\"mpeg\") -> \"mp3\"\n                            mimeType.contains(\"flac\") -> \"flac\"\n                            mimeType.contains(\"dts\") -> \"dts\"\n                            else -> mimeType.substringAfter(\"/\")\n                        }\n                    } ?: \"codec?\"\n\n                    \n                    val channels: Int = track.channelCount ?: 0\n                    val channelConfig = when (channels) {\n                        1 -> \"mono\"\n                        2 -> \"stereo\"\n                        6 -> \"5.1\"\n                        8 -> \"7.1\"\n                        else -> \"${channels}Ch\"\n                    }\n\n                    listOfNotNull(\n                        \"[$index]\",\n                        language.replaceFirstChar { it.uppercaseChar() },\n                        codec.uppercase(),\n                        channelConfig.replaceFirstChar { it.uppercaseChar() }\n                    ).joinToString(\" • \")\n                    \n                    \"[$index] $language $codec $channelConfig\"\n                })\n\n                audioList.adapter = audioArrayAdapter\n                audioList.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n\n                audioList.setSelection(audioIndexStart)\n                audioList.setItemChecked(audioIndexStart, true)\n\n                audioList.setOnItemClickListener { _, _, which, _ ->\n                    audioIndexStart = which\n                    audioList.setItemChecked(which, true)\n                }\n\n                binding.cancelBtt.setOnClickListener {\n                    trackDialog.dismissSafe(activity)\n                }\n\n                binding.applyBtt.setOnClickListener {\n                    val currentTrack = currentAudioTracks.getOrNull(audioIndexStart)\n                    player.setPreferredAudioTrack(\n                        currentTrack?.language, \n                        currentTrack?.id,\n                        currentTrack?.formatIndex,\n                    )\n\n                    val currentVideo = currentVideoTracks.getOrNull(videoIndex)\n                    val width = currentVideo?.width ?: NO_VALUE\n                    val height = currentVideo?.height ?: NO_VALUE\n                    if (width != NO_VALUE && height != NO_VALUE) {\n                        player.setMaxVideoSize(width, height, currentVideo?.id)\n                    }\n                    trackDialog.dismissSafe(activity)\n                }\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n\n    override fun playerError(exception: Throwable) {\n        val currentUrl =\n            currentSelectedLink?.let { it.first?.url ?: it.second?.uri?.toString() } ?: \"unknown\"\n        val headers = currentSelectedLink?.first?.headers?.toString() ?: \"none\"\n        val referer = currentSelectedLink?.first?.referer ?: \"none\"\n        Log.e(\n            TAG,\n            \"playerError: $currentSelectedLink, \" +\n                    \"type=${exception::class.java.canonicalName}, \" +\n                    \"message=${exception.message}, url=$currentUrl, headers=$headers, \" +\n                    \"referer=$referer, position=${player.getPosition() ?: \"unknown\"}, \" +\n                    \"duration=${player.getDuration() ?: \"unknown\"}, \" +\n                    \"isPlaying=${player.getIsPlaying()}\", exception\n        )\n\n        if (!hasNextMirror()) {\n            viewModel.forceClearCache = true\n        }\n        super.playerError(exception)\n    }\n\n    private fun noLinksFound() {\n        viewModel.forceClearCache = true\n\n        showToast(R.string.no_links_found_toast, Toast.LENGTH_SHORT)\n        activity?.popCurrentPage()\n    }\n\n    private fun startPlayer() {\n        if (isActive) return // we don't want double load when you skip loading\n\n        val links = sortLinks(currentQualityProfile)\n        if (links.isEmpty()) {\n            noLinksFound()\n            return\n        }\n        loadLink(links.first(), false)\n    }\n\n    override fun nextEpisode() {\n        if (viewModel.hasNextEpisode() == true) {\n            isNextEpisode = true\n            player.release()\n            viewModel.loadLinksNext()\n        }\n    }\n\n    override fun prevEpisode() {\n        if (viewModel.hasPrevEpisode() == true) {\n            isNextEpisode = true\n            player.release()\n            viewModel.loadLinksPrev()\n        }\n    }\n\n    override fun hasNextMirror(): Boolean {\n        val links = sortLinks(currentQualityProfile)\n        return links.isNotEmpty() && links.indexOf(currentSelectedLink) + 1 < links.size\n    }\n\n    override fun nextMirror() {\n        val links = sortLinks(currentQualityProfile)\n        if (links.isEmpty()) {\n            noLinksFound()\n            return\n        }\n\n        val newIndex = links.indexOf(currentSelectedLink) + 1\n        if (newIndex >= links.size) {\n            noLinksFound()\n            return\n        }\n\n        loadLink(links[newIndex], true)\n    }\n\n    override fun onDestroy() {\n        ResultFragment.updateUI()\n        currentVerifyLink?.cancel()\n        super.onDestroy()\n    }\n\n    var maxEpisodeSet: Int? = null\n    var hasRequestedStamps: Boolean = false\n    override fun playerPositionChanged(position: Long, duration: Long) {\n        // Don't save livestream data\n        if ((currentMeta as? ResultEpisode)?.tvType?.isLiveStream() == true) return\n\n        // Don't save NSFW data\n        if ((currentMeta as? ResultEpisode)?.tvType == TvType.NSFW) return\n\n        if (duration <= 0L) return // idk how you achieved this, but div by zero crash\n        if (!hasRequestedStamps) {\n            hasRequestedStamps = true\n            val fetchStamps = context?.let { ctx ->\n                val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n                settingsManager.getBoolean(\n                    ctx.getString(R.string.enable_skip_op_from_database),\n                    true\n                )\n            } ?: true\n            if (fetchStamps)\n                viewModel.loadStamps(duration)\n        }\n\n        val percentage = position * 100L / duration\n\n        DataStoreHelper.setViewPosAndResume(\n            viewModel.getId(),\n            position,\n            duration,\n            currentMeta,\n            nextMeta\n        )\n\n        var isOpVisible = false\n        when (val meta = currentMeta) {\n            is ResultEpisode -> {\n                if (percentage >= UPDATE_SYNC_PROGRESS_PERCENTAGE && (maxEpisodeSet\n                        ?: -1) < meta.episode\n                ) {\n                    context?.let { ctx ->\n                        val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n                        if (settingsManager.getBoolean(\n                                ctx.getString(R.string.episode_sync_enabled_key), true\n                            )\n                        ) maxEpisodeSet = meta.episode\n                        sync.modifyMaxEpisode(meta.totalEpisodeIndex ?: meta.episode)\n                    }\n                }\n\n                if (meta.tvType.isAnimeOp()) isOpVisible = percentage < SKIP_OP_VIDEO_PERCENTAGE\n            }\n        }\n\n        playerBinding?.playerSkipOp?.isVisible = isOpVisible\n\n        when {\n            isLayout(PHONE) ->\n                playerBinding?.playerSkipEpisode?.isVisible =\n                    !isOpVisible && viewModel.hasNextEpisode() == true\n\n            else -> {\n                val hasNextEpisode = viewModel.hasNextEpisode() == true\n                playerBinding?.playerGoForward?.isVisible = hasNextEpisode\n                playerBinding?.playerGoForwardRoot?.isVisible = hasNextEpisode\n            }\n\n        }\n\n        if (percentage >= PRELOAD_NEXT_EPISODE_PERCENTAGE) {\n            viewModel.preLoadNextLinks()\n        }\n    }\n\n    private fun getAutoSelectSubtitle(\n        subtitles: Set<SubtitleData>, settings: Boolean, downloads: Boolean\n    ): SubtitleData? {\n        val langCode = preferredAutoSelectSubtitles ?: return null\n        if (downloads) {\n            return sortSubs(subtitles).firstOrNull { it.origin == SubtitleOrigin.DOWNLOADED_FILE && it.matchesLanguageCode(langCode) }\n        }\n\n        if (!settings) return null\n\n        return sortSubs(subtitles).firstOrNull { it.matchesLanguageCode(langCode) }\n    }\n    \n    private fun autoSelectFromSettings(): Boolean {\n        // auto select subtitle based on settings\n        val langCode = preferredAutoSelectSubtitles\n        val current = player.getCurrentPreferredSubtitle()\n        Log.i(TAG, \"autoSelectFromSettings = $current\")\n        context?.let { ctx ->\n            // Only use the player preferred subtitle if it matches the available language\n            if (current != null && (langCode == null || current.matchesLanguageCode(langCode))) {\n                if (setSubtitles(current, false)) {\n                    player.saveData()\n                    player.reloadPlayer(ctx)\n                    player.handleEvent(CSPlayerEvent.Play)\n                    return true\n                }\n            } else if (!langCode.isNullOrEmpty()) {\n                getAutoSelectSubtitle(\n                    currentSubs, settings = true, downloads = false\n                )?.let { sub ->\n                    if (setSubtitles(sub, false)) {\n                        player.saveData()\n                        player.reloadPlayer(ctx)\n                        player.handleEvent(CSPlayerEvent.Play)\n                        return true\n                    }\n                }\n            }\n        }\n        return false\n    }\n\n    private fun autoSelectFromDownloads(): Boolean {\n        if (player.getCurrentPreferredSubtitle() == null) {\n            getAutoSelectSubtitle(currentSubs, settings = false, downloads = true)?.let { sub ->\n                context?.let { ctx ->\n                    if (setSubtitles(sub, false)) {\n                        player.saveData()\n                        player.reloadPlayer(ctx)\n                        player.handleEvent(CSPlayerEvent.Play)\n                        return true\n                    }\n                }\n            }\n        }\n        return false\n    }\n\n    private fun autoSelectSubtitles() {\n        //Log.i(TAG, \"autoSelectSubtitles\")\n        safe {\n            if (!autoSelectFromSettings()) {\n                autoSelectFromDownloads()\n            }\n        }\n    }\n\n    private fun getHeaderName(): String? {\n        return when (val meta = currentMeta) {\n            is ResultEpisode -> meta.headerName\n            is ExtractorUri -> meta.headerName\n            else -> null\n        }\n    }\n\n    private fun getPlayerVideoTitle(): String {\n        var headerName: String? = null\n        var subName: String? = null\n        var episode: Int? = null\n        var season: Int? = null\n        var tvType: TvType? = null\n\n        when (val meta = currentMeta) {\n            is ResultEpisode -> {\n                headerName = meta.headerName\n                subName = meta.name\n                episode = meta.episode\n                season = meta.season\n                tvType = meta.tvType\n            }\n\n            is ExtractorUri -> {\n                headerName = meta.headerName\n                subName = meta.name\n                episode = meta.episode\n                season = meta.season\n                tvType = meta.tvType\n            }\n        }\n        context?.let { ctx ->\n            //Generate video title\n            val playerVideoTitle = if (headerName != null) {\n                (headerName + if (tvType.isEpisodeBased() && episode != null) if (season == null) \" - ${\n                    ctx.getString(\n                        R.string.episode\n                    )\n                } $episode\"\n                else \" \\\"${ctx.getString(R.string.season_short)}${season}:${\n                    ctx.getString(\n                        R.string.episode_short\n                    )\n                }${episode}\\\"\"\n                else \"\") + if (subName.isNullOrBlank() || subName == headerName) \"\" else \" - $subName\"\n            } else {\n                \"\"\n            }\n            return playerVideoTitle\n        }\n        return \"\"\n    }\n\n\n    @SuppressLint(\"SetTextI18n\")\n    fun setTitle() {\n        var playerVideoTitle = getPlayerVideoTitle()\n\n        //Hide title, if set in setting\n        if (limitTitle < 0) {\n            playerBinding?.playerVideoTitle?.visibility = View.GONE\n        } else {\n            //Truncate video title if it exceeds limit\n            val differenceInLength = playerVideoTitle.length - limitTitle\n            val margin = 3 //If the difference is smaller than or equal to this value, ignore it\n            if (limitTitle > 0 && differenceInLength > margin) {\n                playerVideoTitle = playerVideoTitle.substring(0, limitTitle - 1) + \"...\"\n            }\n        }\n        val isFiller: Boolean? = (currentMeta as? ResultEpisode)?.isFiller\n\n        playerBinding?.playerEpisodeFillerHolder?.isVisible = isFiller ?: false\n        playerBinding?.playerVideoTitle?.text = playerVideoTitle\n        playerBinding?.offlinePin?.isVisible = lastUsedGenerator is DownloadFileGenerator\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    fun setPlayerDimen(widthHeight: Pair<Int, Int>?) {\n        val resolution = widthHeight?.let { \"${it.first}x${it.second}\" }\n        val name = currentSelectedLink?.first?.name ?: currentSelectedLink?.second?.name\n        val title = getHeaderName()\n\n        val result = listOfNotNull(\n            title?.takeIf { showTitle && it.isNotBlank() },\n            name?.takeIf { showName && it.isNotBlank() },\n            resolution?.takeIf { showResolution && it.isNotBlank() },\n        ).joinToString(\" - \")\n\n        playerBinding?.playerVideoTitleRez?.apply {\n            text = result\n            isVisible = result.isNotBlank()\n        }\n    }\n\n    private fun updatePlayerInfo() {\n        val tracks = player.getVideoTracks()\n\n        val videoTrack = tracks.currentVideoTrack\n        val audioTrack = tracks.currentAudioTrack\n\n        val ctx = context ?: return\n        val prefs = PreferenceManager.getDefaultSharedPreferences(ctx)\n        showMediaInfo = prefs.getBoolean(ctx.getString(R.string.show_media_info_key), false)\n\n        val videoCodec = videoTrack?.sampleMimeType?.substringAfterLast('/')?.uppercase()\n        val audioCodec = audioTrack?.sampleMimeType?.substringAfterLast('/')?.uppercase()\n        val language = listOfNotNull(\n            audioTrack?.label,\n            fromTagToLanguageName(audioTrack?.language)?.let { \"[$it]\" }\n        ).joinToString(\" \")\n\n        val stats = arrayOf(videoCodec, audioCodec, language).filter { !it.isNullOrBlank() }.joinToString(\" • \")\n\n        playerBinding?.playerVideoInfo?.apply {\n            text = stats\n            isVisible = showMediaInfo && stats.isNotBlank()\n        }\n    }\n\n    override fun playerDimensionsLoaded(width: Int, height: Int) {\n        super.playerDimensionsLoaded(width, height)\n        setPlayerDimen(width to height)\n    }\n\n    private fun unwrapBundle(savedInstanceState: Bundle?) {\n        Log.i(TAG, \"unwrapBundle = $savedInstanceState\")\n        savedInstanceState?.let { bundle ->\n            sync.addSyncs(bundle.getSafeSerializable<HashMap<String, String>>(\"syncData\"))\n        }\n    }\n\n    override fun onCreateView(\n        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?\n    ): View? {\n        // this is used instead of layout-television to follow the settings and some TV devices are not classified as TV for some reason\n        layout =\n            if (isLayout(TV or EMULATOR)) R.layout.fragment_player_tv else R.layout.fragment_player\n\n        viewModel = ViewModelProvider(this)[PlayerGeneratorViewModel::class.java]\n        sync = ViewModelProvider(this)[SyncViewModel::class.java]\n\n        viewModel.attachGenerator(lastUsedGenerator)\n        unwrapBundle(savedInstanceState)\n        unwrapBundle(arguments)\n\n        val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null\n        binding = FragmentPlayerBinding.bind(root)\n        return root\n    }\n\n    override fun onDestroyView() {\n        binding = null\n        super.onDestroyView()\n    }\n\n    var skipAnimator: ValueAnimator? = null\n    var skipIndex = 0\n\n    private fun displayTimeStamp(show: Boolean) {\n        if (timestampShowState == show) return\n        skipIndex++\n        timestampShowState = show\n        playerBinding?.skipChapterButton?.apply {\n            val showWidth = 170.toPx\n            val noShowWidth = 10.toPx\n            //if((show && width == showWidth) || (!show && width == noShowWidth)) {\n            //    return\n            //}\n            val to = if (show) showWidth else noShowWidth\n            val from = if (!show) showWidth else noShowWidth\n\n            skipAnimator?.cancel()\n            isVisible = true\n\n            // just in case\n            val lay = layoutParams\n            lay.width = from\n            layoutParams = lay\n            skipAnimator = ValueAnimator.ofInt(\n                from, to\n            ).apply {\n                addListener(onEnd = {\n                    if (show) {\n                        if (!isShowing) {\n                            // Automatically request focus if the menu is not opened\n                            playerBinding?.skipChapterButton?.requestFocus()\n                        }\n                    } else {\n                        playerBinding?.skipChapterButton?.isVisible = false\n                        if (!isShowing) {\n                            // Automatically return focus to play pause\n                            playerBinding?.playerPausePlay?.requestFocus()\n                        }\n                    }\n                })\n                addUpdateListener { valueAnimator ->\n                    val value = valueAnimator.animatedValue as Int\n                    val layoutParams: ViewGroup.LayoutParams = layoutParams\n                    layoutParams.width = value\n                    setLayoutParams(layoutParams)\n                }\n                duration = 500\n                start()\n            }\n        }\n    }\n\n    override fun onTimestampSkipped(timestamp: EpisodeSkip.SkipStamp) {\n        displayTimeStamp(false)\n    }\n\n    override fun onTimestamp(timestamp: EpisodeSkip.SkipStamp?) {\n        if (timestamp != null) {\n            playerBinding?.skipChapterButton?.setText(timestamp.uiText)\n            displayTimeStamp(true)\n            val currentIndex = skipIndex\n            playerBinding?.skipChapterButton?.handler?.postDelayed({\n                if (skipIndex == currentIndex)\n                    displayTimeStamp(false)\n            }, 6000)\n        } else {\n            displayTimeStamp(false)\n        }\n    }\n\n    override fun isThereEpisodes(): Boolean {\n        val meta = allMeta\n        return !meta.isNullOrEmpty() && meta.size > 1\n    }\n\n    override fun showEpisodesOverlay() {\n        try {\n            playerBinding?.apply {\n                playerEpisodeList.setRecycledViewPool(EpisodeAdapter.sharedPool)\n                playerEpisodeList.adapter = EpisodeAdapter(\n                    false,\n                    { episodeClick ->\n                        if (episodeClick.action == ACTION_CLICK_DEFAULT) {\n                            isNextEpisode = false\n                            player.release()\n                            playerEpisodeOverlay.isGone = true\n                            episodeClick.position?.let { viewModel.loadThisEpisode(it) }\n                        }\n                    },\n                    { downloadClickEvent ->\n                        DownloadButtonSetup.handleDownloadClick(downloadClickEvent)\n                    }\n                )\n                playerEpisodeList.setLinearListLayout(\n                    isHorizontal = false,\n                    nextUp = FOCUS_SELF,\n                    nextDown = FOCUS_SELF,\n                    nextRight = FOCUS_SELF,\n                )\n                val episodes = allMeta ?: emptyList()\n                (playerEpisodeList.adapter as? EpisodeAdapter)?.submitList(episodes)\n\n                // Scroll to current episode\n                viewModel.getCurrentIndex()?.let { index ->\n                    playerEpisodeList.scrollToPosition(index)\n                    // Ensure focus on tv\n                    if (isLayout(TV)) {\n                        playerEpisodeList.post {\n                            val viewHolder =\n                                playerEpisodeList.findViewHolderForAdapterPosition(index)\n                            viewHolder?.itemView?.requestFocus()\n                            viewHolder?.itemView?.let { itemView ->\n                                itemView.isFocusableInTouchMode = true\n                                itemView.requestFocus()\n                            }\n                        }\n                    }\n                }\n\n                // update overlay season title\n                var lastTopIndex = -1\n                playerEpisodeList.addOnScrollListener(object : RecyclerView.OnScrollListener() {\n                    @SuppressLint(\"SetTextI18n\", \"DefaultLocale\")\n                    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {\n                        val layoutManager =\n                            recyclerView.layoutManager as? LinearLayoutManager ?: return\n                        val topIndex = layoutManager.findFirstCompletelyVisibleItemPosition()\n                        if (topIndex != RecyclerView.NO_POSITION && topIndex != lastTopIndex) {\n                            lastTopIndex = topIndex\n                            val topItem = episodes.getOrNull(topIndex)\n\n                            topItem?.let {\n                                playerEpisodeOverlayTitle.setText(\n                                    ResultViewModel2.seasonToTxt(\n                                        topItem.seasonData,\n                                        topItem.seasonIndex\n                                    )\n                                )\n                            }\n                        }\n                    }\n                })\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        var langFilterList = listOf<String>()\n        var filterSubByLang = false\n\n        context?.let { ctx ->\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n            showName        = settingsManager.getBoolean(ctx.getString(R.string.show_name_key), true)\n            showResolution  = settingsManager.getBoolean(ctx.getString(R.string.show_resolution_key), true)\n            showMediaInfo   = settingsManager.getBoolean(ctx.getString(R.string.show_media_info_key), false)\n            limitTitle      = settingsManager.getInt(ctx.getString(R.string.prefer_title_limit_key), 0)\n            updateForcedEncoding(ctx)\n            filterSubByLang =\n                settingsManager.getBoolean(getString(R.string.filter_sub_lang_key), false)\n            if (filterSubByLang) {\n                val langFromPrefMedia = settingsManager.getStringSet(\n                    this.getString(R.string.provider_lang_key), mutableSetOf(\"en\")\n                )\n                langFilterList = langFromPrefMedia?.mapNotNull {\n                    fromTagToEnglishLanguageName(it)?.lowercase() ?: return@mapNotNull null\n                } ?: listOf()\n            }\n        }\n\n        unwrapBundle(savedInstanceState)\n        unwrapBundle(arguments)\n\n        sync.updateUserData()\n\n        preferredAutoSelectSubtitles = getAutoSelectLanguageTagIETF()\n\n        if (currentSelectedLink == null) {\n            viewModel.loadLinks()\n        }\n\n        binding?.overlayLoadingSkipButton?.setOnClickListener {\n            startPlayer()\n        }\n\n        binding?.playerLoadingGoBack?.setOnClickListener {\n            exitFullscreen()\n            player.release()\n            activity?.popCurrentPage()\n        }\n\n        playerBinding?.downloadHeader?.setOnClickListener {\n            it?.isVisible = false\n        }\n\n        playerBinding?.downloadHeaderToggle?.setOnClickListener {\n            playerBinding?.downloadHeader?.let {\n                it.isVisible = !it.isVisible\n            }\n        }\n\n        observe(viewModel.currentStamps) { stamps ->\n            player.addTimeStamps(stamps)\n        }\n\n        observe(viewModel.loadingLinks) {\n            when (it) {\n                is Resource.Loading -> {\n                    startLoading()\n                }\n\n                is Resource.Success -> {\n                    // provider returned false\n                    //if (it.value != true) {\n                    //    showToast(activity, R.string.unexpected_error, Toast.LENGTH_SHORT)\n                    //}\n                    startPlayer()\n                }\n\n                is Resource.Failure -> {\n                    showToast(it.errorString, Toast.LENGTH_LONG)\n                    startPlayer()\n                }\n            }\n        }\n\n        observe(viewModel.currentLinks) {\n            currentLinks = it\n            val turnVisible = it.isNotEmpty() && lastUsedGenerator?.canSkipLoading == true\n            val wasGone = binding?.overlayLoadingSkipButton?.isGone == true\n\n            binding?.overlayLoadingSkipButton?.apply {\n                isVisible = turnVisible\n                val value = viewModel.currentLinks.value\n                if (value.isNullOrEmpty()) {\n                    setText(R.string.skip_loading)\n                } else {\n                    text = \"${context.getString(R.string.skip_loading)} (${value.size})\"\n                }\n            }\n\n            safe {\n                if (currentLinks.any { link ->\n                        getLinkPriority(currentQualityProfile, link.first) >=\n                                QualityDataHelper.AUTO_SKIP_PRIORITY\n                    }\n                ) {\n                    startPlayer()\n                }\n            }\n\n            if (turnVisible && wasGone) {\n                binding?.overlayLoadingSkipButton?.requestFocus()\n            }\n        }\n\n        observe(viewModel.currentSubs) { set ->\n            val setOfSub = mutableSetOf<SubtitleData>()\n            if (langFilterList.isNotEmpty() && filterSubByLang) {\n                Log.i(\"subfilter\", \"Filtering subtitle\")\n                langFilterList.forEach { lang ->\n                    Log.i(\"subfilter\", \"Lang: $lang\")\n                    setOfSub += set.filter {\n                        it.originalName.contains(lang, ignoreCase = true) ||\n                                it.origin != SubtitleOrigin.URL\n                    }\n                }\n                currentSubs = setOfSub\n            } else {\n                currentSubs = set\n            }\n            player.setActiveSubtitles(set)\n\n            // If the file is downloaded then do not select auto select the subtitles\n            // Downloaded subtitles cannot be selected immediately after loading since\n            // player.getCurrentPreferredSubtitle() cannot fetch data from non-loaded subtitles\n            // Resulting in unselecting the downloaded subtitle\n            if (set.lastOrNull()?.origin != SubtitleOrigin.DOWNLOADED_FILE) {\n                autoSelectSubtitles()\n            }\n        }\n    }\n\n}\n\n@Suppress(\"DEPRECATION\")\ninline fun <reified T : Serializable> Bundle.getSafeSerializable(key: String): T? =\n    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) getSerializable(key) as? T else getSerializable(\n        key,\n        T::class.java\n    )\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/IGenerator.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport kotlin.math.max\nimport kotlin.math.min\n\nval LOADTYPE_INAPP = setOf(\n    ExtractorLinkType.VIDEO,\n    ExtractorLinkType.DASH,\n    ExtractorLinkType.M3U8,\n    ExtractorLinkType.TORRENT,\n    ExtractorLinkType.MAGNET\n)\n\nval LOADTYPE_INAPP_DOWNLOAD = setOf(\n    ExtractorLinkType.VIDEO,\n    ExtractorLinkType.M3U8\n)\n\nval LOADTYPE_CHROMECAST = setOf(\n    ExtractorLinkType.VIDEO,\n    ExtractorLinkType.DASH,\n    ExtractorLinkType.M3U8\n)\n\nval LOADTYPE_ALL = ExtractorLinkType.entries.toSet()\n\n\nabstract class NoVideoGenerator : VideoGenerator<Nothing>(emptyList(), 0) {\n    override val hasCache = false\n    override val canSkipLoading = false\n}\n\nabstract class VideoGenerator<T : Any>(val videos: List<T>, var videoIndex: Int = 0) :\n    IGenerator {\n\n    override fun hasNext(): Boolean = videoIndex < videos.lastIndex\n    override fun hasPrev(): Boolean = videoIndex > 0\n    override fun getAll(): List<T>? = videos\n    override fun getCurrent(offset: Int): T? = videos.getOrNull(videoIndex + offset)\n    override fun next() {\n        if (hasNext()) {\n            videoIndex += 1\n        }\n    }\n\n    override fun prev() {\n        if (hasPrev()) {\n            videoIndex -= 1\n        }\n    }\n\n    override fun goto(index: Int) {\n        videoIndex = min(videos.lastIndex, max(0, index))\n    }\n\n    override fun getCurrentId(): Int? {\n        return when (val current = getCurrent()) {\n            is ResultEpisode -> {\n                current.id\n            }\n\n            is ExtractorUri -> {\n                current.id\n            }\n\n            else -> null\n        }\n    }\n}\n\n// TODO deprecate/remove IGenerator in favor of a more ergonomic and correct implementation\ninterface IGenerator {\n    val hasCache: Boolean\n    val canSkipLoading: Boolean\n\n    fun hasNext(): Boolean\n    fun hasPrev(): Boolean\n    fun next()\n    fun prev()\n    fun goto(index: Int)\n\n    fun getCurrentId(): Int?                    // this is used to save data or read data about this id\n    fun getCurrent(offset: Int = 0): Any?      // this is used to get metadata about the current playing, can return null\n    fun getAll(): List<Any>?                   // this us used to get the metadata about all entries, not needed\n\n    /* not safe, must use try catch */\n    suspend fun generateLinks(\n        clearCache: Boolean,\n        sourceTypes: Set<ExtractorLinkType>,\n        callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,\n        subtitleCallback: (SubtitleData) -> Unit,\n        offset: Int = 0,\n        isCasting: Boolean = false\n    ): Boolean\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/IPlayer.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.util.Rational\nimport com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle\nimport com.lagradost.cloudstream3.utils.EpisodeSkip\nimport com.lagradost.cloudstream3.utils.ExtractorLink\n\nenum class PlayerEventType(val value: Int) {\n    Pause(0),\n    Play(1),\n    SeekForward(2),\n    SeekBack(3),\n\n    SkipCurrentChapter(4),\n    NextEpisode(5),\n    PrevEpisode(6),\n    PlayPauseToggle(7),\n    ToggleMute(8),\n    Lock(9),\n    ToggleHide(10),\n    ShowSpeed(11),\n    ShowMirrors(12),\n    Resize(13),\n    SearchSubtitlesOnline(14),\n    SkipOp(15),\n    Restart(16),\n}\n\nenum class CSPlayerEvent(val value: Int) {\n    Pause(0),\n    Play(1),\n    SeekForward(2),\n    SeekBack(3),\n\n    SkipCurrentChapter(4),\n    NextEpisode(5),\n    PrevEpisode(6),\n    PlayPauseToggle(7),\n    ToggleMute(8),\n    Restart(9),\n    PlayAsAudio(10),\n}\n\nenum class CSPlayerLoading {\n    IsPaused,\n    IsPlaying,\n    IsBuffering,\n    IsEnded,\n}\n\nenum class PlayerEventSource {\n    /** This event was invoked from the user pressing some button or selecting something */\n    UI,\n\n    /** This event was invoked automatically */\n    Player,\n\n    /** This event was invoked from a external sync tool like WatchTogether */\n    Sync,\n}\n\nabstract class PlayerEvent {\n    abstract val source: PlayerEventSource\n}\n\n/** this is used to update UI based of the current time,\n * using requestedListeningPercentages as well as saving time */\ndata class PositionEvent(\n    override val source: PlayerEventSource,\n    val fromMs: Long,\n    val toMs: Long,\n    /** duration of the entire video */\n    val durationMs: Long,\n) : PlayerEvent() {\n    /** how many ms (+-) we have skipped */\n    val seekMs : Long get() = toMs - fromMs\n}\n\n/** player error when rendering or misc, used to display toast or log */\ndata class ErrorEvent(\n    val error: Throwable,\n    override val source: PlayerEventSource = PlayerEventSource.Player,\n) : PlayerEvent()\n\n/** Event when timestamps appear, null when it should disappear */\ndata class TimestampInvokedEvent(\n    val timestamp: EpisodeSkip.SkipStamp,\n    override val source: PlayerEventSource = PlayerEventSource.Player,\n) : PlayerEvent()\n\n/** Event for when a chapter is skipped, aka when event is handled (or for future use when skip automatically ads/sponsor) */\ndata class TimestampSkippedEvent(\n    val timestamp: EpisodeSkip.SkipStamp,\n    override val source: PlayerEventSource = PlayerEventSource.Player,\n) : PlayerEvent()\n\n/** this is used by the player to load the next or prev episode */\ndata class EpisodeSeekEvent(\n    /** -1 = prev, 1 = next, will never be 0, atm the user cant seek more than +-1 */\n    val offset: Int,\n    override val source: PlayerEventSource = PlayerEventSource.Player,\n) : PlayerEvent() {\n    init {\n        assert(offset != 0)\n    }\n}\n\n/** Event when the video is resized aka changed resolution or mirror */\ndata class ResizedEvent(\n    val height: Int,\n    val width: Int,\n    override val source: PlayerEventSource = PlayerEventSource.Player,\n) : PlayerEvent()\n\n/** Event when the player status update, along with the previous status (for animation)*/\ndata class StatusEvent(\n    val wasPlaying: CSPlayerLoading,\n    val isPlaying: CSPlayerLoading,\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\n/** Event when tracks are changed, used for UI changes */\ndata class TracksChangedEvent(\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\n/** Event from player to give all embedded subtitles */\ndata class EmbeddedSubtitlesFetchedEvent(\n    val tracks: List<SubtitleData>,\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\n/** on attach player to view */\ndata class PlayerAttachedEvent(\n    val player: Any?,\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\n/** Event from player to inform that subtitles have updated in some way */\ndata class SubtitlesUpdatedEvent(\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\n/** current player starts, asking for all other programs to shut the fuck up */\ndata class RequestAudioFocusEvent(\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\n/** Pause event, separate from StatusEvent */\ndata class PauseEvent(\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\n/** Play event, separate from StatusEvent */\ndata class PlayEvent(\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\n/** Event when the player video has ended, up to the settings on what to do when that happens */\ndata class VideoEndedEvent(\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\n/** Used for torrent to pre-download a video before playing it */\ndata class DownloadEvent(\n    val downloadedBytes: Long,\n    val totalBytes: Long,\n    /** bytes / sec */\n    val downloadSpeed: Long,\n    val connections: Int?,\n\n    override val source: PlayerEventSource = PlayerEventSource.Player\n) : PlayerEvent()\n\ninterface Track {\n    /**\n     * Unique among the class, used to check which track is used.\n     * VideoTrack and AudioTrack can have the same id\n     **/\n    val id: String?\n    val label: String?\n    val language: String?\n    val sampleMimeType : String?\n}\n\ndata class VideoTrack(\n    override val id: String?,\n    override val label: String?,\n    override val language: String?,\n    val width: Int?,\n    val height: Int?,\n    override val sampleMimeType: String?,\n) : Track\n\ndata class AudioTrack(\n    override val id: String?,\n    override val label: String?,\n    override val language: String?,\n    override val sampleMimeType: String?,\n    val channelCount: Int?,\n    val formatIndex: Int?,\n) : Track\n\ndata class TextTrack(\n    override val id: String?,\n    override val label: String?,\n    override val language: String?,\n    override val sampleMimeType: String?,\n) : Track\n\n\ndata class CurrentTracks(\n    val currentVideoTrack: VideoTrack?,\n    val currentAudioTrack: AudioTrack?,\n    val currentTextTracks: List<TextTrack>,\n    val allVideoTracks: List<VideoTrack>,\n    val allAudioTracks: List<AudioTrack>,\n    val allTextTracks: List<TextTrack>,\n)\n\nclass InvalidFileException(msg: String) : Exception(msg)\n\n//http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4\nconst val ACTION_MEDIA_CONTROL = \"media_control\"\nconst val EXTRA_CONTROL_TYPE = \"control_type\"\n\n/** Abstract Exoplayer logic, can be expanded to other players */\ninterface IPlayer {\n    fun getPlaybackSpeed(): Float\n    fun setPlaybackSpeed(speed: Float)\n\n    fun getIsPlaying(): Boolean\n    /** Current player duration in milliseconds */\n    fun getDuration(): Long?\n    /** Current player position in milliseconds */\n    fun getPosition(): Long?\n\n    fun seekTime(time: Long, source: PlayerEventSource = PlayerEventSource.UI)\n    fun seekTo(time: Long, source: PlayerEventSource = PlayerEventSource.UI)\n\n    fun getSubtitleOffset(): Long // in ms\n    fun setSubtitleOffset(offset: Long) // in ms\n\n    fun initCallbacks(\n        eventHandler: ((PlayerEvent) -> Unit),\n        /** this is used to request when the player should report back view percentage */\n        requestedListeningPercentages: List<Int>? = null,\n    )\n\n    fun releaseCallbacks()\n\n    fun updateSubtitleStyle(style: SaveCaptionStyle)\n    fun saveData()\n\n    fun addTimeStamps(timeStamps: List<EpisodeSkip.SkipStamp>)\n\n    fun loadPlayer(\n        context: Context,\n        sameEpisode: Boolean,\n        link: ExtractorLink? = null,\n        data: ExtractorUri? = null,\n        startPosition: Long? = null,\n        subtitles: Set<SubtitleData>,\n        subtitle: SubtitleData?,\n        autoPlay: Boolean? = true,\n        preview : Boolean = true,\n    )\n\n    fun reloadPlayer(context: Context)\n\n    fun getPreview(fraction : Float) : Bitmap?\n    fun hasPreview() : Boolean\n\n    fun setActiveSubtitles(subtitles: Set<SubtitleData>)\n    fun setPreferredSubtitles(subtitle: SubtitleData?): Boolean // returns true if the player requires a reload, null for nothing\n    fun getCurrentPreferredSubtitle(): SubtitleData?\n\n    fun handleEvent(event: CSPlayerEvent, source: PlayerEventSource = PlayerEventSource.UI)\n\n    fun onStop()\n    fun onPause()\n    fun onResume(context: Context)\n\n    fun release()\n\n    /** Get if player is actually used */\n    fun isActive(): Boolean\n\n    fun getVideoTracks(): CurrentTracks\n\n    /**\n     * Original video aspect ratio used for PiP mode\n     *\n     * Set using: Width, Height.\n     * Example: Rational(16, 9)\n     *\n     * If null will default to set no aspect ratio.\n     *\n     * PiP functions calling this needs to coerce this value between 0.418410 and 2.390000\n     * to prevent crashes.\n     */\n    fun getAspectRatio(): Rational?\n\n    /** If no parameters are set it'll default to no set size, Specifying the id allows for track overrides to force the player to pick the quality. */\n    fun setMaxVideoSize(width: Int = Int.MAX_VALUE, height: Int = Int.MAX_VALUE, id: String? = null)\n\n    /** If no trackLanguage is set it'll default to first track. Specifying the id allows for track overrides as the language can be identical. */\n    fun setPreferredAudioTrack(trackLanguage: String?, id: String? = null, trackIndex: Int? = null)\n\n    /** Get the current subtitle cues, for use with syncing */\n    fun getSubtitleCues(): List<SubtitleCue>\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/LinkGenerator.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.net.Uri\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.actions.temp.CloudStreamPackage\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.loadExtractor\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport com.lagradost.cloudstream3.utils.unshortenLinkSafe\n\ndata class ExtractorUri(\n    val uri: Uri,\n    val name: String,\n\n    val basePath: String? = null,\n    val relativePath: String? = null,\n    val displayName: String? = null,\n\n    val id: Int? = null,\n    val parentId: Int? = null,\n    val episode: Int? = null,\n    val season: Int? = null,\n    val headerName: String? = null,\n    val tvType: TvType? = null,\n)\n\n/**\n * Used to open the player more easily with the LinkGenerator\n **/\ndata class BasicLink(\n    val url: String,\n    val name: String? = null,\n)\n\nclass LinkGenerator(\n    private val links: List<BasicLink>,\n    private val extract: Boolean = true,\n    private val refererUrl: String? = null,\n) : NoVideoGenerator() {\n    override suspend fun generateLinks(\n        clearCache: Boolean,\n        sourceTypes: Set<ExtractorLinkType>,\n        callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,\n        subtitleCallback: (SubtitleData) -> Unit,\n        offset: Int,\n        isCasting: Boolean\n    ): Boolean {\n        links.amap { link ->\n            if (!extract || !loadExtractor(link.url, refererUrl, {\n                    subtitleCallback(PlayerSubtitleHelper.getSubtitleData(it))\n                }) {\n                    callback(it to null)\n                }) {\n\n                // if don't extract or if no extractor found simply return the link\n                callback(\n                    newExtractorLink(\n                        \"\",\n                        link.name ?: link.url,\n                        unshortenLinkSafe(link.url), // unshorten because it might be a raw link\n                        type = INFER_TYPE,\n                    ) {\n                        this.referer = refererUrl ?: \"\"\n                        this.quality = Qualities.Unknown.value\n                    } to null\n                )\n            }\n        }\n\n        return true\n    }\n}\n\nclass MinimalLinkGenerator(\n    private val links: List<CloudStreamPackage.MinimalVideoLink>,\n    private val subs: List<CloudStreamPackage.MinimalSubtitleLink>,\n    private val id: Int? = null\n) : NoVideoGenerator() {\n    override fun getCurrentId(): Int? = id\n\n    override suspend fun generateLinks(\n        clearCache: Boolean,\n        sourceTypes: Set<ExtractorLinkType>,\n        callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,\n        subtitleCallback: (SubtitleData) -> Unit,\n        offset: Int,\n        isCasting: Boolean\n    ): Boolean {\n        for (link in links) {\n            callback(link.toExtractorLink())\n        }\n        for (link in subs) {\n            subtitleCallback(link.toSubtitleData())\n        }\n\n        return true\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/OfflinePlaybackHelper.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.app.Activity\nimport android.content.ContentUris\nimport android.content.Intent\nimport android.net.Uri\nimport androidx.core.content.ContextCompat.getString\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.actions.temp.CloudStreamPackage\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.safefile.SafeFile\n\nobject OfflinePlaybackHelper {\n    fun playLink(activity: Activity, url: String) {\n        activity.navigate(\n            R.id.global_to_navigation_player, GeneratorPlayer.newInstance(\n                LinkGenerator(\n                    listOf(\n                        BasicLink(url)\n                    )\n                )\n            )\n        )\n    }\n\n    // See CloudStreamPackage\n    fun playIntent(activity: Activity, intent: Intent?): Boolean {\n        if (intent == null) return false\n        val links = intent.getStringArrayExtra(CloudStreamPackage.LINKS_EXTRA)\n            ?.mapNotNull { tryParseJson<CloudStreamPackage.MinimalVideoLink>(it) } ?: emptyList()\n        if (links.isEmpty()) return false\n        val subs = intent.getStringArrayExtra(CloudStreamPackage.SUBTITLE_EXTRA)\n            ?.mapNotNull { tryParseJson<CloudStreamPackage.MinimalSubtitleLink>(it) } ?: emptyList()\n\n        val id = intent.getIntExtra(CloudStreamPackage.ID_EXTRA, -1)\n        //val title = intent.getStringExtra(CloudStreamPackage.TITLE_EXTRA) // unused\n        val pos = intent.getLongExtra(CloudStreamPackage.POSITION_EXTRA, -1L)\n        val dur = intent.getLongExtra(CloudStreamPackage.DURATION_EXTRA, -1L)\n\n        if (id != -1 && pos != -1L) {\n            val duration = if (dur != -1L) {\n                dur\n            } else DataStoreHelper.getViewPos(id)?.duration ?: pos\n            DataStoreHelper.setViewPos(id, pos, duration)\n        }\n\n        activity.navigate(\n            R.id.global_to_navigation_player, GeneratorPlayer.newInstance(\n                MinimalLinkGenerator(\n                    links,\n                    subs,\n                    if (id != -1) id else null,\n                )\n            )\n        )\n        return true\n    }\n\n    fun playUri(activity: Activity, uri: Uri) {\n        if (uri.scheme == \"magnet\") {\n            playLink(activity, uri.toString())\n            return\n        }\n        val name = SafeFile.fromUri(activity, uri)?.name()\n        activity.navigate(\n            R.id.global_to_navigation_player, GeneratorPlayer.newInstance(\n                DownloadFileGenerator(\n                    listOf(\n                        ExtractorUri(\n                            uri = uri,\n                            name = name ?: getString(activity, R.string.downloaded_file),\n                            // well not the same as a normal id, but we take it as users may want to\n                            // play downloaded files and save the location\n                            id = kotlin.runCatching { ContentUris.parseId(uri) }.getOrNull()\n                                ?.hashCode()\n                        )\n                    )\n                )\n            )\n        )\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/OutlineSpan.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.text.TextPaint\nimport android.text.style.CharacterStyle\nimport androidx.annotation.Px\n\n// source: https://github.com/androidx/media/pull/1840\nclass OutlineSpan(@Px val outlineWidth : Float) : CharacterStyle() {\n    override fun updateDrawState(tp: TextPaint?) { tp?.strokeWidth = outlineWidth }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerGeneratorViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.util.Log\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.launchSafe\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.mvvm.safeApiCall\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.EpisodeSkip\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.launch\n\nclass PlayerGeneratorViewModel : ViewModel() {\n    companion object {\n        const val TAG = \"PlayViewGen\"\n    }\n\n    private var generator: IGenerator? = null\n\n    private val _currentLinks = MutableLiveData<Set<Pair<ExtractorLink?, ExtractorUri?>>>(setOf())\n    val currentLinks: LiveData<Set<Pair<ExtractorLink?, ExtractorUri?>>> = _currentLinks\n\n    private val _currentSubs = MutableLiveData<Set<SubtitleData>>(setOf())\n    val currentSubs: LiveData<Set<SubtitleData>> = _currentSubs\n\n    private val _loadingLinks = MutableLiveData<Resource<Boolean?>>()\n    val loadingLinks: LiveData<Resource<Boolean?>> = _loadingLinks\n\n    private val _currentStamps = MutableLiveData<List<EpisodeSkip.SkipStamp>>(emptyList())\n    val currentStamps: LiveData<List<EpisodeSkip.SkipStamp>> = _currentStamps\n\n    private val _currentSubtitleYear = MutableLiveData<Int?>(null)\n    val currentSubtitleYear: LiveData<Int?> = _currentSubtitleYear\n\n    /**\n     * Save the Episode ID to prevent starting multiple link loading Jobs when preloading links.\n     */\n    private var currentLoadingEpisodeId: Int? = null\n\n    var forceClearCache = false\n\n    fun setSubtitleYear(year: Int?) {\n        _currentSubtitleYear.postValue(year)\n    }\n\n    fun getId(): Int? {\n        return generator?.getCurrentId()\n    }\n\n    fun loadLinks(episode: Int) {\n        generator?.goto(episode)\n        loadLinks()\n    }\n\n    fun loadLinksPrev() {\n        Log.i(TAG, \"loadLinksPrev\")\n        if (generator?.hasPrev() == true) {\n            generator?.prev()\n            loadLinks()\n        }\n    }\n\n    fun loadLinksNext() {\n        Log.i(TAG, \"loadLinksNext\")\n        if (generator?.hasNext() == true) {\n            generator?.next()\n            loadLinks()\n        }\n    }\n\n    fun hasNextEpisode(): Boolean? {\n        return generator?.hasNext()\n    }\n\n    fun hasPrevEpisode(): Boolean? {\n        return generator?.hasPrev()\n    }\n\n    fun preLoadNextLinks() {\n        val id = getId()\n        // Do not preload if already loading\n        if (id == currentLoadingEpisodeId) return\n\n        Log.i(TAG, \"preLoadNextLinks\")\n        currentJob?.cancel()\n        currentLoadingEpisodeId = id\n\n        currentJob = viewModelScope.launch {\n            try {\n                if (generator?.hasCache == true && generator?.hasNext() == true) {\n                    safeApiCall {\n                        generator?.generateLinks(\n                            sourceTypes = LOADTYPE_INAPP,\n                            clearCache = false,\n                            callback = {},\n                            subtitleCallback = {},\n                            offset = 1\n                        )\n                    }\n                }\n            } catch (t: Throwable) {\n                logError(t)\n            } finally {\n                if (currentLoadingEpisodeId == id) {\n                    currentLoadingEpisodeId = null\n                }\n            }\n        }\n    }\n\n    fun getLoadResponse(): LoadResponse? {\n        return safe { (generator as? RepoLinkGenerator?)?.page }\n    }\n\n    fun getMeta(): Any? {\n        return safe { generator?.getCurrent() }\n    }\n\n    fun getAllMeta(): List<Any>? {\n        return safe { generator?.getAll() }\n    }\n\n    fun getNextMeta(): Any? {\n        return safe {\n            if (generator?.hasNext() == false) return@safe null\n            generator?.getCurrent(offset = 1)\n        }\n    }\n\n    fun loadThisEpisode(index:Int) {\n        generator?.goto(index)\n        loadLinks()\n    }\n\n    fun getCurrentIndex():Int?{\n        val repoGen = generator as? RepoLinkGenerator ?: return null\n        return repoGen.videoIndex\n    }\n\n    fun attachGenerator(newGenerator: IGenerator?) {\n        if (generator == null) {\n            generator = newGenerator\n        }\n    }\n\n    private var extraSubtitles : MutableSet<SubtitleData> = mutableSetOf()\n\n    /**\n     * If duplicate nothing will happen\n     * */\n    fun addSubtitles(file: Set<SubtitleData>) = synchronized(extraSubtitles) {\n        extraSubtitles += file\n        val current = _currentSubs.value ?: emptySet()\n        val next = extraSubtitles + current\n\n        // if it is of a different size then we have added distinct items\n        if (next.size != current.size) {\n            // Posting will refresh subtitles which will in turn\n            // make the subs to english if previously unselected\n            _currentSubs.postValue(next)\n        }\n    }\n\n    private var currentJob: Job? = null\n    private var currentStampJob: Job? = null\n\n    fun loadStamps(duration: Long) {\n        //currentStampJob?.cancel()\n        currentStampJob = ioSafe {\n            val meta = generator?.getCurrent()\n            val page = (generator as? RepoLinkGenerator?)?.page\n            if (page != null && meta is ResultEpisode) {\n                _currentStamps.postValue(listOf())\n                _currentStamps.postValue(\n                    EpisodeSkip.getStamps(\n                        page,\n                        meta,\n                        duration,\n                        hasNextEpisode() ?: false\n                    )\n                )\n            }\n        }\n    }\n\n    fun loadLinks(sourceTypes: Set<ExtractorLinkType> = LOADTYPE_INAPP) {\n        Log.i(TAG, \"loadLinks\")\n        currentJob?.cancel()\n\n        currentJob = viewModelScope.launchSafe {\n            // if we load links then we clear the prev loaded links\n            synchronized(extraSubtitles) {\n                extraSubtitles.clear()\n            }\n            val currentLinks = mutableSetOf<Pair<ExtractorLink?, ExtractorUri?>>()\n            val currentSubs = mutableSetOf<SubtitleData>()\n\n            // clear old data\n            _currentSubs.postValue(emptySet())\n            _currentLinks.postValue(emptySet())\n\n            // load more data\n            _loadingLinks.postValue(Resource.Loading())\n            val loadingState = safeApiCall {\n                generator?.generateLinks(\n                    sourceTypes = sourceTypes,\n                    clearCache = forceClearCache,\n                    callback = {\n                        synchronized(currentLinks) {\n                            currentLinks.add(it)\n                            // Clone to prevent ConcurrentModificationException\n                            safe {\n                                // Extra safe since .toSet() iterates.\n                                _currentLinks.postValue(currentLinks.toSet())\n                            }\n                        }\n                    },\n                    subtitleCallback = {\n                        synchronized(extraSubtitles) {\n                            currentSubs.add(it)\n                            safe {\n                                _currentSubs.postValue(currentSubs + extraSubtitles)\n                            }\n                        }\n                    })\n            }\n\n            _loadingLinks.postValue(loadingState)\n            _currentLinks.postValue(currentLinks)\n            synchronized(extraSubtitles) {\n                _currentSubs.postValue(currentSubs + extraSubtitles)\n            }\n        }\n\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerPipHelper.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.app.Activity\nimport android.app.AppOpsManager\nimport android.app.PendingIntent\nimport android.app.PictureInPictureParams\nimport android.app.RemoteAction\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.graphics.drawable.Icon\nimport android.os.Build\nimport android.util.Rational\nimport androidx.annotation.RequiresApi\nimport androidx.annotation.StringRes\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport kotlin.math.roundToInt\n\nobject PlayerPipHelper {\n    /** Is pip (Player in Player) supported, and enabled? */\n    fun Context.isPIPPossible() : Boolean {\n        return try {\n            this.hasPIPEnabled() && this.hasPIPFeature()\n        } catch (t : Throwable) {\n            // While both hasPIPEnabled and hasPIPFeature should never throw, this catches it just in case\n            logError(t)\n            false\n        }\n    }\n\n    /** Is pip enabled in app settings? */\n    private fun Context.hasPIPEnabled(): Boolean {\n        return try {\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n            settingsManager?.getBoolean(\n                getString(R.string.pip_enabled_key),\n                true\n            ) ?: true\n        } catch (e: Exception) {\n            logError(e)\n            false\n        }\n    }\n\n\n    /**\n     * Is pip supported by the OS?\n     *\n     * Source:\n     * https://stackoverflow.com/questions/52594181/how-to-know-if-user-has-disabled-picture-in-picture-feature-permission\n     * https://developer.android.com/guide/topics/ui/picture-in-picture\n     * */\n    private fun Context.hasPIPFeature(): Boolean =\n        // OS Support\n        Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&\n                // Might have the feature, but OS blocked due to power drain\n                this.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) &&\n                // Might have been disabled by the user\n                this.hasPIPPermission()\n\n    /** Is pip enabled in the OS settings? */\n    private fun Context.hasPIPPermission(): Boolean {\n        val appOps =\n            getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager\n        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            appOps.checkOpNoThrow(\n                AppOpsManager.OPSTR_PICTURE_IN_PICTURE,\n                android.os.Process.myUid(),\n                packageName\n            ) == AppOpsManager.MODE_ALLOWED\n        } else true\n    }\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    private fun getPen(activity: Activity, code: Int): PendingIntent {\n        return PendingIntent.getBroadcast(\n            activity,\n            code,\n            Intent(ACTION_MEDIA_CONTROL).putExtra(EXTRA_CONTROL_TYPE, code),\n            PendingIntent.FLAG_IMMUTABLE\n        )\n    }\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    private fun getRemoteAction(\n        activity: Activity,\n        id: Int,\n        @StringRes title: Int,\n        event: CSPlayerEvent\n    ): RemoteAction {\n        val text = activity.getString(title)\n        return RemoteAction(\n            Icon.createWithResource(activity, id),\n            text,\n            text,\n            getPen(activity, event.value)\n        )\n    }\n\n    fun updatePIPModeActions(\n        activity: Activity?,\n        status: CSPlayerLoading,\n        pipEnabled: Boolean,\n        aspectRatio: Rational?\n    ) {\n        // Is it even desired to enter pip mode right now if we ignore all settings?\n        // This does not check for isPIPPossible as that is deferred to later\n        val isPipDesired = when (status) {\n            CSPlayerLoading.IsBuffering, CSPlayerLoading.IsPlaying -> pipEnabled\n            else -> false\n        }\n\n        // On lower api ver setPictureInPictureParams is not supported,\n        // so we enter pip manually in onUserLeaveHint\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n            CommonActivity.isPipDesired = isPipDesired\n            return\n        }\n\n        if(activity == null) return\n\n        val actions: ArrayList<RemoteAction> = ArrayList()\n        actions.add(\n            getRemoteAction(\n                activity,\n                R.drawable.baseline_headphones_24,\n                R.string.audio_singluar,\n                CSPlayerEvent.PlayAsAudio\n            )\n        )\n        /*actions.add(\n            getRemoteAction(\n                activity,\n                R.drawable.go_back_30,\n                R.string.go_back_30,\n                CSPlayerEvent.SeekBack\n            )\n        )*/\n\n        if (status == CSPlayerLoading.IsPlaying) {\n            actions.add(\n                getRemoteAction(\n                    activity,\n                    R.drawable.netflix_pause,\n                    R.string.pause,\n                    CSPlayerEvent.Pause\n                )\n            )\n        } else {\n            actions.add(\n                getRemoteAction(\n                    activity,\n                    R.drawable.ic_baseline_play_arrow_24,\n                    R.string.pause,\n                    CSPlayerEvent.Play\n                )\n            )\n        }\n\n        actions.add(\n            getRemoteAction(\n                activity,\n                R.drawable.go_forward_30,\n                R.string.go_forward_30,\n                CSPlayerEvent.SeekForward\n            )\n        )\n\n        // Necessary to prevent crashing.\n        val mixAspectRatio = 0.41841f // ~1/2.39\n        val maxAspectRatio = 2.39f // widescreen standard\n        val ratioAccuracy = 100000 // To convert the float to int\n\n        // java.lang.IllegalArgumentException: setPictureInPictureParams: Aspect ratio is too extreme\n        // (must be between 0.418410 and 2.390000)\n        val fixedRational =\n            aspectRatio?.toFloat()?.coerceIn(mixAspectRatio, maxAspectRatio)?.let {\n                Rational((it * ratioAccuracy).roundToInt(), ratioAccuracy)\n            }\n\n        safe {\n            activity.setPictureInPictureParams(\n                PictureInPictureParams.Builder()\n                    .apply {\n                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                            setSeamlessResizeEnabled(true)\n                            setAutoEnterEnabled(isPipDesired && activity.isPIPPossible())\n                        } else {\n                            // We enter pip manually in onUserLeaveHint as the smooth transition\n                            // is not supported yet\n                            CommonActivity.isPipDesired = isPipDesired\n                        }\n                    }\n                    .setAspectRatio(fixedRational)\n                    .setActions(actions)\n                    .build()\n            )\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.util.Log\nimport android.util.TypedValue\nimport android.view.ViewGroup\nimport android.widget.FrameLayout\nimport androidx.annotation.OptIn\nimport androidx.media3.common.MimeTypes\nimport androidx.media3.common.util.UnstableApi\nimport androidx.media3.ui.SubtitleView\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle\nimport com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.setSubtitleViewStyle\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromLanguageToTagIETF\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\n\nenum class SubtitleStatus {\n    IS_ACTIVE,\n    REQUIRES_RELOAD,\n    NOT_FOUND,\n}\n\nenum class SubtitleOrigin {\n    URL,\n    DOWNLOADED_FILE,\n    EMBEDDED_IN_VIDEO\n}\n\n/**\n * @param originalName the start of the name to be displayed in the player\n * @param nameSuffix An extra suffix added to the subtitle to make sure it is unique\n * @param url Url for the subtitle, when EMBEDDED_IN_VIDEO this variable is used as the real backend id\n * @param headers if empty it will use the base onlineDataSource headers else only the specified headers\n * @param languageCode usually, tags such as \"en\", \"es-mx\", or \"zh-hant-TW\". But it could be something like \"English 4\"\n * */\ndata class SubtitleData(\n    val originalName: String,\n    val nameSuffix: String,\n    val url: String,\n    val origin: SubtitleOrigin,\n    val mimeType: String,\n    val headers: Map<String, String>,\n    val languageCode: String?,\n) {\n    /** Internal ID for exoplayer, unique for each link*/\n    fun getId(): String {\n        return if (origin == SubtitleOrigin.EMBEDDED_IN_VIDEO) url\n        else \"$url|$name\"\n    }\n\n    /** Returns true if langCode is the same as the IETF tag */\n    fun matchesLanguageCode(langCode: String): Boolean {\n        return getIETF_tag() == langCode\n    }\n\n    /** Tries hard to figure out a valid IETF tag based on language code and name. Will return null if not found. */\n    fun getIETF_tag(): String? {\n        return fromLanguageToTagIETF(this.languageCode) ?: fromLanguageToTagIETF(this.originalName, halfMatch = true)\n    }\n\n    val name = \"$originalName $nameSuffix\"\n\n    /**\n     * Gets the URL, but tries to fix it if it is malformed.\n     */\n    fun getFixedUrl(): String {\n        // Some extensions fail to include the protocol, this helps with that.\n        val fixedSubUrl = if (this.url.startsWith(\"//\")) {\n            \"https:${this.url}\"\n        } else {\n            this.url\n        }\n        return fixedSubUrl\n    }\n}\n\n@OptIn(UnstableApi::class)\nclass PlayerSubtitleHelper {\n    private var activeSubtitles: Set<SubtitleData> = emptySet()\n    private var allSubtitles: Set<SubtitleData> = emptySet()\n\n    fun getAllSubtitles(): Set<SubtitleData> {\n        return allSubtitles\n    }\n\n    fun setActiveSubtitles(list: Set<SubtitleData>) {\n        activeSubtitles = list\n    }\n\n    fun setAllSubtitles(list: Set<SubtitleData>) {\n        allSubtitles = list\n    }\n\n    var subtitleView: SubtitleView? = null\n\n    companion object {\n        fun String.toSubtitleMimeType(): String {\n            return when {\n                endsWith(\"vtt\", true) -> MimeTypes.TEXT_VTT\n                endsWith(\"srt\", true) -> MimeTypes.APPLICATION_SUBRIP\n                endsWith(\"xml\", true) || endsWith(\"ttml\", true) -> MimeTypes.APPLICATION_TTML\n                else -> MimeTypes.APPLICATION_SUBRIP\n            }\n        }\n\n        fun getSubtitleData(subtitleFile: SubtitleFile): SubtitleData {\n            return SubtitleData(\n                originalName = subtitleFile.lang,\n                nameSuffix = \"\",\n                url = subtitleFile.url,\n                origin = SubtitleOrigin.URL,\n                mimeType = subtitleFile.url.toSubtitleMimeType(),\n                headers = subtitleFile.headers ?: emptyMap(),\n                languageCode = subtitleFile.langTag ?: subtitleFile.lang\n            )\n        }\n    }\n\n    fun subtitleStatus(sub: SubtitleData?): SubtitleStatus {\n        if (activeSubtitles.contains(sub)) {\n            return SubtitleStatus.IS_ACTIVE\n        }\n        if (allSubtitles.contains(sub)) {\n            return SubtitleStatus.REQUIRES_RELOAD\n        }\n        return SubtitleStatus.NOT_FOUND\n    }\n\n    fun setSubStyle(style: SaveCaptionStyle) {\n        Log.i(TAG, \"SET STYLE = $style\")\n        subtitleView?.translationY = -style.elevation.toPx.toFloat()\n        setSubtitleViewStyle(subtitleView, style, true)\n    }\n\n    fun initSubtitles(subView: SubtitleView?, subHolder: FrameLayout?, style: SaveCaptionStyle?) {\n        subtitleView = subView\n        subView?.let { sView ->\n            (sView.parent as ViewGroup?)?.removeView(sView)\n            subHolder?.addView(sView)\n        }\n        style?.let {\n            setSubStyle(it)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/PreviewGenerator.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport android.media.MediaMetadataRetriever\nimport android.net.Uri\nimport android.os.Build\nimport android.util.Log\nimport androidx.annotation.WorkerThread\nimport androidx.core.graphics.scale\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.CloudStreamApp\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport com.lagradost.cloudstream3.utils.M3u8Helper2\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.isActive\nimport kotlinx.coroutines.withContext\nimport kotlin.math.absoluteValue\nimport kotlin.math.ceil\nimport kotlin.math.log2\n\nconst val MAX_LOD = 6\nconst val MIN_LOD = 3\n\ndata class ImageParams(\n    val width: Int,\n    val height: Int,\n) {\n    companion object {\n        val DEFAULT = ImageParams(200, 320)\n        fun new16by9(width: Int): ImageParams {\n            if (width < 100) {\n                return DEFAULT\n            }\n            return ImageParams(\n                width / 4,\n                (width * 9) / (4 * 16)\n            )\n        }\n    }\n\n    init {\n        assert(width > 0 && height > 0)\n    }\n}\n\ninterface IPreviewGenerator {\n    fun hasPreview(): Boolean\n    fun getPreviewImage(fraction: Float): Bitmap?\n    fun release()\n\n    var params: ImageParams\n\n    var durationMs: Long\n    var loadedImages: Int\n\n    companion object {\n        fun new(): IPreviewGenerator {\n            val userDisabled = CloudStreamApp.context?.let { ctx ->\n                PreferenceManager.getDefaultSharedPreferences(ctx)?.getBoolean(\n                    ctx.getString(R.string.preview_seekbar_key), true\n                ) == false\n            } ?: false\n            /** because TV has low ram + not show we disable this for now */\n            return if (isLayout(TV) || userDisabled) {\n                empty()\n            } else {\n                PreviewGenerator()\n            }\n        }\n\n        fun empty(): IPreviewGenerator {\n            return NoPreviewGenerator()\n        }\n    }\n}\n\nprivate fun rescale(image: Bitmap, params: ImageParams): Bitmap {\n    if (image.width <= params.width && image.height <= params.height) return image\n    val new = image.scale(params.width, params.height)\n    // throw away the old image\n    if (new != image) {\n        image.recycle()\n    }\n    return new\n}\n\n/** rescale to not take up as much memory */\nprivate fun MediaMetadataRetriever.image(timeUs: Long, params: ImageParams): Bitmap? {\n    /*if (timeUs <= 0 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n        try {\n            val primary = this.primaryImage\n            if (primary != null) {\n                return rescale(primary, params)\n            }\n        } catch (t: Throwable) {\n            logError(t)\n        }\n    }*/\n\n    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {\n        this.getScaledFrameAtTime(\n            timeUs,\n            MediaMetadataRetriever.OPTION_CLOSEST_SYNC,\n            params.width,\n            params.height\n        )\n    } else {\n        return rescale(this.getFrameAtTime(timeUs) ?: return null, params)\n    }\n}\n\n/** PreviewGenerator that hides the implementation details of the sub generators that is used, used for source switch cache */\nclass PreviewGenerator : IPreviewGenerator {\n\n    /** the most up to date generator, will always mirror the actual source in the player */\n    private var currentGenerator: IPreviewGenerator = NoPreviewGenerator()\n\n    /** the longest generated preview of the same episode */\n    private var lastGenerator: IPreviewGenerator = NoPreviewGenerator()\n\n    /** always NoPreviewGenerator, used as a cache for nothing */\n    private val dummy: IPreviewGenerator = NoPreviewGenerator()\n\n    /** if the current generator is the same as the last by checking time */\n    private fun isSameLength(): Boolean =\n        currentGenerator.durationMs.minus(lastGenerator.durationMs).absoluteValue < 10_000L\n\n    /** use the backup if the current generator is init or if they have the same length */\n    private val backupGenerator: IPreviewGenerator\n        get() {\n            if (currentGenerator.durationMs == 0L || isSameLength()) {\n                return lastGenerator\n            }\n            return dummy\n        }\n\n    override fun hasPreview(): Boolean {\n        return currentGenerator.hasPreview() || backupGenerator.hasPreview()\n    }\n\n    override fun getPreviewImage(fraction: Float): Bitmap? {\n        return try {\n            currentGenerator.getPreviewImage(fraction) ?: backupGenerator.getPreviewImage(fraction)\n        } catch (t: Throwable) {\n            logError(t)\n            null\n        }\n    }\n\n    override fun release() {\n        lastGenerator.release()\n        currentGenerator.release()\n        lastGenerator = NoPreviewGenerator()\n        currentGenerator = NoPreviewGenerator()\n    }\n\n    override var params: ImageParams = ImageParams.DEFAULT\n        set(value) {\n            field = value\n            lastGenerator.params = value\n            backupGenerator.params = value\n            currentGenerator.params = value\n        }\n\n    override var durationMs: Long\n        get() = currentGenerator.durationMs\n        set(_) {}\n    override var loadedImages: Int\n        get() = currentGenerator.loadedImages\n        set(_) {}\n\n    fun clear(keepCache: Boolean) {\n        if (keepCache) {\n            if (!isSameLength() || currentGenerator.loadedImages >= lastGenerator.loadedImages || lastGenerator.durationMs == 0L) {\n                // the current generator is better than the last generator, therefore keep the current\n                // or the lengths are not the same, therefore favoring the more recent selection\n\n                // if they are the same we favor the current generator\n                lastGenerator.release()\n                lastGenerator = currentGenerator\n            } else {\n                // otherwise just keep the last generator and throw away the current generator\n                currentGenerator.release()\n            }\n        } else {\n            // we switched the episode, therefore keep nothing\n            lastGenerator.release()\n            lastGenerator = NoPreviewGenerator()\n            currentGenerator.release()\n            // we assume that we set currentGenerator right after this, so currentGenerator != NoPreviewGenerator\n        }\n    }\n\n    fun load(link: ExtractorLink, keepCache: Boolean) {\n        clear(keepCache)\n\n        when (link.type) {\n            ExtractorLinkType.M3U8 -> {\n                currentGenerator = M3u8PreviewGenerator(params).apply {\n                    load(url = link.url, headers = link.getAllHeaders())\n                }\n            }\n\n            ExtractorLinkType.VIDEO -> {\n                currentGenerator = Mp4PreviewGenerator(params).apply {\n                    load(url = link.url, headers = link.getAllHeaders())\n                }\n            }\n\n            else -> {\n                Log.i(\"PreviewImg\", \"unsupported format for $link\")\n            }\n        }\n    }\n\n    fun load(context: Context, link: ExtractorUri, keepCache: Boolean) {\n        clear(keepCache)\n        currentGenerator = Mp4PreviewGenerator(params).apply {\n            load(keepCache = keepCache, context = context, uri = link.uri)\n        }\n    }\n}\n\n@Suppress(\"UNUSED_PARAMETER\")\nprivate class NoPreviewGenerator : IPreviewGenerator {\n    override fun hasPreview(): Boolean = false\n    override fun getPreviewImage(fraction: Float): Bitmap? = null\n    override fun release() = Unit\n    override var params: ImageParams\n        get() = ImageParams(0, 0)\n        set(value) {}\n    override var durationMs: Long = 0L\n    override var loadedImages: Int = 0\n}\n\nprivate class M3u8PreviewGenerator(override var params: ImageParams) : IPreviewGenerator {\n    // generated images 1:1 to idx of hsl\n    private var images: Array<Bitmap?> = arrayOf()\n\n    companion object {\n        private const val TAG = \"PreviewImgM3u8\"\n    }\n\n\n    // prefixSum[i] = sum(hsl.ts[0..i].time)\n    // where [0] = 0, [1] = hsl.ts[0].time aka time at start of segment, do [b] - [a] for range a,b\n    private var prefixSum: Array<Double> = arrayOf()\n\n    // how many images has been generated\n    override var loadedImages: Int = 0\n\n    // how many images we can generate in total, == hsl.size ?: 0\n    private var totalImages: Int = 0\n\n    override fun hasPreview(): Boolean {\n        return totalImages > 0 && loadedImages >= minOf(totalImages, 4)\n    }\n\n    override fun getPreviewImage(fraction: Float): Bitmap? {\n        var bestIdx = -1\n        var bestDiff = Double.MAX_VALUE\n        synchronized(images) {\n            // just find the best one in a for loop, we don't care about bin searching rn\n            for (i in images.indices) {\n                val diff = prefixSum[i].minus(fraction).absoluteValue\n                if (diff > bestDiff) {\n                    break\n                }\n                if (images[i] != null) {\n                    bestIdx = i\n                    bestDiff = diff\n                }\n            }\n            return images.getOrNull(bestIdx)\n        }\n        /*\n        val targetIndex = prefixSum.binarySearch(target)\n        var ret = images[targetIndex]\n        if (ret != null) {\n            return ret\n        }\n        for (i in 0..images.size) {\n            ret = images.getOrNull(i+targetIndex) ?:\n        }*/\n    }\n\n    private fun clear() {\n        synchronized(images) {\n            currentJob?.cancel()\n            // for (i in images.indices) {\n            //     images[i]?.recycle()\n            // }\n            images = arrayOf()\n            prefixSum = arrayOf()\n            loadedImages = 0\n            totalImages = 0\n        }\n    }\n\n    override fun release() {\n        clear()\n        images = arrayOf()\n    }\n\n    override var durationMs: Long = 0L\n\n    private var currentJob: Job? = null\n    fun load(url: String, headers: Map<String, String>) {\n        clear()\n        currentJob?.cancel()\n        currentJob = ioSafe {\n            withContext(Dispatchers.IO) {\n                Log.i(TAG, \"Loading with url = $url headers = $headers\")\n                //tmpFile =\n                //    File.createTempFile(\"video\", \".ts\", context.cacheDir).apply {\n                //        deleteOnExit()\n                //    }\n                val retriever = MediaMetadataRetriever()\n                val hsl = M3u8Helper2.hslLazy(\n                    M3u8Helper.M3u8Stream(\n                        streamUrl = url,\n                        headers = headers\n                    ),\n                    selectBest = false,\n                    requireAudio = false,\n                )\n\n                // no support for encryption atm\n                if (hsl.isEncrypted) {\n                    Log.i(TAG, \"m3u8 is encrypted\")\n                    totalImages = 0\n                    return@withContext\n                }\n\n                // total duration of the entire m3u8 in seconds\n                val duration = hsl.allTsLinks.sumOf { it.time ?: 0.0 }\n                durationMs = (duration * 1000.0).toLong()\n                val durationInv = 1.0 / duration\n\n                // if the total duration is less then 10s then something is very wrong or\n                // too short playback to matter\n                if (duration <= 10.0) {\n                    totalImages = 0\n                    return@withContext\n                }\n\n                totalImages = hsl.allTsLinks.size\n\n                // we cant init directly as it is no guarantee of in order\n                prefixSum = Array(hsl.allTsLinks.size + 1) { 0.0 }\n                var runningSum = 0.0\n                for (i in hsl.allTsLinks.indices) {\n                    runningSum += (hsl.allTsLinks[i].time ?: 0.0)\n                    prefixSum[i + 1] = runningSum * durationInv\n                }\n                synchronized(images) {\n                    images = Array(hsl.size) { null }\n                    loadedImages = 0\n                }\n\n                val maxLod = ceil(log2(duration)).toInt().coerceIn(MIN_LOD, MAX_LOD)\n                val count = hsl.allTsLinks.size\n                for (l in 1..maxLod) {\n                    val items = (1 shl (l - 1))\n                    for (i in 0 until items) {\n                        val index = (count.div(1 shl l) + (i * count) / items).coerceIn(0, hsl.size)\n                        if (synchronized(images) { images[index] } != null) {\n                            continue\n                        }\n                        Log.i(TAG, \"Generating preview for $index\")\n\n                        val ts = hsl.allTsLinks[index]\n                        try {\n                            retriever.setDataSource(ts.url, hsl.headers)\n                            if (!isActive) {\n                                return@withContext\n                            }\n                            val img = retriever.image(0, params)\n                            if (!isActive) {\n                                return@withContext\n                            }\n                            if (img == null || img.width <= 1 || img.height <= 1) continue\n                            synchronized(images) {\n                                images[index] = img\n                                loadedImages += 1\n                            }\n                        } catch (t: Throwable) {\n                            logError(t)\n                            continue\n                        }\n                    }\n                }\n\n            }\n        }\n    }\n}\n\nprivate class Mp4PreviewGenerator(override var params: ImageParams) : IPreviewGenerator {\n    // lod = level of detail where the number indicates how many ones there is\n    // 2^(lod-1) = images\n    private var loadedLod = 0\n    override var loadedImages = 0\n    private var images = Array<Bitmap?>((1 shl MAX_LOD) - 1) {\n        null\n    }\n\n    companion object {\n        private const val TAG = \"PreviewImgMp4\"\n    }\n\n    override fun hasPreview(): Boolean {\n        synchronized(images) {\n            return loadedLod >= MIN_LOD\n        }\n    }\n\n    override fun getPreviewImage(fraction: Float): Bitmap? {\n        synchronized(images) {\n            if (loadedLod < MIN_LOD) {\n                Log.i(TAG, \"Requesting preview for $fraction but $loadedLod < $MIN_LOD\")\n                return null\n            }\n            Log.i(TAG, \"Requesting preview for $fraction\")\n\n            var bestIdx = 0\n            var bestDiff = 0.5f.minus(fraction).absoluteValue\n\n            // this should be done mathematically, but for now we just loop all images\n            for (l in 1..loadedLod + 1) {\n                val items = (1 shl (l - 1))\n                for (i in 0 until items) {\n                    val idx = items - 1 + i\n                    if (idx > loadedImages) {\n                        break\n                    }\n                    if (images[idx] == null) {\n                        continue\n                    }\n                    val currentFraction =\n                        (1.0f.div((1 shl l).toFloat()) + i * 1.0f.div(items.toFloat()))\n                    val diff = currentFraction.minus(fraction).absoluteValue\n                    if (diff < bestDiff) {\n                        bestDiff = diff\n                        bestIdx = idx\n                    }\n                }\n            }\n            Log.i(TAG, \"Best diff found at ${bestDiff * 100}% diff (${bestIdx})\")\n            return images[bestIdx]\n        }\n    }\n\n    // also check out https://github.com/wseemann/FFmpegMediaMetadataRetriever\n    private val retriever: MediaMetadataRetriever = MediaMetadataRetriever()\n\n    private fun clear(keepCache: Boolean) {\n        if (keepCache) return\n        synchronized(images) {\n            loadedLod = 0\n            loadedImages = 0\n            // for (i in images.indices) {\n            //    images[i]?.recycle()\n            //     images[i] = null\n            //}\n            images.fill(null)\n        }\n    }\n\n    private var currentJob: Job? = null\n    fun load(url: String, headers: Map<String, String>) {\n        currentJob?.cancel()\n        currentJob = ioSafe {\n            Log.i(TAG, \"Loading with url = $url headers = $headers\")\n            clear(true)\n            retriever.setDataSource(url, headers)\n            start(this)\n        }\n    }\n\n    fun load(keepCache: Boolean, context: Context, uri: Uri) {\n        currentJob?.cancel()\n        currentJob = ioSafe {\n            Log.i(TAG, \"Loading with uri = $uri\")\n            clear(keepCache)\n            retriever.setDataSource(context, uri)\n            start(this)\n        }\n    }\n\n    override fun release() {\n        currentJob?.cancel()\n        clear(false)\n    }\n\n    override var durationMs: Long = 0L\n\n    @Throws\n    @WorkerThread\n    private fun start(scope: CoroutineScope) {\n        Log.i(TAG, \"Started loading preview\")\n\n        val durationMs =\n            retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong()\n                ?: throw IllegalArgumentException(\"Bad video duration\")\n        this.durationMs = durationMs\n        val durationUs = (durationMs * 1000L).toFloat()\n        //val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt() ?: throw IllegalArgumentException(\"Bad video width\")\n        //val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt() ?: throw IllegalArgumentException(\"Bad video height\")\n\n        // log2 # 10s durations in the video ~= how many segments we have\n        val maxLod = ceil(log2((durationMs / 10_000).toFloat())).toInt().coerceIn(MIN_LOD, MAX_LOD)\n\n        for (l in 1..maxLod) {\n            val items = (1 shl (l - 1))\n            for (i in 0 until items) {\n                val idx = items - 1 + i // as sum(prev) = cur-1\n                // frame = 100 / 2^lod + i * 100 / 2^(lod-1) = duration % where lod is one indexed\n                val fraction = (1.0f.div((1 shl l).toFloat()) + i * 1.0f.div(items.toFloat()))\n                Log.i(TAG, \"Generating preview for ${fraction * 100}%\")\n                val frame = durationUs * fraction\n                val img = retriever.image(frame.toLong(), params)\n                if (!scope.isActive) return\n                if (img == null || img.width <= 1 || img.height <= 1) continue\n                synchronized(images) {\n                    images[idx] = img\n                    loadedImages = maxOf(loadedImages, idx)\n                }\n            }\n\n            synchronized(images) {\n                loadedLod = maxOf(loadedLod, l)\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/RepoLinkGenerator.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.util.Log\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.APIHolder.unixTime\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.ui.APIRepository\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport kotlin.math.max\nimport kotlin.math.min\n\ndata class Cache(\n    val linkCache: MutableSet<ExtractorLink>,\n    val subtitleCache: MutableSet<SubtitleData>,\n    /** When it was last updated */\n    var lastCachedTimestamp: Long = unixTime,\n    /** If it has fully loaded */\n    var saturated: Boolean,\n)\n\nclass RepoLinkGenerator(\n    episodes: List<ResultEpisode>,\n    currentIndex: Int = 0,\n    val page: LoadResponse? = null,\n) : VideoGenerator<ResultEpisode>(episodes, currentIndex) {\n    companion object {\n        const val TAG = \"RepoLink\"\n        val cache: HashMap<Pair<String, Int>, Cache> =\n            hashMapOf()\n    }\n\n    override val hasCache = true\n    override val canSkipLoading = true\n\n    // this is a simple array that is used to instantly load links if they are already loaded\n    //var linkCache = Array<Set<ExtractorLink>>(size = episodes.size, init = { setOf() })\n    //var subsCache = Array<Set<SubtitleData>>(size = episodes.size, init = { setOf() })\n\n    @Throws\n    override suspend fun generateLinks(\n        clearCache: Boolean,\n        sourceTypes: Set<ExtractorLinkType>,\n        callback: (Pair<ExtractorLink?, ExtractorUri?>) -> Unit,\n        subtitleCallback: (SubtitleData) -> Unit,\n        offset: Int,\n        isCasting: Boolean,\n    ): Boolean {\n        val current = getCurrent(offset) ?: return false\n\n        val currentCache = synchronized(cache) {\n            cache[current.apiName to current.id] ?: Cache(\n                mutableSetOf(),\n                mutableSetOf(),\n                unixTime,\n                false\n            ).also {\n                cache[current.apiName to current.id] = it\n            }\n        }\n\n        // these act as a general filter to prevent duplication of links or names\n        val currentLinksUrls = mutableSetOf<String>()       // makes all urls unique\n        val currentSubsUrls = mutableSetOf<String>()    // makes all subs urls unique\n        val lastCountedSuffix = mutableMapOf<String, UInt>()\n\n        synchronized(currentCache) {\n            val outdatedCache =\n                unixTime - currentCache.lastCachedTimestamp > 60 * 20 // 20 minutes\n\n            if (outdatedCache || clearCache) {\n                currentCache.linkCache.clear()\n                currentCache.subtitleCache.clear()\n                currentCache.saturated = false\n            } else if (currentCache.linkCache.isNotEmpty()) {\n                Log.d(TAG, \"Resumed previous loading from ${unixTime - currentCache.lastCachedTimestamp}s ago\")\n            }\n\n            // call all callbacks\n            currentCache.linkCache.forEach { link ->\n                currentLinksUrls.add(link.url)\n                if (sourceTypes.contains(link.type)) {\n                    callback(link to null)\n                }\n            }\n\n            currentCache.subtitleCache.forEach { sub ->\n                currentSubsUrls.add(sub.url)\n                val suffixCount = lastCountedSuffix.getOrDefault(sub.originalName, 0u) + 1u\n                lastCountedSuffix[sub.originalName] = suffixCount\n                subtitleCallback(sub)\n            }\n\n            // this stops all execution if links are cached\n            // no extra get requests\n            if (currentCache.saturated) {\n                return true\n            }\n        }\n\n        val result = APIRepository(\n            getApiFromNameNull(current.apiName) ?: throw Exception(\"This provider does not exist\")\n        ).loadLinks(\n            current.data,\n            isCasting = isCasting,\n            subtitleCallback = { file ->\n                Log.d(TAG, \"Loaded SubtitleFile: $file\")\n                val correctFile = PlayerSubtitleHelper.getSubtitleData(file)\n                if (correctFile.url.isBlank() || currentSubsUrls.contains(correctFile.url)) {\n                    return@loadLinks\n                }\n                currentSubsUrls.add(correctFile.url)\n\n                // this part makes sure that all names are unique for UX\n\n                val nameDecoded = correctFile.originalName.html().toString().trim() // `%3Ch1%3Esub%20name…` → `<h1>sub name…` → `sub name…`\n\n                val suffixCount = lastCountedSuffix.getOrDefault(nameDecoded, 0u) +1u\n                lastCountedSuffix[nameDecoded] = suffixCount\n\n                val updatedFile =\n                    correctFile.copy(originalName = nameDecoded, nameSuffix = \"$suffixCount\")\n\n                synchronized(currentCache) {\n                    if (currentCache.subtitleCache.add(updatedFile)) {\n                        subtitleCallback(updatedFile)\n                        currentCache.lastCachedTimestamp = unixTime\n                    }\n                }\n            },\n            callback = { link ->\n                Log.d(TAG, \"Loaded ExtractorLink: $link\")\n                if (link.url.isBlank() || currentLinksUrls.contains(link.url)) {\n                    return@loadLinks\n                }\n                currentLinksUrls.add(link.url)\n\n                synchronized(currentCache) {\n                    if (currentCache.linkCache.add(link)) {\n                        if (sourceTypes.contains(link.type)) {\n                            callback(Pair(link, null))\n                        }\n\n                        currentCache.linkCache.add(link)\n                        currentCache.lastCachedTimestamp = unixTime\n                    }\n                }\n            }\n        )\n\n        synchronized(currentCache) {\n            currentCache.saturated = currentCache.linkCache.isNotEmpty()\n            currentCache.lastCachedTimestamp = unixTime\n        }\n\n        return result\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/RoundedBackgroundColorSpan.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\r\n\r\n/**\r\n * Inspired by https://medium.com/@Semper_Viventem/simple-implementation-of-rounded-background-for-text-in-android-60a7706c0419\r\n * however the connecting triangles cant be rendered on a transparent bg, also does not support alignment.\r\n *\r\n * This current implementation may be expanded to only draw the drawRoundRect with rounded corners iff\r\n * it is on an edge for a nice look:\r\n *\r\n * /----------\\\r\n * |  large   |\r\n * \\----------/\r\n *  |       |  <- this instead of / and \\\r\n *  | small |\r\n *  \\-------/\r\n *\r\n *  Also note that the background may be drawn wildly different from where exoplayer places it\r\n *  because exoplayer has their own custom drawing. This is only an attempt to correlate it.\r\n *\r\n *  Additionally, not tested on RTL\r\n*/\r\n\r\nimport android.graphics.Canvas\r\nimport android.graphics.Color\r\nimport android.graphics.Paint\r\nimport android.os.Build\r\nimport android.text.Layout.Alignment\r\nimport android.text.StaticLayout\r\nimport android.text.TextPaint\r\nimport android.text.style.LineBackgroundSpan\r\n\r\nclass RoundedBackgroundColorSpan(\r\n    private val backgroundColor: Int,\r\n    private val alignment: Alignment,\r\n    private val padding: Float,\r\n    private val radius: Float\r\n) : LineBackgroundSpan {\r\n    private val paint = Paint().apply {\r\n        color = backgroundColor\r\n        isAntiAlias = true\r\n    }\r\n\r\n    override fun drawBackground(\r\n        c: Canvas,\r\n        p: Paint,\r\n        left: Int,\r\n        right: Int,\r\n        top: Int,\r\n        baseline: Int,\r\n        bottom: Int,\r\n        text: CharSequence,\r\n        start: Int,\r\n        end: Int,\r\n        lineNumber: Int\r\n    ) {\r\n\r\n        // https://github.com/androidx/media/blob/main/libraries/ui/src/main/java/androidx/media3/ui/SubtitlePainter.java\r\n        if (Color.alpha(backgroundColor) <= 0) {\r\n            return\r\n        }\r\n\r\n        val width = p.measureText(text, start, end)\r\n        val textLayout: StaticLayout = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\r\n            StaticLayout.Builder\r\n                .obtain(text, 0, text.length, TextPaint(p), width.toInt())\r\n                .setAlignment(alignment)\r\n                .setLineSpacing(0.0f, 1.0f)\r\n                .setIncludePad(true)\r\n                .build()\r\n        } else {\r\n            @Suppress(\"DEPRECATION\")\r\n            StaticLayout(\r\n                text,\r\n                TextPaint(p),\r\n                width.toInt(),\r\n                alignment,\r\n                1.0f,\r\n                0.0f,\r\n                true\r\n            )\r\n        }\r\n\r\n        val center = (left + right).toFloat() * 0.5f\r\n\r\n        // I know this is not how you actually do it, but fuck it.\r\n        // You have to override the subtitle painter to get all the correct value\r\n        val textLeft = when (alignment) {\r\n            Alignment.ALIGN_NORMAL -> {\r\n                0.0f\r\n            }\r\n\r\n            Alignment.ALIGN_OPPOSITE -> {\r\n                right - width\r\n            }\r\n\r\n            Alignment.ALIGN_CENTER -> {\r\n                center - width * 0.5f\r\n            }\r\n        }\r\n\r\n        val textTop = textLayout.getLineTop(lineNumber).toFloat()\r\n        val textBottom = textLayout.getLineBottom(lineNumber).toFloat()\r\n\r\n        c.drawRoundRect(\r\n            textLeft - padding,\r\n            textTop,\r\n            textLeft + width + padding,\r\n            textBottom,\r\n            radius,\r\n            radius,\r\n            paint\r\n        )\r\n    }\r\n}\r\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/SSLTrustManager.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport java.security.cert.X509Certificate\nimport javax.net.ssl.X509TrustManager\n\nclass SSLTrustManager : X509TrustManager {\n    override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {\n    }\n\n    override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) {\n    }\n\n    override fun getAcceptedIssuers(): Array<X509Certificate> {\n        return arrayOf()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/SubtitleOffsetItemAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport android.animation.ObjectAnimator\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport android.view.animation.DecelerateInterpolator\nimport androidx.core.view.isInvisible\nimport com.lagradost.cloudstream3.databinding.SubtitleOffsetItemBinding\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport kotlin.math.roundToInt\n\ndata class SubtitleCue(val startTimeMs: Long, val durationMs: Long, val text: List<String>) {\n    val endTimeMs = startTimeMs + durationMs\n}\n\nclass SubtitleOffsetItemAdapter(\n    private var currentTimeMs: Long,\n    val clickCallback: (SubtitleCue) -> Unit\n) :\n    NoStateAdapter<SubtitleCue>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n        a.startTimeMs == b.startTimeMs\n    })) {\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        val inflater = LayoutInflater.from(parent.context)\n        val binding = SubtitleOffsetItemBinding.inflate(inflater, parent, false)\n        return ViewHolderState(binding)\n    }\n\n    override fun onBindContent(holder: ViewHolderState<Any>, item: SubtitleCue, position: Int) {\n        val binding = holder.view as? SubtitleOffsetItemBinding ?: return\n\n        binding.root.setOnClickListener {\n            clickCallback.invoke(item)\n        }\n\n        binding.subtitleText.text = item.text.joinToString(\"\\n\")\n\n        val timeMs = currentTimeMs\n        val startTime = item.startTimeMs\n        val endTime = item.endTimeMs\n\n        val newAlpha = if (timeMs >= startTime) 1f else 0.5f\n        ObjectAnimator.ofFloat(\n            binding.subtitleText,\n            \"alpha\",\n            binding.subtitleText.alpha,\n            newAlpha\n        ).apply {\n            interpolator = DecelerateInterpolator()\n        }.start()\n\n        val showProgress = timeMs in startTime..<endTime\n        // Invisible to prevent layout changes\n        binding.subtitleProgress.isInvisible = !showProgress\n\n        if (showProgress) {\n            // Set progress to currentTime/remainingTime\n            // Multiply by 1000 since the max is 1000\n            val progressValue = ((timeMs - startTime) * 1000f / item.durationMs).roundToInt()\n\n            // Animate the progress change\n            ObjectAnimator.ofInt(\n                binding.subtitleProgress,\n                \"progress\",\n                binding.subtitleProgress.progress,\n                progressValue\n            ).apply {\n                interpolator = DecelerateInterpolator()\n            }.start()\n        } else {\n            // Reset progress when not visible\n            binding.subtitleProgress.progress = 0\n        }\n    }\n\n    fun getLatestActiveItem(position: Long): Int {\n        return immutableCurrentList.withIndex().lastOrNull {\n            position >= it.value.startTimeMs\n        }?.index ?: 0\n    }\n\n    fun updateTime(timeMs: Long) {\n        val previousTime = currentTimeMs\n        currentTimeMs = timeMs\n\n        val earlyTime = minOf(previousTime, timeMs)\n        val lateTime = maxOf(previousTime, timeMs)\n\n        // TODO Add binary search and notifyItemRangeChanged\n        val affectedItems = immutableCurrentList.withIndex().filter { cue ->\n            // Padding is required in the range because changes can be done within one single subtitle range,\n            // and that subtitle needs to be updated\n            cue.value.startTimeMs in (earlyTime - cue.value.durationMs)..(lateTime + cue.value.durationMs)\n        }\n\n        affectedItems.forEach { item ->\n            // This could likely be a range\n            this.notifyItemChanged(item.index)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt",
    "content": "package com.lagradost.cloudstream3.ui.player\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport torrServer.TorrServer\nimport java.io.File\nimport java.net.ConnectException\nimport java.net.URLEncoder\n\nobject Torrent {\n    var hasAcceptedTorrentForThisSession: Boolean? = null\n    private const val TORRENT_SERVER_PATH: String = \"torrent_tmp\"\n    private const val TIMEOUT: Long = 3\n    private const val TAG: String = \"Torrent\"\n\n    /** Cleans up both old aria2c files and newer go server, (even if the new is also self cleaning) */\n    @Throws\n    fun deleteAllFiles(): Boolean {\n        val act = CommonActivity.activity ?: return false\n        val defaultDirectory = \"${act.cacheDir.path}/$TORRENT_SERVER_PATH\"\n        return File(defaultDirectory).deleteRecursively()\n    }\n\n    private var TORRENT_SERVER_URL = \"\" // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/main/server.go#L23\n\n    /** Returns true if the server is up */\n    private suspend fun echo(): Boolean {\n        if(TORRENT_SERVER_URL.isEmpty()) {\n            return false\n        }\n        return try {\n            app.get(\n                \"$TORRENT_SERVER_URL/echo\",\n            ).text.isNotEmpty()\n        } catch (e: ConnectException) {\n            // `Failed to connect to /127.0.0.1:8090` if the server is down\n            false\n        } catch (t: Throwable) {\n            logError(t)\n            false\n        }\n    }\n\n    // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/web/api/shutdown.go#L22\n    /** Gracefully shutdown the server.\n     * should not be used because I am unable to start it again, and the stopTorrentServer() crashes the app */\n    suspend fun shutdown(): Boolean {\n        if(TORRENT_SERVER_URL.isEmpty()) {\n            return false\n        }\n        return try {\n            app.get(\n                \"$TORRENT_SERVER_URL/shutdown\",\n            ).isSuccessful\n        } catch (t: Throwable) {\n            logError(t)\n            false\n        }\n    }\n\n    /** Lists all torrents by the server */\n    @Throws\n    private suspend fun list(): Array<TorrentStatus> {\n        if(TORRENT_SERVER_URL.isEmpty()) {\n            throw ErrorLoadingException(\"Not initialized\")\n        }\n        return app.post(\n            \"$TORRENT_SERVER_URL/torrents\",\n            json = TorrentRequest(\n                action = \"list\",\n            ),\n            timeout = TIMEOUT,\n            headers = emptyMap()\n        ).parsed<Array<TorrentStatus>>()\n    }\n\n    /** Drops a single torrent, (I think) this means closing the stream. Returns returns if it is successful */\n    private suspend fun drop(hash: String): Boolean {\n        if(TORRENT_SERVER_URL.isEmpty()) {\n            return false\n        }\n        return try {\n            return app.post(\n                \"$TORRENT_SERVER_URL/torrents\",\n                json = TorrentRequest(\n                    action = \"drop\",\n                    hash = hash\n                ),\n                timeout = TIMEOUT,\n                headers = emptyMap()\n            ).isSuccessful\n        } catch (t: Throwable) {\n            logError(t)\n            false\n        }\n    }\n\n    /** Removes a single torrent from the server registry */\n    private suspend fun rem(hash: String): Boolean {\n        if(TORRENT_SERVER_URL.isEmpty()) {\n            return false\n        }\n        return try {\n            return app.post(\n                \"$TORRENT_SERVER_URL/torrents\",\n                json = TorrentRequest(\n                    action = \"rem\",\n                    hash = hash\n                ),\n                timeout = TIMEOUT,\n                headers = emptyMap()\n            ).isSuccessful\n        } catch (t: Throwable) {\n            logError(t)\n            false\n        }\n    }\n\n\n    /** Removes all torrents from the server, and returns if it is successful */\n    suspend fun clearAll(): Boolean {\n        if(TORRENT_SERVER_URL.isEmpty()) {\n            return true\n        }\n        return try {\n            val items = list()\n            var allSuccess = true\n            for (item in items) {\n                val hash = item.hash\n                if (hash == null) {\n                    Log.i(TAG, \"No hash on ${item.name}\")\n                    allSuccess = false\n                    continue\n                }\n                if (drop(hash)) {\n                    Log.i(TAG, \"Successfully dropped ${item.name}\")\n                } else {\n                    Log.i(TAG, \"Failed to drop ${item.name}\")\n                    allSuccess = false\n                    continue\n                }\n                if (rem(hash)) {\n                    Log.i(TAG, \"Successfully removed ${item.name}\")\n                } else {\n                    Log.i(TAG, \"Failed to remove ${item.name}\")\n                    allSuccess = false\n                    continue\n                }\n            }\n            allSuccess\n        } catch (t: Throwable) {\n            logError(t)\n            false\n        }\n    }\n\n    /** Gets all the metadata of a torrent, will throw if that hash does not exists\n     * https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/web/api/torrents.go#L126 */\n    @Throws\n    suspend fun get(\n        hash: String,\n    ): TorrentStatus {\n        if(TORRENT_SERVER_URL.isEmpty()) {\n            throw ErrorLoadingException(\"Not initialized\")\n        }\n        return app.post(\n            \"$TORRENT_SERVER_URL/torrents\",\n            json = TorrentRequest(\n                action = \"get\",\n                hash = hash,\n            ),\n            timeout = TIMEOUT,\n            headers = emptyMap()\n        ).parsed<TorrentStatus>()\n    }\n\n    /** Adds a torrent to the server, this is needed for us to get the hash for further modification, as well as start streaming it*/\n    @Throws\n    private suspend fun add(url: String): TorrentStatus {\n        if(TORRENT_SERVER_URL.isEmpty()) {\n            throw ErrorLoadingException(\"Not initialized\")\n        }\n        return app.post(\n            \"$TORRENT_SERVER_URL/torrents\",\n            json = TorrentRequest(\n                action = \"add\",\n                link = url,\n            ),\n            headers = emptyMap()\n        ).parsed<TorrentStatus>()\n    }\n\n    /** Spins up the torrent server. */\n    private suspend fun setup(dir: String): Boolean {\n        go.Seq.load()\n        if (echo()) {\n            return true\n        }\n        val port = TorrServer.startTorrentServer(dir, 0)\n        if(port < 0) {\n            return false\n        }\n        TORRENT_SERVER_URL = \"http://127.0.0.1:$port\"\n        TorrServer.addTrackers(trackers.joinToString(separator = \",\\n\"))\n        return echo()\n    }\n\n    /** Transforms a torrent link into a streamable link via the server */\n    @Throws\n    suspend fun transformLink(link: ExtractorLink): Pair<ExtractorLink, TorrentStatus> {\n        val act = CommonActivity.activity ?: throw IllegalArgumentException(\"No activity\")\n        val defaultDirectory = \"${act.cacheDir.path}/$TORRENT_SERVER_PATH\"\n        File(defaultDirectory).mkdir()\n        if (!setup(defaultDirectory)) {\n            throw ErrorLoadingException(\"Unable to setup the torrent server\")\n        }\n        val status = add(link.url)\n\n        return newExtractorLink(\n            source = link.source,\n            name = link.name,\n            url = status.streamUrl(link.url),\n            type = ExtractorLinkType.VIDEO\n        ) {\n            this.referer = \"\"\n            this.quality = link.quality\n        } to status\n    }\n\n    private val trackers = listOf(\n        \"udp://tracker.opentrackr.org:1337/announce\",\n        \"https://tracker2.ctix.cn/announce\",\n        \"https://tracker1.520.jp:443/announce\",\n        \"udp://opentracker.i2p.rocks:6969/announce\",\n        \"udp://open.tracker.cl:1337/announce\",\n        \"udp://open.demonii.com:1337/announce\",\n        \"http://tracker.openbittorrent.com:80/announce\",\n        \"udp://tracker.openbittorrent.com:6969/announce\",\n        \"udp://open.stealth.si:80/announce\",\n        \"udp://exodus.desync.com:6969/announce\",\n        \"udp://tracker-udp.gbitt.info:80/announce\",\n        \"udp://explodie.org:6969/announce\",\n        \"https://tracker.gbitt.info:443/announce\",\n        \"http://tracker.gbitt.info:80/announce\",\n        \"udp://uploads.gamecoast.net:6969/announce\",\n        \"udp://tracker1.bt.moack.co.kr:80/announce\",\n        \"udp://tracker.tiny-vps.com:6969/announce\",\n        \"udp://tracker.theoks.net:6969/announce\",\n        \"udp://tracker.dump.cl:6969/announce\",\n        \"udp://tracker.bittor.pw:1337/announce\",\n        \"https://tracker1.520.jp:443/announce\",\n        \"udp://opentracker.i2p.rocks:6969/announce\",\n        \"udp://open.tracker.cl:1337/announce\",\n        \"udp://open.demonii.com:1337/announce\",\n        \"http://tracker.openbittorrent.com:80/announce\",\n        \"udp://tracker.openbittorrent.com:6969/announce\",\n        \"udp://open.stealth.si:80/announce\",\n        \"udp://exodus.desync.com:6969/announce\",\n        \"udp://tracker-udp.gbitt.info:80/announce\",\n        \"udp://explodie.org:6969/announce\",\n        \"https://tracker.gbitt.info:443/announce\",\n        \"http://tracker.gbitt.info:80/announce\",\n        \"udp://uploads.gamecoast.net:6969/announce\",\n        \"udp://tracker1.bt.moack.co.kr:80/announce\",\n        \"udp://tracker.tiny-vps.com:6969/announce\",\n        \"udp://tracker.theoks.net:6969/announce\",\n        \"udp://tracker.dump.cl:6969/announce\",\n        \"udp://tracker.bittor.pw:1337/announce\"\n    )\n\n\n    // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/web/api/torrents.go#L18\n    // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/main/web/api/route.go#L7\n    data class TorrentRequest(\n        @JsonProperty(\"action\")\n        val action: String,\n        @JsonProperty(\"hash\")\n        val hash: String = \"\",\n        @JsonProperty(\"link\")\n        val link: String = \"\",\n        @JsonProperty(\"title\")\n        val title: String = \"\",\n        @JsonProperty(\"poster\")\n        val poster: String = \"\",\n        @JsonProperty(\"data\")\n        val data: String = \"\",\n        @JsonProperty(\"save_to_db\")\n        val saveToDB: Boolean = false,\n    )\n\n    // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/torr/state/state.go#L33\n    // omitempty = nullable\n    data class TorrentStatus(\n        @JsonProperty(\"title\")\n        var title: String,\n        @JsonProperty(\"poster\")\n        var poster: String,\n        @JsonProperty(\"data\")\n        var data: String?,\n        @JsonProperty(\"timestamp\")\n        var timestamp: Long,\n        @JsonProperty(\"name\")\n        var name: String?,\n        @JsonProperty(\"hash\")\n        var hash: String?,\n        @JsonProperty(\"stat\")\n        var stat: Int,\n        @JsonProperty(\"stat_string\")\n        var statString: String,\n        @JsonProperty(\"loaded_size\")\n        var loadedSize: Long?,\n        @JsonProperty(\"torrent_size\")\n        var torrentSize: Long?,\n        @JsonProperty(\"preloaded_bytes\")\n        var preloadedBytes: Long?,\n        @JsonProperty(\"preload_size\")\n        var preloadSize: Long?,\n        @JsonProperty(\"download_speed\")\n        var downloadSpeed: Double?,\n        @JsonProperty(\"upload_speed\")\n        var uploadSpeed: Double?,\n        @JsonProperty(\"total_peers\")\n        var totalPeers: Int?,\n        @JsonProperty(\"pending_peers\")\n        var pendingPeers: Int?,\n        @JsonProperty(\"active_peers\")\n        var activePeers: Int?,\n        @JsonProperty(\"connected_seeders\")\n        var connectedSeeders: Int?,\n        @JsonProperty(\"half_open_peers\")\n        var halfOpenPeers: Int?,\n        @JsonProperty(\"bytes_written\")\n        var bytesWritten: Long?,\n        @JsonProperty(\"bytes_written_data\")\n        var bytesWrittenData: Long?,\n        @JsonProperty(\"bytes_read\")\n        var bytesRead: Long?,\n        @JsonProperty(\"bytes_read_data\")\n        var bytesReadData: Long?,\n        @JsonProperty(\"bytes_read_useful_data\")\n        var bytesReadUsefulData: Long?,\n        @JsonProperty(\"chunks_written\")\n        var chunksWritten: Long?,\n        @JsonProperty(\"chunks_read\")\n        var chunksRead: Long?,\n        @JsonProperty(\"chunks_read_useful\")\n        var chunksReadUseful: Long?,\n        @JsonProperty(\"chunks_read_wasted\")\n        var chunksReadWasted: Long?,\n        @JsonProperty(\"pieces_dirtied_good\")\n        var piecesDirtiedGood: Long?,\n        @JsonProperty(\"pieces_dirtied_bad\")\n        var piecesDirtiedBad: Long?,\n        @JsonProperty(\"duration_seconds\")\n        var durationSeconds: Double?,\n        @JsonProperty(\"bit_rate\")\n        var bitRate: String?,\n        @JsonProperty(\"file_stats\")\n        var fileStats: List<TorrentFileStat>?,\n        @JsonProperty(\"trackers\")\n        var trackers: List<String>?,\n    ) {\n        fun streamUrl(url: String): String {\n            val fileName =\n                this.fileStats?.first { !it.path.isNullOrBlank() }?.path\n                    ?: throw ErrorLoadingException(\"Null path\")\n\n            val index = url.substringAfter(\"index=\").substringBefore(\"&\").toIntOrNull() ?: 0\n\n            //  https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/web/api/stream.go#L18\n            return \"$TORRENT_SERVER_URL/stream/${\n                URLEncoder.encode(fileName, \"utf-8\")\n            }?link=${this.hash}&index=$index&play\"\n        }\n    }\n\n    data class TorrentFileStat(\n        @JsonProperty(\"id\")\n        val id: Int?,\n        @JsonProperty(\"path\")\n        val path: String?,\n        @JsonProperty(\"length\")\n        val length: Long?,\n    )\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/UpdatedDefaultExtractorsFactory.kt",
    "content": "@file:Suppress(\r\n    \"ALL\",\r\n    \"DEPRECATION\",\r\n    \"RedundantVisibilityModifier\",\r\n    \"RemoveRedundantQualifierName\",\r\n    \"UNCHECKED_CAST\",\r\n    \"UNUSED\",\r\n    \"UNUSED_PARAMETER\",\r\n    \"UNUSED_VARIABLE\"\r\n)\r\n\r\npackage com.lagradost.cloudstream3.ui.player\r\n\r\nimport android.net.Uri\r\nimport androidx.annotation.GuardedBy\r\nimport androidx.media3.common.C\r\nimport androidx.media3.common.FileTypes\r\nimport androidx.media3.common.Format\r\nimport androidx.media3.common.util.TimestampAdjuster\r\nimport androidx.media3.common.util.UnstableApi\r\nimport androidx.media3.extractor.Extractor\r\nimport androidx.media3.extractor.ExtractorsFactory\r\nimport androidx.media3.extractor.amr.AmrExtractor\r\nimport androidx.media3.extractor.avi.AviExtractor\r\nimport androidx.media3.extractor.avif.AvifExtractor\r\nimport androidx.media3.extractor.bmp.BmpExtractor\r\nimport androidx.media3.extractor.flac.FlacExtractor\r\nimport androidx.media3.extractor.flv.FlvExtractor\r\nimport androidx.media3.extractor.heif.HeifExtractor\r\nimport androidx.media3.extractor.jpeg.JpegExtractor\r\nimport androidx.media3.extractor.mkv.UpdatedMatroskaExtractor\r\nimport androidx.media3.extractor.mp3.Mp3Extractor\r\nimport androidx.media3.extractor.mp4.FragmentedMp4Extractor\r\nimport androidx.media3.extractor.mp4.Mp4Extractor\r\nimport androidx.media3.extractor.ogg.OggExtractor\r\nimport androidx.media3.extractor.png.PngExtractor\r\nimport androidx.media3.extractor.text.DefaultSubtitleParserFactory\r\nimport androidx.media3.extractor.text.SubtitleParser\r\nimport androidx.media3.extractor.ts.Ac3Extractor\r\nimport androidx.media3.extractor.ts.Ac4Extractor\r\nimport androidx.media3.extractor.ts.AdtsExtractor\r\nimport androidx.media3.extractor.ts.DefaultTsPayloadReaderFactory\r\nimport androidx.media3.extractor.ts.PsExtractor\r\nimport androidx.media3.extractor.ts.TsExtractor\r\nimport androidx.media3.extractor.wav.WavExtractor\r\nimport androidx.media3.extractor.webp.WebpExtractor\r\nimport com.google.common.collect.ImmutableList\r\nimport java.lang.reflect.Constructor\r\nimport java.lang.reflect.InvocationTargetException\r\nimport java.util.concurrent.atomic.AtomicBoolean\r\n\r\n/**\r\n * An [ExtractorsFactory] that provides an array of extractors for the following formats:\r\n *\r\n *\r\n *  * MP4, including M4A ([Mp4Extractor])\r\n *  * fMP4 ([FragmentedMp4Extractor])\r\n *  * Matroska and WebM ([UpdatedMatroskaExtractor])\r\n *  * Ogg Vorbis/FLAC ([OggExtractor]\r\n *  * MP3 ([Mp3Extractor])\r\n *  * AAC ([AdtsExtractor])\r\n *  * MPEG TS ([TsExtractor])\r\n *  * MPEG PS ([PsExtractor])\r\n *  * FLV ([FlvExtractor])\r\n *  * WAV ([WavExtractor])\r\n *  * AC3 ([Ac3Extractor])\r\n *  * AC4 ([Ac4Extractor])\r\n *  * AMR ([AmrExtractor])\r\n *  * FLAC\r\n *\r\n *  * If available, the FLAC extension's `androidx.media3.decoder.flac.FlacExtractor`\r\n * is used.\r\n *  * Otherwise, the core [FlacExtractor] is used. Note that Android devices do not\r\n * generally include a FLAC decoder before API 27. This can be worked around by using\r\n * the FLAC extension or the FFmpeg extension.\r\n *\r\n *  * JPEG ([JpegExtractor])\r\n *  * PNG ([PngExtractor])\r\n *  * WEBP ([WebpExtractor])\r\n *  * BMP ([BmpExtractor])\r\n *  * HEIF ([HeifExtractor])\r\n *  * AVIF ([AvifExtractor])\r\n *  * MIDI, if available, the MIDI extension's `androidx.media3.decoder.midi.MidiExtractor`\r\n * is used.\r\n *\r\n */\r\n@UnstableApi\r\nclass UpdatedDefaultExtractorsFactory : ExtractorsFactory {\r\n    private var constantBitrateSeekingEnabled = false\r\n    private var constantBitrateSeekingAlwaysEnabled = false\r\n    private var adtsFlags: @AdtsExtractor.Flags Int = 0\r\n    private var amrFlags: @AmrExtractor.Flags Int = 0\r\n    private var flacFlags: @FlacExtractor.Flags Int = 0\r\n    private var matroskaFlags: @UpdatedMatroskaExtractor.Flags Int = 0\r\n    private var mp4Flags: @Mp4Extractor.Flags Int = 0\r\n    private var fragmentedMp4Flags: @FragmentedMp4Extractor.Flags Int = 0\r\n    private var mp3Flags: @Mp3Extractor.Flags Int = 0\r\n    private var tsMode: @TsExtractor.Mode Int\r\n    private var tsFlags: @DefaultTsPayloadReaderFactory.Flags Int = 0\r\n\r\n    // TODO (b/261183220): Initialize tsSubtitleFormats in constructor once shrinking bug is fixed.\r\n    private var tsSubtitleFormats: ImmutableList<Format>? = null\r\n    private var tsTimestampSearchBytes: Int\r\n    private var textTrackTranscodingEnabled: Boolean\r\n    private var subtitleParserFactory: SubtitleParser.Factory\r\n    private var codecsToParseWithinGopSampleDependencies: @C.VideoCodecFlags Int\r\n    private var jpegFlags: @JpegExtractor.Flags Int = 0\r\n    private var heifFlags: @HeifExtractor.Flags Int = 0\r\n\r\n    init {\r\n        tsMode = TsExtractor.MODE_SINGLE_PMT\r\n        tsTimestampSearchBytes = TsExtractor.DEFAULT_TIMESTAMP_SEARCH_BYTES\r\n        subtitleParserFactory = DefaultSubtitleParserFactory()\r\n        textTrackTranscodingEnabled = true\r\n        codecsToParseWithinGopSampleDependencies = C.VIDEO_CODEC_FLAG_H264 or C.VIDEO_CODEC_FLAG_H265\r\n    }\r\n\r\n    /**\r\n     * Convenience method to set whether approximate seeking using constant bitrate assumptions should\r\n     * be enabled for all extractors that support it. If set to true, the flags required to enable\r\n     * this functionality will be OR'd with those passed to the setters when creating extractor\r\n     * instances. If set to false then the flags passed to the setters will be used without\r\n     * modification.\r\n     *\r\n     * @param constantBitrateSeekingEnabled Whether approximate seeking using a constant bitrate\r\n     * assumption should be enabled for all extractors that support it.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setConstantBitrateSeekingEnabled(\r\n        constantBitrateSeekingEnabled: Boolean\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.constantBitrateSeekingEnabled = constantBitrateSeekingEnabled\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Convenience method to set whether approximate seeking using constant bitrate assumptions should\r\n     * be enabled for all extractors that support it, and if it should be enabled even if the content\r\n     * length (and hence the duration of the media) is unknown. If set to true, the flags required to\r\n     * enable this functionality will be OR'd with those passed to the setters when creating extractor\r\n     * instances. If set to false then the flags passed to the setters will be used without\r\n     * modification.\r\n     *\r\n     *\r\n     * When seeking into content where the length is unknown, application code should ensure that\r\n     * requested seek positions are valid, or should be ready to handle playback failures reported\r\n     * through [Player.Listener.onPlayerError] with [PlaybackException.errorCode] set to\r\n     * [PlaybackException.ERROR_CODE_IO_READ_POSITION_OUT_OF_RANGE].\r\n     *\r\n     * @param constantBitrateSeekingAlwaysEnabled Whether approximate seeking using a constant bitrate\r\n     * assumption should be enabled for all extractors that support it, including when the content\r\n     * duration is unknown.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setConstantBitrateSeekingAlwaysEnabled(\r\n        constantBitrateSeekingAlwaysEnabled: Boolean\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.constantBitrateSeekingAlwaysEnabled = constantBitrateSeekingAlwaysEnabled\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [AdtsExtractor] instances created by the factory.\r\n     *\r\n     * @see AdtsExtractor.AdtsExtractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setAdtsExtractorFlags(\r\n        flags: @AdtsExtractor.Flags Int\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.adtsFlags = flags\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [AmrExtractor] instances created by the factory.\r\n     *\r\n     * @see AmrExtractor.AmrExtractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setAmrExtractorFlags(flags: @AmrExtractor.Flags Int): UpdatedDefaultExtractorsFactory {\r\n        this.amrFlags = flags\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [FlacExtractor] instances created by the factory. The flags are also used\r\n     * by `androidx.media3.decoder.flac.FlacExtractor` instances if the FLAC extension is being\r\n     * used.\r\n     *\r\n     * @see FlacExtractor.FlacExtractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setFlacExtractorFlags(\r\n        flags: @FlacExtractor.Flags Int\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.flacFlags = flags\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [UpdatedMatroskaExtractor] instances created by the factory.\r\n     *\r\n     * @see UpdatedMatroskaExtractor.MatroskaExtractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setMatroskaExtractorFlags(\r\n        flags: @UpdatedMatroskaExtractor.Flags Int\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.matroskaFlags = flags\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [Mp4Extractor] instances created by the factory.\r\n     *\r\n     * @see Mp4Extractor.Mp4Extractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setMp4ExtractorFlags(flags: @Mp4Extractor.Flags Int): UpdatedDefaultExtractorsFactory {\r\n        this.mp4Flags = flags\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [FragmentedMp4Extractor] instances created by the factory.\r\n     *\r\n     * @see FragmentedMp4Extractor.FragmentedMp4Extractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setFragmentedMp4ExtractorFlags(\r\n        flags: @FragmentedMp4Extractor.Flags Int\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.fragmentedMp4Flags = flags\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [Mp3Extractor] instances created by the factory.\r\n     *\r\n     * @see Mp3Extractor.Mp3Extractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setMp3ExtractorFlags(flags: @Mp3Extractor.Flags Int): UpdatedDefaultExtractorsFactory {\r\n        mp3Flags = flags\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets the mode for [TsExtractor] instances created by the factory.\r\n     *\r\n     * @see TsExtractor.TsExtractor\r\n     * @param mode The mode to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setTsExtractorMode(mode: @TsExtractor.Mode Int): UpdatedDefaultExtractorsFactory {\r\n        tsMode = mode\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [DefaultTsPayloadReaderFactory]s used by [TsExtractor] instances\r\n     * created by the factory.\r\n     *\r\n     * @see TsExtractor.TsExtractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setTsExtractorFlags(\r\n        flags: @DefaultTsPayloadReaderFactory.Flags Int\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        tsFlags = flags\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets a list of subtitle formats to pass to the [DefaultTsPayloadReaderFactory] used by\r\n     * [TsExtractor] instances created by the factory.\r\n     *\r\n     * @see DefaultTsPayloadReaderFactory.DefaultTsPayloadReaderFactory\r\n     * @param subtitleFormats The subtitle formats.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setTsSubtitleFormats(subtitleFormats: List<Format>?): UpdatedDefaultExtractorsFactory {\r\n        tsSubtitleFormats = subtitleFormats?.let { ImmutableList.copyOf(it) }\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets the number of bytes searched to find a timestamp for [TsExtractor] instances created\r\n     * by the factory.\r\n     *\r\n     * @see TsExtractor.TsExtractor\r\n     * @param timestampSearchBytes The number of search bytes to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setTsExtractorTimestampSearchBytes(\r\n        timestampSearchBytes: Int\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        tsTimestampSearchBytes = timestampSearchBytes\r\n        return this\r\n    }\r\n\r\n    @Deprecated(\r\n        \"\"\"This method (and all support for 'legacy' subtitle decoding during rendering) will\r\n        be removed in a future release.\"\"\"\r\n    )\r\n    @Synchronized\r\n    fun setTextTrackTranscodingEnabled(\r\n        textTrackTranscodingEnabled: Boolean\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        return experimentalSetTextTrackTranscodingEnabled(textTrackTranscodingEnabled)\r\n    }\r\n\r\n    @Deprecated(\"\")\r\n    @Synchronized\r\n    override fun experimentalSetTextTrackTranscodingEnabled(\r\n        textTrackTranscodingEnabled: Boolean\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.textTrackTranscodingEnabled = textTrackTranscodingEnabled\r\n        return this\r\n    }\r\n\r\n    @Synchronized\r\n    override fun setSubtitleParserFactory(\r\n        subtitleParserFactory: SubtitleParser.Factory\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.subtitleParserFactory = subtitleParserFactory\r\n        return this\r\n    }\r\n\r\n    @Synchronized\r\n    override fun experimentalSetCodecsToParseWithinGopSampleDependencies(\r\n        codecsToParseWithinGopSampleDependencies: @C.VideoCodecFlags Int\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.codecsToParseWithinGopSampleDependencies = codecsToParseWithinGopSampleDependencies\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [JpegExtractor] instances created by the factory.\r\n     *\r\n     * @see JpegExtractor.JpegExtractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setJpegExtractorFlags(\r\n        flags: @JpegExtractor.Flags Int\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.jpegFlags = flags\r\n        return this\r\n    }\r\n\r\n    /**\r\n     * Sets flags for [HeifExtractor] instances created by the factory.\r\n     *\r\n     * @see HeifExtractor.HeifExtractor\r\n     * @param flags The flags to use.\r\n     * @return The factory, for convenience.\r\n     */\r\n    @Synchronized\r\n    fun setHeifExtractorFlags(\r\n        flags: @HeifExtractor.Flags Int\r\n    ): UpdatedDefaultExtractorsFactory {\r\n        this.heifFlags = flags\r\n        return this\r\n    }\r\n\r\n    @Synchronized\r\n    override fun createExtractors(): Array<Extractor> {\r\n        return createExtractors(Uri.EMPTY, HashMap())\r\n    }\r\n\r\n    @Synchronized\r\n    override fun createExtractors(\r\n        uri: Uri, responseHeaders: Map<String, List<String>>\r\n    ): Array<Extractor> {\r\n        val extractors: MutableList<Extractor> =\r\n            ArrayList<Extractor>( /* initialCapacity= */DEFAULT_EXTRACTOR_ORDER.size)\r\n\r\n        val responseHeadersInferredFileType: @FileTypes.Type Int =\r\n            FileTypes.inferFileTypeFromResponseHeaders(responseHeaders)\r\n        if (responseHeadersInferredFileType != FileTypes.UNKNOWN) {\r\n            addExtractorsForFileType(responseHeadersInferredFileType, extractors)\r\n        }\r\n\r\n        val uriInferredFileType: @FileTypes.Type Int = FileTypes.inferFileTypeFromUri(uri)\r\n        if (uriInferredFileType != FileTypes.UNKNOWN\r\n            && uriInferredFileType != responseHeadersInferredFileType\r\n        ) {\r\n            addExtractorsForFileType(uriInferredFileType, extractors)\r\n        }\r\n\r\n        for (fileType in DEFAULT_EXTRACTOR_ORDER) {\r\n            if (fileType != responseHeadersInferredFileType && fileType != uriInferredFileType) {\r\n                addExtractorsForFileType(fileType, extractors)\r\n            }\r\n        }\r\n        return extractors.toTypedArray<Extractor>()\r\n    }\r\n\r\n    private fun addExtractorsForFileType(\r\n        fileType: @FileTypes.Type Int,\r\n        extractors: MutableList<Extractor>\r\n    ) {\r\n        when (fileType) {\r\n            FileTypes.AC3 -> extractors.add(Ac3Extractor())\r\n            FileTypes.AC4 -> extractors.add(Ac4Extractor())\r\n            FileTypes.ADTS -> extractors.add(\r\n                AdtsExtractor(\r\n                    (adtsFlags\r\n                            or (if (constantBitrateSeekingEnabled)\r\n                        AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING\r\n                    else\r\n                        0)\r\n                            or (if (constantBitrateSeekingAlwaysEnabled)\r\n                        AdtsExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING_ALWAYS\r\n                    else\r\n                        0))\r\n                )\r\n            )\r\n\r\n            FileTypes.AMR -> extractors.add(\r\n                AmrExtractor(\r\n                    (amrFlags\r\n                            or (if (constantBitrateSeekingEnabled)\r\n                        AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING\r\n                    else\r\n                        0)\r\n                            or (if (constantBitrateSeekingAlwaysEnabled)\r\n                        AmrExtractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING_ALWAYS\r\n                    else\r\n                        0))\r\n                )\r\n            )\r\n\r\n            FileTypes.FLAC -> {\r\n                val flacExtractor: Extractor? = FLAC_EXTENSION_LOADER.getExtractor(flacFlags)\r\n                if (flacExtractor != null) {\r\n                    extractors.add(flacExtractor)\r\n                } else {\r\n                    extractors.add(FlacExtractor(flacFlags))\r\n                }\r\n            }\r\n\r\n            FileTypes.FLV -> extractors.add(FlvExtractor())\r\n            FileTypes.MATROSKA -> extractors.add(\r\n                UpdatedMatroskaExtractor(\r\n                    subtitleParserFactory,\r\n                    matroskaFlags\r\n                            or (if (textTrackTranscodingEnabled)\r\n                        0\r\n                    else\r\n                        UpdatedMatroskaExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA)\r\n                )\r\n            )\r\n\r\n            FileTypes.MP3 -> extractors.add(\r\n                Mp3Extractor(\r\n                    (mp3Flags\r\n                            or (if (constantBitrateSeekingEnabled)\r\n                        Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING\r\n                    else\r\n                        0)\r\n                            or (if (constantBitrateSeekingAlwaysEnabled)\r\n                        Mp3Extractor.FLAG_ENABLE_CONSTANT_BITRATE_SEEKING_ALWAYS\r\n                    else\r\n                        0))\r\n                )\r\n            )\r\n\r\n            FileTypes.MP4 -> {\r\n                extractors.add(\r\n                    FragmentedMp4Extractor(\r\n                        subtitleParserFactory,\r\n                        fragmentedMp4Flags or\r\n                            FragmentedMp4Extractor\r\n                                .codecsToParseWithinGopSampleDependenciesAsFlags(\r\n                                    codecsToParseWithinGopSampleDependencies\r\n                                ) or\r\n                        if (textTrackTranscodingEnabled) 0\r\n                        else FragmentedMp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA\r\n                    )\r\n                )\r\n\r\n                extractors.add(\r\n                    Mp4Extractor(\r\n                        subtitleParserFactory,\r\n                        mp4Flags or\r\n                            Mp4Extractor\r\n                                .codecsToParseWithinGopSampleDependenciesAsFlags(\r\n                                    codecsToParseWithinGopSampleDependencies\r\n                                ) or\r\n                        if (textTrackTranscodingEnabled) 0\r\n                        else Mp4Extractor.FLAG_EMIT_RAW_SUBTITLE_DATA\r\n                    )\r\n                )\r\n            }\r\n\r\n            FileTypes.OGG -> extractors.add(OggExtractor())\r\n            FileTypes.PS -> extractors.add(PsExtractor())\r\n            FileTypes.TS -> {\r\n                if (tsSubtitleFormats == null) {\r\n                    tsSubtitleFormats = ImmutableList.of()\r\n                }\r\n                extractors.add(\r\n                    TsExtractor(\r\n                        tsMode,\r\n                        (if (textTrackTranscodingEnabled) 0 else TsExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA),\r\n                        subtitleParserFactory,\r\n                        TimestampAdjuster(0),\r\n                        DefaultTsPayloadReaderFactory(tsFlags, tsSubtitleFormats!!),\r\n                        tsTimestampSearchBytes\r\n                    )\r\n                )\r\n            }\r\n\r\n            FileTypes.WAV -> extractors.add(WavExtractor())\r\n            FileTypes.JPEG -> extractors.add(JpegExtractor(jpegFlags))\r\n            FileTypes.MIDI -> {\r\n                val midiExtractor: Extractor? = MIDI_EXTENSION_LOADER.getExtractor()\r\n                if (midiExtractor != null) {\r\n                    extractors.add(midiExtractor)\r\n                }\r\n            }\r\n\r\n            FileTypes.AVI -> extractors.add(\r\n                AviExtractor(\r\n                    (if (textTrackTranscodingEnabled) 0 else AviExtractor.FLAG_EMIT_RAW_SUBTITLE_DATA),\r\n                    subtitleParserFactory\r\n                )\r\n            )\r\n\r\n            FileTypes.PNG -> extractors.add(PngExtractor())\r\n            FileTypes.WEBP -> extractors.add(WebpExtractor())\r\n            FileTypes.BMP -> extractors.add(BmpExtractor())\r\n            FileTypes.HEIF -> extractors.add(HeifExtractor(heifFlags))\r\n            FileTypes.AVIF -> extractors.add(AvifExtractor())\r\n            FileTypes.WEBVTT, FileTypes.UNKNOWN -> {}\r\n            else -> {}\r\n        }\r\n    }\r\n\r\n    private class ExtensionLoader(private val constructorSupplier: ConstructorSupplier) {\r\n        interface ConstructorSupplier {\r\n            @get:Throws(\r\n                InvocationTargetException::class,\r\n                IllegalAccessException::class,\r\n                NoSuchMethodException::class,\r\n                ClassNotFoundException::class\r\n            )\r\n            val constructor: Constructor<out Extractor?>?\r\n        }\r\n\r\n        private val extensionLoaded = AtomicBoolean(false)\r\n\r\n        @GuardedBy(\"extensionLoaded\")\r\n        private val extractorConstructor: Constructor<out Extractor?>? = null\r\n\r\n        fun getExtractor(vararg constructorParams: Any?): Extractor? {\r\n            val extractorConstructor: Constructor<out Extractor?> = maybeLoadExtractorConstructor()\r\n                ?: return null\r\n            try {\r\n                return extractorConstructor.newInstance(*constructorParams)\r\n            } catch (e: Exception) {\r\n                throw IllegalStateException(\"Unexpected error creating extractor\", e)\r\n            }\r\n        }\r\n\r\n        fun maybeLoadExtractorConstructor(): Constructor<out Extractor?>? {\r\n            synchronized(extensionLoaded) {\r\n                if (extensionLoaded.get()) {\r\n                    return extractorConstructor\r\n                }\r\n                try {\r\n                    return constructorSupplier.constructor\r\n                } catch (e: ClassNotFoundException) {\r\n                    // Expected if the app was built without the extension.\r\n                } catch (e: Exception) {\r\n                    // The extension is present, but instantiation failed.\r\n                    throw RuntimeException(\"Error instantiating extension\", e)\r\n                }\r\n                extensionLoaded.set(true)\r\n                return extractorConstructor\r\n            }\r\n        }\r\n    }\r\n\r\n    companion object {\r\n        // Extractors order is optimized according to\r\n        // https://docs.google.com/document/d/1w2mKaWMxfz2Ei8-LdxqbPs1VLe_oudB-eryXXw9OvQQ.\r\n        // The JPEG extractor appears after audio/video extractors because we expect audio/video input to\r\n        // be more common.\r\n        private val DEFAULT_EXTRACTOR_ORDER = intArrayOf(\r\n            FileTypes.FLV,\r\n            FileTypes.FLAC,\r\n            FileTypes.WAV,\r\n            FileTypes.MP4,\r\n            FileTypes.AMR,\r\n            FileTypes.PS,\r\n            FileTypes.OGG,\r\n            FileTypes.TS,\r\n            FileTypes.MATROSKA,\r\n            FileTypes.ADTS,\r\n            FileTypes.AC3,\r\n            FileTypes.AC4,\r\n            FileTypes.MP3,  // The following extractors are not part of the optimized ordering, and were appended\r\n            // without further analysis.\r\n            FileTypes.AVI,\r\n            FileTypes.MIDI,\r\n            FileTypes.JPEG,\r\n            FileTypes.PNG,\r\n            FileTypes.WEBP,\r\n            FileTypes.BMP,\r\n            FileTypes.HEIF,\r\n            FileTypes.AVIF\r\n        )\r\n\r\n        private val FLAC_EXTENSION_LOADER =\r\n            ExtensionLoader(object : ExtensionLoader.ConstructorSupplier {\r\n                override val constructor get() = flacExtractorConstructor\r\n            })\r\n        private val MIDI_EXTENSION_LOADER =\r\n            ExtensionLoader(object : ExtensionLoader.ConstructorSupplier {\r\n                override val constructor get() = midiExtractorConstructor\r\n            })\r\n\r\n        @get:Throws(\r\n            ClassNotFoundException::class,\r\n            NoSuchMethodException::class\r\n        )\r\n        private val midiExtractorConstructor: Constructor<out Extractor?>\r\n            get() = Class.forName(\"androidx.media3.decoder.midi.MidiExtractor\")\r\n                .asSubclass<Extractor>(Extractor::class.java)\r\n                .getConstructor()\r\n\r\n        @get:Throws(\r\n            ClassNotFoundException::class,\r\n            NoSuchMethodException::class,\r\n            InvocationTargetException::class,\r\n            IllegalAccessException::class\r\n        )\r\n        private val flacExtractorConstructor: Constructor<out Extractor?>?\r\n            get() {\r\n                val isFlacNativeLibraryAvailable =\r\n                    java.lang.Boolean.TRUE == Class.forName(\"androidx.media3.decoder.flac.FlacLibrary\")\r\n                        .getMethod(\"isAvailable\")\r\n                        .invoke( /* obj= */null)\r\n                if (isFlacNativeLibraryAvailable) {\r\n                    return Class.forName(\"androidx.media3.decoder.flac.FlacExtractor\")\r\n                        .asSubclass<Extractor>(Extractor::class.java)\r\n                        .getConstructor(Int::class.javaPrimitiveType)\r\n                }\r\n                return null\r\n            }\r\n    }\r\n}\r\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/UpdatedMatroskaExtractor.kt",
    "content": "@file:Suppress(\r\n    \"ALL\",\r\n    \"DEPRECATION\",\r\n    \"RedundantVisibilityModifier\",\r\n    \"RemoveRedundantQualifierName\",\r\n    \"UNCHECKED_CAST\",\r\n    \"UNUSED\",\r\n    \"UNUSED_PARAMETER\",\r\n    \"UNUSED_VARIABLE\"\r\n)\r\n\r\n/*\r\n * Copyright (C) 2016 The Android Open Source Project\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\npackage androidx.media3.extractor.mkv // we cant change the pkg as EbmlReader is private\r\n\r\nimport android.util.Pair\r\nimport android.util.SparseArray\r\nimport androidx.annotation.CallSuper\r\nimport androidx.annotation.IntDef\r\nimport androidx.media3.common.C\r\nimport androidx.media3.common.C.BufferFlags\r\nimport androidx.media3.common.C.ColorRange\r\nimport androidx.media3.common.C.ColorTransfer\r\nimport androidx.media3.common.C.PcmEncoding\r\nimport androidx.media3.common.C.SelectionFlags\r\nimport androidx.media3.common.C.StereoMode\r\nimport androidx.media3.common.ColorInfo\r\nimport androidx.media3.common.DrmInitData\r\nimport androidx.media3.common.DrmInitData.SchemeData\r\nimport androidx.media3.common.Format\r\nimport androidx.media3.common.Metadata\r\nimport androidx.media3.common.MimeTypes\r\nimport androidx.media3.common.ParserException\r\nimport androidx.media3.common.util.Log\r\nimport androidx.media3.common.util.ParsableByteArray\r\nimport androidx.media3.common.util.UnstableApi\r\nimport androidx.media3.common.util.Util\r\nimport androidx.media3.container.DolbyVisionConfig\r\nimport androidx.media3.container.NalUnitUtil\r\nimport androidx.media3.extractor.AacUtil\r\nimport androidx.media3.extractor.AvcConfig\r\nimport androidx.media3.extractor.ChunkIndex\r\nimport androidx.media3.extractor.ChunkIndexProvider\r\nimport androidx.media3.extractor.DtsUtil\r\nimport androidx.media3.extractor.Extractor\r\nimport androidx.media3.extractor.ExtractorInput\r\nimport androidx.media3.extractor.ExtractorOutput\r\nimport androidx.media3.extractor.ExtractorsFactory\r\nimport androidx.media3.extractor.HevcConfig\r\nimport androidx.media3.extractor.MpegAudioUtil\r\nimport androidx.media3.extractor.PositionHolder\r\nimport androidx.media3.extractor.SeekMap\r\nimport androidx.media3.extractor.SeekMap.SeekPoints\r\nimport androidx.media3.extractor.SeekPoint\r\nimport androidx.media3.extractor.TrackAwareSeekMap\r\nimport androidx.media3.extractor.TrackOutput\r\nimport androidx.media3.extractor.TrackOutput.CryptoData\r\nimport androidx.media3.extractor.TrueHdSampleRechunker\r\nimport androidx.media3.extractor.metadata.ThumbnailMetadata\r\nimport androidx.media3.extractor.text.SubtitleParser\r\nimport androidx.media3.extractor.text.SubtitleTranscodingExtractorOutput\r\nimport com.google.common.base.Preconditions.checkArgument\r\nimport com.google.common.base.Preconditions.checkNotNull\r\nimport com.google.common.base.Preconditions.checkState\r\nimport com.google.common.collect.ImmutableList\r\nimport java.io.IOException\r\nimport java.nio.ByteBuffer\r\nimport java.nio.ByteOrder\r\nimport java.util.Arrays\r\nimport java.util.Collections\r\nimport java.util.Locale\r\nimport java.util.Objects\r\nimport java.util.UUID\r\nimport kotlin.math.max\r\nimport kotlin.math.min\r\n\r\n/** Extracts data from the Matroska and WebM container formats.  */\r\n@UnstableApi\r\nclass UpdatedMatroskaExtractor private constructor(\r\n    private val reader: EbmlReader,\r\n    flags: @Flags Int,\r\n    subtitleParserFactory: SubtitleParser.Factory\r\n) :\r\n    Extractor {\r\n    /**\r\n     * Flags controlling the behavior of the extractor. Possible flag values are [ ][.FLAG_DISABLE_SEEK_FOR_CUES] and {#FLAG_EMIT_RAW_SUBTITLE_DATA}.\r\n     */\r\n    @MustBeDocumented\r\n    @Retention(AnnotationRetention.SOURCE)\r\n    @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE, AnnotationTarget.TYPE_PARAMETER)\r\n    @IntDef(flag = true, value = [FLAG_DISABLE_SEEK_FOR_CUES, FLAG_EMIT_RAW_SUBTITLE_DATA])\r\n    annotation class Flags\r\n\r\n    private val varintReader: VarintReader\r\n    private val tracks: SparseArray<Track>\r\n    private val seekForCuesEnabled: Boolean\r\n    private val parseSubtitlesDuringExtraction: Boolean\r\n    private val subtitleParserFactory: SubtitleParser.Factory\r\n\r\n    // Temporary arrays.\r\n    private val nalStartCode: ParsableByteArray\r\n    private val nalLength: ParsableByteArray\r\n    private val scratch: ParsableByteArray\r\n    private val vorbisNumPageSamples: ParsableByteArray\r\n    private val seekEntryIdBytes: ParsableByteArray\r\n    private val sampleStrippedBytes: ParsableByteArray\r\n    private val subtitleSample: ParsableByteArray\r\n    private val encryptionInitializationVector: ParsableByteArray\r\n    private val encryptionSubsampleData: ParsableByteArray\r\n    private val supplementalData: ParsableByteArray\r\n    private var encryptionSubsampleDataBuffer: ByteBuffer? = null\r\n\r\n    private var segmentContentSize: Long = 0\r\n    private var segmentContentPosition = C.INDEX_UNSET.toLong()\r\n    private var timecodeScale = C.TIME_UNSET\r\n    private var durationTimecode = C.TIME_UNSET\r\n    private var durationUs = C.TIME_UNSET\r\n    private var isWebm: Boolean = false\r\n    private var pendingEndTracks: Boolean\r\n\r\n    // The track corresponding to the current TrackEntry element, or null.\r\n    private var currentTrack: Track? = null\r\n\r\n    // Whether a seek map has been sent to the output.\r\n    private var sentSeekMap = false\r\n\r\n    // Master seek entry related elements.\r\n    private var seekEntryId = 0\r\n    private var seekEntryPosition: Long = 0\r\n\r\n    // Cue related elements.\r\n    private val perTrackCues: SparseArray<MutableList<MatroskaSeekMap.CuePointData>>\r\n    private var inCuesElement = false\r\n    private var currentCueTimeUs: Long = C.TIME_UNSET\r\n    private var currentCueTrackNumber: Int = C.INDEX_UNSET\r\n    private var currentCueClusterPosition: Long = C.INDEX_UNSET.toLong()\r\n    private var currentCueRelativePosition: Long = C.INDEX_UNSET.toLong()\r\n    private var primarySeekTrackNumber: Int = C.INDEX_UNSET\r\n    private var seekForCues = false\r\n    private var seekForSeekContent = false\r\n    private var visitedSeekHeads: HashSet<Long> = HashSet()\r\n    private var pendingSeekHeads: ArrayList<Long> = ArrayList()\r\n    private var seekPositionAfterSeekingForHead = C.INDEX_UNSET.toLong()\r\n    private var cuesContentPosition = C.INDEX_UNSET.toLong()\r\n    private var seekPositionAfterBuildingCues = C.INDEX_UNSET.toLong()\r\n    private var clusterTimecodeUs = C.TIME_UNSET\r\n\r\n    // Reading state.\r\n    private var haveOutputSample = false\r\n\r\n    // Block reading state.\r\n    private var blockState = 0\r\n    private var blockTimeUs: Long = 0\r\n    private var blockDurationUs: Long = 0\r\n    private var blockSampleIndex = 0\r\n    private var blockSampleCount = 0\r\n    private var blockSampleSizes: IntArray\r\n    private var blockTrackNumber = 0\r\n    private var blockTrackNumberLength = 0\r\n    private var blockFlags: @BufferFlags Int = 0\r\n    private var blockAdditionalId = 0\r\n    private var blockHasReferenceBlock = false\r\n    private var blockGroupDiscardPaddingNs: Long = 0\r\n\r\n    // Sample writing state.\r\n    private var sampleBytesRead = 0\r\n    private var sampleBytesWritten = 0\r\n    private var sampleCurrentNalBytesRemaining = 0\r\n    private var sampleEncodingHandled = false\r\n    private var sampleSignalByteRead = false\r\n    private var samplePartitionCountRead = false\r\n    private var samplePartitionCount = 0\r\n    private var sampleSignalByte: Byte = 0\r\n    private var sampleInitializationVectorRead = false\r\n\r\n    // Extractor outputs.\r\n    private var extractorOutput: ExtractorOutput? =\r\n        null\r\n\r\n    @Deprecated(\"Use {@link #MatroskaExtractor(SubtitleParser.Factory)} instead.\")\r\n    constructor() : this(\r\n        DefaultEbmlReader(),\r\n        FLAG_EMIT_RAW_SUBTITLE_DATA,\r\n        SubtitleParser.Factory.UNSUPPORTED\r\n    )\r\n\r\n    @Deprecated(\"Use {@link #MatroskaExtractor(SubtitleParser.Factory, int)} instead.\")\r\n    constructor(flags: @Flags Int) : this(\r\n        DefaultEbmlReader(),\r\n        flags or FLAG_EMIT_RAW_SUBTITLE_DATA,\r\n        SubtitleParser.Factory.UNSUPPORTED\r\n    )\r\n\r\n    /**\r\n     * Constructs an instance.\r\n     *\r\n     * @param subtitleParserFactory The [SubtitleParser.Factory] for parsing subtitles during\r\n     * extraction.\r\n     */\r\n    constructor(subtitleParserFactory: SubtitleParser.Factory) : this(\r\n        DefaultEbmlReader(),  /* flags= */\r\n        0,\r\n        subtitleParserFactory\r\n    )\r\n\r\n    /**\r\n     * Constructs an instance.\r\n     *\r\n     * @param subtitleParserFactory The [SubtitleParser.Factory] for parsing subtitles during\r\n     * extraction.\r\n     * @param flags Flags that control the extractor's behavior.\r\n     */\r\n    constructor(subtitleParserFactory: SubtitleParser.Factory, flags: @Flags Int) : this(\r\n        DefaultEbmlReader(),\r\n        flags,\r\n        subtitleParserFactory\r\n    )\r\n\r\n    /* package */\r\n    init {\r\n        reader.init(InnerEbmlProcessor())\r\n        this.subtitleParserFactory = subtitleParserFactory\r\n        this.perTrackCues = SparseArray()\r\n        seekForCuesEnabled = (flags and FLAG_DISABLE_SEEK_FOR_CUES) == 0\r\n        parseSubtitlesDuringExtraction = (flags and FLAG_EMIT_RAW_SUBTITLE_DATA) == 0\r\n        varintReader = VarintReader()\r\n        tracks = SparseArray()\r\n        scratch = ParsableByteArray(4)\r\n        vorbisNumPageSamples = ParsableByteArray(ByteBuffer.allocate(4).putInt(-1).array())\r\n        seekEntryIdBytes = ParsableByteArray(4)\r\n        nalStartCode = ParsableByteArray(NalUnitUtil.NAL_START_CODE)\r\n        nalLength = ParsableByteArray(4)\r\n        sampleStrippedBytes = ParsableByteArray()\r\n        subtitleSample = ParsableByteArray()\r\n        encryptionInitializationVector = ParsableByteArray(ENCRYPTION_IV_SIZE)\r\n        encryptionSubsampleData = ParsableByteArray()\r\n        supplementalData = ParsableByteArray()\r\n        blockSampleSizes = IntArray(1)\r\n        pendingEndTracks = true\r\n    }\r\n\r\n    @Throws(IOException::class)\r\n    override fun sniff(input: ExtractorInput): Boolean {\r\n        return Sniffer().sniff(input)\r\n    }\r\n\r\n    override fun init(output: ExtractorOutput) {\r\n        extractorOutput =\r\n            if (parseSubtitlesDuringExtraction)\r\n                SubtitleTranscodingExtractorOutput(output, subtitleParserFactory)\r\n            else\r\n                output\r\n    }\r\n\r\n    @CallSuper\r\n    override fun seek(position: Long, timeUs: Long) {\r\n        clusterTimecodeUs = C.TIME_UNSET\r\n        blockState = BLOCK_STATE_START\r\n        reader.reset()\r\n        varintReader.reset()\r\n        resetWriteSampleData()\r\n        inCuesElement = false\r\n        currentCueTimeUs = C.TIME_UNSET\r\n        currentCueTrackNumber = C.INDEX_UNSET\r\n        currentCueClusterPosition = C.INDEX_UNSET.toLong()\r\n        currentCueRelativePosition = C.INDEX_UNSET.toLong()\r\n        // To prevent creating duplicate cue points on a re-parse, clear any existing cue data if the\r\n        // seek map has not yet been sent. Once sent, the cue data is considered final, and subsequent\r\n        // Cues elements will be ignored by the parsing logic.\r\n        if (!sentSeekMap) {\r\n            perTrackCues.clear()\r\n        }\r\n        for (i in 0..<tracks.size()) {\r\n            tracks.valueAt(i).reset()\r\n        }\r\n    }\r\n\r\n    override fun release() {\r\n        // Do nothing\r\n    }\r\n\r\n    @Throws(IOException::class)\r\n    override fun read(input: ExtractorInput, seekPosition: PositionHolder): Int {\r\n        haveOutputSample = false\r\n        var continueReading = true\r\n        while (continueReading && !haveOutputSample) {\r\n            continueReading = reader.read(input)\r\n            if (maybeSeekForCues(seekPosition, input.position)) {\r\n                return Extractor.RESULT_SEEK\r\n            }\r\n        }\r\n        if (!continueReading) {\r\n            for (i in 0..<tracks.size()) {\r\n                val track = tracks.valueAt(i)\r\n                track.assertOutputInitialized()\r\n                track.outputPendingSampleMetadata()\r\n            }\r\n            return Extractor.RESULT_END_OF_INPUT\r\n        }\r\n        return Extractor.RESULT_CONTINUE\r\n    }\r\n\r\n    /**\r\n     * Maps an element ID to a corresponding type.\r\n     *\r\n     * @see EbmlProcessor.getElementType\r\n     */\r\n    @CallSuper\r\n    protected fun getElementType(id: Int): @EbmlProcessor.ElementType Int {\r\n        return when (id) {\r\n            ID_EBML, ID_SEGMENT, ID_SEEK_HEAD, ID_SEEK, ID_INFO, ID_CLUSTER, ID_TRACKS, ID_TRACK_ENTRY, ID_BLOCK_ADDITION_MAPPING, ID_AUDIO, ID_VIDEO, ID_CONTENT_ENCODINGS, ID_CONTENT_ENCODING, ID_CONTENT_COMPRESSION, ID_CONTENT_ENCRYPTION, ID_CONTENT_ENCRYPTION_AES_SETTINGS, ID_CUES, ID_CUE_POINT, ID_CUE_TRACK_POSITIONS, ID_BLOCK_GROUP, ID_BLOCK_ADDITIONS, ID_BLOCK_MORE, ID_PROJECTION, ID_COLOUR, ID_MASTERING_METADATA -> EbmlProcessor.ELEMENT_TYPE_MASTER\r\n\r\n            ID_EBML_READ_VERSION, ID_DOC_TYPE_READ_VERSION, ID_SEEK_POSITION, ID_TIMECODE_SCALE, ID_TIME_CODE, ID_BLOCK_DURATION, ID_PIXEL_WIDTH, ID_PIXEL_HEIGHT, ID_DISPLAY_WIDTH, ID_DISPLAY_HEIGHT, ID_DISPLAY_UNIT, ID_TRACK_NUMBER, ID_TRACK_TYPE, ID_FLAG_DEFAULT, ID_FLAG_FORCED, ID_DEFAULT_DURATION, ID_MAX_BLOCK_ADDITION_ID, ID_BLOCK_ADD_ID_TYPE, ID_CODEC_DELAY, ID_SEEK_PRE_ROLL, ID_DISCARD_PADDING, ID_CHANNELS, ID_AUDIO_BIT_DEPTH, ID_CONTENT_ENCODING_ORDER, ID_CONTENT_ENCODING_SCOPE, ID_CONTENT_COMPRESSION_ALGORITHM, ID_CONTENT_ENCRYPTION_ALGORITHM, ID_CONTENT_ENCRYPTION_AES_SETTINGS_CIPHER_MODE, ID_CUE_TIME, ID_CUE_CLUSTER_POSITION, ID_CUE_RELATIVE_POSITION, ID_CUE_TRACK, ID_REFERENCE_BLOCK, ID_STEREO_MODE, ID_COLOUR_BITS_PER_CHANNEL, ID_COLOUR_RANGE, ID_COLOUR_TRANSFER, ID_COLOUR_PRIMARIES, ID_MAX_CLL, ID_MAX_FALL, ID_PROJECTION_TYPE, ID_BLOCK_ADD_ID -> EbmlProcessor.ELEMENT_TYPE_UNSIGNED_INT\r\n\r\n            ID_DOC_TYPE, ID_NAME, ID_CODEC_ID, ID_LANGUAGE -> EbmlProcessor.ELEMENT_TYPE_STRING\r\n            ID_SEEK_ID, ID_BLOCK_ADD_ID_EXTRA_DATA, ID_CONTENT_COMPRESSION_SETTINGS, ID_CONTENT_ENCRYPTION_KEY_ID, ID_SIMPLE_BLOCK, ID_BLOCK, ID_CODEC_PRIVATE, ID_PROJECTION_PRIVATE, ID_BLOCK_ADDITIONAL -> EbmlProcessor.ELEMENT_TYPE_BINARY\r\n            ID_DURATION, ID_SAMPLING_FREQUENCY, ID_PRIMARY_R_CHROMATICITY_X, ID_PRIMARY_R_CHROMATICITY_Y, ID_PRIMARY_G_CHROMATICITY_X, ID_PRIMARY_G_CHROMATICITY_Y, ID_PRIMARY_B_CHROMATICITY_X, ID_PRIMARY_B_CHROMATICITY_Y, ID_WHITE_POINT_CHROMATICITY_X, ID_WHITE_POINT_CHROMATICITY_Y, ID_LUMNINANCE_MAX, ID_LUMNINANCE_MIN, ID_PROJECTION_POSE_YAW, ID_PROJECTION_POSE_PITCH, ID_PROJECTION_POSE_ROLL -> EbmlProcessor.ELEMENT_TYPE_FLOAT\r\n\r\n            else -> EbmlProcessor.ELEMENT_TYPE_UNKNOWN\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Checks if the given id is that of a level 1 element.\r\n     *\r\n     * @see EbmlProcessor.isLevel1Element\r\n     */\r\n    @CallSuper\r\n    protected fun isLevel1Element(id: Int): Boolean {\r\n        return id == ID_SEGMENT_INFO || id == ID_CLUSTER || id == ID_CUES || id == ID_TRACKS\r\n    }\r\n\r\n    /**\r\n     * Called when the start of a master element is encountered.\r\n     *\r\n     * @see EbmlProcessor.startMasterElement\r\n     */\r\n    @CallSuper\r\n    @Throws(ParserException::class)\r\n    protected fun startMasterElement(id: Int, contentPosition: Long, contentSize: Long) {\r\n        assertInitialized()\r\n        when (id) {\r\n            ID_SEGMENT -> {\r\n                if (segmentContentPosition != C.INDEX_UNSET.toLong() && segmentContentPosition != contentPosition) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"Multiple Segment elements not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n                segmentContentPosition = contentPosition\r\n                segmentContentSize = contentSize\r\n            }\r\n\r\n            ID_SEEK -> {\r\n                seekEntryId = UNSET_ENTRY_ID\r\n                seekEntryPosition = C.INDEX_UNSET.toLong()\r\n            }\r\n\r\n            ID_CUES -> {\r\n                if (!sentSeekMap) {\r\n                    inCuesElement = true\r\n                }\r\n            }\r\n\r\n            ID_CUE_POINT -> {\r\n                if (!sentSeekMap) {\r\n                    assertInCues(id)\r\n                    currentCueTimeUs = C.TIME_UNSET\r\n                }\r\n            }\r\n\r\n            ID_CUE_TRACK_POSITIONS -> {\r\n                if (!sentSeekMap) {\r\n                    assertInCues(id)\r\n                    currentCueTrackNumber = C.INDEX_UNSET\r\n                    currentCueClusterPosition = C.INDEX_UNSET.toLong()\r\n                    currentCueRelativePosition = C.INDEX_UNSET.toLong()\r\n                }\r\n            }\r\n\r\n            ID_CLUSTER -> if (!sentSeekMap) {\r\n                // We need to build cues before parsing the cluster.\r\n                if (seekForCuesEnabled && cuesContentPosition != C.INDEX_UNSET.toLong()) {\r\n                    // We know where the Cues element is located. Seek to request it.\r\n                    seekForCues = true\r\n                } else if (seekForCuesEnabled && pendingSeekHeads.isNotEmpty()) {\r\n                    // We do not know where the cues are located, however we have seek-heads\r\n                    // we have not yet visited\r\n                    seekForSeekContent = true\r\n                } else {\r\n                    // We don't know where the Cues element is located. It's most likely omitted. Allow\r\n                    // playback, but disable seeking.\r\n                    extractorOutput!!.seekMap(SeekMap.Unseekable(durationUs))\r\n                    sentSeekMap = true\r\n                }\r\n            }\r\n\r\n            ID_BLOCK_GROUP -> {\r\n                blockHasReferenceBlock = false\r\n                blockGroupDiscardPaddingNs = 0L\r\n            }\r\n\r\n            ID_CONTENT_ENCODING -> {}\r\n            ID_CONTENT_ENCRYPTION -> getCurrentTrack(id).hasContentEncryption = true\r\n            ID_TRACK_ENTRY -> {\r\n                currentTrack = Track()\r\n                currentTrack!!.isWebm = isWebm\r\n            }\r\n            ID_MASTERING_METADATA -> getCurrentTrack(id).hasColorInfo = true\r\n            else -> {}\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Called when the end of a master element is encountered.\r\n     *\r\n     * @see EbmlProcessor.endMasterElement\r\n     */\r\n    @CallSuper\r\n    @Throws(ParserException::class)\r\n    protected fun endMasterElement(id: Int) {\r\n        assertInitialized()\r\n        when (id) {\r\n            ID_SEGMENT_INFO -> {\r\n                if (timecodeScale == C.TIME_UNSET) {\r\n                    // timecodeScale was omitted. Use the default value.\r\n                    timecodeScale = 1000000\r\n                }\r\n                if (durationTimecode != C.TIME_UNSET) {\r\n                    durationUs = scaleTimecodeToUs(durationTimecode)\r\n                }\r\n            }\r\n\r\n            ID_SEGMENT -> {\r\n                // We only care if we have not already sent the seek map\r\n                if (!sentSeekMap) {\r\n                    // We have reached the end of the segment, however we can still decide how to handle\r\n                    // pending seek heads.\r\n                    //\r\n                    // This is treated as the end as \"Multiple Segment elements not supported\"\r\n                    if (pendingSeekHeads.isNotEmpty() && seekForCuesEnabled) {\r\n                        // We seek to the next seek point if we can seek and there is seek heads\r\n                        seekForSeekContent = true\r\n                    } else {\r\n                        // Otherwise, if we not found any cues nor any more seek heads then we mark\r\n                        // this as unseekable.\r\n                        extractorOutput!!.seekMap(SeekMap.Unseekable(durationUs))\r\n                        sentSeekMap = true\r\n                    }\r\n                }\r\n            }\r\n\r\n            ID_SEEK -> {\r\n                if (seekEntryId == UNSET_ENTRY_ID || seekEntryPosition == C.INDEX_UNSET.toLong()) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"Mandatory element SeekID or SeekPosition not found\",  /* cause= */null\r\n                    )\r\n                } else if (seekEntryId == ID_SEEK_HEAD) {\r\n                    // We have a set here to prevent inf recursion, only if this seek head is non\r\n                    // visited we add it. VLC limits this to 10, but this should work equally as well.\r\n                    if (visitedSeekHeads.add(seekEntryPosition)) {\r\n                        pendingSeekHeads.add(seekEntryPosition)\r\n                    }\r\n                } else if (seekEntryId == ID_CUES) {\r\n                    cuesContentPosition = seekEntryPosition\r\n                    // We are currently seeking from the seek-head, so we seek again to get to the cues\r\n                    // instead of waiting for the cluster\r\n                    if (seekForCuesEnabled && seekPositionAfterSeekingForHead != C.INDEX_UNSET.toLong()) {\r\n                        seekForCues = true\r\n                    }\r\n                }\r\n            }\r\n\r\n            ID_CUES -> {\r\n                if (!sentSeekMap) {\r\n                    var hasAnyCues = false\r\n                    for (i in 0 until perTrackCues.size()) {\r\n                        if (perTrackCues.valueAt(i).isNotEmpty()) {\r\n                            hasAnyCues = true\r\n                            break\r\n                        }\r\n                    }\r\n\r\n                    if (!hasAnyCues || durationUs == C.TIME_UNSET) {\r\n                        // Cues are missing, empty, or duration is unknown.\r\n                        extractorOutput!!.seekMap(SeekMap.Unseekable(durationUs))\r\n                    } else {\r\n                        for (i in 0 until perTrackCues.size()) {\r\n                            perTrackCues.valueAt(i).sort()\r\n                        }\r\n\r\n                        val seekMap = MatroskaSeekMap(\r\n                            perTrackCues,\r\n                            durationUs,\r\n                            primarySeekTrackNumber,\r\n                            segmentContentPosition,\r\n                            segmentContentSize\r\n                        )\r\n                        extractorOutput!!.seekMap(seekMap)\r\n                    }\r\n                    sentSeekMap = true\r\n                    inCuesElement = false\r\n                    for (i in 0 until tracks.size()) {\r\n                        val track: Track = tracks.valueAt(i)\r\n                        track.maybeAddThumbnailMetadata(perTrackCues, durationUs, segmentContentPosition, segmentContentSize)\r\n                        if (!track.waitingForDtsAnalysis) {\r\n                            track.assertOutputInitialized()\r\n                            track.output!!.format(requireNotNull(track.format))\r\n                        }\r\n                    }\r\n                    maybeEndTracks()\r\n                }\r\n            }\r\n\r\n            ID_CUE_TRACK_POSITIONS -> {\r\n                if (!sentSeekMap) {\r\n                    assertInCues(id)\r\n                    if (currentCueTimeUs != C.TIME_UNSET\r\n                        && currentCueTrackNumber != C.INDEX_UNSET\r\n                        && currentCueClusterPosition != C.INDEX_UNSET.toLong()\r\n                    ) {\r\n                        var trackCues = perTrackCues[currentCueTrackNumber]\r\n                        if (trackCues == null) {\r\n                            trackCues = ArrayList()\r\n                            perTrackCues.put(currentCueTrackNumber, trackCues)\r\n                        }\r\n\r\n                        trackCues.add(\r\n                            MatroskaSeekMap.CuePointData(\r\n                                currentCueTimeUs,\r\n                                /* clusterPosition= */ segmentContentPosition + currentCueClusterPosition,\r\n                                /* relativePosition= */ currentCueRelativePosition\r\n                            )\r\n                        )\r\n                    }\r\n                }\r\n            }\r\n\r\n            ID_BLOCK_GROUP -> {\r\n                if (blockState != BLOCK_STATE_DATA) {\r\n                    // We've skipped this block (due to incompatible track number).\r\n                    return\r\n                }\r\n                val track = tracks[blockTrackNumber]\r\n                track.assertOutputInitialized()\r\n                if (blockGroupDiscardPaddingNs > 0L && CODEC_ID_OPUS == track.codecId) {\r\n                    // For Opus, attach DiscardPadding to the block group samples as supplemental data.\r\n                    supplementalData.reset(\r\n                        ByteBuffer.allocate(8)\r\n                            .order(ByteOrder.LITTLE_ENDIAN)\r\n                            .putLong(blockGroupDiscardPaddingNs)\r\n                            .array()\r\n                    )\r\n                }\r\n\r\n                // Commit sample metadata.\r\n                var sampleOffset = 0\r\n                run {\r\n                    var i = 0\r\n                    while (i < blockSampleCount) {\r\n                        sampleOffset += blockSampleSizes[i]\r\n                        i++\r\n                    }\r\n                }\r\n                var i = 0\r\n                while (i < blockSampleCount) {\r\n                    val sampleTimeUs = blockTimeUs + (i * track.defaultSampleDurationNs) / 1000\r\n                    var sampleFlags = blockFlags\r\n                    if (i == 0 && !blockHasReferenceBlock) {\r\n                        // If the ReferenceBlock element was not found in this block, then the first frame is a\r\n                        // keyframe.\r\n                        sampleFlags = sampleFlags or C.BUFFER_FLAG_KEY_FRAME\r\n                    }\r\n                    val sampleSize = blockSampleSizes[i]\r\n                    sampleOffset -= sampleSize // The offset is to the end of the sample.\r\n                    commitSampleToOutput(track, sampleTimeUs, sampleFlags, sampleSize, sampleOffset)\r\n                    i++\r\n                }\r\n                blockState = BLOCK_STATE_START\r\n            }\r\n\r\n            ID_CONTENT_ENCODING -> {\r\n                assertInTrackEntry(id)\r\n                if (currentTrack!!.hasContentEncryption) {\r\n                    if (currentTrack!!.cryptoData == null) {\r\n                        throw ParserException.createForMalformedContainer(\r\n                            \"Encrypted Track found but ContentEncKeyID was not found\",  /* cause= */\r\n                            null\r\n                        )\r\n                    }\r\n                    currentTrack!!.drmInitData =\r\n                        DrmInitData(\r\n                            SchemeData(\r\n                                C.UUID_NIL,\r\n                                MimeTypes.VIDEO_WEBM,\r\n                                currentTrack!!.cryptoData!!.encryptionKey\r\n                            )\r\n                        )\r\n                }\r\n            }\r\n\r\n            ID_CONTENT_ENCODINGS -> {\r\n                assertInTrackEntry(id)\r\n                if (currentTrack!!.hasContentEncryption && currentTrack!!.sampleStrippedBytes != null) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"Combining encryption and compression is not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n            }\r\n\r\n            ID_TRACK_ENTRY -> {\r\n                val currentTrack = checkNotNull(this.currentTrack)\r\n                if (currentTrack.codecId == null) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"CodecId is missing in TrackEntry element\",  /* cause= */null\r\n                    )\r\n                } else {\r\n                    if (isCodecSupported(currentTrack.codecId!!)) {\r\n                        currentTrack.initializeFormat(currentTrack.number);\r\n                        currentTrack.output = extractorOutput!!.track(currentTrack.number, currentTrack.type);\r\n                        tracks.put(currentTrack.number, currentTrack)\r\n                    }\r\n                }\r\n                this.currentTrack = null\r\n            }\r\n\r\n            ID_TRACKS -> {\r\n                if (tracks.size() == 0) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"No valid tracks were found\",  /* cause= */ null\r\n                    )\r\n                }\r\n\r\n                // Determine the track to use for default seeking.\r\n                var defaultVideoTrackNumber: Int = C.INDEX_UNSET\r\n                var firstVideoTrackNumber: Int = C.INDEX_UNSET\r\n                var defaultAudioTrackNumber: Int = C.INDEX_UNSET\r\n                var firstAudioTrackNumber: Int = C.INDEX_UNSET\r\n\r\n                // If we're not going to seek for cues, output the formats immediately.\r\n                val mayBeSendFormatsEarly = !seekForCuesEnabled || cuesContentPosition == C.INDEX_UNSET.toLong();\r\n\r\n                for (i in 0 until tracks.size()) {\r\n                    val trackItem: Track = tracks.valueAt(i)\r\n\r\n                    val trackType: @C.TrackType Int = trackItem.type\r\n                    when (trackType) {\r\n                        C.TRACK_TYPE_VIDEO -> {\r\n                            if (trackItem.flagDefault) {\r\n                                defaultVideoTrackNumber = trackItem.number\r\n                            }\r\n                            if (firstVideoTrackNumber == C.INDEX_UNSET) {\r\n                                firstVideoTrackNumber = trackItem.number\r\n                            }\r\n                        }\r\n\r\n                        C.TRACK_TYPE_AUDIO -> {\r\n                            if (trackItem.flagDefault) {\r\n                                defaultAudioTrackNumber = trackItem.number\r\n                            }\r\n                            if (firstAudioTrackNumber == C.INDEX_UNSET) {\r\n                                firstAudioTrackNumber = trackItem.number\r\n                            }\r\n                        }\r\n                    }\r\n\r\n                    if (mayBeSendFormatsEarly) {\r\n                        trackItem.assertOutputInitialized()\r\n                        if (!trackItem.waitingForDtsAnalysis) {\r\n                            trackItem.output!!.format(checkNotNull(trackItem.format))\r\n                        }\r\n                    }\r\n                }\r\n\r\n                primarySeekTrackNumber = when {\r\n                    defaultVideoTrackNumber != C.INDEX_UNSET -> defaultVideoTrackNumber\r\n                    firstVideoTrackNumber != C.INDEX_UNSET -> firstVideoTrackNumber\r\n                    defaultAudioTrackNumber != C.INDEX_UNSET -> defaultAudioTrackNumber\r\n                    firstAudioTrackNumber != C.INDEX_UNSET -> firstAudioTrackNumber\r\n                    tracks.size() > 0 -> tracks.valueAt(0).number\r\n                    else -> C.INDEX_UNSET\r\n                }\r\n\r\n                if (mayBeSendFormatsEarly) {\r\n                    maybeEndTracks()\r\n                }\r\n            }\r\n\r\n            else -> {}\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Called when an integer element is encountered.\r\n     *\r\n     * @see EbmlProcessor.integerElement\r\n     */\r\n    @CallSuper\r\n    @Throws(ParserException::class)\r\n    protected fun integerElement(id: Int, value: Long) {\r\n        when (id) {\r\n            ID_EBML_READ_VERSION ->         // Validate that EBMLReadVersion is supported. This extractor only supports v1.\r\n                if (value != 1L) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"EBMLReadVersion $value not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n\r\n            ID_DOC_TYPE_READ_VERSION ->         // Validate that DocTypeReadVersion is supported. This extractor only supports up to v2.\r\n                if (value < 1 || value > 2) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"DocTypeReadVersion $value not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n\r\n            ID_SEEK_POSITION ->         // Seek Position is the relative offset beginning from the Segment. So to get absolute\r\n                // offset from the beginning of the file, we need to add segmentContentPosition to it.\r\n                seekEntryPosition = value + segmentContentPosition\r\n\r\n            ID_TIMECODE_SCALE -> timecodeScale = value\r\n            ID_PIXEL_WIDTH -> getCurrentTrack(id).width = value.toInt()\r\n            ID_PIXEL_HEIGHT -> getCurrentTrack(id).height = value.toInt()\r\n            ID_DISPLAY_WIDTH -> getCurrentTrack(id).displayWidth = value.toInt()\r\n            ID_DISPLAY_HEIGHT -> getCurrentTrack(id).displayHeight = value.toInt()\r\n            ID_DISPLAY_UNIT -> getCurrentTrack(id).displayUnit = value.toInt()\r\n            ID_TRACK_NUMBER -> getCurrentTrack(id).number = value.toInt()\r\n            ID_FLAG_DEFAULT -> getCurrentTrack(id).flagDefault = value == 1L\r\n            ID_FLAG_FORCED -> getCurrentTrack(id).flagForced = value == 1L\r\n            ID_TRACK_TYPE -> {\r\n                val matroskaTrackType = value.toInt()\r\n                getCurrentTrack(id).type = when (matroskaTrackType) {\r\n                    1 -> C.TRACK_TYPE_VIDEO // Matroska video\r\n                    2 -> C.TRACK_TYPE_AUDIO // Matroska audio\r\n                    17 -> C.TRACK_TYPE_TEXT // Matroska subtitle\r\n                    33 -> C.TRACK_TYPE_METADATA // Matroska metadata\r\n                    else -> C.TRACK_TYPE_UNKNOWN\r\n                }\r\n            }\r\n            ID_DEFAULT_DURATION -> getCurrentTrack(id).defaultSampleDurationNs = value.toInt()\r\n            ID_MAX_BLOCK_ADDITION_ID -> getCurrentTrack(id).maxBlockAdditionId = value.toInt()\r\n            ID_BLOCK_ADD_ID_TYPE -> getCurrentTrack(id).blockAddIdType = value.toInt()\r\n            ID_CODEC_DELAY -> getCurrentTrack(id).codecDelayNs = value\r\n            ID_SEEK_PRE_ROLL -> getCurrentTrack(id).seekPreRollNs = value\r\n            ID_DISCARD_PADDING -> blockGroupDiscardPaddingNs = value\r\n            ID_CHANNELS -> getCurrentTrack(id).channelCount = value.toInt()\r\n            ID_AUDIO_BIT_DEPTH -> getCurrentTrack(id).audioBitDepth = value.toInt()\r\n            ID_REFERENCE_BLOCK -> blockHasReferenceBlock = true\r\n            ID_CONTENT_ENCODING_ORDER ->         // This extractor only supports one ContentEncoding element and hence the order has to be 0.\r\n                if (value != 0L) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"ContentEncodingOrder $value not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n\r\n            ID_CONTENT_ENCODING_SCOPE ->         // This extractor only supports the scope of all frames.\r\n                if (value != 1L) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"ContentEncodingScope $value not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n\r\n            ID_CONTENT_COMPRESSION_ALGORITHM ->         // This extractor only supports header stripping.\r\n                if (value != 3L) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"ContentCompAlgo $value not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n\r\n            ID_CONTENT_ENCRYPTION_ALGORITHM ->         // Only the value 5 (AES) is allowed according to the WebM specification.\r\n                if (value != 5L) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"ContentEncAlgo $value not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n\r\n            ID_CONTENT_ENCRYPTION_AES_SETTINGS_CIPHER_MODE ->         // Only the value 1 is allowed according to the WebM specification.\r\n                if (value != 1L) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"AESSettingsCipherMode $value not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n\r\n            ID_CUE_TIME -> {\r\n                if (!sentSeekMap) {\r\n                    assertInCues(id)\r\n                    currentCueTimeUs = scaleTimecodeToUs(value)\r\n                }\r\n            }\r\n\r\n            ID_CUE_TRACK -> {\r\n                if (!sentSeekMap) {\r\n                    assertInCues(id)\r\n                    currentCueTrackNumber = value.toInt()\r\n                }\r\n            }\r\n\r\n            ID_CUE_CLUSTER_POSITION -> {\r\n                if (!sentSeekMap) {\r\n                    assertInCues(id)\r\n                    if (currentCueClusterPosition == C.INDEX_UNSET.toLong()) {\r\n                        currentCueClusterPosition = value\r\n                    }\r\n                }\r\n            }\r\n\r\n            ID_CUE_RELATIVE_POSITION -> {\r\n                if (!sentSeekMap) {\r\n                    assertInCues(id)\r\n                    if (currentCueRelativePosition == C.INDEX_UNSET.toLong()) {\r\n                        currentCueRelativePosition = value\r\n                    }\r\n                }\r\n            }\r\n\r\n            ID_TIME_CODE -> clusterTimecodeUs = scaleTimecodeToUs(value)\r\n            ID_BLOCK_DURATION -> blockDurationUs = scaleTimecodeToUs(value)\r\n            ID_STEREO_MODE -> {\r\n                val layout = value.toInt()\r\n                assertInTrackEntry(id)\r\n                when (layout) {\r\n                    0 -> currentTrack!!.stereoMode = C.STEREO_MODE_MONO\r\n                    1 -> currentTrack!!.stereoMode = C.STEREO_MODE_LEFT_RIGHT\r\n                    3 -> currentTrack!!.stereoMode = C.STEREO_MODE_TOP_BOTTOM\r\n                    15 -> currentTrack!!.stereoMode = C.STEREO_MODE_STEREO_MESH\r\n                    else -> {}\r\n                }\r\n            }\r\n\r\n            ID_COLOUR_PRIMARIES -> {\r\n                assertInTrackEntry(id)\r\n                currentTrack!!.hasColorInfo = true\r\n                val colorSpace = ColorInfo.isoColorPrimariesToColorSpace(value.toInt())\r\n                if (colorSpace != Format.NO_VALUE) {\r\n                    currentTrack!!.colorSpace = colorSpace\r\n                }\r\n            }\r\n\r\n            ID_COLOUR_TRANSFER -> {\r\n                assertInTrackEntry(id)\r\n                val colorTransfer =\r\n                    ColorInfo.isoTransferCharacteristicsToColorTransfer(value.toInt())\r\n                if (colorTransfer != Format.NO_VALUE) {\r\n                    currentTrack!!.colorTransfer = colorTransfer\r\n                }\r\n            }\r\n\r\n            ID_COLOUR_BITS_PER_CHANNEL -> {\r\n                assertInTrackEntry(id)\r\n                currentTrack!!.hasColorInfo = true\r\n                currentTrack!!.bitsPerChannel = value.toInt()\r\n            }\r\n\r\n            ID_COLOUR_RANGE -> {\r\n                assertInTrackEntry(id)\r\n                when (value.toInt()) {\r\n                    1 -> currentTrack!!.colorRange = C.COLOR_RANGE_LIMITED\r\n                    2 -> currentTrack!!.colorRange = C.COLOR_RANGE_FULL\r\n                    else -> {}\r\n                }\r\n            }\r\n\r\n            ID_MAX_CLL -> getCurrentTrack(id).maxContentLuminance = value.toInt()\r\n            ID_MAX_FALL -> getCurrentTrack(id).maxFrameAverageLuminance = value.toInt()\r\n            ID_PROJECTION_TYPE -> {\r\n                assertInTrackEntry(id)\r\n                when (value.toInt()) {\r\n                    0 -> currentTrack!!.projectionType = C.PROJECTION_RECTANGULAR\r\n                    1 -> currentTrack!!.projectionType = C.PROJECTION_EQUIRECTANGULAR\r\n                    2 -> currentTrack!!.projectionType = C.PROJECTION_CUBEMAP\r\n                    3 -> currentTrack!!.projectionType = C.PROJECTION_MESH\r\n                    else -> {}\r\n                }\r\n            }\r\n\r\n            ID_BLOCK_ADD_ID -> blockAdditionalId = value.toInt()\r\n            else -> {}\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Called when a float element is encountered.\r\n     *\r\n     * @see EbmlProcessor.floatElement\r\n     */\r\n    @CallSuper\r\n    @Throws(ParserException::class)\r\n    protected fun floatElement(id: Int, value: Double) {\r\n        when (id) {\r\n            ID_DURATION -> durationTimecode = value.toLong()\r\n            ID_SAMPLING_FREQUENCY -> getCurrentTrack(id).sampleRate = value.toInt()\r\n            ID_PRIMARY_R_CHROMATICITY_X -> getCurrentTrack(id).primaryRChromaticityX =\r\n                value.toFloat()\r\n\r\n            ID_PRIMARY_R_CHROMATICITY_Y -> getCurrentTrack(id).primaryRChromaticityY =\r\n                value.toFloat()\r\n\r\n            ID_PRIMARY_G_CHROMATICITY_X -> getCurrentTrack(id).primaryGChromaticityX =\r\n                value.toFloat()\r\n\r\n            ID_PRIMARY_G_CHROMATICITY_Y -> getCurrentTrack(id).primaryGChromaticityY =\r\n                value.toFloat()\r\n\r\n            ID_PRIMARY_B_CHROMATICITY_X -> getCurrentTrack(id).primaryBChromaticityX =\r\n                value.toFloat()\r\n\r\n            ID_PRIMARY_B_CHROMATICITY_Y -> getCurrentTrack(id).primaryBChromaticityY =\r\n                value.toFloat()\r\n\r\n            ID_WHITE_POINT_CHROMATICITY_X -> getCurrentTrack(id).whitePointChromaticityX =\r\n                value.toFloat()\r\n\r\n            ID_WHITE_POINT_CHROMATICITY_Y -> getCurrentTrack(id).whitePointChromaticityY =\r\n                value.toFloat()\r\n\r\n            ID_LUMNINANCE_MAX -> getCurrentTrack(id).maxMasteringLuminance = value.toFloat()\r\n            ID_LUMNINANCE_MIN -> getCurrentTrack(id).minMasteringLuminance = value.toFloat()\r\n            ID_PROJECTION_POSE_YAW -> getCurrentTrack(id).projectionPoseYaw = value.toFloat()\r\n            ID_PROJECTION_POSE_PITCH -> getCurrentTrack(id).projectionPosePitch = value.toFloat()\r\n            ID_PROJECTION_POSE_ROLL -> getCurrentTrack(id).projectionPoseRoll = value.toFloat()\r\n            else -> {}\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Called when a string element is encountered.\r\n     *\r\n     * @see EbmlProcessor.stringElement\r\n     */\r\n    @CallSuper\r\n    @Throws(ParserException::class)\r\n    protected fun stringElement(id: Int, value: String) {\r\n        when (id) {\r\n            ID_DOC_TYPE ->         // Validate that DocType is supported.\r\n                if (DOC_TYPE_WEBM != value && DOC_TYPE_MATROSKA != value) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"DocType $value not supported\",  /* cause= */null\r\n                    )\r\n                }\r\n\r\n            ID_NAME -> getCurrentTrack(id).name = value\r\n            ID_CODEC_ID -> getCurrentTrack(id).codecId = value\r\n            ID_LANGUAGE -> getCurrentTrack(id).language = value\r\n            else -> {}\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Called when a binary element is encountered.\r\n     *\r\n     * @see EbmlProcessor.binaryElement\r\n     */\r\n    @CallSuper\r\n    @Throws(IOException::class)\r\n    protected fun binaryElement(id: Int, contentSize: Int, input: ExtractorInput) {\r\n        when (id) {\r\n            ID_SEEK_ID -> {\r\n                Arrays.fill(seekEntryIdBytes.data, 0.toByte())\r\n                input.readFully(seekEntryIdBytes.data, 4 - contentSize, contentSize)\r\n                seekEntryIdBytes.position = 0\r\n                seekEntryId = seekEntryIdBytes.readUnsignedInt().toInt()\r\n            }\r\n\r\n            ID_BLOCK_ADD_ID_EXTRA_DATA -> handleBlockAddIDExtraData(\r\n                getCurrentTrack(id),\r\n                input,\r\n                contentSize\r\n            )\r\n\r\n            ID_CODEC_PRIVATE -> {\r\n                assertInTrackEntry(id)\r\n                currentTrack!!.codecPrivate = ByteArray(contentSize)\r\n                input.readFully(currentTrack!!.codecPrivate!!, 0, contentSize)\r\n            }\r\n\r\n            ID_PROJECTION_PRIVATE -> {\r\n                assertInTrackEntry(id)\r\n                currentTrack!!.projectionData = ByteArray(contentSize)\r\n                input.readFully(currentTrack!!.projectionData!!, 0, contentSize)\r\n            }\r\n\r\n            ID_CONTENT_COMPRESSION_SETTINGS -> {\r\n                assertInTrackEntry(id)\r\n                // This extractor only supports header stripping, so the payload is the stripped bytes.\r\n                currentTrack!!.sampleStrippedBytes = ByteArray(contentSize)\r\n                input.readFully(currentTrack!!.sampleStrippedBytes!!, 0, contentSize)\r\n            }\r\n\r\n            ID_CONTENT_ENCRYPTION_KEY_ID -> {\r\n                val encryptionKey = ByteArray(contentSize)\r\n                input.readFully(encryptionKey, 0, contentSize)\r\n                getCurrentTrack(id).cryptoData =\r\n                    CryptoData(\r\n                        C.CRYPTO_MODE_AES_CTR, encryptionKey, 0, 0\r\n                    ) // We assume patternless AES-CTR.\r\n            }\r\n\r\n            ID_SIMPLE_BLOCK, ID_BLOCK -> {\r\n                // Please refer to http://www.matroska.org/technical/specs/index.html#simpleblock_structure\r\n                // and http://matroska.org/technical/specs/index.html#block_structure\r\n                // for info about how data is organized in SimpleBlock and Block elements respectively. They\r\n                // differ only in the way flags are specified.\r\n                if (blockState == BLOCK_STATE_START) {\r\n                    blockTrackNumber =\r\n                        varintReader.readUnsignedVarint(input, false, true, 8).toInt()\r\n                    blockTrackNumberLength = varintReader.lastLength\r\n                    blockDurationUs = C.TIME_UNSET\r\n                    blockState = BLOCK_STATE_HEADER\r\n                    scratch.reset( /* limit= */0)\r\n                }\r\n\r\n                val track = tracks[blockTrackNumber]\r\n\r\n                // Ignore the block if we don't know about the track to which it belongs.\r\n                if (track == null) {\r\n                    input.skipFully(contentSize - blockTrackNumberLength)\r\n                    blockState = BLOCK_STATE_START\r\n                    return\r\n                }\r\n\r\n                track.assertOutputInitialized()\r\n\r\n                if (blockState == BLOCK_STATE_HEADER) {\r\n                    // Read the relative timecode (2 bytes) and flags (1 byte).\r\n                    readScratch(input, 3)\r\n                    val lacing = (scratch.data[2].toInt() and 0x06) shr 1\r\n                    if (lacing == LACING_NONE) {\r\n                        blockSampleCount = 1\r\n                        blockSampleSizes = ensureArrayCapacity(blockSampleSizes, 1)\r\n                        blockSampleSizes[0] = contentSize - blockTrackNumberLength - 3\r\n                    } else {\r\n                        // Read the sample count (1 byte).\r\n                        readScratch(input, 4)\r\n                        blockSampleCount = (scratch.data[3].toInt() and 0xFF) + 1\r\n                        blockSampleSizes = ensureArrayCapacity(blockSampleSizes, blockSampleCount)\r\n                        if (lacing == LACING_FIXED_SIZE) {\r\n                            val blockLacingSampleSize =\r\n                                (contentSize - blockTrackNumberLength - 4) / blockSampleCount\r\n                            Arrays.fill(\r\n                                blockSampleSizes,\r\n                                0,\r\n                                blockSampleCount,\r\n                                blockLacingSampleSize\r\n                            )\r\n                        } else if (lacing == LACING_XIPH) {\r\n                            var totalSamplesSize = 0\r\n                            var headerSize = 4\r\n                            var sampleIndex = 0\r\n                            while (sampleIndex < blockSampleCount - 1) {\r\n                                blockSampleSizes[sampleIndex] = 0\r\n                                var byteValue: Int\r\n                                do {\r\n                                    readScratch(input, ++headerSize)\r\n                                    byteValue = scratch.data[headerSize - 1].toInt() and 0xFF\r\n                                    blockSampleSizes[sampleIndex] += byteValue\r\n                                } while (byteValue == 0xFF)\r\n                                totalSamplesSize += blockSampleSizes[sampleIndex]\r\n                                sampleIndex++\r\n                            }\r\n                            blockSampleSizes[blockSampleCount - 1] =\r\n                                contentSize - blockTrackNumberLength - headerSize - totalSamplesSize\r\n                        } else if (lacing == LACING_EBML) {\r\n                            var totalSamplesSize = 0\r\n                            var headerSize = 4\r\n                            var sampleIndex = 0\r\n                            while (sampleIndex < blockSampleCount - 1) {\r\n                                blockSampleSizes[sampleIndex] = 0\r\n                                readScratch(input, ++headerSize)\r\n                                if (scratch.data[headerSize - 1].toInt() == 0) {\r\n                                    throw ParserException.createForMalformedContainer(\r\n                                        \"No valid varint length mask found\",  /* cause= */null\r\n                                    )\r\n                                }\r\n                                var readValue: Long = 0\r\n                                var i = 0\r\n                                while (i < 8) {\r\n                                    val lengthMask = 1 shl (7 - i)\r\n                                    if ((scratch.data[headerSize - 1].toInt() and lengthMask) != 0) {\r\n                                        var readPosition = headerSize - 1\r\n                                        headerSize += i\r\n                                        readScratch(input, headerSize)\r\n                                        readValue =\r\n                                            ((scratch.data[readPosition++].toInt() and 0xFF) and lengthMask.inv()).toLong()\r\n                                        while (readPosition < headerSize) {\r\n                                            readValue = readValue shl 8\r\n                                            readValue =\r\n                                                readValue or (scratch.data[readPosition++].toInt() and 0xFF).toLong()\r\n                                        }\r\n                                        // The first read value is the first size. Later values are signed offsets.\r\n                                        if (sampleIndex > 0) {\r\n                                            readValue -= (1L shl (6 + i * 7)) - 1\r\n                                        }\r\n                                        break\r\n                                    }\r\n                                    i++\r\n                                }\r\n                                if (readValue < Int.MIN_VALUE || readValue > Int.MAX_VALUE) {\r\n                                    throw ParserException.createForMalformedContainer(\r\n                                        \"EBML lacing sample size out of range.\",  /* cause= */null\r\n                                    )\r\n                                }\r\n                                val intReadValue = readValue.toInt()\r\n                                blockSampleSizes[sampleIndex] =\r\n                                    if (sampleIndex == 0)\r\n                                        intReadValue\r\n                                    else\r\n                                        blockSampleSizes[sampleIndex - 1] + intReadValue\r\n                                totalSamplesSize += blockSampleSizes[sampleIndex]\r\n                                sampleIndex++\r\n                            }\r\n                            blockSampleSizes[blockSampleCount - 1] =\r\n                                contentSize - blockTrackNumberLength - headerSize - totalSamplesSize\r\n                        } else {\r\n                            // Lacing is always in the range 0--3.\r\n                            throw ParserException.createForMalformedContainer(\r\n                                \"Unexpected lacing value: $lacing\",  /* cause= */null\r\n                            )\r\n                        }\r\n                    }\r\n\r\n                    val timecode =\r\n                        (scratch.data[0].toInt() shl 8) or (scratch.data[1].toInt() and 0xFF)\r\n                    blockTimeUs = clusterTimecodeUs + scaleTimecodeToUs(timecode.toLong())\r\n                    val isKeyframe =\r\n                        track.type == C.TRACK_TYPE_AUDIO\r\n                                || (id == ID_SIMPLE_BLOCK && (scratch.data[2].toInt() and 0x80) == 0x80)\r\n                    blockFlags = if (isKeyframe) C.BUFFER_FLAG_KEY_FRAME else 0\r\n                    blockState = BLOCK_STATE_DATA\r\n                    blockSampleIndex = 0\r\n                }\r\n\r\n                if (id == ID_SIMPLE_BLOCK) {\r\n                    // For SimpleBlock, we can write sample data and immediately commit the corresponding\r\n                    // sample metadata.\r\n                    while (blockSampleIndex < blockSampleCount) {\r\n                        val sampleSize =\r\n                            writeSampleData(\r\n                                input,\r\n                                track,\r\n                                blockSampleSizes[blockSampleIndex],  /* isBlockGroup= */\r\n                                false\r\n                            )\r\n                        val sampleTimeUs =\r\n                            blockTimeUs + (blockSampleIndex * track.defaultSampleDurationNs) / 1000\r\n                        commitSampleToOutput(\r\n                            track,\r\n                            sampleTimeUs,\r\n                            blockFlags,\r\n                            sampleSize,  /* offset= */\r\n                            0\r\n                        )\r\n                        blockSampleIndex++\r\n                    }\r\n                    blockState = BLOCK_STATE_START\r\n                } else {\r\n                    // For Block, we need to wait until the end of the BlockGroup element before committing\r\n                    // sample metadata. This is so that we can handle ReferenceBlock (which can be used to\r\n                    // infer whether the first sample in the block is a keyframe), and BlockAdditions (which\r\n                    // can contain additional sample data to append) contained in the block group. Just output\r\n                    // the sample data, storing the final sample sizes for when we commit the metadata.\r\n                    while (blockSampleIndex < blockSampleCount) {\r\n                        blockSampleSizes[blockSampleIndex] =\r\n                            writeSampleData(\r\n                                input,\r\n                                track,\r\n                                blockSampleSizes[blockSampleIndex],  /* isBlockGroup= */\r\n                                true\r\n                            )\r\n                        blockSampleIndex++\r\n                    }\r\n                }\r\n            }\r\n\r\n            ID_BLOCK_ADDITIONAL -> {\r\n                if (blockState != BLOCK_STATE_DATA) {\r\n                    return\r\n                }\r\n                handleBlockAdditionalData(\r\n                    tracks[blockTrackNumber], blockAdditionalId, input, contentSize\r\n                )\r\n            }\r\n\r\n            else -> throw ParserException.createForMalformedContainer(\r\n                \"Unexpected id: $id\",  /* cause= */null\r\n            )\r\n        }\r\n    }\r\n\r\n    @Throws(IOException::class)\r\n    protected fun handleBlockAddIDExtraData(track: Track, input: ExtractorInput, contentSize: Int) {\r\n        if (track.blockAddIdType == BLOCK_ADD_ID_TYPE_DVVC\r\n            || track.blockAddIdType == BLOCK_ADD_ID_TYPE_DVCC\r\n        ) {\r\n            track.dolbyVisionConfigBytes = ByteArray(contentSize)\r\n            input.readFully(track.dolbyVisionConfigBytes!!, 0, contentSize)\r\n        } else {\r\n            // Unhandled BlockAddIDExtraData.\r\n            input.skipFully(contentSize)\r\n        }\r\n    }\r\n\r\n    @Throws(IOException::class)\r\n    protected fun handleBlockAdditionalData(\r\n        track: Track, blockAdditionalId: Int, input: ExtractorInput, contentSize: Int\r\n    ) {\r\n        if (blockAdditionalId == BLOCK_ADDITIONAL_ID_VP9_ITU_T_35\r\n            && CODEC_ID_VP9 == track.codecId\r\n        ) {\r\n            supplementalData.reset(contentSize)\r\n            input.readFully(supplementalData.data, 0, contentSize)\r\n        } else {\r\n            // Unhandled block additional data.\r\n            input.skipFully(contentSize)\r\n        }\r\n    }\r\n\r\n    @Throws(ParserException::class)\r\n    private fun assertInTrackEntry(id: Int) {\r\n        if (currentTrack == null) {\r\n            throw ParserException.createForMalformedContainer(\r\n                \"Element $id must be in a TrackEntry\",  /* cause= */null\r\n            )\r\n        }\r\n    }\r\n\r\n    @Throws(ParserException::class)\r\n    private fun assertInCues(id: Int) {\r\n        if (!inCuesElement) {\r\n            throw ParserException.createForMalformedContainer(\r\n                \"Element $id must be in a Cues\",  /* cause= */null\r\n            )\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Returns the track corresponding to the current TrackEntry element.\r\n     *\r\n     * @throws ParserException if the element id is not in a TrackEntry.\r\n     */\r\n    @Throws(ParserException::class)\r\n    protected fun getCurrentTrack(currentElementId: Int): Track {\r\n        assertInTrackEntry(currentElementId)\r\n        return currentTrack!!\r\n    }\r\n\r\n    private fun commitSampleToOutput(\r\n        track: Track, timeUs: Long, flags: @BufferFlags Int, size: Int, offset: Int\r\n    ) {\r\n        var size = size\r\n        if (track.trueHdSampleRechunker != null) {\r\n            track.trueHdSampleRechunker!!.sampleMetadata(\r\n                track.output!!, timeUs, flags, size, offset, track.cryptoData\r\n            )\r\n        } else {\r\n            if (CODEC_ID_SUBRIP == track.codecId\r\n                || CODEC_ID_ASS == track.codecId\r\n                || CODEC_ID_SSA == track.codecId\r\n                || CODEC_ID_VTT == track.codecId\r\n            ) {\r\n                if (blockSampleCount > 1) {\r\n                    Log.w(TAG, \"Skipping subtitle sample in laced block.\")\r\n                } else if (blockDurationUs == C.TIME_UNSET) {\r\n                    Log.w(TAG, \"Skipping subtitle sample with no duration.\")\r\n                } else {\r\n                    setSubtitleEndTime(\r\n                        track.codecId!!, blockDurationUs, subtitleSample.data\r\n                    )\r\n                    // The Matroska spec doesn't clearly define whether subtitle samples are null-terminated\r\n                    // or the sample should instead be sized precisely. We truncate the sample at a null-byte\r\n                    // to gracefully handle null-terminated strings followed by garbage bytes.\r\n                    for (i in subtitleSample.position..<subtitleSample.limit()) {\r\n                        if (subtitleSample.data[i].toInt() == 0) {\r\n                            subtitleSample.setLimit(i)\r\n                            break\r\n                        }\r\n                    }\r\n                    // Note: If we ever want to support DRM protected subtitles then we'll need to output the\r\n                    // appropriate encryption data here.\r\n                    track.output!!.sampleData(subtitleSample, subtitleSample.limit())\r\n                    size += subtitleSample.limit()\r\n                }\r\n            }\r\n\r\n            if ((flags and C.BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA) != 0) {\r\n                if (blockSampleCount > 1) {\r\n                    // There were multiple samples in the block. Appending the additional data to the last\r\n                    // sample doesn't make sense. Skip instead.\r\n                    supplementalData.reset( /* limit= */0)\r\n                } else {\r\n                    // Append supplemental data.\r\n                    val supplementalDataSize = supplementalData.limit()\r\n                    track.output!!.sampleData(\r\n                        supplementalData,\r\n                        supplementalDataSize,\r\n                        TrackOutput.SAMPLE_DATA_PART_SUPPLEMENTAL\r\n                    )\r\n                    size += supplementalDataSize\r\n                }\r\n            }\r\n            track.output!!.sampleMetadata(timeUs, flags, size, offset, track.cryptoData)\r\n        }\r\n        haveOutputSample = true\r\n    }\r\n\r\n    /**\r\n     * Ensures [.scratch] contains at least `requiredLength` bytes of data, reading from\r\n     * the extractor input if necessary.\r\n     */\r\n    @Throws(IOException::class)\r\n    private fun readScratch(input: ExtractorInput, requiredLength: Int) {\r\n        if (scratch.limit() >= requiredLength) {\r\n            return\r\n        }\r\n        if (scratch.capacity() < requiredLength) {\r\n            scratch.ensureCapacity(\r\n                max(\r\n                    (scratch.capacity() * 2).toDouble(),\r\n                    requiredLength.toDouble()\r\n                ).toInt()\r\n            )\r\n        }\r\n        input.readFully(scratch.data, scratch.limit(), requiredLength - scratch.limit())\r\n        scratch.setLimit(requiredLength)\r\n    }\r\n\r\n    /**\r\n     * Writes data for a single sample to the track output.\r\n     *\r\n     * @param input The input from which to read sample data.\r\n     * @param track The track to output the sample to.\r\n     * @param size The size of the sample data on the input side.\r\n     * @param isBlockGroup Whether the samples are from a BlockGroup.\r\n     * @return The final size of the written sample.\r\n     * @throws IOException If an error occurs reading from the input.\r\n     */\r\n    @Throws(IOException::class)\r\n    private fun writeSampleData(\r\n        input: ExtractorInput,\r\n        track: Track,\r\n        size: Int,\r\n        isBlockGroup: Boolean\r\n    ): Int {\r\n        var size = size\r\n        if (CODEC_ID_SUBRIP == track.codecId) {\r\n            writeSubtitleSampleData(input, SUBRIP_PREFIX, size)\r\n            return finishWriteSampleData()\r\n        } else if (CODEC_ID_ASS == track.codecId || CODEC_ID_SSA == track.codecId) {\r\n            writeSubtitleSampleData(input, SSA_PREFIX, size)\r\n            return finishWriteSampleData()\r\n        } else if (CODEC_ID_VTT == track.codecId) {\r\n            writeSubtitleSampleData(input, VTT_PREFIX, size)\r\n            return finishWriteSampleData()\r\n        }\r\n\r\n        if (track.waitingForDtsAnalysis) {\r\n            checkNotNull(track.format)\r\n            if (DtsUtil.isSampleDtsHd(input, size)) {\r\n                track.format = track.format!!\r\n                    .buildUpon()\r\n                    .setSampleMimeType(MimeTypes.AUDIO_DTS_HD)\r\n                    .build()\r\n            }\r\n\r\n            track.output!!.format(track.format!!)\r\n            track.waitingForDtsAnalysis = false\r\n            maybeEndTracks()\r\n        }\r\n\r\n        val output = track.output\r\n        if (!sampleEncodingHandled) {\r\n            if (track.hasContentEncryption) {\r\n                // If the sample is encrypted, read its encryption signal byte and set the IV size.\r\n                // Clear the encrypted flag.\r\n                blockFlags = blockFlags and C.BUFFER_FLAG_ENCRYPTED.inv()\r\n                if (!sampleSignalByteRead) {\r\n                    input.readFully(scratch.data, 0, 1)\r\n                    sampleBytesRead++\r\n                    if ((scratch.data[0].toInt() and 0x80) == 0x80) {\r\n                        throw ParserException.createForMalformedContainer(\r\n                            \"Extension bit is set in signal byte\",  /* cause= */null\r\n                        )\r\n                    }\r\n                    sampleSignalByte = scratch.data[0]\r\n                    sampleSignalByteRead = true\r\n                }\r\n                val isEncrypted = (sampleSignalByte.toInt() and 0x01) == 0x01\r\n                if (isEncrypted) {\r\n                    val hasSubsampleEncryption = (sampleSignalByte.toInt() and 0x02) == 0x02\r\n                    blockFlags = blockFlags or C.BUFFER_FLAG_ENCRYPTED\r\n                    if (!sampleInitializationVectorRead) {\r\n                        input.readFully(encryptionInitializationVector.data, 0, ENCRYPTION_IV_SIZE)\r\n                        sampleBytesRead += ENCRYPTION_IV_SIZE\r\n                        sampleInitializationVectorRead = true\r\n                        // Write the signal byte, containing the IV size and the subsample encryption flag.\r\n                        scratch.data[0] =\r\n                            (ENCRYPTION_IV_SIZE or (if (hasSubsampleEncryption) 0x80 else 0x00)).toByte()\r\n                        scratch.position = 0\r\n                        output!!.sampleData(scratch, 1, TrackOutput.SAMPLE_DATA_PART_ENCRYPTION)\r\n                        sampleBytesWritten++\r\n                        // Write the IV.\r\n                        encryptionInitializationVector.position = 0\r\n                        output.sampleData(\r\n                            encryptionInitializationVector,\r\n                            ENCRYPTION_IV_SIZE,\r\n                            TrackOutput.SAMPLE_DATA_PART_ENCRYPTION\r\n                        )\r\n                        sampleBytesWritten += ENCRYPTION_IV_SIZE\r\n                    }\r\n                    if (hasSubsampleEncryption) {\r\n                        if (!samplePartitionCountRead) {\r\n                            input.readFully(scratch.data, 0, 1)\r\n                            sampleBytesRead++\r\n                            scratch.position = 0\r\n                            samplePartitionCount = scratch.readUnsignedByte()\r\n                            samplePartitionCountRead = true\r\n                        }\r\n                        val samplePartitionDataSize = samplePartitionCount * 4\r\n                        scratch.reset(samplePartitionDataSize)\r\n                        input.readFully(scratch.data, 0, samplePartitionDataSize)\r\n                        sampleBytesRead += samplePartitionDataSize\r\n                        val subsampleCount = (1 + (samplePartitionCount / 2)).toShort()\r\n                        val subsampleDataSize = 2 + 6 * subsampleCount\r\n                        if (encryptionSubsampleDataBuffer == null\r\n                            || encryptionSubsampleDataBuffer!!.capacity() < subsampleDataSize\r\n                        ) {\r\n                            encryptionSubsampleDataBuffer = ByteBuffer.allocate(subsampleDataSize)\r\n                        }\r\n                        encryptionSubsampleDataBuffer!!.position(0)\r\n                        encryptionSubsampleDataBuffer!!.putShort(subsampleCount)\r\n                        // Loop through the partition offsets and write out the data in the way ExoPlayer\r\n                        // wants it (ISO 23001-7 Part 7):\r\n                        //   2 bytes - sub sample count.\r\n                        //   for each sub sample:\r\n                        //     2 bytes - clear data size.\r\n                        //     4 bytes - encrypted data size.\r\n                        var partitionOffset = 0\r\n                        for (i in 0..<samplePartitionCount) {\r\n                            val previousPartitionOffset = partitionOffset\r\n                            partitionOffset = scratch.readUnsignedIntToInt()\r\n                            if ((i % 2) == 0) {\r\n                                encryptionSubsampleDataBuffer!!.putShort(\r\n                                    (partitionOffset - previousPartitionOffset).toShort()\r\n                                )\r\n                            } else {\r\n                                encryptionSubsampleDataBuffer!!.putInt(partitionOffset - previousPartitionOffset)\r\n                            }\r\n                        }\r\n                        val finalPartitionSize = size - sampleBytesRead - partitionOffset\r\n                        if ((samplePartitionCount % 2) == 1) {\r\n                            encryptionSubsampleDataBuffer!!.putInt(finalPartitionSize)\r\n                        } else {\r\n                            encryptionSubsampleDataBuffer!!.putShort(finalPartitionSize.toShort())\r\n                            encryptionSubsampleDataBuffer!!.putInt(0)\r\n                        }\r\n                        encryptionSubsampleData.reset(\r\n                            encryptionSubsampleDataBuffer!!.array(),\r\n                            subsampleDataSize\r\n                        )\r\n                        output!!.sampleData(\r\n                            encryptionSubsampleData,\r\n                            subsampleDataSize,\r\n                            TrackOutput.SAMPLE_DATA_PART_ENCRYPTION\r\n                        )\r\n                        sampleBytesWritten += subsampleDataSize\r\n                    }\r\n                }\r\n            } else if (track.sampleStrippedBytes != null) {\r\n                // If the sample has header stripping, prepare to read/output the stripped bytes first.\r\n                sampleStrippedBytes.reset(\r\n                    track.sampleStrippedBytes!!,\r\n                    track.sampleStrippedBytes!!.size\r\n                )\r\n            }\r\n\r\n            if (track.samplesHaveSupplementalData(isBlockGroup)) {\r\n                blockFlags = blockFlags or C.BUFFER_FLAG_HAS_SUPPLEMENTAL_DATA\r\n                supplementalData.reset( /* limit= */0)\r\n                // If there is supplemental data, the structure of the sample data is:\r\n                // encryption data (if any) || sample size (4 bytes) || sample data || supplemental data\r\n                val sampleSize = size + sampleStrippedBytes.limit() - sampleBytesRead\r\n                scratch.reset( /* limit= */4)\r\n                scratch.data[0] = ((sampleSize shr 24) and 0xFF).toByte()\r\n                scratch.data[1] = ((sampleSize shr 16) and 0xFF).toByte()\r\n                scratch.data[2] = ((sampleSize shr 8) and 0xFF).toByte()\r\n                scratch.data[3] = (sampleSize and 0xFF).toByte()\r\n                output!!.sampleData(scratch, 4, TrackOutput.SAMPLE_DATA_PART_SUPPLEMENTAL)\r\n                sampleBytesWritten += 4\r\n            }\r\n\r\n            sampleEncodingHandled = true\r\n        }\r\n        size += sampleStrippedBytes.limit()\r\n\r\n        if (CODEC_ID_H264 == track.codecId || CODEC_ID_H265 == track.codecId) {\r\n            // TODO: Deduplicate with Mp4Extractor.\r\n\r\n            // Zero the top three bytes of the array that we'll use to decode nal unit lengths, in case\r\n            // they're only 1 or 2 bytes long.\r\n\r\n            val nalLengthData = nalLength.data\r\n            nalLengthData[0] = 0\r\n            nalLengthData[1] = 0\r\n            nalLengthData[2] = 0\r\n            val nalUnitLengthFieldLength = track.nalUnitLengthFieldLength\r\n            val nalUnitLengthFieldLengthDiff = 4 - track.nalUnitLengthFieldLength\r\n            // NAL units are length delimited, but the decoder requires start code delimited units.\r\n            // Loop until we've written the sample to the track output, replacing length delimiters with\r\n            // start codes as we encounter them.\r\n            while (sampleBytesRead < size) {\r\n                if (sampleCurrentNalBytesRemaining == 0) {\r\n                    // Read the NAL length so that we know where we find the next one.\r\n                    writeToTarget(\r\n                        input, nalLengthData, nalUnitLengthFieldLengthDiff, nalUnitLengthFieldLength\r\n                    )\r\n                    sampleBytesRead += nalUnitLengthFieldLength\r\n                    nalLength.position = 0\r\n                    sampleCurrentNalBytesRemaining = nalLength.readUnsignedIntToInt()\r\n                    // Write a start code for the current NAL unit.\r\n                    nalStartCode.position = 0\r\n                    output!!.sampleData(nalStartCode, 4)\r\n                    sampleBytesWritten += 4\r\n                } else {\r\n                    // Write the payload of the NAL unit.\r\n                    val bytesWritten = writeToOutput(\r\n                        input,\r\n                        output!!, sampleCurrentNalBytesRemaining\r\n                    )\r\n                    sampleBytesRead += bytesWritten\r\n                    sampleBytesWritten += bytesWritten\r\n                    sampleCurrentNalBytesRemaining -= bytesWritten\r\n                }\r\n            }\r\n        } else {\r\n            if (track.trueHdSampleRechunker != null) {\r\n                checkState(sampleStrippedBytes.limit() == 0)\r\n                track.trueHdSampleRechunker!!.startSample(input)\r\n            }\r\n            while (sampleBytesRead < size) {\r\n                val bytesWritten = writeToOutput(input, output!!, size - sampleBytesRead)\r\n                sampleBytesRead += bytesWritten\r\n                sampleBytesWritten += bytesWritten\r\n            }\r\n        }\r\n\r\n        if (CODEC_ID_VORBIS == track.codecId) {\r\n            // Vorbis decoder in android MediaCodec [1] expects the last 4 bytes of the sample to be the\r\n            // number of samples in the current page. This definition holds good only for Ogg and\r\n            // irrelevant for Matroska. So we always set this to -1 (the decoder will ignore this value if\r\n            // we set it to -1). The android platform media extractor [2] does the same.\r\n            // [1]\r\n            // https://android.googlesource.com/platform/frameworks/av/+/lollipop-release/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp#314\r\n            // [2]\r\n            // https://android.googlesource.com/platform/frameworks/av/+/lollipop-release/media/libstagefright/NuMediaExtractor.cpp#474\r\n            vorbisNumPageSamples.position = 0\r\n            output!!.sampleData(vorbisNumPageSamples, 4)\r\n            sampleBytesWritten += 4\r\n        }\r\n\r\n        return finishWriteSampleData()\r\n    }\r\n\r\n    /**\r\n     * Called by [.writeSampleData] when the sample has\r\n     * been written. Returns the final sample size and resets state for the next sample.\r\n     */\r\n    private fun finishWriteSampleData(): Int {\r\n        val sampleSize = sampleBytesWritten\r\n        resetWriteSampleData()\r\n        return sampleSize\r\n    }\r\n\r\n    /** Resets state used by [.writeSampleData].  */\r\n    private fun resetWriteSampleData() {\r\n        sampleBytesRead = 0\r\n        sampleBytesWritten = 0\r\n        sampleCurrentNalBytesRemaining = 0\r\n        sampleEncodingHandled = false\r\n        sampleSignalByteRead = false\r\n        samplePartitionCountRead = false\r\n        samplePartitionCount = 0\r\n        sampleSignalByte = 0.toByte()\r\n        sampleInitializationVectorRead = false\r\n        sampleStrippedBytes.reset( /* limit= */0)\r\n    }\r\n\r\n    @Throws(IOException::class)\r\n    private fun writeSubtitleSampleData(input: ExtractorInput, samplePrefix: ByteArray, size: Int) {\r\n        val sizeWithPrefix = samplePrefix.size + size\r\n        if (subtitleSample.capacity() < sizeWithPrefix) {\r\n            // Initialize subripSample to contain the required prefix and have space to hold a subtitle\r\n            // twice as long as this one.\r\n            subtitleSample.reset(samplePrefix.copyOf(sizeWithPrefix + size))\r\n        } else {\r\n            System.arraycopy(samplePrefix, 0, subtitleSample.data, 0, samplePrefix.size)\r\n        }\r\n        input.readFully(subtitleSample.data, samplePrefix.size, size)\r\n        subtitleSample.position = 0\r\n        subtitleSample.setLimit(sizeWithPrefix)\r\n        // Defer writing the data to the track output. We need to modify the sample data by setting\r\n        // the correct end timecode, which we might not have yet.\r\n    }\r\n\r\n    /**\r\n     * Writes `length` bytes of sample data into `target` at `offset`, consisting of\r\n     * pending [.sampleStrippedBytes] and any remaining data read from `input`.\r\n     */\r\n    @Throws(IOException::class)\r\n    private fun writeToTarget(input: ExtractorInput, target: ByteArray, offset: Int, length: Int) {\r\n        val pendingStrippedBytes =\r\n            min(length.toDouble(), sampleStrippedBytes.bytesLeft().toDouble()).toInt()\r\n        input.readFully(target, offset + pendingStrippedBytes, length - pendingStrippedBytes)\r\n        if (pendingStrippedBytes > 0) {\r\n            sampleStrippedBytes.readBytes(target, offset, pendingStrippedBytes)\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Outputs up to `length` bytes of sample data to `output`, consisting of either\r\n     * [.sampleStrippedBytes] or data read from `input`.\r\n     */\r\n    @Throws(IOException::class)\r\n    private fun writeToOutput(input: ExtractorInput, output: TrackOutput, length: Int): Int {\r\n        val bytesWritten: Int\r\n        val strippedBytesLeft = sampleStrippedBytes.bytesLeft()\r\n        if (strippedBytesLeft > 0) {\r\n            bytesWritten = min(length.toDouble(), strippedBytesLeft.toDouble()).toInt()\r\n            output.sampleData(sampleStrippedBytes, bytesWritten)\r\n        } else {\r\n            bytesWritten = output.sampleData(input, length, false)\r\n        }\r\n        return bytesWritten\r\n    }\r\n\r\n    /**\r\n     * Updates the position of the holder to Cues element's position if the extractor configuration\r\n     * permits use of master seek entry. After building Cues sets the holder's position back to where\r\n     * it was before.\r\n     *\r\n     * @param seekPosition The holder whose position will be updated.\r\n     * @param currentPosition Current position of the input.\r\n     * @return Whether the seek position was updated.\r\n     */\r\n    private fun maybeSeekForCues(seekPosition: PositionHolder, currentPosition: Long): Boolean {\r\n        // This seeks in a lazy manner, unlike VLC that seeks immediately when encountering a seek head\r\n        // This minimizes the amount of seeking done, but also does not seek if the cues element is\r\n        // already found, even if seek heads exits. This might be nice to change if we need other\r\n        // critical information from seek heads.\r\n        //\r\n        // The nature of each recursive query becomes to consume as much content as possible\r\n        // (until cues or end of segment). However this also means that we only need to seek\r\n        // back to the top once, instead seeking back in a stack like manner.\r\n        if (seekForSeekContent) {\r\n            checkArgument(pendingSeekHeads.isNotEmpty(), \"Illegal value of seekForSeekContent\")\r\n            // The exact order does not really matter, but it is easiest to just do stack (FILO)\r\n            val next = pendingSeekHeads.removeAt(pendingSeekHeads.size - 1)\r\n            seekPosition.position = next\r\n            seekForSeekContent = false\r\n            if (seekPositionAfterSeekingForHead == C.INDEX_UNSET.toLong()) {\r\n                seekPositionAfterSeekingForHead = currentPosition\r\n            }\r\n            return true\r\n        }\r\n\r\n        if (seekForCues) {\r\n            seekPositionAfterBuildingCues = currentPosition\r\n            seekPosition.position = cuesContentPosition\r\n            seekForCues = false\r\n            return true\r\n        }\r\n\r\n        // After parsing Cues, seek back to original position if available. We will not do this unless\r\n        // we seeked to get to the Cues in the first place.\r\n        if (sentSeekMap && seekPositionAfterBuildingCues != C.INDEX_UNSET.toLong()) {\r\n            seekPosition.position = seekPositionAfterBuildingCues\r\n            seekPositionAfterBuildingCues = C.INDEX_UNSET.toLong()\r\n            return true\r\n        }\r\n\r\n        // After we have seeked back from seekPositionAfterBuildingCues seek back again to the seek head\r\n        if (sentSeekMap && seekPositionAfterSeekingForHead != C.INDEX_UNSET.toLong()) {\r\n            seekPosition.position = seekPositionAfterSeekingForHead\r\n            seekPositionAfterSeekingForHead = C.INDEX_UNSET.toLong()\r\n            return true\r\n        }\r\n\r\n        return false\r\n    }\r\n\r\n    @Throws(ParserException::class)\r\n    private fun scaleTimecodeToUs(unscaledTimecode: Long): Long {\r\n        if (timecodeScale == C.TIME_UNSET) {\r\n            throw ParserException.createForMalformedContainer(\r\n                \"Can't scale timecode prior to timecodeScale being set.\",  /* cause= */null\r\n            )\r\n        }\r\n        return Util.scaleLargeTimestamp(unscaledTimecode, timecodeScale, 1000)\r\n    }\r\n\r\n    private fun assertInitialized() {\r\n        checkNotNull<ExtractorOutput?>(\r\n            extractorOutput\r\n        )\r\n    }\r\n\r\n    private fun maybeEndTracks() {\r\n        if (!pendingEndTracks) return\r\n\r\n        for (i in 0 until tracks.size()) {\r\n            if (tracks.valueAt(i).waitingForDtsAnalysis) return\r\n        }\r\n\r\n        checkNotNull(extractorOutput).endTracks()\r\n        pendingEndTracks = false\r\n    }\r\n\r\n    /** Passes events through to the outer [UpdatedMatroskaExtractor].  */\r\n    private inner class InnerEbmlProcessor : EbmlProcessor {\r\n        override fun getElementType(id: Int): @EbmlProcessor.ElementType Int {\r\n            return this@UpdatedMatroskaExtractor.getElementType(id)\r\n        }\r\n\r\n        override fun isLevel1Element(id: Int): Boolean {\r\n            return this@UpdatedMatroskaExtractor.isLevel1Element(id)\r\n        }\r\n\r\n        @Throws(ParserException::class)\r\n        override fun startMasterElement(id: Int, contentPosition: Long, contentSize: Long) {\r\n            this@UpdatedMatroskaExtractor.startMasterElement(id, contentPosition, contentSize)\r\n        }\r\n\r\n        @Throws(ParserException::class)\r\n        override fun endMasterElement(id: Int) {\r\n            this@UpdatedMatroskaExtractor.endMasterElement(id)\r\n        }\r\n\r\n        @Throws(ParserException::class)\r\n        override fun integerElement(id: Int, value: Long) {\r\n            this@UpdatedMatroskaExtractor.integerElement(id, value)\r\n        }\r\n\r\n        @Throws(ParserException::class)\r\n        override fun floatElement(id: Int, value: Double) {\r\n            this@UpdatedMatroskaExtractor.floatElement(id, value)\r\n        }\r\n\r\n        @Throws(ParserException::class)\r\n        override fun stringElement(id: Int, value: String) {\r\n            this@UpdatedMatroskaExtractor.stringElement(id, value)\r\n        }\r\n\r\n        @Throws(IOException::class)\r\n        override fun binaryElement(id: Int, contentsSize: Int, input: ExtractorInput) {\r\n            this@UpdatedMatroskaExtractor.binaryElement(id, contentsSize, input)\r\n        }\r\n    }\r\n\r\n    /** Holds data corresponding to a single track.  */\r\n    protected class Track {\r\n        // Common elements.\r\n        var isWebm: Boolean = false\r\n        var name: String? = null\r\n        var codecId: String? = null\r\n        var number: Int = 0\r\n        var type: @C.TrackType Int = 0\r\n        var defaultSampleDurationNs: Int = 0\r\n        var maxBlockAdditionId: Int = 0\r\n        var blockAddIdType: Int = 0\r\n        var hasContentEncryption: Boolean = false\r\n        var sampleStrippedBytes: ByteArray? = null\r\n        var cryptoData: CryptoData? =\r\n            null\r\n        var codecPrivate: ByteArray? = null\r\n        var drmInitData: DrmInitData? =\r\n            null\r\n\r\n        // Video elements.\r\n        var width: Int = Format.NO_VALUE\r\n        var height: Int = Format.NO_VALUE\r\n        var bitsPerChannel: Int = Format.NO_VALUE\r\n        var displayWidth: Int = Format.NO_VALUE\r\n        var displayHeight: Int = Format.NO_VALUE\r\n        var displayUnit: Int = DISPLAY_UNIT_PIXELS\r\n        var projectionType: @C.Projection Int = Format.NO_VALUE\r\n        var projectionPoseYaw: Float = 0f\r\n        var projectionPosePitch: Float = 0f\r\n        var projectionPoseRoll: Float = 0f\r\n        var projectionData: ByteArray? =\r\n            null\r\n        var stereoMode: @StereoMode Int = Format.NO_VALUE\r\n        var hasColorInfo: Boolean = false\r\n        var colorSpace: @C.ColorSpace Int = Format.NO_VALUE\r\n        var colorTransfer: @ColorTransfer Int = Format.NO_VALUE\r\n        var colorRange: @ColorRange Int = Format.NO_VALUE\r\n        var maxContentLuminance: Int = DEFAULT_MAX_CLL\r\n        var maxFrameAverageLuminance: Int = DEFAULT_MAX_FALL\r\n        var primaryRChromaticityX: Float = Format.NO_VALUE.toFloat()\r\n        var primaryRChromaticityY: Float = Format.NO_VALUE.toFloat()\r\n        var primaryGChromaticityX: Float = Format.NO_VALUE.toFloat()\r\n        var primaryGChromaticityY: Float = Format.NO_VALUE.toFloat()\r\n        var primaryBChromaticityX: Float = Format.NO_VALUE.toFloat()\r\n        var primaryBChromaticityY: Float = Format.NO_VALUE.toFloat()\r\n        var whitePointChromaticityX: Float = Format.NO_VALUE.toFloat()\r\n        var whitePointChromaticityY: Float = Format.NO_VALUE.toFloat()\r\n        var maxMasteringLuminance: Float = Format.NO_VALUE.toFloat()\r\n        var minMasteringLuminance: Float = Format.NO_VALUE.toFloat()\r\n        var dolbyVisionConfigBytes: ByteArray? = null\r\n\r\n        // Audio elements. Initially set to their default values.\r\n        var channelCount: Int = 1\r\n        var audioBitDepth: Int = Format.NO_VALUE\r\n        var sampleRate: Int = 8000\r\n        var codecDelayNs: Long = 0\r\n        var seekPreRollNs: Long = 0\r\n        var trueHdSampleRechunker: TrueHdSampleRechunker? = null\r\n        var waitingForDtsAnalysis: Boolean = false\r\n\r\n        // Text elements.\r\n        var flagForced: Boolean = false\r\n\r\n        // Common track elements.\r\n        var flagDefault: Boolean = true\r\n        var language: String = \"eng\"\r\n\r\n        // Set when the output is initialized. nalUnitLengthFieldLength is only set for H264/H265.\r\n        var output: TrackOutput? = null\r\n        var format: Format? = null\r\n        var nalUnitLengthFieldLength: Int = 0\r\n\r\n        /** Builds the [Format] for the track. */\r\n        @Throws(ParserException::class)\r\n        fun initializeFormat(trackId: Int) {\r\n            var mimeType: String\r\n            var maxInputSize = Format.NO_VALUE\r\n            var pcmEncoding: @PcmEncoding Int = Format.NO_VALUE\r\n            var initializationData: List<ByteArray>? = null\r\n            var codecs: String? = null\r\n            when (codecId) {\r\n                CODEC_ID_VP8 -> mimeType = MimeTypes.VIDEO_VP8\r\n                CODEC_ID_VP9 -> {\r\n                    mimeType = MimeTypes.VIDEO_VP9\r\n                    initializationData =\r\n                        if (codecPrivate == null) null else ImmutableList.of(\r\n                            codecPrivate!!\r\n                        )\r\n                }\r\n                CODEC_ID_AV1 -> {\r\n                    mimeType = MimeTypes.VIDEO_AV1\r\n                    initializationData =\r\n                        if (codecPrivate == null) null else ImmutableList.of(\r\n                            codecPrivate!!\r\n                        )\r\n                }\r\n                CODEC_ID_MPEG2 -> mimeType = MimeTypes.VIDEO_MPEG2\r\n                CODEC_ID_MPEG4_SP, CODEC_ID_MPEG4_ASP, CODEC_ID_MPEG4_AP -> {\r\n                    mimeType = MimeTypes.VIDEO_MP4V\r\n                    initializationData =\r\n                        if (codecPrivate == null) null else listOf(\r\n                            codecPrivate!!\r\n                        )\r\n                }\r\n\r\n                CODEC_ID_H264 -> {\r\n                    mimeType = MimeTypes.VIDEO_H264\r\n                    val avcConfig = AvcConfig.parse(\r\n                        ParsableByteArray(\r\n                            getCodecPrivate(\r\n                                codecId!!\r\n                            )\r\n                        )\r\n                    )\r\n                    initializationData = avcConfig.initializationData\r\n                    nalUnitLengthFieldLength = avcConfig.nalUnitLengthFieldLength\r\n                    codecs = avcConfig.codecs\r\n                }\r\n\r\n                CODEC_ID_H265 -> {\r\n                    mimeType = MimeTypes.VIDEO_H265\r\n                    val hevcConfig = HevcConfig.parse(\r\n                        ParsableByteArray(\r\n                            getCodecPrivate(\r\n                                codecId!!\r\n                            )\r\n                        )\r\n                    )\r\n                    initializationData = hevcConfig.initializationData\r\n                    nalUnitLengthFieldLength = hevcConfig.nalUnitLengthFieldLength\r\n                    codecs = hevcConfig.codecs\r\n                }\r\n\r\n                CODEC_ID_FOURCC -> {\r\n                    val pair =\r\n                        parseFourCcPrivate(\r\n                            ParsableByteArray(\r\n                                getCodecPrivate(\r\n                                    codecId!!\r\n                                )\r\n                            )\r\n                        )\r\n                    mimeType = pair.first\r\n                    initializationData = pair.second\r\n                }\r\n\r\n                CODEC_ID_THEORA ->           // TODO: This can be set to the real mimeType if/when we work out what initializationData\r\n                    // should be set to for this case.\r\n                    mimeType = MimeTypes.VIDEO_UNKNOWN\r\n\r\n                CODEC_ID_VORBIS -> {\r\n                    mimeType = MimeTypes.AUDIO_VORBIS\r\n                    maxInputSize = VORBIS_MAX_INPUT_SIZE\r\n                    initializationData = parseVorbisCodecPrivate(\r\n                        getCodecPrivate(\r\n                            codecId!!\r\n                        )\r\n                    )\r\n                }\r\n\r\n                CODEC_ID_OPUS -> {\r\n                    mimeType = MimeTypes.AUDIO_OPUS\r\n                    maxInputSize = OPUS_MAX_INPUT_SIZE\r\n                    initializationData = ArrayList(3)\r\n                    initializationData.add(getCodecPrivate(codecId!!))\r\n                    initializationData.add(\r\n                        ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(codecDelayNs)\r\n                            .array()\r\n                    )\r\n                    initializationData.add(\r\n                        ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN).putLong(seekPreRollNs)\r\n                            .array()\r\n                    )\r\n                }\r\n\r\n                CODEC_ID_AAC -> {\r\n                    mimeType = MimeTypes.AUDIO_AAC\r\n                    initializationData = listOf(\r\n                        getCodecPrivate(\r\n                            codecId!!\r\n                        )\r\n                    )\r\n                    val aacConfig = AacUtil.parseAudioSpecificConfig(codecPrivate!!)\r\n                    // Update sampleRate and channelCount from the AudioSpecificConfig initialization data,\r\n                    // which is more reliable. See [Internal: b/10903778].\r\n                    sampleRate = aacConfig.sampleRateHz\r\n                    channelCount = aacConfig.channelCount\r\n                    codecs = aacConfig.codecs\r\n                }\r\n\r\n                CODEC_ID_MP2 -> {\r\n                    mimeType = MimeTypes.AUDIO_MPEG_L2\r\n                    maxInputSize = MpegAudioUtil.MAX_FRAME_SIZE_BYTES\r\n                }\r\n\r\n                CODEC_ID_MP3 -> {\r\n                    mimeType = MimeTypes.AUDIO_MPEG\r\n                    maxInputSize = MpegAudioUtil.MAX_FRAME_SIZE_BYTES\r\n                }\r\n\r\n                CODEC_ID_AC3 -> mimeType = MimeTypes.AUDIO_AC3\r\n                CODEC_ID_E_AC3 -> mimeType = MimeTypes.AUDIO_E_AC3\r\n                CODEC_ID_TRUEHD -> {\r\n                    mimeType = MimeTypes.AUDIO_TRUEHD\r\n                    trueHdSampleRechunker = TrueHdSampleRechunker()\r\n                }\r\n\r\n                CODEC_ID_DTS, CODEC_ID_DTS_EXPRESS -> {\r\n                    mimeType = MimeTypes.AUDIO_DTS // temporary\r\n                    waitingForDtsAnalysis = true\r\n                }\r\n                CODEC_ID_DTS_LOSSLESS -> mimeType = MimeTypes.AUDIO_DTS_HD\r\n                CODEC_ID_FLAC -> {\r\n                    mimeType = MimeTypes.AUDIO_FLAC\r\n                    initializationData = listOf(\r\n                        getCodecPrivate(\r\n                            codecId!!\r\n                        )\r\n                    )\r\n                }\r\n\r\n                CODEC_ID_ACM -> {\r\n                    mimeType = MimeTypes.AUDIO_RAW\r\n                    if (parseMsAcmCodecPrivate(\r\n                            ParsableByteArray(\r\n                                getCodecPrivate(\r\n                                    codecId!!\r\n                                )\r\n                            )\r\n                        )\r\n                    ) {\r\n                        pcmEncoding = Util.getPcmEncoding(audioBitDepth)\r\n                        if (pcmEncoding == C.ENCODING_INVALID) {\r\n                            pcmEncoding = Format.NO_VALUE\r\n                            mimeType = MimeTypes.AUDIO_UNKNOWN\r\n                            Log.w(\r\n                                TAG,\r\n                                (\"Unsupported PCM bit depth: \"\r\n                                        + audioBitDepth\r\n                                        + \". Setting mimeType to \"\r\n                                        + mimeType)\r\n                            )\r\n                        }\r\n                    } else {\r\n                        mimeType = MimeTypes.AUDIO_UNKNOWN\r\n                        Log.w(\r\n                            TAG,\r\n                            \"Non-PCM MS/ACM is unsupported. Setting mimeType to $mimeType\"\r\n                        )\r\n                    }\r\n                }\r\n\r\n                CODEC_ID_PCM_INT_LIT -> {\r\n                    mimeType = MimeTypes.AUDIO_RAW\r\n                    pcmEncoding = Util.getPcmEncoding(audioBitDepth)\r\n                    if (pcmEncoding == C.ENCODING_INVALID) {\r\n                        pcmEncoding = Format.NO_VALUE\r\n                        mimeType = MimeTypes.AUDIO_UNKNOWN\r\n                        Log.w(\r\n                            TAG,\r\n                            (\"Unsupported little endian PCM bit depth: \"\r\n                                    + audioBitDepth\r\n                                    + \". Setting mimeType to \"\r\n                                    + mimeType)\r\n                        )\r\n                    }\r\n                }\r\n\r\n                CODEC_ID_PCM_INT_BIG -> {\r\n                    mimeType = MimeTypes.AUDIO_RAW\r\n                    if (audioBitDepth == 8) {\r\n                        pcmEncoding = C.ENCODING_PCM_8BIT\r\n                    } else if (audioBitDepth == 16) {\r\n                        pcmEncoding = C.ENCODING_PCM_16BIT_BIG_ENDIAN\r\n                    } else if (audioBitDepth == 24) {\r\n                        pcmEncoding = C.ENCODING_PCM_24BIT_BIG_ENDIAN\r\n                    } else if (audioBitDepth == 32) {\r\n                        pcmEncoding = C.ENCODING_PCM_32BIT_BIG_ENDIAN\r\n                    } else {\r\n                        pcmEncoding = Format.NO_VALUE\r\n                        mimeType = MimeTypes.AUDIO_UNKNOWN\r\n                        Log.w(\r\n                            TAG,\r\n                            (\"Unsupported big endian PCM bit depth: \"\r\n                                    + audioBitDepth\r\n                                    + \". Setting mimeType to \"\r\n                                    + mimeType)\r\n                        )\r\n                    }\r\n                }\r\n\r\n                CODEC_ID_PCM_FLOAT -> {\r\n                    mimeType = MimeTypes.AUDIO_RAW\r\n                    if (audioBitDepth == 32) {\r\n                        pcmEncoding = C.ENCODING_PCM_FLOAT\r\n                    } else {\r\n                        pcmEncoding = Format.NO_VALUE\r\n                        mimeType = MimeTypes.AUDIO_UNKNOWN\r\n                        Log.w(\r\n                            TAG,\r\n                            (\"Unsupported floating point PCM bit depth: \"\r\n                                    + audioBitDepth\r\n                                    + \". Setting mimeType to \"\r\n                                    + mimeType)\r\n                        )\r\n                    }\r\n                }\r\n\r\n                CODEC_ID_SUBRIP -> mimeType = MimeTypes.APPLICATION_SUBRIP\r\n                CODEC_ID_ASS, CODEC_ID_SSA -> {\r\n                    mimeType = MimeTypes.TEXT_SSA\r\n                    initializationData = ImmutableList.of(\r\n                        SSA_DIALOGUE_FORMAT, getCodecPrivate(\r\n                            codecId!!\r\n                        )\r\n                    )\r\n                }\r\n\r\n                CODEC_ID_VTT -> mimeType = MimeTypes.TEXT_VTT\r\n                CODEC_ID_VOBSUB -> {\r\n                    mimeType = MimeTypes.APPLICATION_VOBSUB\r\n                    initializationData = ImmutableList.of(\r\n                        getCodecPrivate(\r\n                            codecId!!\r\n                        )\r\n                    )\r\n                }\r\n\r\n                CODEC_ID_PGS -> mimeType = MimeTypes.APPLICATION_PGS\r\n                CODEC_ID_DVBSUB -> {\r\n                    mimeType = MimeTypes.APPLICATION_DVBSUBS\r\n                    // Init data: composition_page (2), ancillary_page (2)\r\n                    val initializationDataBytes = ByteArray(4)\r\n                    System.arraycopy(getCodecPrivate(codecId!!), 0, initializationDataBytes, 0, 4)\r\n                    initializationData = ImmutableList.of(initializationDataBytes)\r\n                }\r\n\r\n                else -> throw ParserException.createForMalformedContainer(\r\n                    \"Unrecognized codec identifier.\",  /* cause= */null\r\n                )\r\n            }\r\n\r\n            if (dolbyVisionConfigBytes != null) {\r\n                val dolbyVisionConfig =\r\n                    DolbyVisionConfig.parse(ParsableByteArray(dolbyVisionConfigBytes!!))\r\n                if (dolbyVisionConfig != null) {\r\n                    codecs = dolbyVisionConfig.codecs\r\n                    mimeType = MimeTypes.VIDEO_DOLBY_VISION\r\n                }\r\n            }\r\n\r\n            var selectionFlags: @SelectionFlags Int = 0\r\n            selectionFlags = selectionFlags or if (flagDefault) C.SELECTION_FLAG_DEFAULT else 0\r\n            selectionFlags = selectionFlags or if (flagForced) C.SELECTION_FLAG_FORCED else 0\r\n\r\n            val formatBuilder = Format.Builder()\r\n            // TODO: Consider reading the name elements of the tracks and, if present, incorporating them\r\n            // into the trackId passed when creating the formats.\r\n            if (MimeTypes.isAudio(mimeType)) {\r\n                formatBuilder\r\n                    .setChannelCount(channelCount)\r\n                    .setSampleRate(sampleRate)\r\n                    .setPcmEncoding(pcmEncoding)\r\n            } else if (MimeTypes.isVideo(mimeType)) {\r\n                if (displayUnit == DISPLAY_UNIT_PIXELS) {\r\n                    displayWidth = if (displayWidth == Format.NO_VALUE) width else displayWidth\r\n                    displayHeight = if (displayHeight == Format.NO_VALUE) height else displayHeight\r\n                }\r\n                var pixelWidthHeightRatio = Format.NO_VALUE.toFloat()\r\n                if (displayWidth != Format.NO_VALUE && displayHeight != Format.NO_VALUE) {\r\n                    pixelWidthHeightRatio =\r\n                        ((height * displayWidth).toFloat()) / (width * displayHeight)\r\n                }\r\n                var colorInfo: ColorInfo? = null\r\n                if (hasColorInfo) {\r\n                    val hdrStaticInfo = hdrStaticInfo\r\n                    colorInfo =\r\n                        ColorInfo.Builder()\r\n                            .setColorSpace(colorSpace)\r\n                            .setColorRange(colorRange)\r\n                            .setColorTransfer(colorTransfer)\r\n                            .setHdrStaticInfo(hdrStaticInfo)\r\n                            .setLumaBitdepth(bitsPerChannel)\r\n                            .setChromaBitdepth(bitsPerChannel)\r\n                            .build()\r\n                }\r\n                var rotationDegrees = Format.NO_VALUE\r\n\r\n                if (name != null && TRACK_NAME_TO_ROTATION_DEGREES.containsKey(name)) {\r\n                    rotationDegrees = TRACK_NAME_TO_ROTATION_DEGREES[name]!!\r\n                }\r\n                if (projectionType == C.PROJECTION_RECTANGULAR && java.lang.Float.compare(\r\n                        projectionPoseYaw,\r\n                        0f\r\n                    ) == 0 && java.lang.Float.compare(projectionPosePitch, 0f) == 0\r\n                ) {\r\n                    // The range of projectionPoseRoll is [-180, 180].\r\n                    if (java.lang.Float.compare(projectionPoseRoll, 0f) == 0) {\r\n                        rotationDegrees = 0\r\n                    } else if (java.lang.Float.compare(projectionPoseRoll, 90f) == 0) {\r\n                        rotationDegrees = 90\r\n                    } else if (java.lang.Float.compare(projectionPoseRoll, -180f) == 0\r\n                        || java.lang.Float.compare(projectionPoseRoll, 180f) == 0\r\n                    ) {\r\n                        rotationDegrees = 180\r\n                    } else if (java.lang.Float.compare(projectionPoseRoll, -90f) == 0) {\r\n                        rotationDegrees = 270\r\n                    }\r\n                }\r\n                formatBuilder\r\n                    .setWidth(width)\r\n                    .setHeight(height)\r\n                    .setPixelWidthHeightRatio(pixelWidthHeightRatio)\r\n                    .setRotationDegrees(rotationDegrees)\r\n                    .setProjectionData(projectionData)\r\n                    .setStereoMode(stereoMode)\r\n                    .setColorInfo(colorInfo)\r\n            } else if (MimeTypes.APPLICATION_SUBRIP == mimeType\r\n                || MimeTypes.TEXT_SSA == mimeType\r\n                || MimeTypes.TEXT_VTT == mimeType\r\n                || MimeTypes.APPLICATION_VOBSUB == mimeType\r\n                || MimeTypes.APPLICATION_PGS == mimeType\r\n                || MimeTypes.APPLICATION_DVBSUBS == mimeType\r\n            ) {\r\n            } else {\r\n                throw ParserException.createForMalformedContainer(\r\n                    \"Unexpected MIME type.\",  /* cause= */null\r\n                )\r\n            }\r\n\r\n            if (name != null && !TRACK_NAME_TO_ROTATION_DEGREES.containsKey(name)) {\r\n                formatBuilder.setLabel(name)\r\n            }\r\n\r\n            format =\r\n                formatBuilder\r\n                    .setId(trackId)\r\n                    .setContainerMimeType(if (isWebm) MimeTypes.VIDEO_WEBM else MimeTypes.VIDEO_MATROSKA)\r\n                    .setSampleMimeType(mimeType)\r\n                    .setMaxInputSize(maxInputSize)\r\n                    .setLanguage(language)\r\n                    .setSelectionFlags(selectionFlags)\r\n                    .setInitializationData(initializationData)\r\n                    .setCodecs(codecs)\r\n                    .setDrmInitData(drmInitData)\r\n                    .build()\r\n        }\r\n\r\n        /** Forces any pending sample metadata to be flushed to the output.  */\r\n        fun outputPendingSampleMetadata() {\r\n            if (trueHdSampleRechunker != null) {\r\n                trueHdSampleRechunker!!.outputPendingSampleMetadata(output!!, cryptoData)\r\n            }\r\n        }\r\n\r\n        /** Resets any state stored in the track in response to a seek.  */\r\n        fun reset() {\r\n            if (trueHdSampleRechunker != null) {\r\n                trueHdSampleRechunker!!.reset()\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Returns true if supplemental data will be attached to the samples.\r\n         *\r\n         * @param isBlockGroup Whether the samples are from a BlockGroup.\r\n         */\r\n        fun samplesHaveSupplementalData(isBlockGroup: Boolean): Boolean {\r\n            if (CODEC_ID_OPUS == codecId) {\r\n                // At the end of a BlockGroup, a positive DiscardPadding value will be written out as\r\n                // supplemental data for Opus codec. Otherwise (i.e. DiscardPadding <= 0) supplemental data\r\n                // size will be 0.\r\n                return isBlockGroup\r\n            }\r\n            return maxBlockAdditionId > 0\r\n        }\r\n\r\n        private val hdrStaticInfo: ByteArray?\r\n            /** Returns the HDR Static Info as defined in CTA-861.3.  */\r\n            get() {\r\n                // Are all fields present.\r\n                if (primaryRChromaticityX == Format.NO_VALUE.toFloat() || primaryRChromaticityY == Format.NO_VALUE.toFloat() || primaryGChromaticityX == Format.NO_VALUE.toFloat() || primaryGChromaticityY == Format.NO_VALUE.toFloat() || primaryBChromaticityX == Format.NO_VALUE.toFloat() || primaryBChromaticityY == Format.NO_VALUE.toFloat() || whitePointChromaticityX == Format.NO_VALUE.toFloat() || whitePointChromaticityY == Format.NO_VALUE.toFloat() || maxMasteringLuminance == Format.NO_VALUE.toFloat() || minMasteringLuminance == Format.NO_VALUE.toFloat()) {\r\n                    return null\r\n                }\r\n\r\n                val hdrStaticInfoData = ByteArray(25)\r\n                val hdrStaticInfo =\r\n                    ByteBuffer.wrap(hdrStaticInfoData).order(ByteOrder.LITTLE_ENDIAN)\r\n                hdrStaticInfo.put(0.toByte()) // Type.\r\n                hdrStaticInfo.putShort(\r\n                    ((primaryRChromaticityX * MAX_CHROMATICITY) + 0.5f).toInt().toShort()\r\n                )\r\n                hdrStaticInfo.putShort(\r\n                    ((primaryRChromaticityY * MAX_CHROMATICITY) + 0.5f).toInt().toShort()\r\n                )\r\n                hdrStaticInfo.putShort(\r\n                    ((primaryGChromaticityX * MAX_CHROMATICITY) + 0.5f).toInt().toShort()\r\n                )\r\n                hdrStaticInfo.putShort(\r\n                    ((primaryGChromaticityY * MAX_CHROMATICITY) + 0.5f).toInt().toShort()\r\n                )\r\n                hdrStaticInfo.putShort(\r\n                    ((primaryBChromaticityX * MAX_CHROMATICITY) + 0.5f).toInt().toShort()\r\n                )\r\n                hdrStaticInfo.putShort(\r\n                    ((primaryBChromaticityY * MAX_CHROMATICITY) + 0.5f).toInt().toShort()\r\n                )\r\n                hdrStaticInfo.putShort(\r\n                    ((whitePointChromaticityX * MAX_CHROMATICITY) + 0.5f).toInt().toShort()\r\n                )\r\n                hdrStaticInfo.putShort(\r\n                    ((whitePointChromaticityY * MAX_CHROMATICITY) + 0.5f).toInt().toShort()\r\n                )\r\n                hdrStaticInfo.putShort((maxMasteringLuminance + 0.5f).toInt().toShort())\r\n                hdrStaticInfo.putShort((minMasteringLuminance + 0.5f).toInt().toShort())\r\n                hdrStaticInfo.putShort(maxContentLuminance.toShort())\r\n                hdrStaticInfo.putShort(maxFrameAverageLuminance.toShort())\r\n                return hdrStaticInfoData\r\n            }\r\n\r\n        /**\r\n         * Finds the best thumbnail timestamp from the cue points and adds it to the track's format as\r\n         * [ThumbnailMetadata].\r\n         */\r\n        fun maybeAddThumbnailMetadata(\r\n            perTrackCues: SparseArray<MutableList<MatroskaSeekMap.CuePointData>>,\r\n            durationUs: Long,\r\n            segmentContentPosition: Long,\r\n            segmentContentSize: Long\r\n        ) {\r\n            if (type != C.TRACK_TYPE_VIDEO) return\r\n\r\n            val cuePoints = perTrackCues[number]\r\n            if (cuePoints.isNullOrEmpty()) return\r\n\r\n            val thumbnailTimestampUs = findBestThumbnailPresentationTimeUs(\r\n                cuePoints, durationUs, segmentContentPosition, segmentContentSize\r\n            )\r\n\r\n            if (thumbnailTimestampUs != C.TIME_UNSET) {\r\n                val currentFormat = requireNotNull(format)\r\n                val existingMetadata = currentFormat.metadata\r\n                val thumbnailMetadata = ThumbnailMetadata(thumbnailTimestampUs)\r\n                val newMetadata = if (existingMetadata == null) {\r\n                    Metadata(thumbnailMetadata)\r\n                } else {\r\n                    existingMetadata.copyWithAppendedEntries(thumbnailMetadata)\r\n                }\r\n                format = currentFormat.buildUpon().setMetadata(newMetadata).build()\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Finds the best thumbnail timestamp from the provided cue points.\r\n         *\r\n         * <p>The heuristic seeks to find a visually interesting frame by assuming that a larger chunk\r\n         * size corresponds to a more complex and representative frame. It calculates an approximate\r\n         * bitrate for each chunk and selects the timestamp of the chunk with the highest bitrate.\r\n         */\r\n        private fun findBestThumbnailPresentationTimeUs(\r\n            cuePoints: MutableList<MatroskaSeekMap.CuePointData>,\r\n            durationUs: Long,\r\n            segmentContentPosition: Long,\r\n            segmentContentSize: Long\r\n        ): Long {\r\n            if (cuePoints.isEmpty()) return C.TIME_UNSET\r\n\r\n            var maxBitrate = 0.0\r\n            var bestCueIndex = -1\r\n            val scanLimit = min(cuePoints.size, MAX_CHUNKS_TO_SCAN_FOR_THUMBNAIL)\r\n\r\n            for (i in 0 until scanLimit) {\r\n                val cue = cuePoints[i]\r\n\r\n                if (cue.timeUs > MAX_DURATION_US_TO_SCAN_FOR_THUMBNAIL) break\r\n\r\n                val bytesBetweenCues: Long\r\n                val durationBetweenCuesUs: Long\r\n\r\n                if (i < cuePoints.size - 1) {\r\n                    val nextCue = cuePoints[i + 1]\r\n                    bytesBetweenCues = (nextCue.clusterPosition + nextCue.relativePosition) -\r\n                        (cue.clusterPosition + cue.relativePosition)\r\n                    durationBetweenCuesUs = nextCue.timeUs - cue.timeUs\r\n                } else {\r\n                    // Last cue point\r\n                    bytesBetweenCues = (segmentContentPosition + segmentContentSize) -\r\n                        (cue.clusterPosition + cue.relativePosition)\r\n                    durationBetweenCuesUs = durationUs - cue.timeUs\r\n                }\r\n\r\n                if (durationBetweenCuesUs > 0) {\r\n                    // This is an approximation of the bitrate for thumbnail heuristic.\r\n                    val bitrate = bytesBetweenCues.toDouble() / durationBetweenCuesUs\r\n                    if (bitrate > maxBitrate) {\r\n                        maxBitrate = bitrate\r\n                        bestCueIndex = i\r\n                    }\r\n                }\r\n            }\r\n\r\n            return if (bestCueIndex == -1) C.TIME_UNSET else cuePoints[bestCueIndex].timeUs\r\n        }\r\n\r\n        /**\r\n         * Checks that the track has an output.\r\n         *\r\n         *\r\n         * It is unfortunately not possible to mark [UpdatedMatroskaExtractor.tracks] as only\r\n         * containing tracks with output with the nullness checker. This method is used to check that\r\n         * fact at runtime.\r\n         */\r\n        fun assertOutputInitialized() {\r\n            checkNotNull<TrackOutput?>(\r\n                output\r\n            )\r\n        }\r\n\r\n        @Throws(ParserException::class)\r\n        private fun getCodecPrivate(codecId: String): ByteArray {\r\n            if (codecPrivate == null) {\r\n                throw ParserException.createForMalformedContainer(\r\n                    \"Missing CodecPrivate for codec $codecId\",  /* cause= */null\r\n                )\r\n            }\r\n            return codecPrivate!!\r\n        }\r\n\r\n        companion object {\r\n            private const val DISPLAY_UNIT_PIXELS = 0\r\n            private const val MAX_CHROMATICITY = 50000 // Defined in CTA-861.3.\r\n\r\n            /** Default max content light level (CLL) that should be encoded into hdrStaticInfo.  */\r\n            private const val DEFAULT_MAX_CLL = 1000 // nits.\r\n\r\n            /** Default frame-average light level (FALL) that should be encoded into hdrStaticInfo.  */\r\n            private const val DEFAULT_MAX_FALL = 200 // nits.\r\n\r\n            /**\r\n             * Builds initialization data for a [Format] from FourCC codec private data.\r\n             *\r\n             * @return The codec MIME type and initialization data. If the compression type is not supported\r\n             * then the MIME type is set to [MimeTypes.VIDEO_UNKNOWN] and the initialization data\r\n             * is `null`.\r\n             * @throws ParserException If the initialization data could not be built.\r\n             */\r\n            @Throws(ParserException::class)\r\n            private fun parseFourCcPrivate(\r\n                buffer: ParsableByteArray\r\n            ): Pair<String, List<ByteArray>> {\r\n                try {\r\n                    buffer.skipBytes(16) // size(4), width(4), height(4), planes(2), bitcount(2).\r\n                    val compression = buffer.readLittleEndianUnsignedInt()\r\n                    if (compression == FOURCC_COMPRESSION_DIVX.toLong()) {\r\n                        return Pair(MimeTypes.VIDEO_DIVX, null)\r\n                    } else if (compression == FOURCC_COMPRESSION_H263.toLong()) {\r\n                        return Pair(MimeTypes.VIDEO_H263, null)\r\n                    } else if (compression == FOURCC_COMPRESSION_VC1.toLong()) {\r\n                        // Search for the initialization data from the end of the BITMAPINFOHEADER. The last 20\r\n                        // bytes of which are: sizeImage(4), xPel/m (4), yPel/m (4), clrUsed(4), clrImportant(4).\r\n                        val startOffset = buffer.position + 20\r\n                        val bufferData = buffer.data\r\n                        for (offset in startOffset..<bufferData.size - 4) {\r\n                            if (bufferData[offset].toInt() == 0x00 && bufferData[offset + 1].toInt() == 0x00 && bufferData[offset + 2].toInt() == 0x01 && bufferData[offset + 3].toInt() == 0x0F) {\r\n                                // We've found the initialization data.\r\n                                val initializationData =\r\n                                    Arrays.copyOfRange(bufferData, offset, bufferData.size)\r\n                                return Pair(MimeTypes.VIDEO_VC1, listOf(initializationData))\r\n                            }\r\n                        }\r\n                        throw ParserException.createForMalformedContainer(\r\n                            \"Failed to find FourCC VC1 initialization data\",  /* cause= */null\r\n                        )\r\n                    }\r\n                } catch (e: ArrayIndexOutOfBoundsException) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"Error parsing FourCC private data\",  /* cause= */null\r\n                    )\r\n                }\r\n\r\n                Log.w(TAG, \"Unknown FourCC. Setting mimeType to \" + MimeTypes.VIDEO_UNKNOWN)\r\n                return Pair(MimeTypes.VIDEO_UNKNOWN, null)\r\n            }\r\n\r\n            /**\r\n             * Builds initialization data for a [Format] from Vorbis codec private data.\r\n             *\r\n             * @return The initialization data for the [Format].\r\n             * @throws ParserException If the initialization data could not be built.\r\n             */\r\n            @Throws(ParserException::class)\r\n            private fun parseVorbisCodecPrivate(codecPrivate: ByteArray): List<ByteArray> {\r\n                try {\r\n                    if (codecPrivate[0].toInt() != 0x02) {\r\n                        throw ParserException.createForMalformedContainer(\r\n                            \"Error parsing vorbis codec private\",  /* cause= */null\r\n                        )\r\n                    }\r\n                    var offset = 1\r\n                    var vorbisInfoLength = 0\r\n                    while ((codecPrivate[offset].toInt() and 0xFF) == 0xFF) {\r\n                        vorbisInfoLength += 0xFF\r\n                        offset++\r\n                    }\r\n                    vorbisInfoLength += codecPrivate[offset++].toInt() and 0xFF\r\n\r\n                    var vorbisSkipLength = 0\r\n                    while ((codecPrivate[offset].toInt() and 0xFF) == 0xFF) {\r\n                        vorbisSkipLength += 0xFF\r\n                        offset++\r\n                    }\r\n                    vorbisSkipLength += codecPrivate[offset++].toInt() and 0xFF\r\n\r\n                    if (codecPrivate[offset].toInt() != 0x01) {\r\n                        throw ParserException.createForMalformedContainer(\r\n                            \"Error parsing vorbis codec private\",  /* cause= */null\r\n                        )\r\n                    }\r\n                    val vorbisInfo = ByteArray(vorbisInfoLength)\r\n                    System.arraycopy(codecPrivate, offset, vorbisInfo, 0, vorbisInfoLength)\r\n                    offset += vorbisInfoLength\r\n                    if (codecPrivate[offset].toInt() != 0x03) {\r\n                        throw ParserException.createForMalformedContainer(\r\n                            \"Error parsing vorbis codec private\",  /* cause= */null\r\n                        )\r\n                    }\r\n                    offset += vorbisSkipLength\r\n                    if (codecPrivate[offset].toInt() != 0x05) {\r\n                        throw ParserException.createForMalformedContainer(\r\n                            \"Error parsing vorbis codec private\",  /* cause= */null\r\n                        )\r\n                    }\r\n                    val vorbisBooks = ByteArray(codecPrivate.size - offset)\r\n                    System.arraycopy(\r\n                        codecPrivate,\r\n                        offset,\r\n                        vorbisBooks,\r\n                        0,\r\n                        codecPrivate.size - offset\r\n                    )\r\n                    val initializationData: MutableList<ByteArray> = ArrayList(2)\r\n                    initializationData.add(vorbisInfo)\r\n                    initializationData.add(vorbisBooks)\r\n                    return initializationData\r\n                } catch (e: ArrayIndexOutOfBoundsException) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"Error parsing vorbis codec private\",  /* cause= */null\r\n                    )\r\n                }\r\n            }\r\n\r\n            /**\r\n             * Parses an MS/ACM codec private, returning whether it indicates PCM audio.\r\n             *\r\n             * @return Whether the codec private indicates PCM audio.\r\n             * @throws ParserException If a parsing error occurs.\r\n             */\r\n            @Throws(ParserException::class)\r\n            private fun parseMsAcmCodecPrivate(buffer: ParsableByteArray): Boolean {\r\n                try {\r\n                    val formatTag = buffer.readLittleEndianUnsignedShort()\r\n                    if (formatTag == WAVE_FORMAT_PCM) {\r\n                        return true\r\n                    } else if (formatTag == WAVE_FORMAT_EXTENSIBLE) {\r\n                        buffer.position = WAVE_FORMAT_SIZE + 6 // unionSamples(2), channelMask(4)\r\n                        return buffer.readLong() == WAVE_SUBFORMAT_PCM.mostSignificantBits\r\n                                && buffer.readLong() == WAVE_SUBFORMAT_PCM.leastSignificantBits\r\n                    } else {\r\n                        return false\r\n                    }\r\n                } catch (e: ArrayIndexOutOfBoundsException) {\r\n                    throw ParserException.createForMalformedContainer(\r\n                        \"Error parsing MS/ACM codec private\",  /* cause= */null\r\n                    )\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    companion object {\r\n        /**\r\n         * Creates a factory for [UpdatedMatroskaExtractor] instances with the provided [ ].\r\n         */\r\n        fun newFactory(subtitleParserFactory: SubtitleParser.Factory): ExtractorsFactory {\r\n            return ExtractorsFactory {\r\n                arrayOf<Extractor>(\r\n                    UpdatedMatroskaExtractor(subtitleParserFactory)\r\n                )\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Flag to disable seeking for cues.\r\n         *\r\n         *\r\n         * Normally (i.e. when this flag is not set) the extractor will seek to the cues element if its\r\n         * position is specified in the seek head and if it's after the first cluster. Setting this flag\r\n         * disables seeking to the cues element. If the cues element is after the first cluster then the\r\n         * media is treated as being unseekable.\r\n         */\r\n        const val FLAG_DISABLE_SEEK_FOR_CUES: Int = 1\r\n\r\n        /**\r\n         * Flag to use the source subtitle formats without modification. If unset, subtitles will be\r\n         * transcoded to [MimeTypes.APPLICATION_MEDIA3_CUES] during extraction.\r\n         */\r\n        const val FLAG_EMIT_RAW_SUBTITLE_DATA: Int = 1 shl 1 // 2\r\n\r\n        @Deprecated(\"Use {@link #newFactory(SubtitleParser.Factory)} instead.\")\r\n        val FACTORY: ExtractorsFactory = ExtractorsFactory {\r\n            arrayOf<Extractor>(\r\n                UpdatedMatroskaExtractor(\r\n                    SubtitleParser.Factory.UNSUPPORTED,\r\n                    FLAG_EMIT_RAW_SUBTITLE_DATA\r\n                )\r\n            )\r\n        }\r\n\r\n        private const val TAG = \"MatroskaExtractor\"\r\n\r\n        private const val UNSET_ENTRY_ID = -1\r\n\r\n        private const val BLOCK_STATE_START = 0\r\n        private const val BLOCK_STATE_HEADER = 1\r\n        private const val BLOCK_STATE_DATA = 2\r\n\r\n        private const val DOC_TYPE_MATROSKA = \"matroska\"\r\n        private const val DOC_TYPE_WEBM = \"webm\"\r\n        private const val CODEC_ID_VP8 = \"V_VP8\"\r\n        private const val CODEC_ID_VP9 = \"V_VP9\"\r\n        private const val CODEC_ID_AV1 = \"V_AV1\"\r\n        private const val CODEC_ID_MPEG2 = \"V_MPEG2\"\r\n        private const val CODEC_ID_MPEG4_SP = \"V_MPEG4/ISO/SP\"\r\n        private const val CODEC_ID_MPEG4_ASP = \"V_MPEG4/ISO/ASP\"\r\n        private const val CODEC_ID_MPEG4_AP = \"V_MPEG4/ISO/AP\"\r\n        private const val CODEC_ID_H264 = \"V_MPEG4/ISO/AVC\"\r\n        private const val CODEC_ID_H265 = \"V_MPEGH/ISO/HEVC\"\r\n        private const val CODEC_ID_FOURCC = \"V_MS/VFW/FOURCC\"\r\n        private const val CODEC_ID_THEORA = \"V_THEORA\"\r\n        private const val CODEC_ID_VORBIS = \"A_VORBIS\"\r\n        private const val CODEC_ID_OPUS = \"A_OPUS\"\r\n        private const val CODEC_ID_AAC = \"A_AAC\"\r\n        private const val CODEC_ID_MP2 = \"A_MPEG/L2\"\r\n        private const val CODEC_ID_MP3 = \"A_MPEG/L3\"\r\n        private const val CODEC_ID_AC3 = \"A_AC3\"\r\n        private const val CODEC_ID_E_AC3 = \"A_EAC3\"\r\n        private const val CODEC_ID_TRUEHD = \"A_TRUEHD\"\r\n        private const val CODEC_ID_DTS = \"A_DTS\"\r\n        private const val CODEC_ID_DTS_EXPRESS = \"A_DTS/EXPRESS\"\r\n        private const val CODEC_ID_DTS_LOSSLESS = \"A_DTS/LOSSLESS\"\r\n        private const val CODEC_ID_FLAC = \"A_FLAC\"\r\n        private const val CODEC_ID_ACM = \"A_MS/ACM\"\r\n        private const val CODEC_ID_PCM_INT_LIT = \"A_PCM/INT/LIT\"\r\n        private const val CODEC_ID_PCM_INT_BIG = \"A_PCM/INT/BIG\"\r\n        private const val CODEC_ID_PCM_FLOAT = \"A_PCM/FLOAT/IEEE\"\r\n        private const val CODEC_ID_SUBRIP = \"S_TEXT/UTF8\"\r\n        private const val CODEC_ID_ASS = \"S_TEXT/ASS\"\r\n        private const val CODEC_ID_SSA = \"S_TEXT/SSA\"\r\n        private const val CODEC_ID_VTT = \"S_TEXT/WEBVTT\"\r\n        private const val CODEC_ID_VOBSUB = \"S_VOBSUB\"\r\n        private const val CODEC_ID_PGS = \"S_HDMV/PGS\"\r\n        private const val CODEC_ID_DVBSUB = \"S_DVBSUB\"\r\n\r\n        private const val VORBIS_MAX_INPUT_SIZE = 8192\r\n        private const val OPUS_MAX_INPUT_SIZE = 5760\r\n        private const val ENCRYPTION_IV_SIZE = 8\r\n        private const val TRACK_TYPE_AUDIO = 2\r\n\r\n        private const val ID_EBML = 0x1A45DFA3\r\n        private const val ID_EBML_READ_VERSION = 0x42F7\r\n        private const val ID_DOC_TYPE = 0x4282\r\n        private const val ID_DOC_TYPE_READ_VERSION = 0x4285\r\n        private const val ID_SEGMENT = 0x18538067\r\n        private const val ID_SEGMENT_INFO = 0x1549A966\r\n        private const val ID_SEEK_HEAD = 0x114D9B74\r\n        private const val ID_SEEK = 0x4DBB\r\n        private const val ID_SEEK_ID = 0x53AB\r\n        private const val ID_SEEK_POSITION = 0x53AC\r\n        private const val ID_INFO = 0x1549A966\r\n        private const val ID_TIMECODE_SCALE = 0x2AD7B1\r\n        private const val ID_DURATION = 0x4489\r\n        private const val ID_CLUSTER = 0x1F43B675\r\n        private const val ID_TIME_CODE = 0xE7\r\n        private const val ID_SIMPLE_BLOCK = 0xA3\r\n        private const val ID_BLOCK_GROUP = 0xA0\r\n        private const val ID_BLOCK = 0xA1\r\n        private const val ID_BLOCK_DURATION = 0x9B\r\n        private const val ID_BLOCK_ADDITIONS = 0x75A1\r\n        private const val ID_BLOCK_MORE = 0xA6\r\n        private const val ID_BLOCK_ADD_ID = 0xEE\r\n        private const val ID_BLOCK_ADDITIONAL = 0xA5\r\n        private const val ID_REFERENCE_BLOCK = 0xFB\r\n        private const val ID_TRACKS = 0x1654AE6B\r\n        private const val ID_TRACK_ENTRY = 0xAE\r\n        private const val ID_TRACK_NUMBER = 0xD7\r\n        private const val ID_TRACK_TYPE = 0x83\r\n        private const val ID_FLAG_DEFAULT = 0x88\r\n        private const val ID_FLAG_FORCED = 0x55AA\r\n        private const val ID_DEFAULT_DURATION = 0x23E383\r\n        private const val ID_MAX_BLOCK_ADDITION_ID = 0x55EE\r\n        private const val ID_BLOCK_ADDITION_MAPPING = 0x41E4\r\n        private const val ID_BLOCK_ADD_ID_TYPE = 0x41E7\r\n        private const val ID_BLOCK_ADD_ID_EXTRA_DATA = 0x41ED\r\n        private const val ID_NAME = 0x536E\r\n        private const val ID_CODEC_ID = 0x86\r\n        private const val ID_CODEC_PRIVATE = 0x63A2\r\n        private const val ID_CODEC_DELAY = 0x56AA\r\n        private const val ID_SEEK_PRE_ROLL = 0x56BB\r\n        private const val ID_DISCARD_PADDING = 0x75A2\r\n        private const val ID_VIDEO = 0xE0\r\n        private const val ID_PIXEL_WIDTH = 0xB0\r\n        private const val ID_PIXEL_HEIGHT = 0xBA\r\n        private const val ID_DISPLAY_WIDTH = 0x54B0\r\n        private const val ID_DISPLAY_HEIGHT = 0x54BA\r\n        private const val ID_DISPLAY_UNIT = 0x54B2\r\n        private const val ID_AUDIO = 0xE1\r\n        private const val ID_CHANNELS = 0x9F\r\n        private const val ID_AUDIO_BIT_DEPTH = 0x6264\r\n        private const val ID_SAMPLING_FREQUENCY = 0xB5\r\n        private const val ID_CONTENT_ENCODINGS = 0x6D80\r\n        private const val ID_CONTENT_ENCODING = 0x6240\r\n        private const val ID_CONTENT_ENCODING_ORDER = 0x5031\r\n        private const val ID_CONTENT_ENCODING_SCOPE = 0x5032\r\n        private const val ID_CONTENT_COMPRESSION = 0x5034\r\n        private const val ID_CONTENT_COMPRESSION_ALGORITHM = 0x4254\r\n        private const val ID_CONTENT_COMPRESSION_SETTINGS = 0x4255\r\n        private const val ID_CONTENT_ENCRYPTION = 0x5035\r\n        private const val ID_CONTENT_ENCRYPTION_ALGORITHM = 0x47E1\r\n        private const val ID_CONTENT_ENCRYPTION_KEY_ID = 0x47E2\r\n        private const val ID_CONTENT_ENCRYPTION_AES_SETTINGS = 0x47E7\r\n        private const val ID_CONTENT_ENCRYPTION_AES_SETTINGS_CIPHER_MODE = 0x47E8\r\n        private const val ID_CUES = 0x1C53BB6B\r\n        private const val ID_CUE_POINT = 0xBB\r\n        private const val ID_CUE_TIME = 0xB3\r\n        private const val ID_CUE_TRACK = 0xF7\r\n        private const val ID_CUE_TRACK_POSITIONS = 0xB7\r\n        private const val ID_CUE_CLUSTER_POSITION = 0xF1\r\n        private const val ID_CUE_RELATIVE_POSITION = 0xF0\r\n        private const val ID_LANGUAGE = 0x22B59C\r\n        private const val ID_PROJECTION = 0x7670\r\n        private const val ID_PROJECTION_TYPE = 0x7671\r\n        private const val ID_PROJECTION_PRIVATE = 0x7672\r\n        private const val ID_PROJECTION_POSE_YAW = 0x7673\r\n        private const val ID_PROJECTION_POSE_PITCH = 0x7674\r\n        private const val ID_PROJECTION_POSE_ROLL = 0x7675\r\n        private const val ID_STEREO_MODE = 0x53B8\r\n        private const val ID_COLOUR = 0x55B0\r\n        private const val ID_COLOUR_RANGE = 0x55B9\r\n        private const val ID_COLOUR_BITS_PER_CHANNEL = 0x55B2\r\n        private const val ID_COLOUR_TRANSFER = 0x55BA\r\n        private const val ID_COLOUR_PRIMARIES = 0x55BB\r\n        private const val ID_MAX_CLL = 0x55BC\r\n        private const val ID_MAX_FALL = 0x55BD\r\n        private const val ID_MASTERING_METADATA = 0x55D0\r\n        private const val ID_PRIMARY_R_CHROMATICITY_X = 0x55D1\r\n        private const val ID_PRIMARY_R_CHROMATICITY_Y = 0x55D2\r\n        private const val ID_PRIMARY_G_CHROMATICITY_X = 0x55D3\r\n        private const val ID_PRIMARY_G_CHROMATICITY_Y = 0x55D4\r\n        private const val ID_PRIMARY_B_CHROMATICITY_X = 0x55D5\r\n        private const val ID_PRIMARY_B_CHROMATICITY_Y = 0x55D6\r\n        private const val ID_WHITE_POINT_CHROMATICITY_X = 0x55D7\r\n        private const val ID_WHITE_POINT_CHROMATICITY_Y = 0x55D8\r\n        private const val ID_LUMNINANCE_MAX = 0x55D9\r\n        private const val ID_LUMNINANCE_MIN = 0x55DA\r\n\r\n        /**\r\n         * BlockAddID value for ITU T.35 metadata in a VP9 track. See also\r\n         * https://www.webmproject.org/docs/container/.\r\n         */\r\n        private const val BLOCK_ADDITIONAL_ID_VP9_ITU_T_35 = 4\r\n\r\n        /**\r\n         * BlockAddIdType value for Dolby Vision configuration with profile <= 7. See also\r\n         * https://www.matroska.org/technical/codec_specs.html.\r\n         */\r\n        private const val BLOCK_ADD_ID_TYPE_DVCC = 0x64766343\r\n\r\n        /**\r\n         * BlockAddIdType value for Dolby Vision configuration with profile > 7. See also\r\n         * https://www.matroska.org/technical/codec_specs.html.\r\n         */\r\n        private const val BLOCK_ADD_ID_TYPE_DVVC = 0x64767643\r\n\r\n        private const val LACING_NONE = 0\r\n        private const val LACING_XIPH = 1\r\n        private const val LACING_FIXED_SIZE = 2\r\n        private const val LACING_EBML = 3\r\n\r\n        private const val FOURCC_COMPRESSION_DIVX = 0x58564944\r\n        private const val FOURCC_COMPRESSION_H263 = 0x33363248\r\n        private const val FOURCC_COMPRESSION_VC1 = 0x31435657\r\n\r\n        /** The maximum number of chunks to scan when searching for a thumbnail. */\r\n        private const val MAX_CHUNKS_TO_SCAN_FOR_THUMBNAIL = 20\r\n\r\n        /** The maximum duration to scan for a thumbnail, in microseconds. */\r\n        private const val MAX_DURATION_US_TO_SCAN_FOR_THUMBNAIL = 10_000_000L\r\n\r\n        /**\r\n         * A template for the prefix that must be added to each subrip sample.\r\n         *\r\n         *\r\n         * The display time of each subtitle is passed as `timeUs` to [ ][TrackOutput.sampleMetadata]. The start and end timecodes in this template are relative to\r\n         * `timeUs`. Hence the start timecode is always zero. The 12 byte end timecode starting at\r\n         * [.SUBRIP_PREFIX_END_TIMECODE_OFFSET] is set to a placeholder value, and must be replaced\r\n         * with the duration of the subtitle.\r\n         *\r\n         *\r\n         * Equivalent to the UTF-8 string: \"1\\n00:00:00,000 --> 00:00:00,000\\n\".\r\n         */\r\n        private val SUBRIP_PREFIX = byteArrayOf(\r\n            49,\r\n            10,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            44,\r\n            48,\r\n            48,\r\n            48,\r\n            32,\r\n            45,\r\n            45,\r\n            62,\r\n            32,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            44,\r\n            48,\r\n            48,\r\n            48,\r\n            10\r\n        )\r\n\r\n        /** The byte offset of the end timecode in [.SUBRIP_PREFIX].  */\r\n        private const val SUBRIP_PREFIX_END_TIMECODE_OFFSET = 19\r\n\r\n        /**\r\n         * The value by which to divide a time in microseconds to convert it to the unit of the last value\r\n         * in a subrip timecode (milliseconds).\r\n         */\r\n        private const val SUBRIP_TIMECODE_LAST_VALUE_SCALING_FACTOR: Long = 1000\r\n\r\n        /** The format of a subrip timecode.  */\r\n        private const val SUBRIP_TIMECODE_FORMAT = \"%02d:%02d:%02d,%03d\"\r\n\r\n        /** Matroska specific format line for SSA subtitles.  */\r\n        private val SSA_DIALOGUE_FORMAT = Util.getUtf8Bytes(\r\n            \"Format: Start, End, \"\r\n                    + \"ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text\"\r\n        )\r\n\r\n        /**\r\n         * A template for the prefix that must be added to each SSA sample.\r\n         *\r\n         *\r\n         * The display time of each subtitle is passed as `timeUs` to [ ][TrackOutput.sampleMetadata]. The start and end timecodes in this template are relative to\r\n         * `timeUs`. Hence the start timecode is always zero. The 12 byte end timecode starting at\r\n         * [.SUBRIP_PREFIX_END_TIMECODE_OFFSET] is set to a placeholder value, and must be replaced\r\n         * with the duration of the subtitle.\r\n         *\r\n         *\r\n         * Equivalent to the UTF-8 string: \"Dialogue: 0:00:00:00,0:00:00:00,\".\r\n         */\r\n        private val SSA_PREFIX = byteArrayOf(\r\n            68,\r\n            105,\r\n            97,\r\n            108,\r\n            111,\r\n            103,\r\n            117,\r\n            101,\r\n            58,\r\n            32,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            44,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            44\r\n        )\r\n\r\n        /** The byte offset of the end timecode in [.SSA_PREFIX].  */\r\n        private const val SSA_PREFIX_END_TIMECODE_OFFSET = 21\r\n\r\n        /**\r\n         * The value by which to divide a time in microseconds to convert it to the unit of the last value\r\n         * in an SSA timecode (1/100ths of a second).\r\n         */\r\n        private const val SSA_TIMECODE_LAST_VALUE_SCALING_FACTOR: Long = 10000\r\n\r\n        /** The format of an SSA timecode.  */\r\n        private const val SSA_TIMECODE_FORMAT = \"%01d:%02d:%02d:%02d\"\r\n\r\n        /**\r\n         * A template for the prefix that must be added to each VTT sample.\r\n         *\r\n         *\r\n         * The display time of each subtitle is passed as `timeUs` to [ ][TrackOutput.sampleMetadata]. The start and end timecodes in this template are relative to\r\n         * `timeUs`. Hence the start timecode is always zero. The 12 byte end timecode starting at\r\n         * [.VTT_PREFIX_END_TIMECODE_OFFSET] is set to a placeholder value, and must be replaced\r\n         * with the duration of the subtitle.\r\n         *\r\n         *\r\n         * Equivalent to the UTF-8 string: \"WEBVTT\\n\\n00:00:00.000 --> 00:00:00.000\\n\".\r\n         */\r\n        private val VTT_PREFIX = byteArrayOf(\r\n            87,\r\n            69,\r\n            66,\r\n            86,\r\n            84,\r\n            84,\r\n            10,\r\n            10,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            46,\r\n            48,\r\n            48,\r\n            48,\r\n            32,\r\n            45,\r\n            45,\r\n            62,\r\n            32,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            58,\r\n            48,\r\n            48,\r\n            46,\r\n            48,\r\n            48,\r\n            48,\r\n            10\r\n        )\r\n\r\n        /** The byte offset of the end timecode in [.VTT_PREFIX].  */\r\n        private const val VTT_PREFIX_END_TIMECODE_OFFSET = 25\r\n\r\n        /**\r\n         * The value by which to divide a time in microseconds to convert it to the unit of the last value\r\n         * in a VTT timecode (milliseconds).\r\n         */\r\n        private const val VTT_TIMECODE_LAST_VALUE_SCALING_FACTOR: Long = 1000\r\n\r\n        /** The format of a VTT timecode.  */\r\n        private const val VTT_TIMECODE_FORMAT = \"%02d:%02d:%02d.%03d\"\r\n\r\n        /** The length in bytes of a WAVEFORMATEX structure.  */\r\n        private const val WAVE_FORMAT_SIZE = 18\r\n\r\n        /** Format tag indicating a WAVEFORMATEXTENSIBLE structure.  */\r\n        private const val WAVE_FORMAT_EXTENSIBLE = 0xFFFE\r\n\r\n        /** Format tag for PCM.  */\r\n        private const val WAVE_FORMAT_PCM = 1\r\n\r\n        /** Sub format for PCM.  */\r\n        private val WAVE_SUBFORMAT_PCM = UUID(0x0100000000001000L, -0x7fffff55ffc7648fL)\r\n\r\n        /** Some HTC devices signal rotation in track names.  */\r\n        private val TRACK_NAME_TO_ROTATION_DEGREES: Map<String, Int>\r\n\r\n        init {\r\n            val trackNameToRotationDegrees: MutableMap<String, Int> = HashMap()\r\n            trackNameToRotationDegrees[\"htc_video_rotA-000\"] = 0\r\n            trackNameToRotationDegrees[\"htc_video_rotA-090\"] = 90\r\n            trackNameToRotationDegrees[\"htc_video_rotA-180\"] = 180\r\n            trackNameToRotationDegrees[\"htc_video_rotA-270\"] = 270\r\n            TRACK_NAME_TO_ROTATION_DEGREES = Collections.unmodifiableMap(trackNameToRotationDegrees)\r\n        }\r\n\r\n        /**\r\n         * Overwrites the end timecode in `subtitleData` with the correctly formatted time derived\r\n         * from `durationUs`.\r\n         *\r\n         *\r\n         * See documentation on [.SSA_DIALOGUE_FORMAT] and [.SUBRIP_PREFIX] for why we use\r\n         * the duration as the end timecode.\r\n         *\r\n         * @param codecId The subtitle codec; must be [.CODEC_ID_SUBRIP], [.CODEC_ID_ASS],\r\n         * [.CODEC_ID_SSA] or [.CODEC_ID_VTT].\r\n         * @param durationUs The duration of the sample, in microseconds.\r\n         * @param subtitleData The subtitle sample in which to overwrite the end timecode (output\r\n         * parameter).\r\n         */\r\n        private fun setSubtitleEndTime(codecId: String, durationUs: Long, subtitleData: ByteArray) {\r\n            val endTimecode: ByteArray\r\n            val endTimecodeOffset: Int\r\n            when (codecId) {\r\n                CODEC_ID_SUBRIP -> {\r\n                    endTimecode =\r\n                        formatSubtitleTimecode(\r\n                            durationUs,\r\n                            SUBRIP_TIMECODE_FORMAT,\r\n                            SUBRIP_TIMECODE_LAST_VALUE_SCALING_FACTOR\r\n                        )\r\n                    endTimecodeOffset = SUBRIP_PREFIX_END_TIMECODE_OFFSET\r\n                }\r\n\r\n                CODEC_ID_ASS, CODEC_ID_SSA -> {\r\n                    endTimecode =\r\n                        formatSubtitleTimecode(\r\n                            durationUs, SSA_TIMECODE_FORMAT, SSA_TIMECODE_LAST_VALUE_SCALING_FACTOR\r\n                        )\r\n                    endTimecodeOffset = SSA_PREFIX_END_TIMECODE_OFFSET\r\n                }\r\n\r\n                CODEC_ID_VTT -> {\r\n                    endTimecode =\r\n                        formatSubtitleTimecode(\r\n                            durationUs, VTT_TIMECODE_FORMAT, VTT_TIMECODE_LAST_VALUE_SCALING_FACTOR\r\n                        )\r\n                    endTimecodeOffset = VTT_PREFIX_END_TIMECODE_OFFSET\r\n                }\r\n\r\n                else -> throw IllegalArgumentException()\r\n            }\r\n            System.arraycopy(endTimecode, 0, subtitleData, endTimecodeOffset, endTimecode.size)\r\n        }\r\n\r\n        /**\r\n         * Formats `timeUs` using `timecodeFormat`, and sets it as the end timecode in `subtitleSampleData`.\r\n         */\r\n        private fun formatSubtitleTimecode(\r\n            timeUs: Long, timecodeFormat: String, lastTimecodeValueScalingFactor: Long\r\n        ): ByteArray {\r\n            var timeUs = timeUs\r\n            checkArgument(timeUs != C.TIME_UNSET)\r\n            val timeCodeData: ByteArray\r\n            val hours = (timeUs / (3600 * C.MICROS_PER_SECOND)).toInt()\r\n            timeUs -= (hours * 3600L * C.MICROS_PER_SECOND)\r\n            val minutes = (timeUs / (60 * C.MICROS_PER_SECOND)).toInt()\r\n            timeUs -= (minutes * 60L * C.MICROS_PER_SECOND)\r\n            val seconds = (timeUs / C.MICROS_PER_SECOND).toInt()\r\n            timeUs -= (seconds * C.MICROS_PER_SECOND)\r\n            val lastValue = (timeUs / lastTimecodeValueScalingFactor).toInt()\r\n            timeCodeData =\r\n                Util.getUtf8Bytes(\r\n                    String.format(Locale.US, timecodeFormat, hours, minutes, seconds, lastValue)\r\n                )\r\n            return timeCodeData\r\n        }\r\n\r\n        private fun isCodecSupported(codecId: String): Boolean {\r\n            return when (codecId) {\r\n                CODEC_ID_VP8, CODEC_ID_VP9, CODEC_ID_AV1, CODEC_ID_MPEG2, CODEC_ID_MPEG4_SP, CODEC_ID_MPEG4_ASP, CODEC_ID_MPEG4_AP, CODEC_ID_H264, CODEC_ID_H265, CODEC_ID_FOURCC, CODEC_ID_THEORA, CODEC_ID_OPUS, CODEC_ID_VORBIS, CODEC_ID_AAC, CODEC_ID_MP2, CODEC_ID_MP3, CODEC_ID_AC3, CODEC_ID_E_AC3, CODEC_ID_TRUEHD, CODEC_ID_DTS, CODEC_ID_DTS_EXPRESS, CODEC_ID_DTS_LOSSLESS, CODEC_ID_FLAC, CODEC_ID_ACM, CODEC_ID_PCM_INT_LIT, CODEC_ID_PCM_INT_BIG, CODEC_ID_PCM_FLOAT, CODEC_ID_SUBRIP, CODEC_ID_ASS, CODEC_ID_SSA, CODEC_ID_VTT, CODEC_ID_VOBSUB, CODEC_ID_PGS, CODEC_ID_DVBSUB -> true\r\n\r\n                else -> false\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Returns an array that can store (at least) `length` elements, which will be either a new\r\n         * array or `array` if it's not null and large enough.\r\n         */\r\n        private fun ensureArrayCapacity(array: IntArray?, length: Int): IntArray {\r\n            return if (array == null) {\r\n                IntArray(length)\r\n            } else if (array.size >= length) {\r\n                array\r\n            } else {\r\n                // Double the size to avoid allocating constantly if the required length increases gradually.\r\n                IntArray(\r\n                    max((array.size * 2).toDouble(), length.toDouble())\r\n                        .toInt()\r\n                )\r\n            }\r\n        }\r\n    }\r\n\r\n    class MatroskaSeekMap(\r\n        private val perTrackCues: SparseArray<MutableList<CuePointData>>,\r\n        private val durationUs: Long,\r\n        private val primarySeekTrackNumber: Int,\r\n        segmentContentPosition: Long,\r\n        segmentContentSize: Long\r\n    ) : TrackAwareSeekMap, ChunkIndexProvider {\r\n\r\n        private val chunkIndex: ChunkIndex? =\r\n            buildChunkIndex(\r\n                perTrackCues,\r\n                durationUs,\r\n                primarySeekTrackNumber,\r\n                segmentContentPosition,\r\n                segmentContentSize\r\n            )\r\n\r\n        override fun isSeekable(): Boolean {\r\n            // The media is seekable overall only if the primary seek track has cue points.\r\n            return isSeekable(primarySeekTrackNumber)\r\n        }\r\n\r\n        override fun isSeekable(trackId: Int): Boolean {\r\n            val cuePoints = perTrackCues[trackId]\r\n            return !cuePoints.isNullOrEmpty()\r\n        }\r\n\r\n        override fun getDurationUs(): Long = durationUs\r\n\r\n        override fun getSeekPoints(timeUs: Long): SeekPoints =\r\n            chunkIndex?.getSeekPoints(timeUs)\r\n                ?: SeekPoints(SeekPoint.START)\r\n\r\n        override fun getSeekPoints(timeUs: Long, trackId: Int): SeekPoints {\r\n            var cuePoints = perTrackCues[trackId]\r\n\r\n            if ((cuePoints.isNullOrEmpty()) && trackId != primarySeekTrackNumber) {\r\n                cuePoints = perTrackCues[primarySeekTrackNumber]\r\n            }\r\n\r\n            if (cuePoints.isNullOrEmpty()) {\r\n                return SeekPoints(SeekPoint.START)\r\n            }\r\n\r\n            val bestIndex = Util.binarySearchFloor(\r\n                cuePoints,\r\n                CuePointData(timeUs, C.INDEX_UNSET.toLong(), C.INDEX_UNSET.toLong()),\r\n                /* inclusive= */ true,\r\n                /* stayInBounds= */ false\r\n            )\r\n\r\n            return if (bestIndex != -1) {\r\n                val bestCue = cuePoints[bestIndex]\r\n                val firstPoint = SeekPoint(bestCue.timeUs, bestCue.clusterPosition)\r\n\r\n                if (bestCue.timeUs < timeUs && bestIndex + 1 < cuePoints.size) {\r\n                    val nextCue = cuePoints[bestIndex + 1]\r\n                    val secondPoint = SeekPoint(nextCue.timeUs, nextCue.clusterPosition)\r\n                    SeekPoints(firstPoint, secondPoint)\r\n                } else {\r\n                    SeekPoints(firstPoint)\r\n                }\r\n            } else {\r\n                val firstCue = cuePoints[0]\r\n                SeekPoints(SeekPoint(firstCue.timeUs, firstCue.clusterPosition))\r\n            }\r\n        }\r\n\r\n        override fun getChunkIndex(): ChunkIndex? = chunkIndex\r\n\r\n        private companion object {\r\n\r\n            private fun buildChunkIndex(\r\n                perTrackCues: SparseArray<MutableList<CuePointData>>,\r\n                durationUs: Long,\r\n                primarySeekTrackNumber: Int,\r\n                segmentContentPosition: Long,\r\n                segmentContentSize: Long\r\n            ): ChunkIndex? {\r\n\r\n                val primaryTrackCuePoints =\r\n                    perTrackCues[primarySeekTrackNumber] ?: return null\r\n\r\n                if (primaryTrackCuePoints.isEmpty()) {\r\n                    return null\r\n                }\r\n\r\n                val cuePointsSize = primaryTrackCuePoints.size\r\n                var sizes = IntArray(cuePointsSize)\r\n                var offsets = LongArray(cuePointsSize)\r\n                var durationsUs = LongArray(cuePointsSize)\r\n                var timesUs = LongArray(cuePointsSize)\r\n\r\n                for (i in 0 until cuePointsSize) {\r\n                    val cue = primaryTrackCuePoints[i]\r\n                    timesUs[i] = cue.timeUs\r\n                    offsets[i] = cue.clusterPosition\r\n                }\r\n\r\n                for (i in 0 until cuePointsSize - 1) {\r\n                    sizes[i] = (offsets[i + 1] - offsets[i]).toInt()\r\n                    durationsUs[i] = timesUs[i + 1] - timesUs[i]\r\n                }\r\n\r\n                // Start from the last cue point and move backward until a valid duration is found.\r\n                var lastValidIndex = cuePointsSize - 1\r\n                while (lastValidIndex > 0 && timesUs[lastValidIndex] >= durationUs) {\r\n                    lastValidIndex--\r\n                }\r\n\r\n                // Calculate sizes and durations for the last valid index\r\n                sizes[lastValidIndex] =\r\n                    (segmentContentPosition + segmentContentSize - offsets[lastValidIndex]).toInt()\r\n                durationsUs[lastValidIndex] = durationUs - timesUs[lastValidIndex]\r\n\r\n                // If trailing cue points were found, truncate the arrays to the last valid index.\r\n                if (lastValidIndex < cuePointsSize - 1) {\r\n                    Log.w(TAG, \"Discarding trailing cue points with timestamps greater than total duration.\")\r\n                    sizes = sizes.copyOf(lastValidIndex + 1)\r\n                    offsets = offsets.copyOf(lastValidIndex + 1)\r\n                    durationsUs = durationsUs.copyOf(lastValidIndex + 1)\r\n                    timesUs = timesUs.copyOf(lastValidIndex + 1)\r\n                }\r\n\r\n                return ChunkIndex(sizes, offsets, durationsUs, timesUs)\r\n            }\r\n        }\r\n\r\n        class CuePointData(\r\n            /** The timestamp of the cue point, in microseconds. */\r\n            val timeUs: Long,\r\n\r\n            /** The absolute byte offset of the start of the cluster containing this cue point. */\r\n            val clusterPosition: Long,\r\n\r\n            /**\r\n             * The relative byte offset of the cue point's data block within its cluster.\r\n             *\r\n             * <p>Note: For seeking, use {@link #clusterPosition} to prevent A/V desync.\r\n             */\r\n            val relativePosition: Long\r\n        ) : Comparable<CuePointData> {\r\n\r\n            override fun compareTo(other: CuePointData): Int {\r\n                return timeUs.compareTo(other.timeUs)\r\n            }\r\n\r\n            override fun equals(other: Any?): Boolean {\r\n                if (this === other) {\r\n                    return true\r\n                }\r\n                if (other !is CuePointData) {\r\n                    return false\r\n                }\r\n                return this.timeUs == other.timeUs &&\r\n                    this.clusterPosition == other.clusterPosition &&\r\n                    this.relativePosition == other.relativePosition\r\n            }\r\n\r\n            override fun hashCode(): Int {\r\n                return Objects.hash(timeUs, clusterPosition, relativePosition)\r\n            }\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/source_priority/PriorityAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.player.source_priority\n\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport com.lagradost.cloudstream3.databinding.PlayerPrioritizeItemBinding\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\n\ndata class SourcePriority<T>(\n    val data: T,\n    val name: String,\n    var priority: Int\n)\n\nclass PriorityAdapter<T>() :\n    NoStateAdapter<SourcePriority<T>>() {\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            PlayerPrioritizeItemBinding.inflate(\n                LayoutInflater.from(parent.context),\n                parent,\n                false\n            )\n        )\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Any>,\n        item: SourcePriority<T>,\n        position: Int\n    ) {\n        val binding = holder.view as? PlayerPrioritizeItemBinding ?: return\n        binding.priorityText.text = item.name\n\n        fun updatePriority() {\n            binding.priorityNumber.text = item.priority.toString()\n        }\n\n        updatePriority()\n        binding.addButton.setOnClickListener {\n            // If someone clicks til the integer limit then they deserve to crash.\n            item.priority++\n            updatePriority()\n        }\n\n        binding.subtractButton.setOnClickListener {\n            item.priority--\n            updatePriority()\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/source_priority/ProfilesAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.player.source_priority\n\nimport android.content.res.ColorStateList\nimport android.graphics.Typeface\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.core.content.ContextCompat\nimport androidx.core.view.isVisible\nimport androidx.palette.graphics.Palette\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.PlayerQualityProfileItemBinding\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.drawableToBitmap\nimport com.lagradost.cloudstream3.utils.setText\n\nclass ProfilesAdapter(\n    val usedProfile: Int?,\n    val clickCallback: (oldIndex: Int?, newIndex: Int) -> Unit,\n) :\n    NoStateAdapter<QualityDataHelper.QualityProfile>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n        a.id == b.id\n    })) {\n\n    companion object {\n        private val art = arrayOf(\n            R.drawable.profile_bg_teal,\n            R.drawable.profile_bg_blue,\n            R.drawable.profile_bg_dark_blue,\n            R.drawable.profile_bg_purple,\n            R.drawable.profile_bg_pink,\n            R.drawable.profile_bg_red,\n            R.drawable.profile_bg_orange,\n        )\n    }\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            PlayerQualityProfileItemBinding.inflate(\n                LayoutInflater.from(parent.context),\n                parent,\n                false\n            )\n        )\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        when (val binding = holder.view) {\n            is PlayerQualityProfileItemBinding -> {\n                clearImage(binding.profileImageBackground)\n            }\n        }\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Any>,\n        item: QualityDataHelper.QualityProfile,\n        position: Int\n    ) {\n        val binding = holder.view as? PlayerQualityProfileItemBinding ?: return\n\n        val priorityText: TextView = binding.profileText\n        val profileBg: ImageView = binding.profileImageBackground\n        val wifiText: TextView = binding.textIsWifi\n        val dataText: TextView = binding.textIsMobileData\n        val downloadText: TextView = binding.textIsDownloadData\n        val outline: View = binding.outline\n        val cardView: View = binding.cardView\n        val itemView = holder.itemView\n\n        priorityText.setText(item.name)\n        dataText.isVisible = item.types.contains(QualityDataHelper.QualityProfileType.Data)\n        wifiText.isVisible = item.types.contains(QualityDataHelper.QualityProfileType.WiFi)\n        downloadText.isVisible = item.types.contains(QualityDataHelper.QualityProfileType.Download)\n\n        fun setCurrentItem() {\n            val prevIndex = currentItem\n            // Prevent UI bug when re-selecting the item quickly\n            if (prevIndex == position) {\n                return\n            }\n            currentItem = position\n            clickCallback.invoke(prevIndex, position)\n        }\n\n        outline.isVisible = currentItem == position\n        val drawableResId = art[position % art.size]\n        profileBg.loadImage(drawableResId)\n\n        val drawable = ContextCompat.getDrawable(itemView.context, drawableResId)\n        if (drawable != null) {\n            // Convert Drawable to Bitmap\n            val bitmap = drawableToBitmap(drawable)\n            if (bitmap != null) {\n                // Use Palette to extract colors from the bitmap\n                Palette.from(bitmap).generate { palette ->\n                    val color = palette?.getDarkVibrantColor(\n                        ContextCompat.getColor(\n                            itemView.context,\n                            R.color.dubColorBg\n                        )\n                    )\n\n                    if (color != null) {\n                        wifiText.backgroundTintList = ColorStateList.valueOf(color)\n                        dataText.backgroundTintList = ColorStateList.valueOf(color)\n                        downloadText.backgroundTintList = ColorStateList.valueOf(color)\n                    }\n                }\n            }\n        }\n\n        val textStyle =\n            if (item.id == usedProfile) {\n                Typeface.BOLD\n            } else {\n                Typeface.NORMAL\n            }\n\n        priorityText.setTypeface(null, textStyle)\n\n        cardView.setOnClickListener {\n            setCurrentItem()\n        }\n    }\n\n    private var currentItem: Int? = null\n\n    fun getCurrentProfile(): QualityDataHelper.QualityProfile? {\n        return currentItem?.let { index -> immutableCurrentList.getOrNull(index) }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/source_priority/QualityDataHelper.kt",
    "content": "package com.lagradost.cloudstream3.ui.player.source_priority\n\nimport androidx.annotation.StringRes\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.debugAssert\nimport com.lagradost.cloudstream3.utils.UiText\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport kotlin.math.abs\n\nobject QualityDataHelper {\n    private const val VIDEO_SOURCE_PRIORITY = \"video_source_priority\"\n    private const val VIDEO_PROFILE_NAME = \"video_profile_name\"\n    private const val VIDEO_QUALITY_PRIORITY = \"video_quality_priority\"\n\n    // Old key only supporting one type per profile\n    @Deprecated(\"Changed to support multiple types per profile\")\n    private const val VIDEO_PROFILE_TYPE = \"video_profile_type\"\n    // New key supporting more than one type per profile\n\n    private const val VIDEO_PROFILE_TYPES = \"video_profile_types_2\"\n    private const val DEFAULT_SOURCE_PRIORITY = 1\n\n    /**\n     * Automatically skip loading links once this priority is reached\n     **/\n    const val AUTO_SKIP_PRIORITY = 10\n\n    /**\n     * Must be higher than amount of QualityProfileTypes\n     **/\n    private const val PROFILE_COUNT = 7\n\n    /**\n     * Unique guarantees that there will always be one of this type in the profile list.\n     **/\n    enum class QualityProfileType(@StringRes val stringRes: Int, val unique: Boolean) {\n        None(R.string.none, false),\n        WiFi(R.string.wifi, true),\n        Data(R.string.mobile_data, true),\n        Download(R.string.download, true)\n    }\n\n    data class QualityProfile(\n        val name: UiText,\n        val id: Int,\n        val types: Set<QualityProfileType>\n    )\n\n    fun getSourcePriority(profile: Int, name: String?): Int {\n        if (name == null) return DEFAULT_SOURCE_PRIORITY\n        return getKey(\n            \"$currentAccount/$VIDEO_SOURCE_PRIORITY/$profile\",\n            name,\n            DEFAULT_SOURCE_PRIORITY\n        ) ?: DEFAULT_SOURCE_PRIORITY\n    }\n\n    fun getAllSourcePriorityNames(profile: Int): List<String> {\n        val folder = \"$currentAccount/$VIDEO_SOURCE_PRIORITY/$profile\"\n        return getKeys(folder)?.map { key ->\n            key.substringAfter(\"$folder/\")\n        } ?: emptyList()\n    }\n\n    fun setSourcePriority(profile: Int, name: String, priority: Int) {\n        val folder = \"$currentAccount/$VIDEO_SOURCE_PRIORITY/$profile\"\n        // Prevent unnecessary keys\n        if (priority == DEFAULT_SOURCE_PRIORITY) {\n            removeKey(folder, name)\n        } else {\n            setKey(folder, name, priority)\n        }\n    }\n\n    fun setProfileName(profile: Int, name: String?) {\n        val path = \"$currentAccount/$VIDEO_PROFILE_NAME/$profile\"\n        if (name == null) {\n            removeKey(path)\n        } else {\n            setKey(path, name.trim())\n        }\n    }\n\n    fun getProfileName(profile: Int): UiText {\n        return getKey<String>(\"$currentAccount/$VIDEO_PROFILE_NAME/$profile\")?.let { txt(it) }\n            ?: txt(R.string.profile_number, profile)\n    }\n\n    fun getQualityPriority(profile: Int, quality: Qualities): Int {\n        return getKey(\n            \"$currentAccount/$VIDEO_QUALITY_PRIORITY/$profile\",\n            quality.value.toString(),\n            quality.defaultPriority\n        ) ?: quality.defaultPriority\n    }\n\n    fun setQualityPriority(profile: Int, quality: Qualities, priority: Int) {\n        setKey(\n            \"$currentAccount/$VIDEO_QUALITY_PRIORITY/$profile\",\n            quality.value.toString(),\n            priority\n        )\n    }\n\n\n    @Suppress(\"DEPRECATION\")\n    fun getQualityProfileTypes(profile: Int): Set<QualityProfileType> {\n        val newKey = \"$currentAccount/$VIDEO_PROFILE_TYPES/$profile\"\n        // Use arrays for to make with work with setKey properly (weird crashes otherwise)\n        val newProfiles = getKey<Array<QualityProfileType>>(newKey)?.toSet()\n\n        // Migrate to new profile key\n        if (newProfiles == null) {\n            val oldProfile =\n                getKey<QualityProfileType>(\"$currentAccount/$VIDEO_PROFILE_TYPE/$profile\")\n            val newSet = oldProfile?.let { arrayOf(it) } ?: arrayOf()\n            setKey(newKey, newSet)\n            return newSet.toSet()\n        } else {\n            return newProfiles\n        }\n    }\n\n    fun addQualityProfileType(profile: Int, type: QualityProfileType) {\n        val path = \"$currentAccount/$VIDEO_PROFILE_TYPES/$profile\"\n        val currentTypes = getQualityProfileTypes(profile)\n\n        if (type != QualityProfileType.None) {\n            setKey(path, (currentTypes + type).toTypedArray())\n        }\n    }\n\n    fun removeQualityProfileType(profile: Int, type: QualityProfileType) {\n        val path = \"$currentAccount/$VIDEO_PROFILE_TYPES/$profile\"\n        val currentTypes = getQualityProfileTypes(profile)\n\n        if (type != QualityProfileType.None) {\n            setKey(path, (currentTypes - type).toTypedArray())\n        }\n    }\n\n    /**\n     * Gets all quality profiles, always includes one profile with WiFi and Data\n     * Must under all circumstances at least return one profile\n     **/\n    fun getProfiles(): List<QualityProfile> {\n        val availableTypes = QualityProfileType.entries.toMutableList()\n        val profiles = (1..PROFILE_COUNT).map { profileNumber ->\n            // Get the real type\n            val types = getQualityProfileTypes(profileNumber)\n\n            val uniqueTypes = types.mapNotNull { type ->\n                // This makes it impossible to get more than one of each type\n                if (type.unique && !availableTypes.remove(type)) {\n                    null\n                } else {\n                    type\n                }\n            }.toSet()\n\n            QualityProfile(\n                getProfileName(profileNumber),\n                profileNumber,\n                uniqueTypes\n            )\n        }.toMutableList()\n\n        /**\n         * If no profile of this type exists: insert it on the earliest profile\n         **/\n        fun insertType(\n            list: MutableList<QualityProfile>,\n            type: QualityProfileType\n        ) {\n            if (list.any { it.types.contains(type) }) return\n\n            synchronized(list) {\n                val firstItem = list.firstOrNull() ?: return\n                val fixedTypes = firstItem.types + type\n                val fixedItem = firstItem.copy(types = fixedTypes)\n                list.set(0, fixedItem)\n            }\n        }\n\n        QualityProfileType.entries.forEach {\n            if (it.unique) insertType(profiles, it)\n        }\n\n        debugAssert({\n            !QualityProfileType.entries.all { type ->\n                !type.unique || profiles.any { it.types.contains(type) }\n            }\n        }, { \"All unique quality types do not exist\" })\n\n        debugAssert({\n            profiles.isEmpty()\n        }, { \"No profiles!\" })\n\n        return profiles\n    }\n\n    fun getLinkPriority(\n        qualityProfile: Int,\n        linkData: ExtractorLink?\n    ): Int {\n        val qualityPriority = getQualityPriority(\n            qualityProfile,\n            closestQuality(linkData?.quality)\n        )\n        val sourcePriority = getSourcePriority(qualityProfile, linkData?.source)\n\n        return qualityPriority + sourcePriority\n    }\n\n    private fun closestQuality(target: Int?): Qualities {\n        if (target == null) return Qualities.Unknown\n        return Qualities.entries.minBy { abs(it.value - target) }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/source_priority/QualityProfileDialog.kt",
    "content": "package com.lagradost.cloudstream3.ui.player.source_priority\n\nimport android.app.Dialog\nimport androidx.annotation.StyleRes\nimport androidx.core.view.isVisible\nimport androidx.fragment.app.FragmentActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.PlayerQualityProfileDialogBinding\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper.getAllSourcePriorityNames\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper.getProfileName\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper.getProfiles\nimport com.lagradost.cloudstream3.utils.Coroutines.ioWork\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.setText\n\n/** Simplified ExtractorLink for the quality profile dialog */\ndata class LinkSource(\n    val source: String\n) {\n    constructor(extractorLink: ExtractorLink) : this(extractorLink.source)\n}\n\n\nclass QualityProfileDialog private constructor(\n    val activity: FragmentActivity,\n    @StyleRes val themeRes: Int,\n    private val links: List<LinkSource>,\n    private val usedProfile: Int?,\n    private val profileSelectionCallback: ((QualityDataHelper.QualityProfile) -> Unit)?,\n    private val useProfileSelection: Boolean\n) : Dialog(activity, themeRes) {\n    constructor(\n        activity: FragmentActivity,\n        @StyleRes themeRes: Int,\n        links: List<LinkSource>,\n        usedProfile: Int,\n        profileSelectionCallback: ((QualityDataHelper.QualityProfile) -> Unit),\n    ) : this(activity, themeRes, links, usedProfile, profileSelectionCallback, true)\n\n    constructor(\n        activity: FragmentActivity,\n        @StyleRes themeRes: Int,\n        links: List<LinkSource>\n    ) : this(activity, themeRes, links, null, null, false)\n\n    companion object {\n        // Run on IO as this may be a heavy operation\n        suspend fun getAllDefaultSources(): List<LinkSource> = ioWork {\n            getProfiles().flatMap {\n                getAllSourcePriorityNames(it.id)\n            }.distinct().map { LinkSource(it) }\n        }\n    }\n\n    override fun show() {\n        val binding = PlayerQualityProfileDialogBinding.inflate(this.layoutInflater, null, false)\n\n        setContentView(binding.root)\n        fixSystemBarsPadding(binding.root)\n        binding.apply {\n            fun getCurrentProfile(): QualityDataHelper.QualityProfile? {\n                return (profilesRecyclerview.adapter as? ProfilesAdapter)?.getCurrentProfile()\n            }\n\n            fun refreshProfiles() {\n                if (usedProfile != null) {\n                    currentlySelectedProfileText.setText(getProfileName(usedProfile))\n                }\n                (profilesRecyclerview.adapter as? ProfilesAdapter)?.submitList(getProfiles())\n            }\n\n            profilesRecyclerview.adapter = ProfilesAdapter(\n                usedProfile,\n            ) { oldIndex: Int?, newIndex: Int ->\n                profilesRecyclerview.adapter?.notifyItemChanged(newIndex)\n                selectedItemHolder.alpha = 1f\n                if (oldIndex != null) {\n                    profilesRecyclerview.adapter?.notifyItemChanged(oldIndex)\n                }\n            }\n\n            refreshProfiles()\n\n            editBtt.setOnClickListener {\n                getCurrentProfile()?.let { profile ->\n                    SourcePriorityDialog(context, themeRes, links, profile) {\n                        refreshProfiles()\n                    }.show()\n                }\n            }\n\n\n            setDefaultBtt.setOnClickListener {\n                val currentProfile = getCurrentProfile() ?: return@setOnClickListener\n                val choices =\n                    QualityDataHelper.QualityProfileType.entries.filter { it != QualityDataHelper.QualityProfileType.None }\n                val choiceNames = choices.map { txt(it.stringRes).asString(context) }\n                val selectedIndices = choices.mapIndexed { index, type -> index to type }\n                    .filter { currentProfile.types.contains(it.second) }.map { it.first }\n\n                activity.showMultiDialog(\n                    choiceNames,\n                    selectedIndices,\n                    txt(R.string.set_default).asString(context),\n                    {},\n                    { index ->\n                        val pickedChoices = index.mapNotNull { choices.getOrNull(it) }\n\n                        pickedChoices.forEach { pickedChoice ->\n                            // Remove previous picks\n                            if (pickedChoice.unique) {\n                                getProfiles().filter { it.types.contains(pickedChoice) }.forEach {\n                                    QualityDataHelper.removeQualityProfileType(it.id, pickedChoice)\n                                }\n                            }\n\n                            QualityDataHelper.addQualityProfileType(currentProfile.id, pickedChoice)\n                        }\n\n                        refreshProfiles()\n                    })\n            }\n\n            cancelBtt.isVisible = useProfileSelection\n            useBtt.isVisible = useProfileSelection\n            applyBtt.isVisible = !useProfileSelection\n\n            if (useProfileSelection) {\n                cancelBtt.setOnClickListener {\n                    this@QualityProfileDialog.dismissSafe()\n                }\n\n                useBtt.setOnClickListener {\n                    getCurrentProfile()?.let {\n                        profileSelectionCallback?.invoke(it)\n                        this@QualityProfileDialog.dismissSafe()\n                    }\n                }\n            } else {\n                applyBtt.setOnClickListener {\n                    this@QualityProfileDialog.dismissSafe()\n                }\n            }\n        }\n        super.show()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/player/source_priority/SourcePriorityDialog.kt",
    "content": "package com.lagradost.cloudstream3.ui.player.source_priority\n\nimport android.app.Dialog\nimport android.content.Context\nimport android.view.LayoutInflater\nimport androidx.annotation.StyleRes\nimport androidx.appcompat.app.AlertDialog\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.PlayerSelectSourcePriorityBinding\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\n\nclass SourcePriorityDialog(\n    val ctx: Context,\n    @StyleRes themeRes: Int,\n    val links: List<LinkSource>,\n    private val profile: QualityDataHelper.QualityProfile,\n    /**\n     * Notify that the profile overview should be updated, for example if the name has been updated\n     * Should not be called excessively.\n     **/\n    private val updatedCallback: () -> Unit\n) : Dialog(ctx, themeRes) {\n    override fun show() {\n        val binding =\n            PlayerSelectSourcePriorityBinding.inflate(LayoutInflater.from(ctx), null, false)\n        setContentView(binding.root)\n        fixSystemBarsPadding(binding.root)\n        val sourcesRecyclerView = binding.sortSources\n        val qualitiesRecyclerView = binding.sortQualities\n        val profileText = binding.profileTextEditable\n        val saveBtt = binding.saveBtt\n        val exitBtt = binding.closeBtt\n        val helpBtt = binding.helpBtt\n\n        profileText.setText(QualityDataHelper.getProfileName(profile.id).asString(context))\n        profileText.hint = txt(R.string.profile_number, profile.id).asString(context)\n\n        sourcesRecyclerView.adapter = PriorityAdapter<Nothing?>(\n        ).apply {\n            submitList(links.map { link ->\n                SourcePriority(\n                    null,\n                    link.source,\n                    QualityDataHelper.getSourcePriority(profile.id, link.source)\n                )\n            }.distinctBy { it.name }.sortedBy { -it.priority })\n        }\n\n        qualitiesRecyclerView.adapter = PriorityAdapter<Qualities>(\n        ).apply {\n            submitList(Qualities.entries.mapNotNull {\n                SourcePriority(\n                    it,\n                    Qualities.getStringByIntFull(it.value).ifBlank { return@mapNotNull null },\n                    QualityDataHelper.getQualityPriority(profile.id, it)\n                )\n            }.sortedBy { -it.priority })\n        }\n\n        @Suppress(\"UNCHECKED_CAST\") // We know the types\n        saveBtt.setOnClickListener {\n            val qualityAdapter = qualitiesRecyclerView.adapter as? PriorityAdapter<Qualities>\n            val sourcesAdapter = sourcesRecyclerView.adapter as? PriorityAdapter<Nothing?>\n\n            val qualities = qualityAdapter?.immutableCurrentList ?: emptyList()\n            val sources = sourcesAdapter?.immutableCurrentList ?: emptyList()\n\n            qualities.forEach {\n                QualityDataHelper.setQualityPriority(profile.id, it.data, it.priority)\n            }\n\n            sources.forEach {\n                QualityDataHelper.setSourcePriority(profile.id, it.name, it.priority)\n            }\n\n            qualityAdapter?.submitList(qualities.sortedBy { -it.priority })\n            sourcesAdapter?.submitList(sources.sortedBy { -it.priority })\n\n            val savedProfileName = profileText.text.toString()\n            if (savedProfileName.isBlank()) {\n                QualityDataHelper.setProfileName(profile.id, null)\n            } else {\n                QualityDataHelper.setProfileName(profile.id, savedProfileName)\n            }\n            updatedCallback.invoke()\n        }\n\n        exitBtt.setOnClickListener {\n            this.dismissSafe()\n        }\n\n        helpBtt.setOnClickListener {\n            AlertDialog.Builder(context, R.style.AlertDialogCustom).apply {\n                setMessage(R.string.quality_profile_help)\n            }.show()\n        }\n\n        super.show()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/quicksearch/QuickSearchFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.quicksearch\n\nimport android.app.Activity\nimport android.content.Context\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.WindowManager\nimport android.widget.ImageView\nimport androidx.appcompat.widget.SearchView\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.lifecycle.ViewModelProvider\nimport androidx.recyclerview.widget.GridLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.HomePageList\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.QuickSearchBinding\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.home.HomeFragment\nimport com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.loadHomepageList\nimport com.lagradost.cloudstream3.ui.home.HomeViewModel\nimport com.lagradost.cloudstream3.ui.home.ParentItemAdapter\nimport com.lagradost.cloudstream3.ui.search.SearchAdapter\nimport com.lagradost.cloudstream3.ui.search.SearchClickCallback\nimport com.lagradost.cloudstream3.ui.search.SearchHelper\nimport com.lagradost.cloudstream3.ui.search.SearchViewModel\nimport com.lagradost.cloudstream3.ui.setRecycledViewPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.filterProviderByPreferredMedia\nimport com.lagradost.cloudstream3.utils.AppContextUtils.filterSearchResultByFilmQuality\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isRecyclerScrollable\nimport com.lagradost.cloudstream3.utils.AppContextUtils.ownShow\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.getSpanCount\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage\nimport java.util.concurrent.locks.ReentrantLock\n\nclass QuickSearchFragment : BaseFragment<QuickSearchBinding>(\n    BaseFragment.BindingCreator.Inflate(QuickSearchBinding::inflate)\n) {\n    companion object {\n        const val AUTOSEARCH_KEY = \"autosearch\"\n        const val PROVIDER_KEY = \"providers\"\n\n        fun pushSearch(\n            autoSearch: String? = null,\n            providers: Array<String>? = null\n        ) {\n            pushSearch(activity, autoSearch, providers)\n        }\n\n        fun pushSearch(\n            activity: Activity?,\n            autoSearch: String? = null,\n            providers: Array<String>? = null\n        ) {\n            activity.navigate(R.id.global_to_navigation_quick_search, Bundle().apply {\n                providers?.let {\n                    putStringArray(PROVIDER_KEY, it)\n                }\n                autoSearch?.let {\n                    putString(\n                        AUTOSEARCH_KEY,\n                        it.trim()\n                            .removeSuffix(\"(DUB)\")\n                            .removeSuffix(\"(SUB)\")\n                            .removeSuffix(\"(Dub)\")\n                            .removeSuffix(\"(Sub)\").trim()\n                    )\n                }\n            })\n        }\n\n        var clickCallback: ((SearchClickCallback) -> Unit)? = null\n    }\n\n    private var providers: Set<String>? = null\n    private lateinit var searchViewModel: SearchViewModel\n\n    private var bottomSheetDialog: BottomSheetDialog? = null\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(view)\n\n        // Fix grid\n        HomeFragment.currentSpan = view.context.getSpanCount()\n        binding?.quickSearchAutofitResults?.spanCount = HomeFragment.currentSpan\n        HomeFragment.configEvent.invoke()\n    }\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? {\n        activity?.window?.setSoftInputMode(\n            WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE\n        )\n        searchViewModel = ViewModelProvider(this)[SearchViewModel::class.java]\n        bottomSheetDialog?.ownShow()\n        return super.onCreateView(inflater, container, savedInstanceState)\n    }\n\n    override fun onDestroy() {\n        super.onDestroy()\n        clickCallback = null\n    }\n\n    fun search(context: Context?, query: String, isQuickSearch: Boolean): Boolean {\n        (providers ?: context?.filterProviderByPreferredMedia(hasHomePageIsRequired = false)\n            ?.map { it.name }?.toSet())?.let { active ->\n            searchViewModel.searchAndCancel(\n                query = query,\n                ignoreSettings = false,\n                providersActive = active,\n                isQuickSearch = isQuickSearch\n            )\n            return true\n        }\n        return false\n    }\n\n    override fun onBindingCreated(binding: QuickSearchBinding) {\n        arguments?.getStringArray(PROVIDER_KEY)?.let {\n            providers = it.toSet()\n        }\n\n        val isSingleProvider = providers?.size == 1\n        val isSingleProviderQuickSearch = if (isSingleProvider) {\n            getApiFromNameNull(providers?.first())?.hasQuickSearch ?: false\n        } else false\n\n        val firstProvider = providers?.firstOrNull()\n        if (isSingleProvider && firstProvider != null) {\n            binding.quickSearchAutofitResults.apply {\n                setRecycledViewPool(SearchAdapter.sharedPool)\n                adapter = SearchAdapter(\n                    this,\n                ) { callback ->\n                    SearchHelper.handleSearchClickCallback(callback)\n                }\n            }\n\n            binding.quickSearchAutofitResults.addOnScrollListener(object :\n                RecyclerView.OnScrollListener() {\n                var expandCount = 0\n\n                override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {\n                    super.onScrollStateChanged(recyclerView, newState)\n\n                    val adapter = recyclerView.adapter\n                    if (adapter !is SearchAdapter) return\n\n                    val count = adapter.itemCount\n                    val currentHasNext = adapter.hasNext\n\n                    if (!recyclerView.isRecyclerScrollable() && currentHasNext && expandCount != count) {\n                        expandCount = count\n                        ioSafe {\n                            searchViewModel.expandAndReturn(firstProvider)\n                        }\n                    }\n                }\n            })\n\n            try {\n                binding.quickSearch.queryHint =\n                    getString(R.string.search_hint_site).format(firstProvider)\n            } catch (e: Exception) {\n                logError(e)\n            }\n        } else {\n            binding.quickSearchMasterRecycler.setRecycledViewPool(ParentItemAdapter.sharedPool)\n            binding.quickSearchMasterRecycler.adapter =\n                ParentItemAdapter(\n                    id = \"quickSearchMasterRecycler\".hashCode(),\n                    { callback ->\n                        SearchHelper.handleSearchClickCallback(callback)\n                        //when (callback.action) {\n                        //SEARCH_ACTION_LOAD -> {\n                        //    clickCallback?.invoke(callback)\n                        //}\n                        //    else -> SearchHelper.handleSearchClickCallback(activity, callback)\n                        //}\n                    },\n                    { item ->\n                        bottomSheetDialog = activity?.loadHomepageList(item, dismissCallback = {\n                            bottomSheetDialog = null\n                        }, expandCallback = { searchViewModel.expandAndReturn(it) })\n                    },\n                    expandCallback = { name ->\n                        ioSafe {\n                            searchViewModel.expandAndReturn(name)\n                        }\n                    })\n            binding.quickSearchMasterRecycler.layoutManager = GridLayoutManager(context, 1)\n        }\n        binding.quickSearchAutofitResults.isVisible = isSingleProvider\n        binding.quickSearchMasterRecycler.isGone = isSingleProvider\n\n        val listLock = ReentrantLock()\n        observe(searchViewModel.currentSearch) { list ->\n            try {\n                // https://stackoverflow.com/questions/6866238/concurrent-modification-exception-adding-to-an-arraylist\n                listLock.lock()\n                (binding.quickSearchMasterRecycler.adapter as? ParentItemAdapter)?.apply {\n                    val newItems = list.map { ongoing ->\n                        val dataList = ongoing.value.list\n                        val dataListFiltered =\n                            context?.filterSearchResultByFilmQuality(dataList) ?: dataList\n\n                        val homePageList = HomePageList(\n                            ongoing.key,\n                            dataListFiltered\n                        )\n\n                        val expandableList = HomeViewModel.ExpandableHomepageList(\n                            homePageList,\n                            ongoing.value.currentPage,\n                            ongoing.value.hasNext\n                        )\n\n                        expandableList\n                    }\n\n                    submitList(newItems)\n                    //notifyDataSetChanged()\n                }\n            } catch (e: Exception) {\n                logError(e)\n            } finally {\n                listLock.unlock()\n            }\n        }\n\n        val searchExitIcon =\n            binding.quickSearch.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)\n\n        binding.quickSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener {\n            override fun onQueryTextSubmit(query: String): Boolean {\n                if (search(context, query, false))\n                    hideKeyboard(binding.quickSearch)\n                return true\n            }\n\n            override fun onQueryTextChange(newText: String): Boolean {\n                if (isSingleProviderQuickSearch)\n                    search(context, newText, true)\n                return true\n            }\n        })\n        binding.quickSearchLoadingBar.alpha = 0f\n        observe(searchViewModel.searchResponse) {\n            when (it) {\n                is Resource.Success -> {\n                    it.value.let { data ->\n                        val adapter =\n                            (binding.quickSearchAutofitResults.adapter as? SearchAdapter)\n                        adapter?.submitList(\n                            context?.filterSearchResultByFilmQuality(data.list) ?: data.list\n                        )\n                        adapter?.hasNext = data.hasNext\n                    }\n                    searchExitIcon?.alpha = 1f\n                    binding.quickSearchLoadingBar.alpha = 0f\n                }\n\n                is Resource.Failure -> {\n                    // Toast.makeText(activity, \"Server error\", Toast.LENGTH_LONG).show()\n                    searchExitIcon?.alpha = 1f\n                    binding.quickSearchLoadingBar.alpha = 0f\n                }\n\n                is Resource.Loading -> {\n                    searchExitIcon?.alpha = 0f\n                    binding.quickSearchLoadingBar.alpha = 1f\n                }\n            }\n        }\n\n        if (isLayout(PHONE or EMULATOR)) {\n            binding.quickSearchBack.apply {\n                isVisible = true\n                setOnClickListener {\n                    activity?.popCurrentPage()\n                }\n            }\n        }\n\n        if (isLayout(TV)) {\n            binding.quickSearch.requestFocus()\n        }\n\n        arguments?.getString(AUTOSEARCH_KEY)?.let {\n            binding.quickSearch.setQuery(it, true)\n            arguments?.remove(AUTOSEARCH_KEY)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/ActorAdaptor.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.app.SearchManager\nimport android.content.Intent\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.core.view.isVisible\nimport com.lagradost.cloudstream3.ActorData\nimport com.lagradost.cloudstream3.ActorRole\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.CastItemBinding\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.newSharedPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\n\nclass ActorAdaptor(\n    private var nextFocusUpId: Int? = null,\n    private val focusCallback: (View?) -> Unit = {}\n) : NoStateAdapter<ActorData>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n    a.actor.name == b.actor.name\n})) {\n    companion object {\n        val sharedPool =\n            newSharedPool { setMaxRecycledViews(CONTENT, 10) }\n    }\n\n    // Easier to store it here than to store it in the ActorData\n    val inverted: HashMap<ActorData, Boolean> = hashMapOf()\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            CastItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)\n        )\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        when (val binding = holder.view) {\n            is CastItemBinding -> {\n                clearImage(binding.actorImage)\n            }\n        }\n    }\n\n    override fun onBindContent(holder: ViewHolderState<Any>, item: ActorData, position: Int) {\n        when (val binding = holder.view) {\n            is CastItemBinding -> {\n                val itemView = binding.root\n                val isInverted = inverted.getOrDefault(item, false)\n\n                val (mainImg, vaImage) = if (!isInverted || item.voiceActor?.image.isNullOrBlank()) {\n                    Pair(item.actor.image, item.voiceActor?.image)\n                } else {\n                    Pair(item.voiceActor?.image, item.actor.image)\n                }\n\n                // Fix tv focus escaping the recyclerview\n                if (position == 0) {\n                    itemView.nextFocusLeftId = R.id.result_cast_items\n                } else if ((position - 1) == itemCount) {\n                    itemView.nextFocusRightId = R.id.result_cast_items\n                }\n                nextFocusUpId?.let {\n                    itemView.nextFocusUpId = it\n                }\n\n                itemView.setOnFocusChangeListener { v, hasFocus ->\n                    if (hasFocus) {\n                        focusCallback(v)\n                    }\n                }\n\n                itemView.setOnClickListener {\n                    inverted[item] = !isInverted\n                    this.onUpdateContent(holder, getItem(position), position)\n                }\n\n                itemView.setOnLongClickListener {\n                    if (isLayout(PHONE)) {\n                        Intent(Intent.ACTION_WEB_SEARCH).apply {\n                            putExtra(SearchManager.QUERY, item.actor.name)\n                        }.also { intent ->\n                            itemView.context.packageManager?.let { pm ->\n                                if (intent.resolveActivity(pm) != null) {\n                                    itemView.context.startActivity(intent)\n                                }\n                            }\n                        }\n                    }\n                    true\n                }\n\n                binding.apply {\n                    actorImage.loadImage(mainImg)\n\n                    actorName.text = item.actor.name\n                    item.role?.let {\n                        actorExtra.context?.getString(\n                            when (it) {\n                                ActorRole.Main -> {\n                                    R.string.actor_main\n                                }\n\n                                ActorRole.Supporting -> {\n                                    R.string.actor_supporting\n                                }\n\n                                ActorRole.Background -> {\n                                    R.string.actor_background\n                                }\n                            }\n                        )?.let { text ->\n                            actorExtra.isVisible = true\n                            actorExtra.text = text\n                        }\n                    } ?: item.roleString?.let {\n                        actorExtra.isVisible = true\n                        actorExtra.text = it\n                    } ?: run {\n                        actorExtra.isVisible = false\n                    }\n\n                    if (item.voiceActor == null) {\n                        voiceActorImageHolder.isVisible = false\n                        voiceActorName.isVisible = false\n                    } else {\n                        voiceActorName.text = item.voiceActor?.name\n                        if (!vaImage.isNullOrEmpty())\n                            voiceActorImageHolder.isVisible = true\n                        voiceActorImage.loadImage(vaImage)\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.content.Context\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.core.view.setPadding\nimport androidx.preference.PreferenceManager\nimport coil3.dispose\nimport com.lagradost.cloudstream3.APIHolder.unixTimeMS\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.actions.VideoClickActionHolder\nimport com.lagradost.cloudstream3.databinding.ResultEpisodeBinding\nimport com.lagradost.cloudstream3.databinding.ResultEpisodeLargeBinding\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.secondsToReadable\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_LONG_CLICK\nimport com.lagradost.cloudstream3.ui.download.DownloadClickEvent\nimport com.lagradost.cloudstream3.ui.newSharedPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\nimport com.lagradost.cloudstream3.utils.setText\nimport com.lagradost.cloudstream3.utils.txt\nimport java.text.DateFormat\nimport java.text.SimpleDateFormat\nimport java.util.Date\nimport java.util.Locale\n\n/**\n * Ids >= 1000 are reserved for VideoClickActions\n * @see VideoClickActionHolder\n */\nconst val ACTION_PLAY_EPISODE_IN_PLAYER = 1\nconst val ACTION_CHROME_CAST_EPISODE = 4\nconst val ACTION_CHROME_CAST_MIRROR = 5\n\nconst val ACTION_DOWNLOAD_EPISODE = 6\nconst val ACTION_DOWNLOAD_MIRROR = 7\n\nconst val ACTION_RELOAD_EPISODE = 8\n\nconst val ACTION_SHOW_OPTIONS = 10\n\nconst val ACTION_CLICK_DEFAULT = 11\nconst val ACTION_SHOW_TOAST = 12\nconst val ACTION_SHOW_DESCRIPTION = 15\n\nconst val ACTION_DOWNLOAD_EPISODE_SUBTITLE = 13\nconst val ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR = 14\n\nconst val ACTION_MARK_AS_WATCHED = 18\n\nconst val TV_EP_SIZE = 400\nconst val ACTION_MARK_WATCHED_UP_TO_THIS_EPISODE = 19\n\ndata class EpisodeClickEvent(val position: Int?, val action: Int, val data: ResultEpisode) {\n    constructor(action: Int, data: ResultEpisode) : this(null, action, data)\n}\n\nclass EpisodeAdapter(\n    private val hasDownloadSupport: Boolean,\n    private val clickCallback: (EpisodeClickEvent) -> Unit,\n    private val downloadClickCallback: (DownloadClickEvent) -> Unit,\n) : NoStateAdapter<ResultEpisode>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n    a.id == b.id\n}, contentSame = { a, b ->\n    a == b\n})) {\n    companion object {\n        const val HAS_POSTER: Int = 0\n        const val HAS_NO_POSTER: Int = 1\n        fun getPlayerAction(context: Context): Int {\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)\n            val playerPref =\n                settingsManager.getString(context.getString(R.string.player_default_key), \"\")\n\n            return VideoClickActionHolder.uniqueIdToId(playerPref) ?: ACTION_PLAY_EPISODE_IN_PLAYER\n        }\n\n        val sharedPool =\n            newSharedPool {\n                setMaxRecycledViews(HAS_POSTER or CONTENT, 10)\n                setMaxRecycledViews(HAS_NO_POSTER or CONTENT, 10)\n            }\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        if (holder.itemView.hasFocus()) {\n            holder.itemView.clearFocus()\n        }\n\n        when (val binding = holder.view) {\n            is ResultEpisodeLargeBinding -> {\n                clearImage(binding.episodePoster)\n            }\n        }\n        super.onClearView(holder)\n    }\n\n    override fun customContentViewType(item: ResultEpisode): Int =\n        if (item.poster.isNullOrBlank() && item.description.isNullOrBlank()) HAS_NO_POSTER else HAS_POSTER\n\n    override fun onCreateCustomContent(parent: ViewGroup, viewType: Int): ViewHolderState<Any> {\n        return when (viewType) {\n            HAS_NO_POSTER -> {\n                ViewHolderState(\n                    ResultEpisodeBinding.inflate(\n                        LayoutInflater.from(parent.context),\n                        parent,\n                        false\n                    )\n                )\n            }\n\n            HAS_POSTER -> {\n                ViewHolderState(\n                    ResultEpisodeLargeBinding.inflate(\n                        LayoutInflater.from(parent.context),\n                        parent,\n                        false\n                    )\n                )\n            }\n\n            else -> throw NotImplementedError()\n        }\n    }\n\n    override fun onBindContent(holder: ViewHolderState<Any>, item: ResultEpisode, position: Int) {\n        val itemView = holder.itemView\n        when (val binding = holder.view) {\n            is ResultEpisodeLargeBinding -> {\n                val setWidth =\n                    if (isLayout(TV or EMULATOR)) TV_EP_SIZE.toPx else ViewGroup.LayoutParams.MATCH_PARENT\n\n                binding.apply {\n                    episodeLinHolder.layoutParams.width = setWidth\n                    episodeHolderLarge.layoutParams.width = setWidth\n                    episodeHolder.layoutParams.width = setWidth\n\n                    if (isLayout(PHONE or EMULATOR) && CommonActivity.appliedTheme == R.style.AmoledMode) {\n                        episodeHolderLarge.radius = 0.0f\n                        episodeHolder.setPadding(0)\n                    }\n\n                    downloadButton.isVisible = hasDownloadSupport\n                    downloadButton.setDefaultClickListener(\n                        DownloadObjects.DownloadEpisodeCached(\n                            name = item.name,\n                            poster = item.poster,\n                            episode = item.episode,\n                            season = item.season,\n                            id = item.id,\n                            parentId = item.parentId,\n                            score = item.score,\n                            description = item.description,\n                            cacheTime = System.currentTimeMillis(),\n                        ), null\n                    ) {\n                        when (it.action) {\n                            DOWNLOAD_ACTION_DOWNLOAD -> {\n                                clickCallback.invoke(\n                                    EpisodeClickEvent(\n                                        position,\n                                        ACTION_DOWNLOAD_EPISODE,\n                                        item\n                                    )\n                                )\n                            }\n\n                            DOWNLOAD_ACTION_LONG_CLICK -> {\n                                clickCallback.invoke(\n                                    EpisodeClickEvent(\n                                        position,\n                                        ACTION_DOWNLOAD_MIRROR,\n                                        item\n                                    )\n                                )\n                            }\n\n                            else -> {\n                                downloadClickCallback.invoke(it)\n                            }\n                        }\n                    }\n\n                    val status = VideoDownloadManager.downloadStatus[item.id]\n                    downloadButton.resetView()\n                    downloadButton.setPersistentId(item.id)\n                    downloadButton.setStatus(status)\n\n                    val name =\n                        if (item.name == null) \"${episodeText.context.getString(R.string.episode)} ${item.episode}\" else \"${item.episode}. ${item.name}\"\n                    episodeFiller.isVisible = item.isFiller == true\n                    episodeText.text =\n                        name//if(card.isFiller == true) episodeText.context.getString(R.string.filler).format(name) else name\n                    episodeText.isSelected = true // is needed for text repeating\n\n                    if (item.videoWatchState == VideoWatchState.Watched) {\n                        // This cannot be done in getDisplayPosition() as when you have not watched something\n                        // the duration and position is 0\n                        //episodeProgress.max = 1\n                        //episodeProgress.progress = 1\n                        episodePlayIcon.setImageResource(R.drawable.ic_baseline_check_24)\n                        episodeProgress.isVisible = false\n                    } else {\n                        val displayPos = item.getDisplayPosition()\n                        val durationSec = (item.duration / 1000).toInt()\n                        val progressSec = (displayPos / 1000).toInt()\n\n                        if (displayPos >= item.duration && displayPos > 0) {\n                            episodePlayIcon.setImageResource(R.drawable.ic_baseline_check_24)\n                            episodeProgress.isVisible = false\n                        } else {\n                            episodePlayIcon.setImageResource(R.drawable.netflix_play)\n                            episodeProgress.apply {\n                                max = durationSec\n                                progress = progressSec\n                                isVisible = displayPos > 0L\n                            }\n                        }\n                    }\n\n                    val posterVisible = !item.poster.isNullOrBlank()\n                    if (posterVisible) {\n                        val isUpcoming = item.airDate != null && unixTimeMS < item.airDate\n                        episodePoster.loadImage(item.poster) {\n                            if (isUpcoming) {\n                                error {\n                                    // If the poster has an url, but it is faulty then\n                                    // we use the episodeUpcomingIcon if it is an upcoming episode\n                                    main {\n                                        // Make sure it is on the main thread\n                                        episodeUpcomingIcon.isVisible = true\n                                    }\n\n                                    null // We only care about the runnable\n                                }\n                            }\n                        }\n                    } else {\n                        // Clear the image\n                        episodePoster.dispose()\n                    }\n                    episodePoster.isVisible = posterVisible\n\n                    val rating10p = item.score?.toFloat(10)\n                    if (rating10p != null && rating10p > 0.1) {\n                        episodeRating.text = episodeRating.context?.getString(R.string.rated_format)\n                            ?.format(rating10p) // TODO Change rated_format to use card.score.toString()\n                    } else {\n                        episodeRating.text = \"\"\n                    }\n\n                    episodeRating.isGone = episodeRating.text.isNullOrBlank()\n\n                    episodeDescript.apply {\n                        text = item.description.html()\n                        isGone = text.isNullOrBlank()\n\n                        var isExpanded = false\n                        setOnClickListener {\n                            if (isLayout(TV)) {\n                                clickCallback.invoke(\n                                    EpisodeClickEvent(\n                                        position,\n                                        ACTION_SHOW_DESCRIPTION,\n                                        item\n                                    )\n                                )\n                            } else {\n                                isExpanded = !isExpanded\n                                maxLines = if (isExpanded) {\n                                    Integer.MAX_VALUE\n                                } else 4\n                            }\n                        }\n                    }\n\n                    if (item.airDate != null) {\n                        val isUpcoming = unixTimeMS < item.airDate\n\n                        if (isUpcoming) {\n                            episodeProgress.isVisible = false\n                            episodePlayIcon.isVisible = false\n                            episodeUpcomingIcon.isVisible = !posterVisible\n                            episodeDate.setText(\n                                txt(\n                                    R.string.episode_upcoming_format,\n                                    secondsToReadable(\n                                        item.airDate.minus(unixTimeMS).div(1000).toInt(),\n                                        \"\"\n                                    )\n                                )\n                            )\n                        } else {\n                            episodePlayIcon.isVisible = true\n                            episodeUpcomingIcon.isVisible = false\n\n                            val formattedAirDate = SimpleDateFormat.getDateInstance(\n                                DateFormat.LONG,\n                                Locale.getDefault()\n                            ).apply {\n                            }.format(Date(item.airDate))\n\n                            episodeDate.setText(txt(formattedAirDate))\n                        }\n                    } else {\n                        episodeUpcomingIcon.isVisible = false\n                        episodePlayIcon.isVisible = true\n                        episodeDate.isVisible = false\n                    }\n\n                    episodeRuntime.setText(\n                        txt(\n                            item.runTime?.times(60L)?.toInt()?.let { secondsToReadable(it, \"\") }\n                        )\n                    )\n\n                    if (isLayout(EMULATOR or PHONE)) {\n                        episodePoster.setOnClickListener {\n                            clickCallback.invoke(\n                                EpisodeClickEvent(\n                                    position,\n                                    ACTION_CLICK_DEFAULT,\n                                    item\n                                )\n                            )\n                        }\n\n                        episodePoster.setOnLongClickListener {\n                            clickCallback.invoke(\n                                EpisodeClickEvent(\n                                    position,\n                                    ACTION_SHOW_TOAST,\n                                    item\n                                )\n                            )\n                            return@setOnLongClickListener true\n                        }\n                    }\n                }\n\n                itemView.setOnClickListener {\n                    clickCallback.invoke(EpisodeClickEvent(position, ACTION_CLICK_DEFAULT, item))\n                }\n\n                if (isLayout(TV)) {\n                    itemView.isFocusable = true\n                    itemView.isFocusableInTouchMode = true\n                    //itemView.touchscreenBlocksFocus = false\n                }\n\n                itemView.setOnLongClickListener {\n                    clickCallback.invoke(EpisodeClickEvent(position, ACTION_SHOW_OPTIONS, item))\n                    return@setOnLongClickListener true\n                }\n            }\n\n            is ResultEpisodeBinding -> {\n                binding.episodeHolder.layoutParams.apply {\n                    width =\n                        if (isLayout(TV or EMULATOR)) TV_EP_SIZE.toPx else ViewGroup.LayoutParams.MATCH_PARENT\n                }\n\n                binding.apply {\n                    downloadButton.isVisible = hasDownloadSupport\n                    downloadButton.setDefaultClickListener(\n                        DownloadObjects.DownloadEpisodeCached(\n                            name = item.name,\n                            poster = item.poster,\n                            episode = item.episode,\n                            season = item.season,\n                            id = item.id,\n                            parentId = item.parentId,\n                            score = item.score,\n                            description = item.description,\n                            cacheTime = System.currentTimeMillis(),\n                        ), null\n                    ) {\n                        when (it.action) {\n                            DOWNLOAD_ACTION_DOWNLOAD -> {\n                                clickCallback.invoke(\n                                    EpisodeClickEvent(\n                                        position,\n                                        ACTION_DOWNLOAD_EPISODE,\n                                        item\n                                    )\n                                )\n                            }\n\n                            DOWNLOAD_ACTION_LONG_CLICK -> {\n                                clickCallback.invoke(\n                                    EpisodeClickEvent(\n                                        position,\n                                        ACTION_DOWNLOAD_MIRROR,\n                                        item\n                                    )\n                                )\n                            }\n\n                            else -> {\n                                downloadClickCallback.invoke(it)\n                            }\n                        }\n                    }\n\n                    val status = VideoDownloadManager.downloadStatus[item.id]\n                    downloadButton.resetView()\n                    downloadButton.setPersistentId(item.id)\n                    downloadButton.setStatus(status)\n\n                    val name =\n                        if (item.name == null) \"${episodeText.context.getString(R.string.episode)} ${item.episode}\" else \"${item.episode}. ${item.name}\"\n                    episodeFiller.isVisible = item.isFiller == true\n                    episodeText.text =\n                        name//if(card.isFiller == true) episodeText.context.getString(R.string.filler).format(name) else name\n                    episodeText.isSelected = true // is needed for text repeating\n\n                    if (item.videoWatchState == VideoWatchState.Watched) {\n                        episodePlayIcon.setImageResource(R.drawable.ic_baseline_check_24)\n                        episodeProgress.isVisible = false\n                    } else {\n                        val displayPos = item.getDisplayPosition()\n                        val durationSec = (item.duration / 1000).toInt()\n                        val progressSec = (displayPos / 1000).toInt()\n\n                        if (displayPos >= item.duration && displayPos > 0) {\n                            episodePlayIcon.setImageResource(R.drawable.ic_baseline_check_24)\n                            episodeProgress.isVisible = false\n                        } else {\n                            episodePlayIcon.setImageResource(R.drawable.play_button_transparent)\n                            episodeProgress.apply {\n                                max = durationSec\n                                progress = progressSec\n                                isVisible = displayPos > 0L\n                            }\n                        }\n                    }\n\n                    itemView.setOnClickListener {\n                        clickCallback.invoke(\n                            EpisodeClickEvent(\n                                position,\n                                ACTION_CLICK_DEFAULT,\n                                item\n                            )\n                        )\n                    }\n\n                    if (isLayout(TV)) {\n                        itemView.isFocusable = true\n                        itemView.isFocusableInTouchMode = true\n                        //itemView.touchscreenBlocksFocus = false\n                    }\n\n                    itemView.setOnLongClickListener {\n                        clickCallback.invoke(EpisodeClickEvent(position, ACTION_SHOW_OPTIONS, item))\n                        return@setOnLongClickListener true\n                    }\n\n                    //binding.resultEpisodeDownload.isVisible = hasDownloadSupport\n                    //binding.resultEpisodeProgressDownloaded.isVisible = hasDownloadSupport\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/ImageAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport com.lagradost.cloudstream3.databinding.ResultMiniImageBinding\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.newSharedPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\n\nconst val IMAGE_CLICK = 0\nconst val IMAGE_LONG_CLICK = 1\n\nclass ImageAdapter(\n    val clickCallback: ((Int) -> Unit)? = null,\n    val nextFocusUp: Int? = null,\n    val nextFocusDown: Int? = null,\n) :\n    NoStateAdapter<Int>(\n        diffCallback = BaseDiffCallback(\n            itemSame = Int::equals,\n            contentSame = Int::equals\n        )\n    ) {\n    companion object {\n        val sharedPool =\n            newSharedPool { setMaxRecycledViews(CONTENT, 10) }\n    }\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            ResultMiniImageBinding.inflate(LayoutInflater.from(parent.context), parent, false)\n        )\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        val binding = holder.view as? ResultMiniImageBinding ?: return\n        clearImage(binding.root)\n    }\n\n    override fun onBindContent(holder: ViewHolderState<Any>, item: Int, position: Int) {\n        val binding = holder.view as? ResultMiniImageBinding ?: return\n\n        binding.root.apply {\n            loadImage(item)\n            if (nextFocusDown != null) {\n                this.nextFocusDownId = nextFocusDown\n            }\n            if (nextFocusUp != null) {\n                this.nextFocusUpId = nextFocusUp\n            }\n            if (clickCallback != null) {\n                if (isLayout(TV)) {\n                    isClickable = true\n                    isLongClickable = true\n                    isFocusable = true\n                    isFocusableInTouchMode = true\n                }\n                setOnClickListener {\n                    clickCallback.invoke(IMAGE_CLICK)\n                }\n                setOnLongClickListener {\n                    clickCallback.invoke(IMAGE_LONG_CLICK)\n                    return@setOnLongClickListener true\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/LinearListLayout.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.content.Context\nimport android.view.View\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.FocusDirection\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\n\nconst val FOCUS_SELF = View.NO_ID - 1\nconst val FOCUS_INHERIT = FOCUS_SELF - 1\n\nfun RecyclerView?.setLinearListLayout(\n    isHorizontal: Boolean = true,\n    nextLeft: Int = FOCUS_INHERIT,\n    nextRight: Int = FOCUS_INHERIT,\n    nextUp: Int = FOCUS_INHERIT,\n    nextDown: Int = FOCUS_INHERIT\n) {\n    if (this == null) return\n    val ctx = this.context ?: return\n    this.layoutManager = (this.layoutManager as? LinearListLayout ?: LinearListLayout(ctx)).apply {\n        if (isHorizontal) setHorizontal() else setVertical()\n        nextFocusLeft =\n            if (nextLeft == FOCUS_INHERIT) this@setLinearListLayout.nextFocusLeftId else nextLeft\n        nextFocusRight =\n            if (nextRight == FOCUS_INHERIT) this@setLinearListLayout.nextFocusRightId else nextRight\n        nextFocusUp =\n            if (nextUp == FOCUS_INHERIT) this@setLinearListLayout.nextFocusUpId else nextUp\n        nextFocusDown =\n            if (nextDown == FOCUS_INHERIT) this@setLinearListLayout.nextFocusDownId else nextDown\n    }\n}\n\nopen class LinearListLayout(context: Context?) :\n    LinearLayoutManager(context) {\n\n    var nextFocusLeft: Int = View.NO_ID\n    var nextFocusRight: Int = View.NO_ID\n    var nextFocusUp: Int = View.NO_ID\n    var nextFocusDown: Int = View.NO_ID\n\n    fun setHorizontal() {\n        orientation = HORIZONTAL\n    }\n\n    fun setVertical() {\n        orientation = VERTICAL\n    }\n\n    private fun getCorrectParent(focused: View?): View? {\n        if (focused == null) return null\n        var current: View? = focused\n        val last: ArrayList<View> = arrayListOf(focused)\n        while (current != null && current !is RecyclerView) {\n            current = (current.parent as? View?)?.also { last.add(it) }\n        }\n        return last.getOrNull(last.count() - 2)\n    }\n\n    private fun getPosition(view: View?): Int? {\n        return (view?.layoutParams as? RecyclerView.LayoutParams?)?.absoluteAdapterPosition\n    }\n\n    private fun getViewFromPos(pos: Int): View? {\n        for (i in 0 until childCount) {\n            val child = getChildAt(i)\n            if ((child?.layoutParams as? RecyclerView.LayoutParams?)?.absoluteAdapterPosition == pos) {\n                return child\n            }\n        }\n        return null\n        //return recyclerView.children.firstOrNull { child -> (child.layoutParams as? RecyclerView.LayoutParams?)?.absoluteAdapterPosition == pos) }\n    }\n\n    /*\n    private fun scrollTo(position: Int) {\n        val linearSmoothScroller = LinearSmoothScroller(recyclerView.context)\n        linearSmoothScroller.targetPosition = position\n        startSmoothScroll(linearSmoothScroller)\n    }*/\n\n    /** from the current focus go to a direction */\n    private fun getNextDirection(focused: View?, direction: FocusDirection): View? {\n        val id = when (direction) {\n            FocusDirection.Start -> if (isLayoutRTL) nextFocusRight else nextFocusLeft\n            FocusDirection.End -> if (isLayoutRTL) nextFocusLeft else nextFocusRight\n            FocusDirection.Up -> nextFocusUp\n            FocusDirection.Down -> nextFocusDown\n        }\n\n        return when (id) {\n            View.NO_ID -> null\n            FOCUS_SELF -> focused\n            else -> CommonActivity.continueGetNextFocus(\n                activity ?: focused,\n                focused ?: return null,\n                direction,\n                id\n            )\n        }\n    }\n\n    fun redirectRecycleToFirstItem(focused: View): View? {\n        return when (focused) {\n            is RecyclerView -> {\n                (focused.layoutManager as? LinearListLayout)?.let { focusedLayoutManager ->\n                    val firstPosition = focusedLayoutManager.findFirstVisibleItemPosition()\n                    val firstView = focusedLayoutManager.findViewByPosition(firstPosition)\n                    firstView\n                } ?: focused\n            }\n\n            else -> focused\n        }\n    }\n\n    override fun onInterceptFocusSearch(focused: View, direction: Int): View? {\n        val dir = if (orientation == HORIZONTAL) {\n            if (direction == View.FOCUS_DOWN) getNextDirection(\n                focused,\n                FocusDirection.Down\n            )?.let { newFocus ->\n                return redirectRecycleToFirstItem(newFocus)\n            }\n            if (direction == View.FOCUS_UP) getNextDirection(\n                focused,\n                FocusDirection.Up\n            )?.let { newFocus ->\n                return redirectRecycleToFirstItem(newFocus)\n            }\n\n            if (direction == View.FOCUS_DOWN || direction == View.FOCUS_UP) {\n                // This scrolls the recyclerview before doing focus search, which\n                // allows the focus search to work better.\n\n                // Without this the recyclerview focus location on the screen\n                // would change when scrolling between recyclerviews.\n                (focused.parent as? RecyclerView)?.focusSearch(direction)\n                return null\n            }\n            var ret = if (direction == View.FOCUS_RIGHT) 1 else -1\n            // only flip on horizontal layout\n            if (isLayoutRTL) {\n                ret = -ret\n            }\n            ret\n        } else {\n            if (direction == View.FOCUS_RIGHT) getNextDirection(\n                focused,\n                FocusDirection.End\n            )?.let { newFocus ->\n                return newFocus\n            }\n            if (direction == View.FOCUS_LEFT) getNextDirection(\n                focused,\n                FocusDirection.Start\n            )?.let { newFocus ->\n                return newFocus\n            }\n\n            if (direction == View.FOCUS_RIGHT || direction == View.FOCUS_LEFT) {\n                (focused.parent as? RecyclerView)?.focusSearch(direction)\n                return null\n            }\n\n            //if (direction == View.FOCUS_RIGHT || direction == View.FOCUS_LEFT) return null\n            if (direction == View.FOCUS_DOWN) 1 else -1\n        }\n\n        try {\n            val position = getPosition(getCorrectParent(focused)) ?: return null\n            val lookFor = dir + position\n\n            // if out of bounds then refocus as specified\n            return if (lookFor >= itemCount) {\n                getNextDirection(\n                    focused,\n                    if (orientation == HORIZONTAL) FocusDirection.End else FocusDirection.Down\n                )\n            } else if (lookFor < 0) {\n                getNextDirection(\n                    focused,\n                    if (orientation == HORIZONTAL) FocusDirection.Start else FocusDirection.Up\n                )\n            } else {\n                getViewFromPos(lookFor) ?: run {\n                    scrollToPosition(lookFor)\n                    null\n                }\n            }\n        } catch (e: Exception) {\n            logError(e)\n            return null\n        }\n    }\n\n    override fun requestChildRectangleOnScreen(\n        parent: RecyclerView,\n        child: View,\n        rect: android.graphics.Rect,\n        immediate: Boolean,\n        focusedChildVisible: Boolean\n    ): Boolean {\n        if (isLayout(TV) && orientation == HORIZONTAL) {\n            val dx = when {\n                isLayoutRTL -> getDecoratedRight(child) - (parent.width - parent.paddingRight)\n                else -> getDecoratedLeft(child) - parent.paddingLeft\n            }\n            return if (dx != 0) {\n                when {\n                    immediate -> parent.scrollBy(dx, 0)\n                    else -> parent.smoothScrollBy(dx, 0)\n                }\n                true\n            } else {\n                false\n            }\n        } else {\n            return super.requestChildRectangleOnScreen(\n                parent,\n                child,\n                rect,\n                immediate,\n                focusedChildVisible\n            )\n        }\n    }\n\n    /*override fun onRequestChildFocus(\n        parent: RecyclerView,\n        state: RecyclerView.State,\n        child: View,\n        focused: View?\n    ): Boolean {\n        return super.onRequestChildFocus(parent, state, child, focused)\n        getPosition(getCorrectParent(focused ?: return true))?.let {\n            val startView = findFirstVisibleChildClosestToStart(true,true)\n            val endView = findFirstVisibleChildClosestToEnd(true,true)\n            val start = getPosition(startView)\n            val end = getPosition(endView)\n            fill(parent,LayoutState())\n\n            val helper = mOrientationHelper ?: return false\n            val laidOutArea: Int = abs(\n                helper.getDecoratedEnd(startView)\n                        - helper.getDecoratedStart(endView)\n            )\n            val itemRange: Int = abs(\n                (start\n                        - end)\n            ) + 1\n\n            val avgSizePerRow = laidOutArea.toFloat() / itemRange\n\n            return Math.round(\n                itemsBefore * avgSizePerRow + ((orientation.getStartAfterPadding()\n                        - orientation.getDecoratedStart(startChild)))\n            )\n            recyclerView.scrollToPosition(it)\n        }\n        return true*/\n\n    //return super.onRequestChildFocus(parent, state, child, focused)\n    /* if (focused == null || focused == child) {\n         return super.onRequestChildFocus(parent, state, child, focused)\n     }\n\n     try {\n         val pos = getPosition(getCorrectParent(focused) ?: return true)\n         scrollToPosition(pos)\n     } catch (e: Exception) {\n         logError(e)\n     }\n     return true\n}*/\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.os.Bundle\nimport android.widget.ImageView\nimport android.widget.TextView\nimport androidx.core.view.isVisible\nimport androidx.fragment.app.Fragment\nimport androidx.preference.PreferenceManager\nimport coil3.dispose\nimport com.lagradost.cloudstream3.DubStatus\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.SeasonData\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.ui.result.EpisodeAdapter.Companion.getPlayerAction\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiDubstatusSettings\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getVideoWatchState\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\nimport com.lagradost.cloudstream3.utils.Event\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.UiImage\n\nconst val START_ACTION_RESUME_LATEST = 1\nconst val START_ACTION_LOAD_EP = 2\n\n/**\n * Future proofed way to mark episodes as watched\n **/\nenum class VideoWatchState {\n    /** Default value when no key is set */\n    None,\n    Watched\n}\n\ndata class ResultEpisode(\n    val headerName: String,\n    val name: String?,\n    val poster: String?,\n    val episode: Int,\n    val seasonIndex: Int?,  // this is the \"season\" index used season names\n    val season: Int?, // this is the display\n    val data: String,\n    val apiName: String,\n    val id: Int,\n    val index: Int,\n    val position: Long, // time in MS\n    val duration: Long, // duration in MS\n    val score: Score?,\n    val description: String?,\n    val isFiller: Boolean?,\n    val tvType: TvType,\n    val parentId: Int,\n    /**\n     * Conveys if the episode itself is marked as watched\n     **/\n    val videoWatchState: VideoWatchState,\n    /** Sum of all previous season episode counts + episode */\n    val totalEpisodeIndex: Int? = null,\n    val airDate: Long? = null,\n    val runTime: Int? = null,\n    val seasonData: SeasonData? = null,\n)\n\nfun ResultEpisode.getRealPosition(): Long {\n    if (duration <= 0) return 0\n    val percentage = position * 100 / duration\n    if (percentage <= 5 || percentage >= 95) return 0\n    return position\n}\n\nfun ResultEpisode.getDisplayPosition(): Long {\n    if (duration <= 0) return 0\n    val percentage = position * 100 / duration\n    if (percentage <= 1) return 0\n    if (percentage <= 5) return 5 * duration / 100\n    if (percentage >= 95) return duration\n    return position\n}\n\nfun buildResultEpisode(\n    headerName: String,\n    name: String? = null,\n    poster: String? = null,\n    episode: Int,\n    seasonIndex: Int? = null,\n    season: Int? = null,\n    data: String,\n    apiName: String,\n    id: Int,\n    index: Int,\n    rating: Score? = null,\n    description: String? = null,\n    isFiller: Boolean? = null,\n    tvType: TvType,\n    parentId: Int,\n    totalEpisodeIndex: Int? = null,\n    airDate: Long? = null,\n    runTime: Int? = null,\n    seasonData: SeasonData? = null,\n): ResultEpisode {\n    val posDur = getViewPos(id)\n    val videoWatchState = getVideoWatchState(id) ?: VideoWatchState.None\n    return ResultEpisode(\n        headerName = headerName,\n        name = name,\n        poster = poster,\n        episode = episode,\n        seasonIndex = seasonIndex,\n        season = season,\n        data = data,\n        apiName = apiName,\n        id = id,\n        index = index,\n        position = posDur?.position ?: 0,\n        duration = posDur?.duration ?: 0,\n        score = rating,\n        description = description,\n        isFiller = isFiller,\n        tvType = tvType,\n        parentId = parentId,\n        videoWatchState = videoWatchState,\n        totalEpisodeIndex = totalEpisodeIndex,\n        airDate = airDate,\n        runTime = runTime,\n        seasonData = seasonData\n    )\n}\n\n/** 0f-1f */\nfun ResultEpisode.getWatchProgress(): Float {\n    return (getDisplayPosition() / 1000).toFloat() / (duration / 1000).toFloat()\n}\n\nobject ResultFragment {\n    private const val URL_BUNDLE = \"url\"\n    private const val NAME_BUNDLE = \"name\"\n    private const val API_NAME_BUNDLE = \"apiName\"\n    private const val SEASON_BUNDLE = \"season\"\n    private const val EPISODE_BUNDLE = \"episode\"\n    private const val START_ACTION_BUNDLE = \"startAction\"\n    private const val START_VALUE_BUNDLE = \"startValue\"\n    private const val RESTART_BUNDLE = \"restart\"\n\n    fun newInstance(\n        card: SearchResponse, startAction: Int = 0, startValue: Int? = null\n    ): Bundle {\n        return Bundle().apply {\n            putString(URL_BUNDLE, card.url)\n            putString(API_NAME_BUNDLE, card.apiName)\n            putString(NAME_BUNDLE, card.name)\n            if (card is DataStoreHelper.ResumeWatchingResult) {\n                if (card.season != null)\n                    putInt(SEASON_BUNDLE, card.season)\n                if (card.episode != null)\n                    putInt(EPISODE_BUNDLE, card.episode)\n            }\n            putInt(START_ACTION_BUNDLE, startAction)\n            if (startValue != null)\n                putInt(START_VALUE_BUNDLE, startValue)\n\n\n            putBoolean(RESTART_BUNDLE, true)\n        }\n    }\n\n    fun newInstance(\n        url: String,\n        apiName: String,\n        name: String,\n        startAction: Int = 0,\n        startValue: Int = 0\n    ): Bundle {\n        return Bundle().apply {\n            putString(URL_BUNDLE, url)\n            putString(API_NAME_BUNDLE, apiName)\n            putString(NAME_BUNDLE, name)\n            putInt(START_ACTION_BUNDLE, startAction)\n            putInt(START_VALUE_BUNDLE, startValue)\n            putBoolean(RESTART_BUNDLE, true)\n        }\n    }\n\n    fun updateUI(id: Int? = null) {\n        // updateUIListener?.invoke()\n        updateUIEvent.invoke(id)\n    }\n\n    val updateUIEvent = Event<Int?>()\n\n    //private var updateUIListener: (() -> Unit)? = null\n\n\n    //protected open val resultLayout = R.layout.fragment_result_swipe\n\n    /* override var layout = R.layout.fragment_result_swipe\n\n     override fun onCreateView(\n         inflater: LayoutInflater,\n         container: ViewGroup?,\n         savedInstanceState: Bundle?,\n     ): View? {\n\n         return super.onCreateView(inflater, container, savedInstanceState)\n         //return inflater.inflate(resultLayout, container, false)\n     }\n\n     override fun onDestroyView() {\n         updateUIListener = null\n         super.onDestroyView()\n     }\n\n     override fun onResume() {\n         afterPluginsLoadedEvent += ::reloadViewModel\n         super.onResume()\n         activity?.setNavigationBarColorCompat(R.attr.primaryBlackBackground)\n     }\n\n     override fun onDestroy() {\n         afterPluginsLoadedEvent -= ::reloadViewModel\n         super.onDestroy()\n     }\n\n\n     private fun updateUI() {\n         syncModel.updateUserData()\n         viewModel.reloadEpisodes()\n     }*/\n\n    data class StoredData(\n        val url: String,\n        val apiName: String,\n        val name: String,\n        val showFillers: Boolean,\n        val dubStatus: DubStatus,\n        val start: AutoResume?,\n        val playerAction: Int,\n        val restart: Boolean,\n    )\n\n    fun bindLogo(\n        url: String?,\n        headers: Map<String, String>?,\n        logoView: ImageView,\n        titleView: TextView\n    ) {\n        // Cancel it, as we want to remove the listener onSuccess race condition\n        logoView.dispose()\n\n        if (url.isNullOrBlank()) {\n            logoView.isVisible = false\n            titleView.isVisible = true\n            return\n        }\n\n        logoView.isVisible = true\n        titleView.isVisible = false\n\n        logoView.loadImage(\n            imageData = UiImage.Image(url, headers = headers),\n            builder = {\n                listener(\n                    onSuccess = { _, _ ->\n                        logoView.isVisible = true\n                        titleView.isVisible = false\n                    },\n                    onError = { _, _ ->\n                        logoView.isVisible = false\n                        titleView.isVisible = true\n                    },\n                    onCancel = {\n                        // If we manually cancel, then it should not do anything\n                    }\n                )\n            }\n        )\n    }\n\n    fun Fragment.getStoredData(): StoredData? {\n        val context = this.context ?: this.activity ?: return null\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)\n        val url = arguments?.getString(URL_BUNDLE) ?: return null\n        val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return null\n        val name = arguments?.getString(NAME_BUNDLE) ?: return null\n        val showFillers =\n            settingsManager.getBoolean(context.getString(R.string.show_fillers_key), false)\n        val dubStatus = if (context.getApiDubstatusSettings()\n                .contains(DubStatus.Dubbed)\n        ) DubStatus.Dubbed else DubStatus.Subbed\n        val startAction = arguments?.getInt(START_ACTION_BUNDLE)\n\n        val playerAction = getPlayerAction(context)\n\n        val restart = arguments?.getBoolean(RESTART_BUNDLE) ?: false\n        if (restart) {\n            arguments?.putBoolean(RESTART_BUNDLE, false)\n        }\n\n        val start = startAction?.let { action ->\n            val startValue = arguments?.getInt(START_VALUE_BUNDLE)\n            val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)\n            val resumeSeason = arguments?.getInt(SEASON_BUNDLE)\n\n            arguments?.remove(START_VALUE_BUNDLE)\n            arguments?.remove(START_ACTION_BUNDLE)\n            AutoResume(\n                startAction = action,\n                id = startValue,\n                episode = resumeEpisode,\n                season = resumeSeason\n            )\n        }\n        return StoredData(url, apiName, name, showFillers, dubStatus, start, playerAction, restart)\n    }\n\n    /*private fun reloadViewModel(forceReload: Boolean) {\n        if (!viewModel.hasLoaded() || forceReload) {\n            val storedData = getStoredData(activity ?: context ?: return) ?: return\n\n            viewModel.load(\n                activity,\n                storedData.url ?: return,\n                storedData.apiName,\n                storedData.showFillers,\n                storedData.dubStatus,\n                storedData.start\n            )\n        }\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n\n        updateUIListener = ::updateUI\n\n        val restart = arguments?.getBoolean(RESTART_BUNDLE) ?: false\n        if (restart) {\n            arguments?.putBoolean(RESTART_BUNDLE, false)\n        }\n\n        activity?.window?.decorView?.clearFocus()\n        hideKeyboard()\n        context?.updateHasTrailers()\n        activity?.loadCache()\n\n        /* val backParameter = result_back.layoutParams as FrameLayout.LayoutParams\n         backParameter.setMargins(\n             backParameter.leftMargin,\n             backParameter.topMargin + requireContext().getStatusBarHeight(),\n             backParameter.rightMargin,\n             backParameter.bottomMargin\n         )\n         result_back.layoutParams = backParameter*/\n\n        val storedData = (activity ?: context)?.let {\n            getStoredData(it)\n        }\n\n        // This is to band-aid FireTV navigation\n        val isTv = isTvSettings()\n        result_season_button?.isFocusableInTouchMode = isTv\n        result_episode_select?.isFocusableInTouchMode = isTv\n        result_dub_select?.isFocusableInTouchMode = isTv\n            if (storedData?.url != null) {\n                if (restart || !viewModel.hasLoaded()) {\n                    //viewModel.clear()\n                    viewModel.load(\n                        activity,\n                        storedData.url,\n                        storedData.apiName,\n                        storedData.showFillers,\n                        storedData.dubStatus,\n                        storedData.start\n                    )\n                }\n            }\n    }*/\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.annotation.SuppressLint\nimport android.app.Dialog\nimport android.content.Intent\nimport android.content.res.ColorStateList\nimport android.content.res.Configuration\nimport android.graphics.Rect\nimport android.os.Build\nimport android.os.Bundle\nimport android.text.Editable\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.animation.AlphaAnimation\nimport android.view.animation.Animation\nimport android.view.animation.DecelerateInterpolator\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.view.isGone\nimport androidx.core.view.isInvisible\nimport androidx.core.view.isVisible\nimport androidx.core.widget.NestedScrollView\nimport androidx.core.widget.doOnTextChanged\nimport androidx.lifecycle.ViewModelProvider\nimport com.discord.panels.OverlappingPanelsLayout\nimport com.discord.panels.PanelState\nimport com.discord.panels.PanelsChildGestureRegionObserver\nimport com.google.android.gms.cast.framework.CastButtonFactory\nimport com.google.android.gms.cast.framework.CastContext\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.google.android.material.button.MaterialButton\nimport com.lagradost.cloudstream3.APIHolder\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.DubStatus\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.base64Encode\nimport com.lagradost.cloudstream3.databinding.FragmentResultBinding\nimport com.lagradost.cloudstream3.databinding.FragmentResultSwipeBinding\nimport com.lagradost.cloudstream3.databinding.ResultRecommendationsBinding\nimport com.lagradost.cloudstream3.databinding.ResultSyncBinding\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.mvvm.observeNullable\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.services.SubscriptionWorkManager\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING_SHARE\nimport com.lagradost.cloudstream3.ui.WatchType\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_LONG_CLICK\nimport com.lagradost.cloudstream3.ui.download.DownloadButtonSetup\nimport com.lagradost.cloudstream3.ui.player.CSPlayerEvent\nimport com.lagradost.cloudstream3.ui.player.FullScreenPlayer\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityProfileDialog\nimport com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment\nimport com.lagradost.cloudstream3.ui.result.ResultFragment.bindLogo\nimport com.lagradost.cloudstream3.ui.result.ResultFragment.getStoredData\nimport com.lagradost.cloudstream3.ui.result.ResultFragment.updateUIEvent\nimport com.lagradost.cloudstream3.ui.search.SearchAdapter\nimport com.lagradost.cloudstream3.ui.search.SearchHelper\nimport com.lagradost.cloudstream3.ui.setRecycledViewPool\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isCastApiAvailable\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadCache\nimport com.lagradost.cloudstream3.utils.AppContextUtils.openBrowser\nimport com.lagradost.cloudstream3.utils.AppContextUtils.updateHasTrailers\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.openBatteryOptimizationSettings\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog\nimport com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage\nimport com.lagradost.cloudstream3.utils.UIHelper.populateChips\nimport com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes\nimport com.lagradost.cloudstream3.utils.UIHelper.setListViewHeightBasedOnItems\nimport com.lagradost.cloudstream3.utils.UIHelper.setNavigationBarColorCompat\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\nimport com.lagradost.cloudstream3.utils.getImageFromDrawable\nimport com.lagradost.cloudstream3.utils.setText\nimport com.lagradost.cloudstream3.utils.setTextHtml\nimport com.lagradost.cloudstream3.utils.txt\nimport java.net.URLEncoder\nimport kotlin.math.roundToInt\n\nopen class ResultFragmentPhone : FullScreenPlayer() {\n    private val gestureRegionsListener =\n        object : PanelsChildGestureRegionObserver.GestureRegionsListener {\n            override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {\n                binding?.resultOverlappingPanels?.setChildGestureRegions(gestureRegions)\n            }\n        }\n\n    protected lateinit var viewModel: ResultViewModel2\n    protected lateinit var syncModel: SyncViewModel\n\n    protected var binding: FragmentResultSwipeBinding? = null\n    protected var resultBinding: FragmentResultBinding? = null\n    protected var recommendationBinding: ResultRecommendationsBinding? = null\n    protected var syncBinding: ResultSyncBinding? = null\n\n    override var layout = R.layout.fragment_result_swipe\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? {\n        viewModel = ViewModelProvider(this)[ResultViewModel2::class.java]\n        syncModel = ViewModelProvider(this)[SyncViewModel::class.java]\n        updateUIEvent += ::updateUI\n\n        val root = super.onCreateView(inflater, container, savedInstanceState) ?: return null\n        FragmentResultSwipeBinding.bind(root).let { bind ->\n            resultBinding = bind.fragmentResult\n            recommendationBinding = bind.resultRecommendations\n            syncBinding = bind.resultSync\n            binding = bind\n        }\n\n        return root\n    }\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        PanelsChildGestureRegionObserver.Provider.get().apply {\n            resultBinding?.resultCastItems?.let { register(it) }\n        }\n    }\n\n    var currentTrailers: List<Pair<ExtractorLink, String>> = emptyList()\n    var currentTrailerIndex = 0\n\n    override fun nextMirror() {\n        currentTrailerIndex++\n        loadTrailer()\n    }\n\n    override fun hasNextMirror(): Boolean {\n        return currentTrailerIndex + 1 < currentTrailers.size\n    }\n\n    override fun playerError(exception: Throwable) {\n        if (player.getIsPlaying()) { // because we don't want random toasts in player\n            super.playerError(exception)\n        } else {\n            nextMirror()\n        }\n    }\n\n    private fun loadTrailer(index: Int? = null) {\n\n        val isSuccess =\n            currentTrailers.getOrNull(index ?: currentTrailerIndex)\n                ?.let { (extractedTrailerLink, _) ->\n                    context?.let { ctx ->\n                        player.onPause()\n                        player.loadPlayer(\n                            ctx,\n                            false,\n                            extractedTrailerLink,\n                            null,\n                            startPosition = 0L,\n                            subtitles = emptySet(),\n                            subtitle = null,\n                            autoPlay = false,\n                            preview = false\n                        )\n                        true\n                    } ?: run {\n                        false\n                    }\n                } ?: run {\n                false\n            }\n        //result_trailer_thumbnail?.setImageBitmap(result_poster_background?.drawable?.toBitmap())\n\n\n        // result_trailer_loading?.isVisible = isSuccess\n        val turnVis = !isSuccess && !isFullScreenPlayer\n        resultBinding?.apply {\n            // If we load a trailer, then cancel the big logo and only show the small title\n            if (isSuccess) {\n                // This is still a bit of a race condition, but it should work if we have the\n                // trailers observe after the page observe!\n                bindLogo(\n                    url = null,\n                    headers = null,\n                    logoView = backgroundPosterWatermarkBadge,\n                    titleView = resultTitle\n                )\n            }\n            resultSmallscreenHolder.isVisible = turnVis\n            resultPosterBackgroundHolder.apply {\n                val fadeIn: Animation = AlphaAnimation(alpha, if (turnVis) 1.0f else 0.0f).apply {\n                    interpolator = DecelerateInterpolator()\n                    duration = 200\n                    fillAfter = true\n                }\n                clearAnimation()\n                startAnimation(fadeIn)\n            }\n\n            // We don't want the trailer to be focusable if it's not visible\n            resultSmallscreenHolder.descendantFocusability = if (isSuccess) {\n                ViewGroup.FOCUS_AFTER_DESCENDANTS\n            } else {\n                ViewGroup.FOCUS_BLOCK_DESCENDANTS\n            }\n            binding?.resultFullscreenHolder?.isVisible = !isSuccess && isFullScreenPlayer\n        }\n        //player_view?.apply {\n        //alpha = 0.0f\n        //ObjectAnimator.ofFloat(player_view, \"alpha\", 1f).apply {\n        //    duration = 200\n        //    start()\n        //}\n\n        //val fadeIn: Animation = AlphaAnimation(0.0f, 1f).apply {\n        //    interpolator = DecelerateInterpolator()\n        //    duration = 2000\n        //    fillAfter = true\n        //}\n        //startAnimation(fadeIn)\n        //}\n    }\n\n    private fun setTrailers(trailers: List<Pair<ExtractorLink, String>>?) {\n        context?.updateHasTrailers()\n        if (!LoadResponse.isTrailersEnabled) return\n        currentTrailers = trailers?.sortedBy { -it.first.quality } ?: emptyList()\n        loadTrailer()\n    }\n\n    override fun onDestroyView() {\n        PanelsChildGestureRegionObserver.Provider.get().let { obs ->\n            resultBinding?.resultCastItems?.let {\n                obs.unregister(it)\n            }\n\n            obs.removeGestureRegionsUpdateListener(gestureRegionsListener)\n        }\n\n        updateUIEvent -= ::updateUI\n        binding = null\n        resultBinding?.resultScroll?.setOnClickListener(null)\n        resultBinding = null\n        syncBinding = null\n        recommendationBinding = null\n        activity?.detachBackPressedCallback(this@ResultFragmentPhone.toString())\n        super.onDestroyView()\n    }\n\n    var loadingDialog: Dialog? = null\n    var popupDialog: Dialog? = null\n\n    /**\n     * Sets next focus to allow navigation up and down between 2 views\n     * if either of them is null nothing happens.\n     **/\n    private fun setFocusUpAndDown(upper: View?, down: View?) {\n        if (upper == null || down == null) return\n        upper.nextFocusDownId = down.id\n        down.nextFocusUpId = upper.id\n    }\n\n    var selectSeason: String? = null\n    var selectEpisodeRange: String? = null\n    var selectSort: EpisodeSortType? = null\n\n    private fun setUrl(url: String?) {\n        if (url == null) {\n            binding?.resultOpenInBrowser?.isVisible = false\n            return\n        }\n\n        val valid = url.startsWith(\"http\")\n\n        binding?.resultOpenInBrowser?.apply {\n            isVisible = valid\n            setOnClickListener {\n                context?.openBrowser(url)\n            }\n        }\n\n        resultBinding?.resultReloadConnectionOpenInBrowser?.setOnClickListener {\n            view?.context?.openBrowser(url)\n        }\n\n        resultBinding?.resultMetaSite?.setOnClickListener {\n            view?.context?.openBrowser(url)\n        }\n    }\n\n    private fun reloadViewModel(forceReload: Boolean) {\n        if (!viewModel.hasLoaded() || forceReload) {\n            val storedData = getStoredData() ?: return\n            viewModel.load(\n                activity,\n                storedData.url,\n                storedData.apiName,\n                storedData.showFillers,\n                storedData.dubStatus,\n                storedData.start\n            )\n        }\n    }\n\n    override fun onResume() {\n        afterPluginsLoadedEvent += ::reloadViewModel\n        activity?.setNavigationBarColorCompat(R.attr.primaryBlackBackground)\n        super.onResume()\n        PanelsChildGestureRegionObserver.Provider.get()\n            .addGestureRegionsUpdateListener(gestureRegionsListener)\n    }\n\n    override fun onStop() {\n        afterPluginsLoadedEvent -= ::reloadViewModel\n        super.onStop()\n    }\n\n    private fun updateUI(id: Int?) {\n        syncModel.updateUserData()\n        viewModel.reloadEpisodes()\n    }\n\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n        view?.let { fixSystemBarsPadding(it) }\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        // ===== setup =====\n        fixSystemBarsPadding(view)\n        val storedData = getStoredData() ?: return\n        activity?.window?.decorView?.clearFocus()\n        activity?.loadCache()\n        context?.updateHasTrailers()\n        hideKeyboard()\n        if (storedData.restart || !viewModel.hasLoaded())\n            viewModel.load(\n                activity,\n                storedData.url,\n                storedData.apiName,\n                storedData.showFillers,\n                storedData.dubStatus,\n                storedData.start\n            )\n\n        setUrl(storedData.url)\n        syncModel.addFromUrl(storedData.url)\n        val api = APIHolder.getApiFromNameNull(storedData.apiName)\n\n        // This may not be 100% reliable, and may delay for small period\n        // before resultCastItems will be scrollable again, but this does work\n        // most of the time.\n        binding?.resultOverlappingPanels?.registerEndPanelStateListeners(\n            object : OverlappingPanelsLayout.PanelStateListener {\n                override fun onPanelStateChange(panelState: PanelState) {\n                    PanelsChildGestureRegionObserver.Provider.get().apply {\n                        resultBinding?.resultCastItems?.let { register(it) }\n                    }\n                }\n            }\n        )\n\n        // ===== ===== =====\n\n        binding?.resultSearch?.isGone = storedData.name.isBlank()\n        binding?.resultSearch?.setOnClickListener {\n            QuickSearchFragment.pushSearch(activity, storedData.name)\n        }\n\n        resultBinding?.apply {\n            resultReloadConnectionerror.setOnClickListener {\n                viewModel.load(\n                    activity,\n                    storedData.url,\n                    storedData.apiName,\n                    storedData.showFillers,\n                    storedData.dubStatus,\n                    storedData.start\n                )\n            }\n\n            resultCastItems.setLinearListLayout(\n                isHorizontal = true,\n                nextLeft = FOCUS_SELF,\n                nextRight = FOCUS_SELF\n            )\n            /*resultCastItems.layoutManager = object : LinearListLayout(view.context) {\n                override fun onRequestChildFocus(\n                    parent: RecyclerView,\n                    state: RecyclerView.State,\n                    child: View,\n                    focused: View?\n                ): Boolean {\n                    // Make the cast always focus the first visible item when focused\n                    // from somewhere else. Otherwise it jumps to the last item.\n                    return if (parent.focusedChild == null) {\n                        scrollToPosition(this.findFirstCompletelyVisibleItemPosition())\n                        true\n                    } else {\n                        super.onRequestChildFocus(parent, state, child, focused)\n                    }\n                }\n            }.apply {\n                this.orientation = RecyclerView.HORIZONTAL\n            }*/\n            resultCastItems.setRecycledViewPool(ActorAdaptor.sharedPool)\n            resultCastItems.adapter = ActorAdaptor()\n            resultEpisodes.setRecycledViewPool(EpisodeAdapter.sharedPool)\n            resultEpisodes.adapter =\n                EpisodeAdapter(\n                    api?.hasDownloadSupport == true,\n                    { episodeClick ->\n                        viewModel.handleAction(episodeClick)\n                    },\n                    { downloadClickEvent ->\n                        DownloadButtonSetup.handleDownloadClick(downloadClickEvent)\n                    }\n\n                )\n\n            observeNullable(viewModel.selectedSorting) {\n                resultSortButton.setText(it)\n            }\n\n            observe(viewModel.sortSelections) { sort ->\n                resultBinding?.resultSortButton?.setOnClickListener { view ->\n                    view?.context?.let { ctx ->\n                        val names = sort\n                            .mapNotNull { (text, r) ->\n                                r to (text.asStringNull(ctx) ?: return@mapNotNull null)\n                            }\n\n                        activity?.showDialog(\n                            names.map { it.second },\n                            viewModel.selectedSortingIndex.value ?: -1,\n                            ctx.getString(R.string.sort_by),\n                            false,\n                            {}) { itemId ->\n                            viewModel.setSort(names[itemId].first)\n                        }\n                    }\n                }\n            }\n\n            resultScroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->\n                val dy = scrollY - oldScrollY\n                if (dy > 0) { //check for scroll down\n                    binding?.resultBookmarkFab?.shrink()\n                } else if (dy < -5) {\n                    binding?.resultBookmarkFab?.extend()\n                }\n                if (!isFullScreenPlayer && player.getIsPlaying()) {\n                    if (scrollY > (resultBinding?.fragmentTrailer?.playerBackground?.height\n                            ?: scrollY)\n                    ) {\n                        player.handleEvent(CSPlayerEvent.Pause)\n                    }\n                }\n            })\n        }\n\n        binding?.apply {\n            resultOverlappingPanels.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)\n            resultOverlappingPanels.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)\n            resultBack.setOnClickListener {\n                activity?.popCurrentPage()\n            }\n\n            activity?.attachBackPressedCallback(this@ResultFragmentPhone.toString()) {\n                if (resultOverlappingPanels.getSelectedPanel().ordinal == 1) {\n                    runDefault()\n                } else resultOverlappingPanels.closePanels()\n            }\n\n            resultMiniSync.setOnClickListener {\n                if (resultOverlappingPanels.getSelectedPanel().ordinal == 1) {\n                    resultOverlappingPanels.openStartPanel()\n                } else resultOverlappingPanels.closePanels()\n            }\n\n            /*\n            resultMiniSync.setRecycledViewPool(ImageAdapter.sharedPool)\n            resultMiniSync.adapter = ImageAdapter(\n                nextFocusDown = R.id.result_sync_set_score,\n                clickCallback = { action ->\n                    if (action == IMAGE_CLICK || action == IMAGE_LONG_CLICK) {\n                        if (resultOverlappingPanels.getSelectedPanel().ordinal == 1) {\n                            resultOverlappingPanels.openStartPanel()\n                        } else resultOverlappingPanels.closePanels()\n                    }\n                })\n            */\n            resultSubscribe.setOnClickListener {\n                viewModel.toggleSubscriptionStatus(context) { newStatus: Boolean? ->\n                    if (newStatus == null) return@toggleSubscriptionStatus\n\n                    val message = if (newStatus) {\n                        // Kinda icky to have this here, but it works.\n                        SubscriptionWorkManager.enqueuePeriodicWork(context)\n                        R.string.subscription_new\n                    } else {\n                        R.string.subscription_deleted\n                    }\n\n                    val name = (viewModel.page.value as? Resource.Success)?.value?.title\n                        ?: com.lagradost.cloudstream3.utils.txt(R.string.no_data)\n                            .asStringNull(context) ?: \"\"\n                    showToast(\n                        com.lagradost.cloudstream3.utils.txt(message, name),\n                        Toast.LENGTH_SHORT\n                    )\n                }\n                context?.let { openBatteryOptimizationSettings(it) }\n            }\n            resultFavorite.setOnClickListener {\n                viewModel.toggleFavoriteStatus(context) { newStatus: Boolean? ->\n                    if (newStatus == null) return@toggleFavoriteStatus\n\n                    val message = if (newStatus) {\n                        R.string.favorite_added\n                    } else {\n                        R.string.favorite_removed\n                    }\n\n                    val name = (viewModel.page.value as? Resource.Success)?.value?.title\n                        ?: com.lagradost.cloudstream3.utils.txt(R.string.no_data)\n                            .asStringNull(context) ?: \"\"\n                    showToast(\n                        com.lagradost.cloudstream3.utils.txt(message, name),\n                        Toast.LENGTH_SHORT\n                    )\n                }\n            }\n            mediaRouteButton.apply {\n                val chromecastSupport = api?.hasChromecastSupport == true\n                alpha = if (chromecastSupport) 1f else 0.3f\n                if (!chromecastSupport) {\n                    setOnClickListener {\n                        showToast(\n                            R.string.no_chromecast_support_toast,\n                            Toast.LENGTH_LONG\n                        )\n                    }\n                }\n                activity?.let { act ->\n                    if (act.isCastApiAvailable()) {\n                        try {\n                            CastButtonFactory.setUpMediaRouteButton(act, this)\n                            CastContext.getSharedInstance(act.applicationContext) {\n                                it.run()\n                            }.addOnCompleteListener {\n                                isGone = !it.isSuccessful\n                            }\n                            // this shit leaks for some reason\n                            //castContext.addCastStateListener { state ->\n                            //    media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE\n                            //}\n                        } catch (e: Exception) {\n                            logError(e)\n                        }\n                    }\n                }\n            }\n        }\n\n        playerBinding?.apply {\n            playerOpenSource.setOnClickListener {\n                currentTrailers.getOrNull(currentTrailerIndex)?.let { (_, ogTrailerLink) ->\n                    context?.openBrowser(ogTrailerLink)\n                }\n            }\n        }\n\n        recommendationBinding?.apply {\n            resultRecommendationsList.apply {\n                spanCount = 3\n                setRecycledViewPool(SearchAdapter.sharedPool)\n                adapter =\n                    SearchAdapter(\n                        this,\n                    ) { callback ->\n                        SearchHelper.handleSearchClickCallback(callback)\n                    }\n            }\n        }\n\n\n        /*\n        result_bookmark_button?.setOnClickListener {\n            it.popupMenuNoIcons(\n                items = WatchType.values()\n                    .map { watchType -> Pair(watchType.internalId, watchType.stringRes) },\n                //.map { watchType -> Triple(watchType.internalId, watchType.iconRes, watchType.stringRes) },\n            ) {\n                viewModel.updateWatchStatus(WatchType.fromInternalId(this.itemId))\n            }\n        }*/\n\n        observeNullable(viewModel.resumeWatching) { resume ->\n            resultBinding?.apply {\n                if (resume == null) {\n                    resultResumeParent.isVisible = false\n                    resultPlayParent.isVisible = true\n                    resultResumeProgressHolder.isVisible = false\n                    return@observeNullable\n                }\n                resultResumeParent.isVisible = true\n                resume.progress?.let { progress ->\n                    resultNextSeriesButton.isVisible = false\n                    resultResumeSeriesTitle.apply {\n                        isVisible = !resume.isMovie\n                        text =\n                            if (resume.isMovie) null else context?.getNameFull(\n                                resume.result.name,\n                                resume.result.episode,\n                                resume.result.season\n                            )\n                    }\n                    if (resume.isMovie) {\n                        resultPlayParent.isGone = true\n                        resultResumeSeriesProgressText.isVisible = true\n                        resultResumeSeriesProgressText.setText(progress.progressLeft)\n                    }\n                    resultResumeSeriesProgress.apply {\n                        isVisible = true\n                        this.max = progress.maxProgress\n                        this.progress = progress.progress\n                    }\n                    resultResumeProgressHolder.isVisible = true\n                } ?: run {\n                    resultResumeProgressHolder.isVisible = false\n                    if (!resume.isMovie) {\n                        resultNextSeriesButton.isVisible = true\n                        resultNextSeriesButton.text = context?.getNameFull(\n                            resume.result.name,\n                            resume.result.episode,\n                            resume.result.season\n                        )\n                    }\n                    resultResumeSeriesProgress.isVisible = false\n                    resultResumeSeriesTitle.isVisible = false\n                    resultResumeSeriesProgressText.isVisible = false\n                }\n\n                resultResumeSeriesButton.setOnClickListener {\n                    resumeAction(storedData, resume)\n                }\n                resultNextSeriesButton.setOnClickListener {\n                    resumeAction(storedData, resume)\n                }\n            }\n        }\n\n        observeNullable(viewModel.subscribeStatus) { isSubscribed ->\n            binding?.resultSubscribe?.isVisible = isSubscribed != null\n            if (isSubscribed == null) return@observeNullable\n\n            val drawable = if (isSubscribed) {\n                R.drawable.ic_baseline_notifications_active_24\n            } else {\n                R.drawable.baseline_notifications_none_24\n            }\n\n            binding?.resultSubscribe?.setImageResource(drawable)\n        }\n\n        observeNullable(viewModel.favoriteStatus) { isFavorite ->\n            binding?.resultFavorite?.isVisible = isFavorite != null\n            if (isFavorite == null) return@observeNullable\n\n            val drawable = if (isFavorite) {\n                R.drawable.ic_baseline_favorite_24\n            } else {\n                R.drawable.ic_baseline_favorite_border_24\n            }\n\n            binding?.resultFavorite?.setImageResource(drawable)\n        }\n\n        observeNullable(viewModel.episodes) { episodes ->\n            resultBinding?.apply {\n                // no failure?\n                resultEpisodeLoading.isVisible = episodes is Resource.Loading\n                resultEpisodes.isVisible = episodes is Resource.Success\n                resultBatchDownloadButton.isVisible =\n                    episodes is Resource.Success && episodes.value.isNotEmpty()\n\n                if (episodes is Resource.Success) {\n                    (resultEpisodes.adapter as? EpisodeAdapter)?.submitList(episodes.value)\n\n                    // Show quality dialog with all sources\n                    resultBatchDownloadButton.setOnLongClickListener {\n                        ioSafe {\n                            val defaultSources = QualityProfileDialog.getAllDefaultSources()\n                            val activity = activity ?: return@ioSafe\n                            activity.runOnUiThread {\n                                QualityProfileDialog(\n                                    activity,\n                                    R.style.DialogFullscreenPlayer,\n                                    defaultSources,\n                                ).show()\n                            }\n                        }\n\n                        true\n                    }\n\n                    resultBatchDownloadButton.setOnClickListener { view ->\n                        val episodeStart =\n                            episodes.value.firstOrNull()?.episode ?: return@setOnClickListener\n                        val episodeEnd =\n                            episodes.value.lastOrNull()?.episode ?: return@setOnClickListener\n\n                        val episodeRange = if (episodeStart == episodeEnd) {\n                            episodeStart.toString()\n                        } else {\n                            txt(\n                                R.string.episodes_range,\n                                episodeStart,\n                                episodeEnd\n                            ).asString(view.context)\n                        }\n\n                        val rangeMessage = txt(\n                            R.string.download_episode_range,\n                            episodeRange\n                        ).asString(view.context)\n\n                        AlertDialog.Builder(view.context, R.style.AlertDialogCustom)\n                            .setTitle(R.string.download_all)\n                            .setMessage(rangeMessage)\n                            .setPositiveButton(R.string.yes) { _, _ ->\n                                ioSafe {\n                                    episodes.value.forEach { episode ->\n                                        viewModel.handleAction(\n                                            EpisodeClickEvent(\n                                                ACTION_DOWNLOAD_EPISODE,\n                                                episode\n                                            )\n                                        )\n                                            // Join to make the episodes ordered\n                                            .join()\n                                    }\n                                }\n                            }\n                            .setNegativeButton(R.string.cancel) { _, _ ->\n\n                            }.show()\n\n                    }\n\n                }\n\n\n            }\n\n        }\n\n        observeNullable(viewModel.movie) { data ->\n            resultBinding?.apply {\n                resultPlayMovie.isVisible = data is Resource.Success\n                downloadButton.isVisible =\n                    data is Resource.Success && viewModel.currentRepo?.api?.hasDownloadSupport == true\n\n                (data as? Resource.Success)?.value?.let { (text, ep) ->\n                    resultPlayMovie.setText(text)\n                    resultPlayMovie.setOnClickListener {\n                        viewModel.handleAction(\n                            EpisodeClickEvent(ACTION_CLICK_DEFAULT, ep)\n                        )\n                    }\n                    resultPlayMovie.setOnLongClickListener {\n                        viewModel.handleAction(\n                            EpisodeClickEvent(ACTION_SHOW_OPTIONS, ep)\n                        )\n                        return@setOnLongClickListener true\n                    }\n                    resultResumeSeriesButton.setOnLongClickListener {\n                        viewModel.handleAction(\n                            EpisodeClickEvent(ACTION_SHOW_OPTIONS, ep)\n                        )\n                        return@setOnLongClickListener true\n                    }\n\n                    val status = VideoDownloadManager.downloadStatus[ep.id]\n                    downloadButton.setStatus(status)\n                    downloadButton.setDefaultClickListener(\n                        DownloadObjects.DownloadEpisodeCached(\n                            name = ep.name,\n                            poster = ep.poster,\n                            episode = 0,\n                            season = null,\n                            id = ep.id,\n                            parentId = ep.id,\n                            score = ep.score,\n                            description = ep.description,\n                            cacheTime = System.currentTimeMillis(),\n                        ),\n                        null\n                    ) { click ->\n                        context?.let { openBatteryOptimizationSettings(it) }\n\n                        when (click.action) {\n                            DOWNLOAD_ACTION_DOWNLOAD -> {\n                                viewModel.handleAction(\n                                    EpisodeClickEvent(ACTION_DOWNLOAD_EPISODE, ep)\n                                )\n                            }\n\n                            DOWNLOAD_ACTION_LONG_CLICK -> {\n                                viewModel.handleAction(\n                                    EpisodeClickEvent(\n                                        ACTION_DOWNLOAD_MIRROR,\n                                        ep\n                                    )\n                                )\n                            }\n\n                            else -> DownloadButtonSetup.handleDownloadClick(click)\n                        }\n                    }\n                }\n            }\n        }\n\n        observe(viewModel.page) { data ->\n            if (data == null) return@observe\n            resultBinding?.apply {\n                PanelsChildGestureRegionObserver.Provider.get().apply {\n                    register(resultCastItems)\n                }\n                (data as? Resource.Success)?.value?.let { d ->\n                    resultVpn.setText(d.vpnText)\n                    resultInfo.setText(d.metaText)\n                    resultNoEpisodes.setText(d.noEpisodesFoundText)\n                    resultTitle.setText(d.titleText)\n                    resultMetaSite.setText(d.apiName)\n                    resultMetaType.setText(d.typeText)\n                    resultMetaYear.setText(d.yearText)\n                    resultMetaDuration.setText(d.durationText)\n                    resultMetaRating.setText(d.ratingText)\n                    resultMetaStatus.setText(d.onGoingText)\n                    resultMetaContentRating.setText(d.contentRatingText)\n                    resultCastText.setText(d.actorsText)\n                    resultNextAiring.setText(d.nextAiringEpisode)\n                    resultNextAiringTime.setText(d.nextAiringDate)\n                    resultPoster.loadImage(d.posterImage, headers = d.posterHeaders) {\n                        error {\n                            getImageFromDrawable(\n                                context ?: return@error null,\n                                R.drawable.default_cover\n                            )\n                        }\n                    }\n                    resultPosterBackground.loadImage(\n                        d.posterBackgroundImage,\n                        headers = d.posterHeaders\n                    ) {\n                        error {\n                            getImageFromDrawable(\n                                context ?: return@error null,\n                                R.drawable.default_cover\n                            )\n                        }\n                    }\n\n                    bindLogo(\n                        url = d.logoUrl,\n                        headers = d.posterHeaders,\n                        titleView = resultTitle,\n                        logoView = backgroundPosterWatermarkBadge\n                    )\n\n                    var isExpanded = false\n                    resultDescription.apply {\n                        setTextHtml(d.plotText)\n                        setOnClickListener {\n                            isExpanded = !isExpanded\n                            maxLines = if (isExpanded) {\n                                Integer.MAX_VALUE\n                            } else 10\n                        }\n                    }\n\n                    populateChips(resultTag, d.tags)\n\n                    resultComingSoon.isVisible = d.comingSoon\n                    resultDataHolder.isGone = d.comingSoon\n\n                    val prefs =\n                        androidx.preference.PreferenceManager.getDefaultSharedPreferences(root.context)\n                    val showCast = prefs.getBoolean(\n                        root.context.getString(R.string.show_cast_in_details_key),\n                        true\n                    )\n\n                    resultCastItems.isGone = !showCast || d.actors.isNullOrEmpty()\n                    (resultCastItems.adapter as? ActorAdaptor)?.submitList(if (showCast) d.actors else emptyList())\n\n                    if (d.contentRatingText == null) {\n                        // If there is no rating to display, we don't want an empty gap\n                        resultMetaContentRating.width = 0\n                    }\n\n                    if (syncModel.addSyncs(d.syncData)) {\n                        syncModel.updateMetaAndUser()\n                        syncModel.updateSynced()\n                    } else {\n                        syncModel.addFromUrl(d.url)\n                    }\n\n                    binding?.apply {\n                        resultSearch.isGone = d.title.isBlank()\n                        resultSearch.setOnClickListener {\n                            QuickSearchFragment.pushSearch(activity, d.title)\n                        }\n\n                        resultShare.setOnClickListener {\n                            try {\n                                val i = Intent(Intent.ACTION_SEND)\n                                val nameBase64 =\n                                    base64Encode(d.apiName.toString().toByteArray(Charsets.UTF_8))\n                                val urlBase64 = base64Encode(d.url.toByteArray(Charsets.UTF_8))\n                                val encodedUri = URLEncoder.encode(\n                                    \"$APP_STRING_SHARE:$nameBase64?$urlBase64\",\n                                    \"UTF-8\"\n                                )\n                                val redirectUrl =\n                                    \"https://recloudstream.github.io/csredirect?redirectto=$encodedUri\"\n                                i.type = \"text/plain\"\n                                i.putExtra(Intent.EXTRA_SUBJECT, d.title)\n                                i.putExtra(Intent.EXTRA_TEXT, redirectUrl)\n                                startActivity(Intent.createChooser(i, d.title))\n                            } catch (e: Exception) {\n                                logError(e)\n                            }\n                        }\n                        setUrl(d.url)\n                        resultBookmarkFab.apply {\n                            isVisible = true\n                            extend()\n                        }\n                    }\n                }\n\n                (data as? Resource.Failure)?.let { data ->\n                    resultErrorText.text = storedData.url.plus(\"\\n\") + data.errorString\n                }\n\n                binding?.resultBookmarkFab?.isVisible = data is Resource.Success\n                resultFinishLoading.isVisible = data is Resource.Success\n\n                resultLoading.isVisible = data is Resource.Loading\n\n                resultLoadingError.isVisible = data is Resource.Failure\n                resultErrorText.isVisible = data is Resource.Failure\n                resultReloadConnectionOpenInBrowser.isVisible = data is Resource.Failure\n\n                resultTitle.setOnLongClickListener {\n                    clipboardHelper(\n                        com.lagradost.cloudstream3.utils.txt(R.string.title),\n                        resultTitle.text\n                    )\n                    true\n                }\n            }\n        }\n\n        observeNullable(viewModel.episodesCountText) { count ->\n            resultBinding?.resultEpisodesText.setText(count)\n        }\n\n        observeNullable(viewModel.selectPopup) { popup ->\n            if (popup == null) {\n                popupDialog?.dismissSafe(activity)\n                popupDialog = null\n                return@observeNullable\n            }\n            popupDialog?.dismissSafe(activity)\n\n            popupDialog = activity?.let { act ->\n                val options = popup.getOptions(act)\n                val title = popup.getTitle(act)\n\n                act.showBottomDialogInstant(\n                    options, title, {\n                        popupDialog = null\n                        popup.callback(null)\n                    }, {\n                        popupDialog = null\n                        popup.callback(it)\n                    }\n                )\n            }\n        }\n\n        observe(viewModel.trailers) { trailers ->\n            setTrailers(trailers.flatMap { it.mirros }) // I dont care about subtitles yet!\n        }\n\n        observe(syncModel.synced) { list ->\n            syncBinding?.resultSyncNames?.text =\n                list.filter { it.isSynced && it.hasAccount }.joinToString { it.name }\n\n            val newList = list.filter { it.isSynced && it.hasAccount }\n\n            binding?.resultMiniSync?.isVisible = newList.isNotEmpty()\n            //(binding?.resultMiniSync?.adapter as? ImageAdapter)?.submitList(newList.mapNotNull { it.icon })\n        }\n\n\n        var currentSyncProgress = 0\n        fun setSyncMaxEpisodes(totalEpisodes: Int?) {\n            syncBinding?.resultSyncEpisodes?.max = (totalEpisodes ?: 0) * 1000\n\n            safe {\n                val ctx = syncBinding?.resultSyncEpisodes?.context\n                syncBinding?.resultSyncMaxEpisodes?.text =\n                    totalEpisodes?.let { episodes ->\n                        ctx?.getString(R.string.sync_total_episodes_some)?.format(episodes)\n                    } ?: run {\n                        ctx?.getString(R.string.sync_total_episodes_none)\n                    }\n            }\n        }\n        observe(syncModel.metadata) { meta ->\n            when (meta) {\n                is Resource.Success -> {\n                    val d = meta.value\n                    syncBinding?.resultSyncEpisodes?.progress = currentSyncProgress * 1000\n                    setSyncMaxEpisodes(d.totalEpisodes)\n\n                    viewModel.setMeta(d, syncModel.getSyncs())\n                }\n\n                is Resource.Loading -> {\n                    syncBinding?.resultSyncMaxEpisodes?.text =\n                        syncBinding?.resultSyncMaxEpisodes?.context?.getString(R.string.sync_total_episodes_none)\n                }\n\n                else -> {}\n            }\n        }\n\n\n        observe(syncModel.userData) { status ->\n            var closed = false\n            syncBinding?.apply {\n                when (status) {\n                    is Resource.Failure -> {\n                        resultSyncLoadingShimmer.stopShimmer()\n                        resultSyncLoadingShimmer.isVisible = false\n                        resultSyncHolder.isVisible = false\n                        closed = true\n                    }\n\n                    is Resource.Loading -> {\n                        resultSyncLoadingShimmer.startShimmer()\n                        resultSyncLoadingShimmer.isVisible = true\n                        resultSyncHolder.isVisible = false\n                    }\n\n                    is Resource.Success -> {\n                        resultSyncLoadingShimmer.stopShimmer()\n                        resultSyncLoadingShimmer.isVisible = false\n                        resultSyncHolder.isVisible = true\n\n                        val d = status.value\n                        val desiredScore = d.score?.toFloat(1) ?: 0.0f\n                        val totalSteps = (resultSyncRating.valueTo / resultSyncRating.stepSize)\n                        val desiredStep = (totalSteps * desiredScore).roundToInt()\n                        resultSyncRating.value = desiredStep * resultSyncRating.stepSize\n\n                        resultSyncCheck.setItemChecked(d.status.internalId + 1, true)\n                        val watchedEpisodes = d.watchedEpisodes ?: 0\n                        currentSyncProgress = watchedEpisodes\n\n                        d.maxEpisodes?.let {\n                            // don't directly call it because we don't want to override metadata observe\n                            setSyncMaxEpisodes(it)\n                        }\n\n                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                            resultSyncEpisodes.setProgress(watchedEpisodes * 1000, true)\n                        } else {\n                            resultSyncEpisodes.progress = watchedEpisodes * 1000\n                        }\n                        resultSyncCurrentEpisodes.text =\n                            Editable.Factory.getInstance()?.newEditable(watchedEpisodes.toString())\n                        safe { // format might fail\n                            val text = d.score?.toFloat(10)?.roundToInt()?.let {\n                                context?.getString(R.string.sync_score_format)?.format(it)\n                            } ?: \"?\"\n                            resultSyncScoreText.text = text\n                        }\n                    }\n\n                    null -> {\n                        closed = false\n                    }\n                }\n            }\n            binding?.resultOverlappingPanels?.setStartPanelLockState(if (closed) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)\n        }\n        observe(viewModel.recommendations) { recommendations ->\n            setRecommendations(recommendations, null)\n        }\n        context?.let { ctx ->\n            val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)\n            /*\n            -1 -> None\n            0 -> Watching\n            1 -> Completed\n            2 -> OnHold\n            3 -> Dropped\n            4 -> PlanToWatch\n            5 -> ReWatching\n            */\n            val items = listOf(\n                R.string.none,\n                R.string.type_watching,\n                R.string.type_completed,\n                R.string.type_on_hold,\n                R.string.type_dropped,\n                R.string.type_plan_to_watch,\n                R.string.type_re_watching\n            ).map { ctx.getString(it) }\n            arrayAdapter.addAll(items)\n            syncBinding?.apply {\n                resultSyncCheck.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n                resultSyncCheck.adapter = arrayAdapter\n                setListViewHeightBasedOnItems(resultSyncCheck)\n\n                resultSyncCheck.setOnItemClickListener { _, _, which, _ ->\n                    syncModel.setStatus(which - 1)\n                }\n\n                resultSyncRating.addOnChangeListener { it, value, fromUser ->\n                    if (fromUser) syncModel.setScore(Score.from(value, it.valueTo.roundToInt()))\n                }\n\n                resultSyncAddEpisode.setOnClickListener {\n                    syncModel.setEpisodesDelta(1)\n                }\n\n                resultSyncSubEpisode.setOnClickListener {\n                    syncModel.setEpisodesDelta(-1)\n                }\n\n                resultSyncCurrentEpisodes.doOnTextChanged { text, _, before, count ->\n                    if (count == before) return@doOnTextChanged\n                    text?.toString()?.toIntOrNull()?.let { ep ->\n                        syncModel.setEpisodes(ep)\n                    }\n                }\n            }\n        }\n\n        syncBinding?.resultSyncSetScore?.setOnClickListener {\n            syncModel.publishUserData()\n        }\n\n        observe(viewModel.watchStatus) { watchType ->\n            binding?.resultBookmarkFab?.apply {\n                setText(watchType.stringRes)\n                if (watchType == WatchType.NONE) {\n                    context?.colorFromAttribute(R.attr.white)\n                } else {\n                    context?.colorFromAttribute(R.attr.colorPrimary)\n                }?.let {\n                    val colorState = ColorStateList.valueOf(it)\n                    iconTint = colorState\n                    setTextColor(colorState)\n                }\n\n                setOnClickListener { fab ->\n                    activity?.showBottomDialog(\n                        WatchType.entries.map { fab.context.getString(it.stringRes) }.toList(),\n                        watchType.ordinal,\n                        fab.context.getString(R.string.action_add_to_bookmarks),\n                        showApply = false,\n                        {}) {\n                        viewModel.updateWatchStatus(WatchType.entries[it], context)\n                    }\n                }\n            }\n        }\n\n\n        observeNullable(viewModel.loadedLinks) { load ->\n            if (load == null) {\n                loadingDialog?.dismissSafe(activity)\n                loadingDialog = null\n                return@observeNullable\n            }\n            if (loadingDialog?.isShowing != true) {\n                loadingDialog?.dismissSafe(activity)\n                loadingDialog = null\n            }\n            loadingDialog = loadingDialog ?: context?.let { ctx ->\n                val builder = BottomSheetDialog(ctx)\n                builder.setContentView(R.layout.bottom_loading)\n                builder.setOnDismissListener {\n                    loadingDialog = null\n                    viewModel.cancelLinks()\n                }\n                builder.setCanceledOnTouchOutside(true)\n                builder.show()\n                builder\n            }\n            loadingDialog?.findViewById<MaterialButton>(R.id.overlay_loading_skip_button)?.apply {\n                if (load.linksLoaded <= 0) {\n                    isInvisible = true\n                } else {\n                    setOnClickListener {\n                        viewModel.skipLoading()\n                    }\n                    isVisible = true\n                    text = \"${context.getString(R.string.skip_loading)} (${load.linksLoaded})\"\n                }\n            }\n        }\n\n        observeNullable(viewModel.selectedSeason) { text ->\n            resultBinding?.apply {\n                resultSeasonButton.setText(text)\n\n                selectSeason =\n                    text?.asStringNull(resultSeasonButton.context)\n                // If the season button is visible the result season button will be next focus down\n                if (resultSeasonButton.isVisible && resultResumeParent.isVisible) {\n                    setFocusUpAndDown(resultResumeSeriesButton, resultSeasonButton)\n                }\n            }\n        }\n\n        observeNullable(viewModel.selectedDubStatus) { status ->\n            resultBinding?.apply {\n                resultDubSelect.setText(status)\n\n                if (resultDubSelect.isVisible && !resultSeasonButton.isVisible && !resultEpisodeSelect.isVisible && resultResumeParent.isVisible) {\n                    setFocusUpAndDown(resultResumeSeriesButton, resultDubSelect)\n                }\n            }\n        }\n        observeNullable(viewModel.selectedRange) { range ->\n            resultBinding?.apply {\n                resultEpisodeSelect.setText(range)\n\n                selectEpisodeRange = range?.asStringNull(resultEpisodeSelect.context)\n                // If Season button is invisible then the bookmark button next focus is episode select\n                if (resultEpisodeSelect.isVisible && !resultSeasonButton.isVisible && resultResumeParent.isVisible) {\n                    setFocusUpAndDown(resultResumeSeriesButton, resultEpisodeSelect)\n                }\n            }\n        }\n\n//        val preferDub = context?.getApiDubstatusSettings()?.all { it == DubStatus.Dubbed } == true\n\n        observe(viewModel.dubSubSelections) { range ->\n            resultBinding?.resultDubSelect?.setOnClickListener { view ->\n                view?.context?.let { ctx ->\n                    view.popupMenuNoIconsAndNoStringRes(\n                        range\n                            .mapNotNull { (text, status) ->\n                                Pair(\n                                    status.ordinal,\n                                    text?.asStringNull(ctx) ?: return@mapNotNull null\n                                )\n                            }) {\n                        viewModel.changeDubStatus(DubStatus.entries[itemId])\n                    }\n                }\n            }\n        }\n\n        observe(viewModel.rangeSelections) { range ->\n            resultBinding?.resultEpisodeSelect?.setOnClickListener { view ->\n                view?.context?.let { ctx ->\n                    val names = range\n                        .mapNotNull { (text, r) ->\n                            r to (text?.asStringNull(ctx) ?: return@mapNotNull null)\n                        }\n\n                    activity?.showDialog(\n                        names.map { it.second },\n                        names.indexOfFirst { it.second == selectEpisodeRange },\n                        ctx.getString(R.string.episodes),\n                        false,\n                        {}) { itemId ->\n                        viewModel.changeRange(names[itemId].first)\n                    }\n                }\n            }\n        }\n\n        observe(viewModel.seasonSelections) { seasonList ->\n            resultBinding?.resultSeasonButton?.setOnClickListener { view ->\n\n                view?.context?.let { ctx ->\n                    val names = seasonList\n                        .mapNotNull { (text, r) ->\n                            r to (text?.asStringNull(ctx) ?: return@mapNotNull null)\n                        }\n\n                    activity?.showDialog(\n                        names.map { it.second },\n                        names.indexOfFirst { it.second == selectSeason },\n                        ctx.getString(R.string.season),\n                        false,\n                        {}) { itemId ->\n                        viewModel.changeSeason(names[itemId].first)\n                    }\n\n\n                    //view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) ->\n                    //    index to name\n                    //}) {\n                    //    viewModel.changeSeason(names[itemId].first)\n                    //}\n                }\n            }\n        }\n    }\n\n    private fun resumeAction(\n        storedData: ResultFragment.StoredData,\n        resume: ResumeWatchingStatus\n    ) {\n        viewModel.handleAction(\n            EpisodeClickEvent(\n                storedData.playerAction, //?: ACTION_PLAY_EPISODE_IN_PLAYER,\n                resume.result\n            )\n        )\n    }\n\n    override fun onPause() {\n        super.onPause()\n        PanelsChildGestureRegionObserver.Provider.get()\n            .addGestureRegionsUpdateListener(gestureRegionsListener)\n    }\n\n    private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {\n        val isInvalid = rec.isNullOrEmpty()\n        val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName\n\n        recommendationBinding?.apply {\n            root.isGone = isInvalid\n            root.post {\n                rec?.let { list ->\n                    (resultRecommendationsList.adapter as? SearchAdapter)?.submitList(list.filter { it.apiName == matchAgainst })\n                }\n            }\n        }\n\n        binding?.apply {\n            resultRecommendationsBtt.isGone = isInvalid\n            resultRecommendationsBtt.setOnClickListener {\n                val nextFocusDown = if (resultOverlappingPanels.getSelectedPanel().ordinal == 1) {\n                    resultOverlappingPanels.openEndPanel()\n                    R.id.result_recommendations\n                } else {\n                    resultOverlappingPanels.closePanels()\n                    R.id.result_description\n                }\n                resultBinding?.apply {\n                    resultRecommendationsBtt.nextFocusDownId = nextFocusDown\n                    resultSearch.nextFocusDownId = nextFocusDown\n                    resultOpenInBrowser.nextFocusDownId = nextFocusDown\n                    resultShare.nextFocusDownId = nextFocusDown\n                }\n            }\n            resultOverlappingPanels.setEndPanelLockState(if (isInvalid) OverlappingPanelsLayout.LockState.CLOSE else OverlappingPanelsLayout.LockState.UNLOCKED)\n\n            rec?.map { it.apiName }?.distinct()?.let { apiNames ->\n                // very dirty selection\n                recommendationBinding?.resultRecommendationsFilterButton?.apply {\n                    isVisible = apiNames.size > 1\n                    text = matchAgainst\n                    setOnClickListener { _ ->\n                        activity?.showBottomDialog(\n                            apiNames,\n                            apiNames.indexOf(matchAgainst),\n                            getString(R.string.home_change_provider_img_des), false, {}\n                        ) {\n                            setRecommendations(rec, apiNames[it])\n                        }\n                    }\n                }\n            } ?: run {\n                recommendationBinding?.resultRecommendationsFilterButton?.isVisible = false\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentTv.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.animation.Animator\nimport android.annotation.SuppressLint\nimport android.app.Dialog\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.animation.DecelerateInterpolator\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.view.isGone\nimport androidx.core.view.isInvisible\nimport androidx.core.view.isVisible\nimport androidx.core.widget.NestedScrollView\nimport androidx.lifecycle.ViewModelProvider\nimport androidx.recyclerview.widget.RecyclerView\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.google.android.material.button.MaterialButton\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.DubStatus\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.databinding.FragmentResultTvBinding\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.mvvm.observeNullable\nimport com.lagradost.cloudstream3.services.SubscriptionWorkManager\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.WatchType\nimport com.lagradost.cloudstream3.ui.download.DownloadButtonSetup\nimport com.lagradost.cloudstream3.ui.player.ExtractorLinkGenerator\nimport com.lagradost.cloudstream3.ui.player.GeneratorPlayer\nimport com.lagradost.cloudstream3.ui.player.NEXT_WATCH_EPISODE_PERCENTAGE\nimport com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment\nimport com.lagradost.cloudstream3.ui.result.ResultFragment.bindLogo\nimport com.lagradost.cloudstream3.ui.result.ResultFragment.getStoredData\nimport com.lagradost.cloudstream3.ui.result.ResultFragment.updateUIEvent\nimport com.lagradost.cloudstream3.ui.search.SEARCH_ACTION_FOCUSED\nimport com.lagradost.cloudstream3.ui.search.SearchAdapter\nimport com.lagradost.cloudstream3.ui.search.SearchHelper\nimport com.lagradost.cloudstream3.ui.setRecycledViewPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isRtl\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadCache\nimport com.lagradost.cloudstream3.utils.AppContextUtils.updateHasTrailers\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogInstant\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UIHelper.populateChips\nimport com.lagradost.cloudstream3.utils.UIHelper.setNavigationBarColorCompat\nimport com.lagradost.cloudstream3.utils.getImageFromDrawable\nimport com.lagradost.cloudstream3.utils.setText\nimport com.lagradost.cloudstream3.utils.setTextHtml\nimport com.lagradost.cloudstream3.utils.txt\n\nclass ResultFragmentTv : BaseFragment<FragmentResultTvBinding>(\n    BindingCreator.Inflate(FragmentResultTvBinding::inflate)\n) {\n\n    private lateinit var viewModel: ResultViewModel2\n\n    override fun onDestroyView() {\n        updateUIEvent -= ::updateUI\n        activity?.detachBackPressedCallback(this@ResultFragmentTv.toString())\n        super.onDestroyView()\n    }\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?\n    ): View? {\n        viewModel =\n            ViewModelProvider(this)[ResultViewModel2::class.java]\n        viewModel.EPISODE_RANGE_SIZE = 50\n        updateUIEvent += ::updateUI\n\n        return super.onCreateView(inflater, container, savedInstanceState)\n    }\n\n    private fun updateUI(id: Int?) {\n        viewModel.reloadEpisodes()\n    }\n\n    private var currentRecommendations: List<SearchResponse> = emptyList()\n\n    private fun handleSelection(data: Any) {\n        when (data) {\n            is EpisodeRange -> {\n                viewModel.changeRange(data)\n            }\n\n            is Int -> {\n                viewModel.changeSeason(data)\n            }\n\n            is DubStatus -> {\n                viewModel.changeDubStatus(data)\n            }\n\n            is String -> {\n                setRecommendations(currentRecommendations, data)\n            }\n        }\n    }\n\n    private fun RecyclerView?.select(index: Int) {\n        (this?.adapter as? SelectAdaptor?)?.select(index, this)\n    }\n\n    private fun RecyclerView?.update(data: List<SelectData>) {\n        (this?.adapter as? SelectAdaptor?)?.submitList(data)\n        this?.isVisible = data.size > 1\n    }\n\n    private fun RecyclerView?.setAdapter() {\n        this?.adapter = SelectAdaptor { data ->\n            handleSelection(data)\n        }\n    }\n\n//    private fun hasNoFocus(): Boolean {\n//        val focus = activity?.currentFocus\n//        if (focus == null || !focus.isVisible) return true\n//        return focus == binding?.resultRoot\n//    }\n\n    /**\n     * Force focus any play button.\n     * Note that this will steal any focus if the episode loading is too slow (unlikely).\n     */\n    private fun focusPlayButton() {\n        binding?.resultPlayMovieButton?.requestFocus()\n        binding?.resultPlaySeriesButton?.requestFocus()\n        binding?.resultResumeSeriesButton?.requestFocus()\n    }\n\n    private fun setRecommendations(rec: List<SearchResponse>?, validApiName: String?) {\n        currentRecommendations = rec ?: emptyList()\n        val isInvalid = rec.isNullOrEmpty()\n        binding?.apply {\n            resultRecommendationsList.isGone = isInvalid\n            resultRecommendationsHolder.isGone = isInvalid\n            val matchAgainst = validApiName ?: rec?.firstOrNull()?.apiName\n            (resultRecommendationsList.adapter as? SearchAdapter)?.submitList(rec?.filter { it.apiName == matchAgainst }\n                ?: emptyList())\n\n            rec?.map { it.apiName }?.distinct()?.let { apiNames ->\n                // very dirty selection\n                resultRecommendationsFilterSelection.isVisible = apiNames.size > 1\n                resultRecommendationsFilterSelection.update(apiNames.map {\n                    txt(\n                        it\n                    ) to it\n                })\n                resultRecommendationsFilterSelection.select(apiNames.indexOf(matchAgainst))\n            } ?: run {\n                resultRecommendationsFilterSelection.isVisible = false\n            }\n        }\n    }\n\n    var loadingDialog: Dialog? = null\n    var popupDialog: Dialog? = null\n\n    private fun reloadViewModel(forceReload: Boolean) {\n        if (!viewModel.hasLoaded() || forceReload) {\n            val storedData = getStoredData() ?: return\n            viewModel.load(\n                activity,\n                storedData.url,\n                storedData.apiName,\n                storedData.showFillers,\n                storedData.dubStatus,\n                storedData.start\n            )\n        }\n    }\n\n    override fun onResume() {\n        activity?.setNavigationBarColorCompat(R.attr.primaryBlackBackground)\n        afterPluginsLoadedEvent += ::reloadViewModel\n        super.onResume()\n    }\n\n    override fun onStop() {\n        afterPluginsLoadedEvent -= ::reloadViewModel\n        super.onStop()\n    }\n\n    private fun View.fade(turnVisible: Boolean) {\n        if (turnVisible) {\n            isVisible = true\n        }\n\n        this.animate().alpha(if (turnVisible) 0.97f else 0.0f).apply {\n            duration = 200\n            interpolator = DecelerateInterpolator()\n            setListener(object : Animator.AnimatorListener {\n                override fun onAnimationStart(animation: Animator) {\n                }\n\n                override fun onAnimationEnd(animation: Animator) {\n                    this@fade.isVisible = turnVisible\n                }\n\n                override fun onAnimationCancel(animation: Animator) {\n                }\n\n                override fun onAnimationRepeat(animation: Animator) {\n                }\n            })\n        }\n        this.animate().translationX(if (turnVisible) 0f else if (isRtl()) -100.0f else 100f).apply {\n            duration = 200\n            interpolator = DecelerateInterpolator()\n        }\n    }\n\n    private fun toggleEpisodes(show: Boolean) {\n        binding?.apply {\n            if (show) {\n                activity?.attachBackPressedCallback(this@ResultFragmentTv.toString()) {\n                    toggleEpisodes(false)\n                }\n            } else {\n                activity?.detachBackPressedCallback(this@ResultFragmentTv.toString())\n            }\n            episodesShadow.fade(show)\n            episodeHolderTv.fade(show)\n            if (episodesShadow.isRtl()) {\n                episodesShadowBackground.scaleX = -1f\n            } else {\n                episodesShadowBackground.scaleX = 1f\n            }\n        }\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(view, padTop = false)\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onBindingCreated(binding: FragmentResultTvBinding) {\n        // ===== setup =====\n        val storedData = getStoredData() ?: return\n        activity?.window?.decorView?.clearFocus()\n        activity?.loadCache()\n        hideKeyboard()\n        if (storedData.restart || !viewModel.hasLoaded())\n            viewModel.load(\n                activity,\n                storedData.url,\n                storedData.apiName,\n                storedData.showFillers,\n                storedData.dubStatus,\n                storedData.start\n            )\n        // ===== ===== =====\n        var comingSoon = false\n\n        binding.apply {\n            //episodesShadow.rotationX = 180.0f//if(episodesShadow.isRtl()) 180.0f else 0.0f\n\n            // parallax on background\n            resultFinishLoading.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { view, _, scrollY, _, oldScrollY ->\n                backgroundPosterHolder.translationY = -scrollY.toFloat() * 0.8f\n            })\n\n            redirectToPlay.setOnFocusChangeListener { _, hasFocus ->\n                if (!hasFocus) return@setOnFocusChangeListener\n                toggleEpisodes(false)\n\n                binding.apply {\n                    val views = listOf(\n                        resultPlayMovieButton,\n                        resultPlaySeriesButton,\n                        resultResumeSeriesButton,\n                        resultPlayTrailerButton,\n                        resultBookmarkButton,\n                        resultFavoriteButton,\n                        resultSubscribeButton,\n                        resultSearchButton\n                    )\n                    for (requestView in views) {\n                        if (!requestView.isVisible) continue\n                        if (requestView.requestFocus()) break\n                    }\n                }\n            }\n\n            redirectToEpisodes.setOnFocusChangeListener { _, hasFocus ->\n                if (!hasFocus) return@setOnFocusChangeListener\n                toggleEpisodes(true)\n                binding.apply {\n                    val views = listOf(\n                        resultDubSelection,\n                        resultSeasonSelection,\n                        resultRangeSelection,\n                        resultEpisodes,\n                        resultPlayTrailerButton,\n                    )\n                    for (requestView in views) {\n                        if (!requestView.isShown) continue\n                        if (requestView.requestFocus()) break // View.FOCUS_RIGHT\n                    }\n                }\n            }\n\n            mapOf(\n                resultPlayMovieButton to resultPlayMovieText,\n                resultPlaySeriesButton to resultPlaySeriesText,\n                resultResumeSeriesButton to resultResumeSeriesText,\n                resultPlayTrailerButton to resultPlayTrailerText,\n                resultBookmarkButton to resultBookmarkText,\n                resultFavoriteButton to resultFavoriteText,\n                resultSubscribeButton to resultSubscribeText,\n                resultSearchButton to resultSearchText,\n                resultEpisodesShowButton to resultEpisodesShowText\n            ).forEach { (button, text) ->\n\n                button.setOnFocusChangeListener { view, hasFocus ->\n                    if (!hasFocus) {\n                        text.isSelected = false\n                        if (view.id == R.id.result_episodes_show_button) toggleEpisodes(false)\n                        return@setOnFocusChangeListener\n                    }\n\n                    text.isSelected = true\n                    if (button.tag == context?.getString(R.string.tv_no_focus_tag)) {\n                        resultFinishLoading.scrollTo(0, 0)\n                    }\n                    when (button.id) {\n                        R.id.result_episodes_show_button -> {\n                            toggleEpisodes(true)\n                        }\n\n                        else -> {\n                            toggleEpisodes(false)\n                        }\n                    }\n                }\n            }\n\n            resultEpisodesShowButton.setOnClickListener {\n                // toggle, to make it more touch accessible just in case someone thinks that a\n                // tv layout is better but is using a touch device\n                toggleEpisodes(!episodeHolderTv.isVisible)\n            }\n\n            resultEpisodes.setLinearListLayout(\n                isHorizontal = false,\n                nextUp = FOCUS_SELF,\n                nextDown = FOCUS_SELF,\n                nextRight = FOCUS_SELF,\n            )\n            resultDubSelection.setLinearListLayout(\n                isHorizontal = false,\n                nextUp = FOCUS_SELF,\n                nextDown = FOCUS_SELF,\n            )\n            resultRangeSelection.setLinearListLayout(\n                isHorizontal = false,\n                nextUp = FOCUS_SELF,\n                nextDown = FOCUS_SELF,\n            )\n            resultSeasonSelection.setLinearListLayout(\n                isHorizontal = false,\n                nextUp = FOCUS_SELF,\n                nextDown = FOCUS_SELF,\n            )\n\n            /*.layoutManager =\n                LinearListLayout(resultEpisodes.context, resultEpisodes.isRtl()).apply {\n                    setVertical()\n                }*/\n\n            resultReloadConnectionerror.setOnClickListener {\n                viewModel.load(\n                    activity,\n                    storedData.url,\n                    storedData.apiName,\n                    storedData.showFillers,\n                    storedData.dubStatus,\n                    storedData.start\n                )\n\n            }\n\n            resultMetaSite.isFocusable = false\n\n            resultSeasonSelection.setAdapter()\n            resultRangeSelection.setAdapter()\n            resultDubSelection.setAdapter()\n            resultRecommendationsFilterSelection.setAdapter()\n\n            resultCastItems.setOnFocusChangeListener { _, hasFocus ->\n                // Always escape focus\n                if (hasFocus) binding.resultBookmarkButton.requestFocus()\n            }\n            //resultBack.setOnClickListener {\n            //    activity?.popCurrentPage()\n            //}\n\n            resultRecommendationsList.spanCount = 8\n            resultRecommendationsList.setRecycledViewPool(SearchAdapter.sharedPool)\n            resultRecommendationsList.adapter =\n                SearchAdapter(\n                    resultRecommendationsList,\n                ) { callback ->\n                    if (callback.action == SEARCH_ACTION_FOCUSED) {\n                        toggleEpisodes(false)\n                    } else SearchHelper.handleSearchClickCallback(callback)\n                }\n\n            resultEpisodes.setRecycledViewPool(EpisodeAdapter.sharedPool)\n            resultEpisodes.adapter =\n                EpisodeAdapter(\n                    false,\n                    { episodeClick ->\n                        viewModel.handleAction(episodeClick)\n                    },\n                    { downloadClickEvent ->\n                        DownloadButtonSetup.handleDownloadClick(downloadClickEvent)\n                    }\n                )\n\n            resultCastItems.layoutManager = object : LinearListLayout(root.context) {\n                override fun onRequestChildFocus(\n                    parent: RecyclerView,\n                    state: RecyclerView.State,\n                    child: View,\n                    focused: View?\n                ): Boolean {\n                    // Make the cast always focus the first visible item when focused\n                    // from somewhere else. Otherwise it jumps to the last item.\n                    return if (parent.focusedChild == null) {\n                        scrollToPosition(this.findFirstCompletelyVisibleItemPosition())\n                        true\n                    } else {\n                        super.onRequestChildFocus(parent, state, child, focused)\n                    }\n                }\n            }.apply { setHorizontal() }\n\n            val aboveCast = listOf(\n                binding.resultEpisodesShow,\n                binding.resultBookmark,\n                binding.resultFavorite,\n                binding.resultSubscribe,\n            ).firstOrNull { it.isVisible }\n\n            resultCastItems.setRecycledViewPool(ActorAdaptor.sharedPool)\n            resultCastItems.adapter = ActorAdaptor(aboveCast?.id) {\n                toggleEpisodes(false)\n            }\n\n            if (isLayout(EMULATOR)) {\n                episodesShadow.setOnClickListener {\n                    toggleEpisodes(false)\n                }\n            }\n        }\n\n        observeNullable(viewModel.resumeWatching) { resume ->\n            binding.apply {\n                if (resume == null) {\n                    return@observeNullable\n                }\n\n                resultResumeSeries.isVisible = true\n                resultPlayMovie.isVisible = false\n                resultPlaySeries.isVisible = false\n\n                // show progress no matter if series or movie\n                resume.progress?.let { progress ->\n                    resultResumeSeriesTitle.apply {\n                        isVisible = !resume.isMovie\n                        text =\n                            if (resume.isMovie) null else context?.getNameFull(\n                                resume.result.name,\n                                resume.result.episode,\n                                resume.result.season\n                            )\n                    }\n                    resultResumeSeriesProgressText.setText(progress.progressLeft)\n                    resultResumeSeriesProgress.apply {\n                        isVisible = true\n                        this.max = progress.maxProgress\n                        this.progress = progress.progress\n                    }\n                    resultResumeProgressHolder.isVisible = true\n                } ?: run {\n                    resultResumeProgressHolder.isVisible = false\n                }\n\n                focusPlayButton()\n                // Stops last button right focus if it is a movie\n                if (resume.isMovie)\n                    resultSearchButton.nextFocusRightId = R.id.result_search_Button\n\n                resultResumeSeriesText.text =\n                    when {\n                        resume.isMovie -> context?.getString(R.string.resume)\n                        resume.result.season != null ->\n                            \"${getString(R.string.season_short)}${resume.result.season}:${\n                                getString(\n                                    R.string.episode_short\n                                )\n                            }${resume.result.episode}\"\n\n                        else -> \"${getString(R.string.episode)} ${resume.result.episode}\"\n                    }\n\n                resultResumeSeriesButton.setOnClickListener {\n                    viewModel.handleAction(\n                        EpisodeClickEvent(\n                            storedData.playerAction, //?: ACTION_PLAY_EPISODE_IN_PLAYER,\n                            resume.result\n                        )\n                    )\n                }\n\n                resultResumeSeriesButton.setOnLongClickListener {\n                    viewModel.handleAction(\n                        EpisodeClickEvent(ACTION_SHOW_OPTIONS, resume.result)\n                    )\n                    return@setOnLongClickListener true\n                }\n\n            }\n        }\n\n        observe(viewModel.trailers) { trailersLinks ->\n            context?.updateHasTrailers()\n            if (!LoadResponse.isTrailersEnabled) return@observe\n            val extractedTrailerLinks = trailersLinks.flatMap { it.mirros }\n                .map { (extractedTrailerLink, _) -> extractedTrailerLink }\n            binding.apply {\n                resultPlayTrailer.isGone = extractedTrailerLinks.isEmpty()\n                resultPlayTrailerButton.setOnClickListener {\n                    if (extractedTrailerLinks.isEmpty()) return@setOnClickListener\n                    activity.navigate(\n                        R.id.global_to_navigation_player, GeneratorPlayer.newInstance(\n                            ExtractorLinkGenerator(\n                                extractedTrailerLinks,\n                                emptyList()\n                            )\n                        )\n                    )\n                }\n            }\n        }\n\n        observe(viewModel.watchStatus) { watchType ->\n            binding.apply {\n                resultBookmarkText.setText(watchType.stringRes)\n\n                resultBookmarkButton.apply {\n                    val drawable = if (watchType.stringRes == R.string.type_none) {\n                        R.drawable.outline_bookmark_add_24\n                    } else R.drawable.ic_baseline_bookmark_24\n                    setIconResource(drawable)\n\n                    setOnClickListener { view ->\n                        activity?.showBottomDialog(\n                            WatchType.entries.map { view.context.getString(it.stringRes) }.toList(),\n                            watchType.ordinal,\n                            view.context.getString(R.string.action_add_to_bookmarks),\n                            showApply = false,\n                            {}) {\n                            viewModel.updateWatchStatus(WatchType.entries[it], context)\n                        }\n                    }\n                }\n            }\n        }\n\n        observeNullable(viewModel.favoriteStatus) { isFavorite ->\n            binding.resultFavorite.isVisible = isFavorite != null\n            binding.resultFavoriteButton.apply {\n                if (isFavorite == null) return@observeNullable\n\n                val drawable = if (isFavorite) {\n                    R.drawable.ic_baseline_favorite_24\n                } else R.drawable.ic_baseline_favorite_border_24\n                setIconResource(drawable)\n\n                setOnClickListener {\n                    viewModel.toggleFavoriteStatus(context) { newStatus: Boolean? ->\n                        if (newStatus == null) return@toggleFavoriteStatus\n\n                        val message = if (newStatus) {\n                            R.string.favorite_added\n                        } else R.string.favorite_removed\n\n                        val name = (viewModel.page.value as? Resource.Success)?.value?.title\n                            ?: txt(R.string.no_data)\n                                .asStringNull(context) ?: \"\"\n                        CommonActivity.showToast(\n                            txt(\n                                message,\n                                name\n                            ), Toast.LENGTH_SHORT\n                        )\n                    }\n                }\n            }\n\n            binding.resultFavoriteText.apply {\n                val text = if (isFavorite == true) {\n                    R.string.unfavorite\n                } else R.string.favorite\n                setText(text)\n            }\n        }\n\n        observeNullable(viewModel.subscribeStatus) { isSubscribed ->\n            binding.resultSubscribe.isVisible = isSubscribed != null && isLayout(EMULATOR)\n            binding.resultSubscribeButton.apply {\n                if (isSubscribed == null) return@observeNullable\n\n                val drawable = if (isSubscribed) {\n                    R.drawable.ic_baseline_notifications_active_24\n                } else R.drawable.baseline_notifications_none_24\n                setIconResource(drawable)\n\n                setOnClickListener {\n                    viewModel.toggleSubscriptionStatus(context) { newStatus: Boolean? ->\n                        if (newStatus == null) return@toggleSubscriptionStatus\n\n                        val message = if (newStatus) {\n                            // Kinda icky to have this here, but it works.\n                            SubscriptionWorkManager.enqueuePeriodicWork(context)\n                            R.string.subscription_new\n                        } else R.string.subscription_deleted\n\n                        val name = (viewModel.page.value as? Resource.Success)?.value?.title\n                            ?: txt(R.string.no_data)\n                                .asStringNull(context) ?: \"\"\n                        CommonActivity.showToast(\n                            txt(\n                                message,\n                                name\n                            ), Toast.LENGTH_SHORT\n                        )\n                    }\n                }\n\n                binding.resultSubscribeText.apply {\n                    val text = if (isSubscribed) {\n                        R.string.action_unsubscribe\n                    } else R.string.action_subscribe\n                    setText(text)\n                }\n            }\n        }\n\n        observeNullable(viewModel.movie) { data ->\n            if (data == null) {\n                return@observeNullable\n            }\n\n            binding.apply {\n                (data as? Resource.Success)?.value?.let { (_, ep) ->\n                    resultPlayMovieButton.setOnClickListener {\n                        viewModel.handleAction(\n                            EpisodeClickEvent(ACTION_CLICK_DEFAULT, ep)\n                        )\n                    }\n                    resultPlayMovieButton.setOnLongClickListener {\n                        viewModel.handleAction(\n                            EpisodeClickEvent(ACTION_SHOW_OPTIONS, ep)\n                        )\n                        return@setOnLongClickListener true\n                    }\n\n                    resultPlayMovie.isVisible = !comingSoon && resultResumeSeries.isGone\n                    if (comingSoon) {\n                        resultBookmarkButton.requestFocus()\n                    } else resultPlayMovieButton.requestFocus()\n\n                    // Stops last button right focus\n                    resultSearchButton.nextFocusRightId = R.id.result_search_Button\n                }\n            }\n        }\n\n        observeNullable(viewModel.selectPopup) { popup ->\n            if (popup == null) {\n                popupDialog?.dismissSafe(activity)\n                popupDialog = null\n                return@observeNullable\n            }\n\n            popupDialog?.dismissSafe(activity)\n\n            popupDialog = activity?.let { act ->\n                val options = popup.getOptions(act)\n                val title = popup.getTitle(act)\n\n                act.showBottomDialogInstant(\n                    options, title, {\n                        popupDialog = null\n                        popup.callback(null)\n                    }, {\n                        popupDialog = null\n                        popup.callback(it)\n                    }\n                )\n            }\n        }\n\n        observeNullable(viewModel.loadedLinks) { load ->\n            if (load == null) {\n                loadingDialog?.dismissSafe(activity)\n                loadingDialog = null\n                return@observeNullable\n            }\n            if (loadingDialog?.isShowing != true) {\n                loadingDialog?.dismissSafe(activity)\n                loadingDialog = null\n            }\n            loadingDialog = loadingDialog ?: context?.let { ctx ->\n                val builder = BottomSheetDialog(ctx)\n                builder.setContentView(R.layout.bottom_loading)\n                builder.setOnDismissListener {\n                    loadingDialog = null\n                    viewModel.cancelLinks()\n                }\n                builder.setCanceledOnTouchOutside(true)\n                builder.show()\n                builder\n            }\n            loadingDialog?.findViewById<MaterialButton>(R.id.overlay_loading_skip_button)?.apply {\n                if (load.linksLoaded <= 0) {\n                    isInvisible = true\n                } else {\n                    setOnClickListener {\n                        viewModel.skipLoading()\n                    }\n                    isVisible = true\n                    text = \"${context.getString(R.string.skip_loading)} (${load.linksLoaded})\"\n                }\n            }\n        }\n\n\n        observeNullable(viewModel.episodesCountText) { count ->\n            binding.resultEpisodesText.setText(count)\n        }\n\n        observe(viewModel.selectedRangeIndex) { selected ->\n            binding.resultRangeSelection.select(selected)\n        }\n        observe(viewModel.selectedSeasonIndex) { selected ->\n            binding.resultSeasonSelection.select(selected)\n        }\n        observe(viewModel.selectedDubStatusIndex) { selected ->\n            binding.resultDubSelection.select(selected)\n        }\n        observe(viewModel.rangeSelections) {\n            binding.resultRangeSelection.update(it)\n        }\n        observe(viewModel.dubSubSelections) {\n            binding.resultDubSelection.update(it)\n        }\n        observe(viewModel.seasonSelections) {\n            binding.resultSeasonSelection.update(it)\n        }\n        observe(viewModel.recommendations) { recommendations ->\n            setRecommendations(recommendations, null)\n        }\n\n        if (isLayout(TV)) {\n            observe(viewModel.episodeSynopsis) { description ->\n                context?.let { ctx ->\n                    val builder: AlertDialog.Builder =\n                        AlertDialog.Builder(ctx, R.style.AlertDialogCustom)\n                    builder.setMessage(description.html())\n                        .setTitle(R.string.synopsis)\n                        .setOnDismissListener {\n                            viewModel.releaseEpisodeSynopsis()\n                        }\n                        .show()\n                }\n            }\n        }\n\n        // Used to request focus the first time the episodes are loaded.\n        var hasLoadedEpisodesOnce = false\n        observeNullable(viewModel.episodes) { episodes ->\n            if (episodes == null) return@observeNullable\n            binding.apply {\n                if (comingSoon) resultBookmarkButton.requestFocus()\n\n                //    resultEpisodeLoading.isVisible = episodes is Resource.Loading\n                if (episodes is Resource.Success) {\n                    val lastWatchedIndex = episodes.value.indexOfLast { ep ->\n                        ep.getWatchProgress() >= NEXT_WATCH_EPISODE_PERCENTAGE.toFloat() / 100.0f || ep.videoWatchState == VideoWatchState.Watched\n                    }\n\n                    val firstUnwatched =\n                        episodes.value.getOrElse(lastWatchedIndex + 1) { episodes.value.firstOrNull() }\n\n                    if (firstUnwatched != null) {\n                        resultPlaySeriesText.text =\n                            when {\n                                firstUnwatched.season != null ->\n                                    \"${getString(R.string.season_short)}${firstUnwatched.season}:${\n                                        getString(\n                                            R.string.episode_short\n                                        )\n                                    }${firstUnwatched.episode}\"\n\n                                else -> \"${getString(R.string.episode)} ${firstUnwatched.episode}\"\n                            }\n                        resultPlaySeriesButton.setOnClickListener {\n                            viewModel.handleAction(\n                                EpisodeClickEvent(\n                                    ACTION_CLICK_DEFAULT,\n                                    firstUnwatched\n                                )\n                            )\n                        }\n                        resultPlaySeriesButton.setOnLongClickListener {\n                            viewModel.handleAction(\n                                EpisodeClickEvent(ACTION_SHOW_OPTIONS, firstUnwatched)\n                            )\n                            return@setOnLongClickListener true\n                        }\n                        if (!hasLoadedEpisodesOnce) {\n                            hasLoadedEpisodesOnce = true\n                            resultPlaySeries.isVisible = resultResumeSeries.isGone && !comingSoon\n                            resultEpisodesShow.isVisible = true && !comingSoon\n                            resultPlaySeriesButton.requestFocus()\n                        }\n                    }\n\n\n                    (resultEpisodes.adapter as? EpisodeAdapter)?.submitList(episodes.value)\n                }\n            }\n        }\n\n        observeNullable(viewModel.page) { data ->\n            if (data == null) return@observeNullable\n            binding.apply {\n                when (data) {\n                    is Resource.Success -> {\n                        val d = data.value\n                        resultVpn.setText(d.vpnText)\n                        resultInfo.setText(d.metaText)\n                        resultNoEpisodes.setText(d.noEpisodesFoundText)\n                        resultTitle.setText(d.titleText)\n                        resultMetaSite.setText(d.apiName)\n                        resultMetaType.setText(d.typeText)\n                        resultMetaYear.setText(d.yearText)\n                        resultMetaDuration.setText(d.durationText)\n                        resultMetaRating.setText(d.ratingText)\n                        resultMetaStatus.setText(d.onGoingText)\n                        resultMetaContentRating.setText(d.contentRatingText)\n                        resultCastText.setText(d.actorsText)\n                        resultNextAiring.setText(d.nextAiringEpisode)\n                        resultNextAiringTime.setText(d.nextAiringDate)\n                        resultPoster.loadImage(d.posterImage)\n\n                        var isExpanded = false\n                        resultDescription.apply {\n                            setTextHtml(d.plotText)\n                            setOnClickListener {\n                                if (isLayout(EMULATOR)) {\n                                    isExpanded = !isExpanded\n                                    maxLines = if (isExpanded) {\n                                        Integer.MAX_VALUE\n                                    } else 10\n                                } else {\n                                    context?.let { ctx ->\n                                        val builder: AlertDialog.Builder =\n                                            AlertDialog.Builder(ctx, R.style.AlertDialogCustom)\n                                        builder.setMessage(d.plotText.asString(ctx).html())\n                                            .setTitle(d.plotHeaderText.asString(ctx))\n                                            .show()\n                                    }\n                                }\n                            }\n                        }\n\n                        val error = listOf(\n                            R.drawable.profile_bg_dark_blue,\n                            R.drawable.profile_bg_blue,\n                            R.drawable.profile_bg_orange,\n                            R.drawable.profile_bg_pink,\n                            R.drawable.profile_bg_purple,\n                            R.drawable.profile_bg_red,\n                            R.drawable.profile_bg_teal\n                        ).random()\n\n                        backgroundPoster.loadImage(d.posterBackgroundImage) {\n                            error { getImageFromDrawable(context ?: return@error null, error) }\n                        }\n\n                        bindLogo(\n                            url = d.logoUrl,\n                            headers = d.posterHeaders,\n                            titleView = resultTitle,\n                            logoView = backgroundPosterWatermarkBadgeHolder\n                        )\n\n                        comingSoon = d.comingSoon\n                        resultTvComingSoon.isVisible = d.comingSoon\n\n                        populateChips(resultTag, d.tags)\n                        val prefs = androidx.preference.PreferenceManager.getDefaultSharedPreferences(root.context)\n                        val showCast = prefs.getBoolean(root.context.getString(R.string.show_cast_in_details_key), true)\n\n                        resultCastItems.isGone = !showCast || d.actors.isNullOrEmpty()\n                        (resultCastItems.adapter as? ActorAdaptor)?.submitList(if (showCast) d.actors else emptyList())\n\n                        if (d.contentRatingText == null) {\n                            // If there is no rating to display, we don't want an empty gap\n                            resultMetaContentRating.width = 0\n                        }\n\n                        resultSearchButton.setOnClickListener {\n                            QuickSearchFragment.pushSearch(activity, d.title)\n                        }\n                    }\n\n                    is Resource.Loading -> {}\n\n                    is Resource.Failure -> {\n                        resultErrorText.text =\n                            storedData.url.plus(\"\\n\") + data.errorString\n                    }\n                }\n\n                resultFinishLoading.isVisible = data is Resource.Success\n\n                resultLoading.isVisible = data is Resource.Loading\n\n                resultLoadingError.isVisible = data is Resource.Failure\n                //resultReloadConnectionOpenInBrowser.isVisible = data is Resource.Failure\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultTrailerPlayer.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.animation.ValueAnimator\nimport android.content.Context\nimport android.content.res.Configuration\nimport android.os.Build\nimport android.os.Bundle\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.FrameLayout\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.core.view.ViewCompat\nimport com.lagradost.cloudstream3.CommonActivity.screenHeight\nimport com.lagradost.cloudstream3.CommonActivity.screenWidth\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.player.CSPlayerEvent\nimport com.lagradost.cloudstream3.ui.player.PlayerEventSource\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\n\nopen class ResultTrailerPlayer : ResultFragmentPhone() {\n\n    override var lockRotation = false\n    override var isFullScreenPlayer = false\n    override var hasPipModeSupport = false\n\n    companion object {\n        const val TAG = \"RESULT_TRAILER\"\n    }\n\n    private var playerWidthHeight: Pair<Int, Int>? = null\n\n    override fun nextEpisode() {}\n\n    override fun prevEpisode() {}\n\n    override fun playerPositionChanged(position: Long, duration : Long) {}\n\n    override fun nextMirror() {}\n\n    override fun onConfigurationChanged(newConfig: Configuration) {\n        super.onConfigurationChanged(newConfig)\n        uiReset()\n        fixPlayerSize()\n    }\n\n    private fun fixPlayerSize() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            binding?.apply {\n                if (isFullScreenPlayer) {\n                    // Remove listener\n                    ViewCompat.setOnApplyWindowInsetsListener(root, null)\n                    root.overlay.clear() // Clear the cutout overlay\n                    root.setPadding(0, 0, 0, 0) // Reset padding for full screen\n                } else {\n                    // Reapply padding when not in full screen\n                    fixSystemBarsPadding(root)\n                    ViewCompat.requestApplyInsets(root)\n                }\n            }\n        }\n\n        playerWidthHeight?.let { (w, h) ->\n            if(w <= 0 || h <= 0) return@let\n\n            val orientation = context?.resources?.configuration?.orientation ?: return\n\n            val sw = if (orientation == Configuration.ORIENTATION_LANDSCAPE) {\n                screenWidth\n            } else {\n                screenHeight\n            }\n\n            //result_trailer_loading?.isVisible = false\n            resultBinding?.resultSmallscreenHolder?.isVisible = !isFullScreenPlayer\n            binding?.resultFullscreenHolder?.isVisible = isFullScreenPlayer\n\n            val to = sw * h / w\n\n            resultBinding?.fragmentTrailer?.playerBackground?.apply {\n                isVisible = true\n                layoutParams =\n                    FrameLayout.LayoutParams(\n                        FrameLayout.LayoutParams.MATCH_PARENT,\n                        if (isFullScreenPlayer) FrameLayout.LayoutParams.MATCH_PARENT else to\n                    )\n            }\n\n            playerBinding?.playerIntroPlay?.apply {\n                layoutParams =\n                    FrameLayout.LayoutParams(\n                        FrameLayout.LayoutParams.MATCH_PARENT,\n                        resultBinding?.resultTopHolder?.measuredHeight\n                            ?: FrameLayout.LayoutParams.MATCH_PARENT\n                    )\n            }\n\n            if (playerBinding?.playerIntroPlay?.isGone == true) {\n                resultBinding?.resultTopHolder?.apply {\n\n                    val anim = ValueAnimator.ofInt(\n                        measuredHeight,\n                        if (isFullScreenPlayer) ViewGroup.LayoutParams.MATCH_PARENT else to\n                    )\n                    anim.addUpdateListener { valueAnimator ->\n                        val `val` = valueAnimator.animatedValue as Int\n                        val layoutParams: ViewGroup.LayoutParams =\n                            layoutParams\n                        layoutParams.height = `val`\n                        setLayoutParams(layoutParams)\n                    }\n                    anim.duration = 200\n                    anim.start()\n                }\n            }\n        }\n    }\n\n    override fun playerDimensionsLoaded(width: Int, height : Int) {\n        playerWidthHeight = width to height\n        fixPlayerSize()\n    }\n\n    override fun showMirrorsDialogue() {}\n    override fun showTracksDialogue() {}\n\n    override fun openOnlineSubPicker(\n        context: Context,\n        loadResponse: LoadResponse?,\n        dismissCallback: () -> Unit\n    ) {\n    }\n\n    override fun subtitlesChanged() {}\n\n    override fun embeddedSubtitlesFetched(subtitles: List<SubtitleData>) {}\n    override fun onTracksInfoChanged() {}\n\n    override fun exitedPipMode() {}\n    private fun updateFullscreen(fullscreen: Boolean) {\n        isFullScreenPlayer = fullscreen\n        lockRotation = fullscreen\n\n        playerBinding?.playerFullscreen?.setImageResource(if (fullscreen) R.drawable.baseline_fullscreen_exit_24 else R.drawable.baseline_fullscreen_24)\n        if (fullscreen) {\n            enterFullscreen()\n            binding?.apply {\n                resultTopBar.isVisible = false\n                resultFullscreenHolder.isVisible = true\n                resultMainHolder.isVisible = false\n            }\n\n            resultBinding?.fragmentTrailer?.playerBackground?.let { view ->\n                (view.parent as ViewGroup?)?.removeView(view)\n                binding?.resultFullscreenHolder?.addView(view)\n            }\n\n        } else {\n            binding?.apply {\n                resultTopBar.isVisible = true\n                resultFullscreenHolder.isVisible = false\n                resultMainHolder.isVisible = true\n                resultBinding?.fragmentTrailer?.playerBackground?.let { view ->\n                    (view.parent as ViewGroup?)?.removeView(view)\n                    resultBinding?.resultSmallscreenHolder?.addView(view)\n                }\n            }\n            exitFullscreen()\n        }\n        fixPlayerSize()\n        uiReset()\n\n        if (isFullScreenPlayer) {\n            activity?.attachBackPressedCallback(\"ResultTrailerPlayer\") {\n                updateFullscreen(false)\n            }\n        } else activity?.detachBackPressedCallback(\"ResultTrailerPlayer\")\n    }\n\n    override fun updateUIVisibility() {\n        super.updateUIVisibility()\n        playerBinding?.playerGoBackHolder?.isVisible = false\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        playerBinding?.playerFullscreen?.setOnClickListener {\n            updateFullscreen(!isFullScreenPlayer)\n        }\n        updateFullscreen(isFullScreenPlayer)\n        uiReset()\n\n        playerBinding?.playerIntroPlay?.setOnClickListener {\n            playerBinding?.playerIntroPlay?.isGone = true\n            player.handleEvent(CSPlayerEvent.Play, PlayerEventSource.UI)\n            updateUIVisibility()\n            fixPlayerSize()\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.app.Activity\nimport android.content.*\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.annotation.MainThread\nimport androidx.appcompat.app.AlertDialog\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.actions.AlwaysAskAction\nimport com.lagradost.cloudstream3.actions.VideoClickActionHolder\nimport com.lagradost.cloudstream3.APIHolder.apis\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.APIHolder.unixTime\nimport com.lagradost.cloudstream3.APIHolder.unixTimeMS\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.context\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.CommonActivity.getCastSession\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer\nimport com.lagradost.cloudstream3.LoadResponse.Companion.getAniListId\nimport com.lagradost.cloudstream3.LoadResponse.Companion.getKitsuId\nimport com.lagradost.cloudstream3.LoadResponse.Companion.getMalId\nimport com.lagradost.cloudstream3.LoadResponse.Companion.isMovie\nimport com.lagradost.cloudstream3.LoadResponse.Companion.readIdFromString\nimport com.lagradost.cloudstream3.metaproviders.SyncRedirector\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.debugAssert\nimport com.lagradost.cloudstream3.mvvm.debugException\nimport com.lagradost.cloudstream3.mvvm.launchSafe\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.mvvm.safeApiCall\nimport com.lagradost.cloudstream3.runAllAsync\nimport com.lagradost.cloudstream3.sortUrls\nimport com.lagradost.cloudstream3.syncproviders.AccountManager\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.secondsToReadable\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.syncproviders.providers.Kitsu\nimport com.lagradost.cloudstream3.ui.APIRepository\nimport com.lagradost.cloudstream3.ui.WatchType\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager\nimport com.lagradost.cloudstream3.ui.player.GeneratorPlayer\nimport com.lagradost.cloudstream3.ui.player.IGenerator\nimport com.lagradost.cloudstream3.ui.player.LOADTYPE_ALL\nimport com.lagradost.cloudstream3.ui.player.LOADTYPE_CHROMECAST\nimport com.lagradost.cloudstream3.ui.player.LOADTYPE_INAPP\nimport com.lagradost.cloudstream3.ui.player.LOADTYPE_INAPP_DOWNLOAD\nimport com.lagradost.cloudstream3.ui.player.RepoLinkGenerator\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.ui.result.EpisodeAdapter.Companion.getPlayerAction\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isConnectedToChromecast\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.AppContextUtils.sortSubs\nimport com.lagradost.cloudstream3.utils.CastHelper.startCast\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.ioWork\nimport com.lagradost.cloudstream3.utils.Coroutines.ioWorkSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE\nimport com.lagradost.cloudstream3.utils.DataStore\nimport com.lagradost.cloudstream3.utils.DataStore.editor\nimport com.lagradost.cloudstream3.utils.DataStore.getFolderName\nimport com.lagradost.cloudstream3.utils.DataStore.setKey\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.deleteBookmarkedData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllBookmarkedData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllFavorites\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllSubscriptions\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getBookmarkedData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getDub\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getFavoritesData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getLastWatched\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getResultEpisode\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getResultSeason\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getResultWatchState\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getSubscribedData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getVideoWatchState\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.removeFavoritesData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.removeSubscribedData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setBookmarkedData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setDub\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setFavoritesData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setResultEpisode\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setResultSeason\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setResultWatchState\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setSubscribedData\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.setVideoWatchState\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.updateSubscribedData\nimport com.lagradost.cloudstream3.utils.Editor\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.FillerEpisodeCheck\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UiText\nimport com.lagradost.cloudstream3.utils.VIDEO_WATCH_STATE\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.sanitizeFilename\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getDownloadEpisodeMetadata\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport com.lagradost.cloudstream3.utils.downloader.DownloadUtils.downloadSubtitle\nimport com.lagradost.cloudstream3.utils.loadExtractor\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport com.lagradost.cloudstream3.utils.txt\nimport kotlinx.coroutines.CancellationException\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.cancelChildren\nimport kotlinx.coroutines.coroutineScope\nimport kotlinx.coroutines.isActive\nimport kotlinx.coroutines.job\nimport kotlinx.coroutines.launch\nimport java.util.concurrent.TimeUnit\n\n/** This starts at 1 */\ndata class EpisodeRange(\n    // used to index data\n    val startIndex: Int,\n    val length: Int,\n    // used to display data\n    val startEpisode: Int,\n    val endEpisode: Int,\n)\n\ndata class AutoResume(\n    val season: Int?,\n    val episode: Int?,\n    val id: Int?,\n    val startAction: Int,\n)\n\ndata class ResultData(\n    val url: String,\n    val tags: List<String>,\n    val actors: List<ActorData>?,\n    val actorsText: UiText?,\n\n    val comingSoon: Boolean,\n    val backgroundPosterUrl: String?,\n    val title: String,\n    var syncData: Map<String, String>,\n\n    val posterImage: String?,\n    val posterBackgroundImage: String?,\n    val logoUrl: String?,\n    val plotText: UiText,\n    val apiName: UiText,\n    val ratingText: UiText?,\n    val contentRatingText: UiText?,\n    val vpnText: UiText?,\n    val metaText: UiText?,\n    val durationText: UiText?,\n    val onGoingText: UiText?,\n    val noEpisodesFoundText: UiText?,\n    val titleText: UiText,\n    val typeText: UiText,\n    val yearText: UiText?,\n    val nextAiringDate: UiText?,\n    val nextAiringEpisode: UiText?,\n    val plotHeaderText: UiText,\n    val posterHeaders: Map<String, String>? = null,\n)\n\ndata class CheckDuplicateData(\n    val name: String,\n    val year: Int?,\n    val syncData: Map<String, String>?\n)\n\nenum class LibraryListType {\n    BOOKMARKS,\n    FAVORITES,\n    SUBSCRIPTIONS\n}\n\nenum class EpisodeSortType {\n    NUMBER_ASC,\n    NUMBER_DESC,\n    RATING_HIGH_LOW,\n    RATING_LOW_HIGH,\n    DATE_NEWEST,\n    DATE_OLDEST\n}\n\nfun txt(status: DubStatus?): UiText? {\n    return txt(\n        when (status) {\n            DubStatus.Dubbed -> R.string.app_dubbed_text\n            DubStatus.Subbed -> R.string.app_subbed_text\n            else -> null\n        }\n    )\n}\n\nfun LoadResponse.toResultData(repo: APIRepository): ResultData {\n    debugAssert({ repo.name != apiName }) {\n        \"Api returned wrong apiName\"\n    }\n\n    val hasActorImages = actors?.firstOrNull()?.actor?.image?.isNotBlank() == true\n\n    var nextAiringEpisode: UiText? = null\n    var nextAiringDate: UiText? = null\n\n    if (this is EpisodeResponse) {\n        val airing = this.nextAiring\n        if (airing != null && airing.unixTime > unixTime) {\n            val seconds = airing.unixTime - unixTime\n            val days = TimeUnit.SECONDS.toDays(seconds)\n            val hours: Long = TimeUnit.SECONDS.toHours(seconds) - days * 24\n            val minute =\n                TimeUnit.SECONDS.toMinutes(seconds) - TimeUnit.SECONDS.toHours(seconds) * 60\n            nextAiringDate = when {\n                days > 0 -> {\n                    txt(\n                        R.string.next_episode_time_day_format,\n                        days,\n                        hours,\n                        minute\n                    )\n                }\n\n                hours > 0 -> txt(\n                    R.string.next_episode_time_hour_format,\n                    hours,\n                    minute\n                )\n\n                minute > 0 -> txt(\n                    R.string.next_episode_time_min_format,\n                    minute\n                )\n\n                else -> null\n            }?.also {\n                nextAiringEpisode = when (airing.season) {\n\n                    null -> txt(R.string.next_episode_format, airing.episode)\n                    else -> txt(R.string.next_season_episode_format, airing.season, airing.episode)\n                }\n            }\n        }\n    }\n    val dur = duration\n    return ResultData(\n        syncData = syncData,\n        plotHeaderText = txt(\n            when (this.type) {\n                TvType.Torrent -> R.string.torrent_plot\n                else -> R.string.result_plot\n            }\n        ),\n        nextAiringDate = nextAiringDate,\n        nextAiringEpisode = nextAiringEpisode,\n        posterImage = posterUrl ?: backgroundPosterUrl,\n        posterHeaders = posterHeaders,\n        posterBackgroundImage = backgroundPosterUrl ?: posterUrl,\n        titleText = txt(name),\n        url = url,\n        tags = tags ?: emptyList(),\n        comingSoon = comingSoon,\n        actors = if (hasActorImages) actors else null,\n        actorsText = if (hasActorImages || actors.isNullOrEmpty()) null else txt(\n            R.string.cast_format,\n            actors?.joinToString { it.actor.name }),\n        plotText =\n            if (plot.isNullOrBlank()) txt(if (this is TorrentLoadResponse) R.string.torrent_no_plot else R.string.normal_no_plot) else txt(\n                plot!!\n            ),\n        backgroundPosterUrl = backgroundPosterUrl,\n        logoUrl = logoUrl,\n        title = name,\n        typeText = txt(\n            when (type) {\n                TvType.TvSeries -> R.string.tv_series_singular\n                TvType.Anime -> R.string.anime_singular\n                TvType.OVA -> R.string.ova_singular\n                TvType.AnimeMovie -> R.string.movies_singular\n                TvType.Cartoon -> R.string.cartoons_singular\n                TvType.Documentary -> R.string.documentaries_singular\n                TvType.Movie -> R.string.movies_singular\n                TvType.Torrent -> R.string.torrent_singular\n                TvType.AsianDrama -> R.string.asian_drama_singular\n                TvType.Live -> R.string.live_singular\n                TvType.Others -> R.string.other_singular\n                TvType.NSFW -> R.string.nsfw_singular\n                TvType.Music -> R.string.music_singlar\n                TvType.AudioBook -> R.string.audio_book_singular\n                TvType.CustomMedia -> R.string.custom_media_singluar\n                TvType.Audio -> R.string.audio_singluar\n                TvType.Podcast -> R.string.podcast_singluar\n            }\n        ),\n        yearText = txt(year?.toString()),\n        apiName = txt(apiName),\n        ratingText = score?.toStringNull(0.1, 10, 1, false, '.')\n            ?.let { txt(R.string.rating_format, it) },\n        contentRatingText = txt(contentRating),\n        vpnText = txt(\n            when (repo.vpnStatus) {\n                VPNStatus.None -> null\n                VPNStatus.Torrent -> R.string.vpn_torrent\n                VPNStatus.MightBeNeeded -> R.string.vpn_might_be_needed\n            }\n        ),\n        metaText =\n            if (repo.providerType == ProviderType.MetaProvider) txt(R.string.provider_info_meta) else null,\n        durationText = if (dur == null || dur <= 0) null else txt(\n            secondsToReadable(dur * 60, \"0 mins\")\n        ),\n        onGoingText = if (this is EpisodeResponse) {\n            txt(\n                when (showStatus) {\n                    ShowStatus.Ongoing -> R.string.status_ongoing\n                    ShowStatus.Completed -> R.string.status_completed\n                    else -> null\n                }\n            )\n        } else null,\n        noEpisodesFoundText =\n            if ((this is TvSeriesLoadResponse && this.episodes.isEmpty()) || (this is AnimeLoadResponse && !this.episodes.any { it.value.isNotEmpty() })) txt(\n                R.string.no_episodes_found\n            ) else null\n    )\n}\n\ndata class ExtractorSubtitleLink(\n    val name: String,\n    override val url: String,\n    override val referer: String,\n    override val headers: Map<String, String> = mapOf()\n) : IDownloadableMinimum\n\nfun LoadResponse.getId(): Int {\n    // this fixes an issue with outdated api as getLoadResponseIdFromUrl might be fucked\n    return (if (this is ResultViewModel2.LoadResponseFromSearch) this.id else null)\n        ?: getLoadResponseIdFromUrl(uniqueUrl, apiName)\n}\n\nprivate fun getLoadResponseIdFromUrl(url: String, apiName: String): Int {\n    return url.replace(getApiFromNameNull(apiName)?.mainUrl ?: \"\", \"\").replace(\"/\", \"\")\n        .hashCode()\n}\n\ndata class LinkProgress(\n    val linksLoaded: Int,\n    val subsLoaded: Int,\n)\n\ndata class ResumeProgress(\n    val progress: Int,\n    val maxProgress: Int,\n    val progressLeft: UiText,\n)\n\ndata class ResumeWatchingStatus(\n    val progress: ResumeProgress?,\n    val isMovie: Boolean,\n    val result: ResultEpisode,\n)\n\ndata class LinkLoadingResult(\n    val links: List<ExtractorLink>,\n    val subs: List<SubtitleData>,\n    val syncData: HashMap<String, String>\n)\n\nsealed class SelectPopup {\n    data class SelectText(\n        val text: UiText,\n        val options: List<UiText>,\n        val callback: (Int?) -> Unit\n    ) : SelectPopup()\n\n    data class SelectArray(\n        val text: UiText,\n        val options: List<Pair<UiText, Int>>,\n        val callback: (Int?) -> Unit\n    ) : SelectPopup()\n}\n\nfun SelectPopup.callback(index: Int?) {\n    val ret = transformResult(index)\n    return when (this) {\n        is SelectPopup.SelectArray -> callback(ret)\n        is SelectPopup.SelectText -> callback(ret)\n    }\n}\n\nfun SelectPopup.transformResult(input: Int?): Int? {\n    if (input == null) return null\n    return when (this) {\n        is SelectPopup.SelectArray -> options.getOrNull(input)?.second\n        is SelectPopup.SelectText -> input\n    }\n}\n\nfun SelectPopup.getTitle(context: Context): String {\n    return when (this) {\n        is SelectPopup.SelectArray -> text.asString(context)\n        is SelectPopup.SelectText -> text.asString(context)\n    }\n}\n\nfun SelectPopup.getOptions(context: Context): List<String> {\n    return when (this) {\n        is SelectPopup.SelectArray -> {\n            this.options.map { it.first.asString(context) }\n        }\n\n        is SelectPopup.SelectText -> options.map { it.asString(context) }\n    }\n}\n\ndata class ExtractedTrailerData(\n    var mirros: List<Pair<ExtractorLink,String>>,//Pair of extracted trailer link and original trailer link\n    var subtitles: List<SubtitleFile> = emptyList(),\n)\n\nclass ResultViewModel2 : ViewModel() {\n    private var currentResponse: LoadResponse? = null\n    var EPISODE_RANGE_SIZE: Int = 20\n    fun clear() {\n        currentResponse = null\n        _page.postValue(null)\n    }\n\n    data class EpisodeIndexer(\n        val dubStatus: DubStatus,\n        val season: Int,\n    )\n\n    /** map<dub, map<season, List<episode>>> */\n    private var currentEpisodes: Map<EpisodeIndexer, List<ResultEpisode>> = mapOf()\n    private var currentRanges: Map<EpisodeIndexer, List<EpisodeRange>> = mapOf()\n    private var currentSeasons: List<Int> = listOf()\n    private var currentDubStatus: List<DubStatus> = listOf()\n    private var currentMeta: SyncAPI.SyncResult? = null\n    private var currentSync: Map<String, String>? = null\n    private var currentIndex: EpisodeIndexer? = null\n    private var currentSorting: EpisodeSortType? = null\n    private var currentRange: EpisodeRange? = null\n    private var currentShowFillers: Boolean = false\n    var currentRepo: APIRepository? = null\n    private var currentId: Int? = null\n    private var fillers: Map<Int, Boolean> = emptyMap()\n    private var generator: IGenerator? = null\n    private var preferDubStatus: DubStatus? = null\n    private var preferStartEpisode: Int? = null\n    private var preferStartSeason: Int? = null\n    //private val currentIsMovie get() = currentResponse?.isEpisodeBased() == false\n    //private val currentHeaderName get() = currentResponse?.name\n\n\n    private val _page: MutableLiveData<Resource<ResultData>?> =\n        MutableLiveData(null)\n    val page: LiveData<Resource<ResultData>?> = _page\n\n    private val _episodes: MutableLiveData<Resource<List<ResultEpisode>>?> =\n        MutableLiveData(Resource.Loading())\n    val episodes: LiveData<Resource<List<ResultEpisode>>?> = _episodes\n\n    private val _movie: MutableLiveData<Resource<Pair<UiText, ResultEpisode>>?> =\n        MutableLiveData(null)\n    val movie: LiveData<Resource<Pair<UiText, ResultEpisode>>?> = _movie\n\n    private val _episodesCountText: MutableLiveData<UiText?> =\n        MutableLiveData(null)\n    val episodesCountText: LiveData<UiText?> = _episodesCountText\n\n    private val _trailers: MutableLiveData<List<ExtractedTrailerData>> =\n        MutableLiveData(mutableListOf())\n    val trailers: LiveData<List<ExtractedTrailerData>> = _trailers\n\n    private val _dubSubSelections: MutableLiveData<List<Pair<UiText?, DubStatus>>> =\n        MutableLiveData(emptyList())\n    val dubSubSelections: LiveData<List<Pair<UiText?, DubStatus>>> = _dubSubSelections\n\n    private val _rangeSelections: MutableLiveData<List<Pair<UiText?, EpisodeRange>>> =\n        MutableLiveData(emptyList())\n    val rangeSelections: LiveData<List<Pair<UiText?, EpisodeRange>>> = _rangeSelections\n\n    private val _seasonSelections: MutableLiveData<List<Pair<UiText?, Int>>> =\n        MutableLiveData(emptyList())\n    val seasonSelections: LiveData<List<Pair<UiText?, Int>>> = _seasonSelections\n\n    private val _recommendations: MutableLiveData<List<SearchResponse>> =\n        MutableLiveData(emptyList())\n    val recommendations: LiveData<List<SearchResponse>> = _recommendations\n\n    private val _selectedRange: MutableLiveData<UiText?> =\n        MutableLiveData(null)\n    val selectedRange: LiveData<UiText?> = _selectedRange\n\n    private val _selectedSorting: MutableLiveData<UiText?> =\n        MutableLiveData(null)\n    val selectedSorting: LiveData<UiText?> = _selectedSorting\n\n    private val _selectedSortingIndex: MutableLiveData<Int> =\n        MutableLiveData(-1)\n    val selectedSortingIndex: LiveData<Int> = _selectedSortingIndex\n\n    private val _sortSelections: MutableLiveData<List<Pair<UiText, EpisodeSortType>>> =\n        MutableLiveData(emptyList())\n    val sortSelections: LiveData<List<Pair<UiText, EpisodeSortType>>> = _sortSelections\n\n    private val _selectedSeason: MutableLiveData<UiText?> =\n        MutableLiveData(null)\n    val selectedSeason: LiveData<UiText?> = _selectedSeason\n\n    private val _selectedDubStatus: MutableLiveData<UiText?> = MutableLiveData(null)\n    val selectedDubStatus: LiveData<UiText?> = _selectedDubStatus\n\n    private val _selectedRangeIndex: MutableLiveData<Int> =\n        MutableLiveData(-1)\n    val selectedRangeIndex: LiveData<Int> = _selectedRangeIndex\n\n    private val _selectedSeasonIndex: MutableLiveData<Int> =\n        MutableLiveData(-1)\n    val selectedSeasonIndex: LiveData<Int> = _selectedSeasonIndex\n\n    private val _selectedDubStatusIndex: MutableLiveData<Int> = MutableLiveData(-1)\n    val selectedDubStatusIndex: LiveData<Int> = _selectedDubStatusIndex\n\n    private val _loadedLinks: MutableLiveData<LinkProgress?> = MutableLiveData(null)\n    val loadedLinks: LiveData<LinkProgress?> = _loadedLinks\n\n    private val _resumeWatching: MutableLiveData<ResumeWatchingStatus?> =\n        MutableLiveData(null)\n    val resumeWatching: LiveData<ResumeWatchingStatus?> = _resumeWatching\n\n    private val _episodeSynopsis: MutableLiveData<String?> = MutableLiveData(null)\n    val episodeSynopsis: LiveData<String?> = _episodeSynopsis\n\n    private val _subscribeStatus: MutableLiveData<Boolean?> = MutableLiveData(null)\n    val subscribeStatus: LiveData<Boolean?> = _subscribeStatus\n\n    private val _favoriteStatus: MutableLiveData<Boolean?> = MutableLiveData(null)\n    val favoriteStatus: LiveData<Boolean?> = _favoriteStatus\n\n    companion object {\n        const val TAG = \"RVM2\"\n        //private const val EPISODE_RANGE_SIZE = 20\n        //private const val EPISODE_RANGE_OVERLOAD = 30\n\n        private fun List<SeasonData>?.getSeason(season: Int?): SeasonData? {\n            if (season == null) return null\n            return this?.firstOrNull { it.season == season }\n        }\n\n        fun seasonToTxt(seasonData: SeasonData?, season: Int?): UiText? {\n            if (season == 0) {\n                return txt(R.string.no_season)\n            }\n\n            // If displaySeason is null then only show the name!\n            return if (seasonData?.name != null && seasonData.displaySeason == null) {\n                txt(seasonData.name)\n            } else {\n                val suffix = seasonData?.name?.let { \" $it\" } ?: \"\"\n                txt(\n                    R.string.season_format,\n                    txt(R.string.season),\n                    seasonData?.displaySeason ?: season,\n                    suffix\n                )\n            }\n        }\n\n        private fun List<SeasonData>?.getSeasonTxt(season: Int?): UiText? =\n            seasonToTxt(getSeason(season), season)\n\n\n        private fun filterName(name: String?): String? {\n            if (name == null) return null\n            Regex(\"^[eE]pisode [0-9]*(.*)\").find(name)?.groupValues?.get(1)?.let {\n                if (it.isEmpty())\n                    return null\n            }\n            return name\n        }\n\n        fun singleMap(ep: ResultEpisode): Map<EpisodeIndexer, List<ResultEpisode>> =\n            mapOf(\n                EpisodeIndexer(DubStatus.None, 0) to listOf(\n                    ep\n                )\n            )\n\n        private fun getRanges(\n            allEpisodes: Map<EpisodeIndexer, List<ResultEpisode>>,\n            EPISODE_RANGE_SIZE: Int\n        ): Map<EpisodeIndexer, List<EpisodeRange>> {\n            return allEpisodes.keys.mapNotNull { index ->\n                val episodes =\n                    allEpisodes[index] ?: return@mapNotNull null // this should never happened\n\n                // fast case\n                val EPISODE_RANGE_OVERLOAD = EPISODE_RANGE_SIZE + 10\n                if (episodes.size <= EPISODE_RANGE_OVERLOAD) {\n                    return@mapNotNull index to listOf(\n                        EpisodeRange(\n                            0,\n                            episodes.size,\n                            episodes.minOf { it.episode },\n                            episodes.maxOf { it.episode })\n                    )\n                }\n\n                if (episodes.isEmpty()) {\n                    return@mapNotNull null\n                }\n\n                val list = mutableListOf<EpisodeRange>()\n\n                val currentEpisode = episodes.first()\n                var currentIndex = 0\n                val maxIndex = episodes.size\n                var targetEpisode = 0\n                var currentMin = currentEpisode.episode\n                var currentMax = currentEpisode.episode\n\n                while (currentIndex < maxIndex) {\n                    val startIndex = currentIndex\n                    targetEpisode += EPISODE_RANGE_SIZE\n                    while (currentIndex < maxIndex && episodes[currentIndex].episode <= targetEpisode) {\n                        val episodeNumber = episodes[currentIndex].episode\n                        if (episodeNumber < currentMin) {\n                            currentMin = episodeNumber\n                        }\n                        if (episodeNumber > currentMax) {\n                            currentMax = episodeNumber\n                        }\n                        ++currentIndex\n                    }\n\n                    val length = currentIndex - startIndex\n                    if (length <= 0) continue\n                    list.add(\n                        EpisodeRange(\n                            startIndex,\n                            length,\n                            currentMin,\n                            currentMax\n                        )\n                    )\n                    currentMin = Int.MAX_VALUE\n                    currentMax = Int.MIN_VALUE\n                }\n\n                /*var currentMin = Int.MAX_VALUE\n                var currentMax = Int.MIN_VALUE\n                var currentStartIndex = 0\n                var currentLength = 0\n                for (ep in episodes) {\n                    val episodeNumber = ep.episode\n                    if (episodeNumber < currentMin) {\n                        currentMin = episodeNumber\n                    } else if (episodeNumber > currentMax) {\n                        currentMax = episodeNumber\n                    }\n\n                    if (++currentLength >= EPISODE_RANGE_SIZE) {\n                        list.add(\n                            EpisodeRange(\n                                currentStartIndex,\n                                currentLength,\n                                currentMin,\n                                currentMax\n                            )\n                        )\n                        currentMin = Int.MAX_VALUE\n                        currentMax = Int.MIN_VALUE\n                        currentStartIndex += currentLength\n                        currentLength = 0\n                    }\n                }\n                if (currentLength > 0) {\n                    list.add(\n                        EpisodeRange(\n                            currentStartIndex,\n                            currentLength,\n                            currentMin,\n                            currentMax\n                        )\n                    )\n                }*/\n\n                index to list\n            }.toMap()\n        }\n    }\n\n    private val _watchStatus: MutableLiveData<WatchType> = MutableLiveData(WatchType.NONE)\n    val watchStatus: LiveData<WatchType> get() = _watchStatus\n\n    private val _selectPopup: MutableLiveData<SelectPopup?> = MutableLiveData(null)\n    val selectPopup: LiveData<SelectPopup?> = _selectPopup\n\n    fun updateWatchStatus(\n        status: WatchType,\n        context: Context?,\n        loadResponse: LoadResponse? = null,\n        statusChangedCallback: ((statusChanged: Boolean) -> Unit)? = null\n    ) {\n        val (response, currentId) = loadResponse?.let { load ->\n            (load to load.getId())\n        } ?: ((currentResponse ?: return) to (currentId ?: return))\n\n        val currentStatus = getResultWatchState(currentId)\n\n        // If the current status is \"NONE\" and the new status is not \"NONE\",\n        // fetch the bookmarked data to check for duplicates, otherwise set this\n        // to an empty list, so that we don't show the duplicate warning dialog,\n        // but we still want to update the current bookmark and refresh the data anyway.\n        val bookmarkedData = if (currentStatus == WatchType.NONE && status != WatchType.NONE) {\n            getAllBookmarkedData()\n        } else emptyList()\n\n        checkAndWarnDuplicates(\n            context,\n            LibraryListType.BOOKMARKS,\n            CheckDuplicateData(\n                name = response.name,\n                year = response.year,\n                syncData = response.syncData,\n            ),\n            bookmarkedData\n        ) { shouldContinue: Boolean, duplicateIds: List<Int?> ->\n            if (!shouldContinue) return@checkAndWarnDuplicates\n\n            if (duplicateIds.isNotEmpty()) {\n                duplicateIds.forEach { duplicateId ->\n                    deleteBookmarkedData(duplicateId)\n                }\n            }\n\n            setResultWatchState(currentId, status.internalId)\n\n            // We don't need to store if WatchType.NONE.\n            // The key is removed in setResultWatchState, we don't want to\n            // re-add it again here if it was just removed.\n            if (status != WatchType.NONE) {\n                val current = getBookmarkedData(currentId)\n\n                setBookmarkedData(\n                    currentId,\n                    DataStoreHelper.BookmarkedData(\n                        current?.bookmarkedTime ?: unixTimeMS,\n                        currentId,\n                        unixTimeMS,\n                        response.name,\n                        response.url,\n                        response.apiName,\n                        response.type,\n                        response.posterUrl,\n                        response.year,\n                        response.syncData,\n                        plot = response.plot,\n                        tags = response.tags,\n                        score = response.score\n                    )\n                )\n            }\n\n            if (currentStatus != status) {\n                MainActivity.bookmarksUpdatedEvent(true)\n                MainActivity.reloadLibraryEvent(true)\n            }\n\n            _watchStatus.postValue(status)\n\n            statusChangedCallback?.invoke(true)\n        }\n    }\n\n    private fun startChromecast(\n        activity: Activity?,\n        result: ResultEpisode,\n        isVisible: Boolean = true\n    ) {\n        if (activity == null) return\n        loadLinks(\n            result,\n            isVisible = isVisible,\n            sourceTypes = LOADTYPE_CHROMECAST,\n            isCasting = true\n        ) { data ->\n            startChromecast(activity, result, data.links, data.subs, 0)\n        }\n    }\n\n    /**\n     * Toggles the subscription status of an item.\n     *\n     * @param context The context to use for operations.\n     * @param statusChangedCallback A callback that is invoked when the subscription status changes.\n     *        It provides the new subscription status (true if subscribed, false if unsubscribed, null if action was canceled).\n     */\n    fun toggleSubscriptionStatus(\n        context: Context?,\n        statusChangedCallback: ((newStatus: Boolean?) -> Unit)? = null\n    ) {\n        val isSubscribed = _subscribeStatus.value ?: return\n        val response = currentResponse ?: return\n        val currentId = currentId ?: return\n\n        // This might be a bit confusing, but even if the loadresponse is not a EpisodeResponse\n        // _subscribeStatus might be true.\n\n        if (isSubscribed) {\n            removeSubscribedData(currentId)\n            statusChangedCallback?.invoke(false)\n            _subscribeStatus.postValue(if (response is EpisodeResponse) false else null)\n            MainActivity.reloadLibraryEvent(true)\n        } else {\n            if (response !is EpisodeResponse) {\n                return\n            }\n            checkAndWarnDuplicates(\n                context,\n                LibraryListType.SUBSCRIPTIONS,\n                CheckDuplicateData(\n                    name = response.name,\n                    year = response.year,\n                    syncData = response.syncData,\n                ),\n                getAllSubscriptions(),\n            ) { shouldContinue: Boolean, duplicateIds: List<Int?> ->\n                if (!shouldContinue) {\n                    statusChangedCallback?.invoke(null)\n                    return@checkAndWarnDuplicates\n                }\n\n                if (duplicateIds.isNotEmpty()) {\n                    duplicateIds.forEach { duplicateId ->\n                        removeSubscribedData(duplicateId)\n                    }\n                }\n\n                val current = getSubscribedData(currentId)\n\n                setSubscribedData(\n                    currentId,\n                    DataStoreHelper.SubscribedData(\n                        current?.subscribedTime ?: unixTimeMS,\n                        response.getLatestEpisodes(),\n                        currentId,\n                        unixTimeMS,\n                        response.name,\n                        response.url,\n                        response.apiName,\n                        response.type,\n                        response.posterUrl,\n                        response.year,\n                        response.syncData,\n                        plot = response.plot,\n                        score = response.score,\n                        tags = response.tags\n                    )\n                )\n\n                _subscribeStatus.postValue(true)\n                statusChangedCallback?.invoke(true)\n                MainActivity.reloadLibraryEvent(true)\n            }\n        }\n    }\n\n    private fun getMeta(\n        episode: ResultEpisode,\n        titleName: String,\n        apiName: String,\n        currentPoster: String?,\n        currentIsMovie: Boolean,\n        tvType: TvType,\n    ): DownloadObjects.DownloadEpisodeMetadata {\n        return DownloadObjects.DownloadEpisodeMetadata(\n            episode.id,\n            episode.parentId,\n            sanitizeFilename(titleName),\n            apiName,\n            episode.poster ?: currentPoster,\n            episode.name,\n            if (currentIsMovie) null else episode.season,\n            if (currentIsMovie) null else episode.episode,\n            tvType,\n        )\n    }\n\n\n    /**\n     * Toggles the favorite status of an item.\n     *\n     * @param context The context to use.\n     * @param statusChangedCallback A callback that is invoked when the favorite status changes.\n     *        It provides the new favorite status (true if added to favorites, false if removed, null if action was canceled).\n     */\n    fun toggleFavoriteStatus(\n        context: Context?,\n        statusChangedCallback: ((newStatus: Boolean?) -> Unit)? = null\n    ) {\n        val isFavorite = _favoriteStatus.value ?: return\n        val response = currentResponse ?: return\n\n        val currentId = currentId ?: return\n\n        if (isFavorite) {\n            removeFavoritesData(currentId)\n            statusChangedCallback?.invoke(false)\n            _favoriteStatus.postValue(false)\n            MainActivity.reloadLibraryEvent(true)\n        } else {\n            checkAndWarnDuplicates(\n                context,\n                LibraryListType.FAVORITES,\n                CheckDuplicateData(\n                    name = response.name,\n                    year = response.year,\n                    syncData = response.syncData,\n                ),\n                getAllFavorites(),\n            ) { shouldContinue: Boolean, duplicateIds: List<Int?> ->\n                if (!shouldContinue) {\n                    statusChangedCallback?.invoke(null)\n                    return@checkAndWarnDuplicates\n                }\n\n                if (duplicateIds.isNotEmpty()) {\n                    duplicateIds.forEach { duplicateId ->\n                        removeFavoritesData(duplicateId)\n                    }\n                }\n\n                val current = getFavoritesData(currentId)\n\n                setFavoritesData(\n                    currentId,\n                    DataStoreHelper.FavoritesData(\n                        current?.favoritesTime ?: unixTimeMS,\n                        currentId,\n                        unixTimeMS,\n                        response.name,\n                        response.url,\n                        response.apiName,\n                        response.type,\n                        response.posterUrl,\n                        response.year,\n                        response.syncData,\n                        plot = response.plot,\n                        score = response.score,\n                        tags = response.tags\n                    )\n                )\n\n                _favoriteStatus.postValue(true)\n                statusChangedCallback?.invoke(true)\n                MainActivity.reloadLibraryEvent(true)\n            }\n        }\n    }\n\n    @MainThread\n    private fun checkAndWarnDuplicates(\n        context: Context?,\n        listType: LibraryListType,\n        checkDuplicateData: CheckDuplicateData,\n        data: List<DataStoreHelper.LibrarySearchResponse>,\n        checkDuplicatesCallback: (shouldContinue: Boolean, duplicateIds: List<Int?>) -> Unit\n    ) {\n        val whitespaceRegex = \"\\\\s+\".toRegex()\n        fun normalizeString(input: String): String {\n            /**\n             * Trim the input string and replace consecutive spaces with a single space.\n             * This covers some edge-cases where the title does not match exactly across providers,\n             * and one provider has the title with an extra whitespace. This is minor enough that\n             * it should still match in this case.\n             */\n            return input.trim().replace(whitespaceRegex, \" \")\n        }\n\n        val syncData = checkDuplicateData.syncData\n\n        val imdbId = getImdbIdFromSyncData(syncData)\n        val tmdbId = getTMDbIdFromSyncData(syncData)\n        val malId = syncData?.get(AccountManager.malApi.idPrefix)\n        val aniListId = syncData?.get(AccountManager.aniListApi.idPrefix)\n        val normalizedName = normalizeString(checkDuplicateData.name)\n        val year = checkDuplicateData.year\n\n        val duplicateEntries = data.filter { it: DataStoreHelper.LibrarySearchResponse ->\n            val librarySyncData = it.syncData\n            val yearCheck = year == it.year || year == null || it.year == null\n\n            val checks = listOf(\n                { imdbId != null && getImdbIdFromSyncData(librarySyncData) == imdbId },\n                { tmdbId != null && getTMDbIdFromSyncData(librarySyncData) == tmdbId },\n                { malId != null && librarySyncData?.get(AccountManager.malApi.idPrefix) == malId },\n                { aniListId != null && librarySyncData?.get(AccountManager.aniListApi.idPrefix) == aniListId },\n                { normalizedName == normalizeString(it.name) && yearCheck }\n            )\n\n            checks.any { it() }\n        }\n\n        if (duplicateEntries.isEmpty() || context == null) {\n            checkDuplicatesCallback.invoke(true, emptyList())\n            return\n        }\n\n        val replaceMessage = if (duplicateEntries.size > 1) {\n            R.string.duplicate_replace_all\n        } else R.string.duplicate_replace\n\n        val message = if (duplicateEntries.size == 1) {\n            val list = when (listType) {\n                LibraryListType.BOOKMARKS -> getResultWatchState(\n                    duplicateEntries[0].id ?: 0\n                ).stringRes\n\n                LibraryListType.FAVORITES -> R.string.favorites_list_name\n                LibraryListType.SUBSCRIPTIONS -> R.string.subscription_list_name\n            }\n\n            context.getString(\n                R.string.duplicate_message_single,\n                \"${normalizeString(duplicateEntries[0].name)} (${context.getString(list)}) — ${duplicateEntries[0].apiName}\"\n            )\n        } else {\n            val bulletPoints = duplicateEntries.joinToString(\"\\n\") {\n                val list = when (listType) {\n                    LibraryListType.BOOKMARKS -> getResultWatchState(it.id ?: 0).stringRes\n                    LibraryListType.FAVORITES -> R.string.favorites_list_name\n                    LibraryListType.SUBSCRIPTIONS -> R.string.subscription_list_name\n                }\n\n                \"• ${it.apiName}: ${normalizeString(it.name)} (${context.getString(list)})\"\n            }\n\n            context.getString(R.string.duplicate_message_multiple, bulletPoints)\n        }\n\n        val builder: AlertDialog.Builder = AlertDialog.Builder(context)\n\n        val dialogClickListener =\n            DialogInterface.OnClickListener { _, which ->\n                when (which) {\n                    DialogInterface.BUTTON_POSITIVE -> {\n                        checkDuplicatesCallback.invoke(true, emptyList())\n                    }\n\n                    DialogInterface.BUTTON_NEGATIVE -> {\n                        checkDuplicatesCallback.invoke(false, emptyList())\n                    }\n\n                    DialogInterface.BUTTON_NEUTRAL -> {\n                        checkDuplicatesCallback.invoke(true, duplicateEntries.map { it.id })\n                    }\n                }\n            }\n\n        builder.setTitle(R.string.duplicate_title)\n            .setMessage(message)\n            .setPositiveButton(R.string.duplicate_add, dialogClickListener)\n            .setNegativeButton(R.string.duplicate_cancel, dialogClickListener)\n            .setNeutralButton(replaceMessage, dialogClickListener)\n            .show().setDefaultFocus()\n    }\n\n    private fun getImdbIdFromSyncData(syncData: Map<String, String>?): String? {\n        return safe {\n            val imdbId = readIdFromString(\n                syncData?.get(AccountManager.simklApi.idPrefix)\n            )[SimklSyncServices.Imdb]\n            if (imdbId == \"null\") null else imdbId\n        }\n    }\n\n    private fun getTMDbIdFromSyncData(syncData: Map<String, String>?): String? {\n        return safe {\n            val tmdbId = readIdFromString(\n                syncData?.get(AccountManager.simklApi.idPrefix)\n            )[SimklSyncServices.Tmdb]\n            if (tmdbId == \"null\") null else tmdbId\n        }\n    }\n\n    private fun startChromecast(\n        activity: Activity?,\n        result: ResultEpisode,\n        links: List<ExtractorLink>,\n        subs: List<SubtitleData>,\n        startIndex: Int,\n    ) {\n        if (activity == null) return\n        val response = currentResponse ?: return\n        val eps = currentEpisodes[currentIndex ?: return] ?: return\n\n        // Main needed because getCastSession needs to be on main thread\n        main {\n            activity.getCastSession()?.startCast(\n                response.apiName,\n                response.isMovie(),\n                response.name,\n                response.posterUrl,\n                result.index,\n                eps,\n                links,\n                subs,\n                startTime = result.getRealPosition(),\n                startIndex = startIndex\n            )\n        }\n    }\n\n    fun cancelLinks() {\n        currentLoadLinkJob?.cancel()\n        currentLoadLinkJob = null\n        _loadedLinks.postValue(null)\n    }\n\n    fun postPopup(text: UiText, options: List<UiText>, callback: suspend (Int?) -> Unit) {\n        _selectPopup.postValue(\n            SelectPopup.SelectText(\n                text,\n                options\n            ) { value ->\n                viewModelScope.launchSafe {\n                    _selectPopup.postValue(null)\n                    callback.invoke(value)\n                }\n            }\n        )\n    }\n\n    @JvmName(\"postPopupArray\")\n    private fun postPopup(\n        text: UiText,\n        options: List<Pair<UiText, Int>>,\n        callback: suspend (Int?) -> Unit\n    ) {\n        _selectPopup.postValue(\n            SelectPopup.SelectArray(\n                text,\n                options,\n            ) { value ->\n                viewModelScope.launchSafe {\n                    _selectPopup.postValue(null)\n                    callback.invoke(value)\n                }\n            }\n        )\n    }\n\n    private fun loadLinks(\n        result: ResultEpisode,\n        isVisible: Boolean,\n        sourceTypes: Set<ExtractorLinkType> = LOADTYPE_ALL,\n        clearCache: Boolean = false,\n        isCasting: Boolean = false,\n        work: suspend (CoroutineScope.(LinkLoadingResult) -> Unit)\n    ) {\n        currentLoadLinkJob?.cancel()\n        currentLoadLinkJob = ioSafe {\n            val parentJob = this.coroutineContext.job\n            launch {\n                val links = loadLinks(\n                    result,\n                    isVisible = isVisible,\n                    sourceTypes = sourceTypes,\n                    clearCache = clearCache,\n                    isCasting = isCasting\n                )\n                // Cancel child = skip link loading\n                // Cancel parent = dismiss dialog\n                if (parentJob.isCancelled) {\n                    return@launch\n                }\n                work(links)\n            }\n        }\n    }\n\n    private var currentLoadLinkJob: Job? = null\n    private fun acquireSingleLink(\n        result: ResultEpisode,\n        sourceTypes: Set<ExtractorLinkType>,\n        text: UiText,\n        isCasting: Boolean = false,\n        callback: (Pair<LinkLoadingResult, Int>) -> Unit\n    ) {\n        // TODO Add skip loading here\n        loadLinks(result, isVisible = true, sourceTypes, isCasting = isCasting) { links ->\n            // Could not find a better way to do this\n            //val context = CloudStreamApp.context\n            postPopup(\n                text,\n                links.links.map { txt(\"${it.name} ${Qualities.getStringByInt(it.quality)}\") }\n                /*.amap {\n                val size =\n                    it.getVideoSize()?.let { size -> \" \" + formatFileSize(context, size) } ?: \"\"\n                txt(\"${it.name} ${Qualities.getStringByInt(it.quality)}$size\")\n                }*/) {\n                callback.invoke(links to (it ?: return@postPopup))\n            }\n        }\n    }\n\n    private fun acquireSingleSubtitle(\n        result: ResultEpisode,\n        text: UiText,\n        callback: (Pair<LinkLoadingResult, Int>) -> Unit,\n    ) {\n        loadLinks(result, isVisible = true) { links ->\n            postPopup(\n                text,\n                links.subs.map { txt(it.name) })\n            {\n                callback.invoke(links to (it ?: return@postPopup))\n            }\n        }\n    }\n\n    fun skipLoading() {\n        currentLoadLinkJob?.cancelChildren()\n        currentLoadLinkJob = null\n    }\n\n    private suspend fun CoroutineScope.loadLinks(\n        result: ResultEpisode,\n        isVisible: Boolean,\n        sourceTypes: Set<ExtractorLinkType> = LOADTYPE_ALL,\n        clearCache: Boolean = false,\n        isCasting: Boolean = false\n    ): LinkLoadingResult {\n        val tempGenerator = RepoLinkGenerator(listOf(result))\n\n        val links: MutableSet<ExtractorLink> = mutableSetOf()\n        val subs: MutableSet<SubtitleData> = mutableSetOf()\n        fun updatePage() {\n            if (isVisible && isActive) {\n                _loadedLinks.postValue(LinkProgress(links.size, subs.size))\n            }\n        }\n        try {\n            updatePage()\n            tempGenerator.generateLinks(\n                clearCache,\n                sourceTypes = sourceTypes,\n                callback = { (link, _) ->\n                    if (link != null) {\n                        links += link\n                        updatePage()\n                    }\n                },\n                subtitleCallback = { sub ->\n                    subs += sub\n                    updatePage()\n                },\n                isCasting = isCasting\n            )\n        } catch (e: CancellationException) {\n            // Do nothing\n        } catch (e: Exception) {\n            logError(e)\n        } finally {\n            _loadedLinks.postValue(null)\n        }\n\n        return LinkLoadingResult(\n            sortUrls(links),\n            sortSubs(subs),\n            HashMap(currentResponse?.syncData ?: emptyMap())\n        )\n    }\n\n    fun handleAction(click: EpisodeClickEvent) =\n        viewModelScope.launchSafe {\n            handleEpisodeClickEvent(click)\n        }\n\n    fun releaseEpisodeSynopsis() {\n        _episodeSynopsis.postValue(null)\n    }\n\n    private fun markEpisodes(\n        editor: Editor,\n        episodeIds: Array<String>,\n        watchState: VideoWatchState\n    ) {\n        val watchStateString = DataStore.mapper.writeValueAsString(watchState)\n        episodeIds.forEach {\n            if (getVideoWatchState(it.toInt()) != watchState) {\n                editor.setKeyRaw(\n                    getFolderName(\"$currentAccount/$VIDEO_WATCH_STATE\", it),\n                    watchStateString\n                )\n            }\n        }\n    }\n\n    private fun getEpisodesIdsBySeason(season: Int): HashMap<Int, Array<String>> {\n        val result = currentEpisodes.entries\n            .asSequence()\n            .filter { it.key.season <= season && it.key.dubStatus == preferDubStatus }\n            .flatMap { entry ->\n                entry.value.asSequence().map { entry.key.season to it.id.toString() }\n            }\n            .groupBy({ it.first }, { it.second })\n            .mapValues { (_, ids) -> ids.toTypedArray() }\n            .toMap(HashMap())\n\n        if (season != 0) {\n            result.remove(0)\n        }\n        return result\n    }\n\n\n    private suspend fun handleEpisodeClickEvent(click: EpisodeClickEvent) {\n        when (click.action) {\n            ACTION_SHOW_OPTIONS -> {\n                val options = mutableListOf<Pair<UiText, Int>>()\n\n                if (activity?.isConnectedToChromecast() == true) {\n                    options.addAll(\n                        listOf(\n                            txt(R.string.episode_action_chromecast_episode) to ACTION_CHROME_CAST_EPISODE,\n                            txt(R.string.episode_action_chromecast_mirror) to ACTION_CHROME_CAST_MIRROR,\n                        )\n                    )\n                }\n\n                options.add(txt(R.string.episode_action_play_in_app) to ACTION_PLAY_EPISODE_IN_PLAYER)\n                options.addAll(\n                    listOf(\n                        txt(R.string.episode_action_auto_download) to ACTION_DOWNLOAD_EPISODE,\n                        txt(R.string.episode_action_download_mirror) to ACTION_DOWNLOAD_MIRROR,\n                        txt(R.string.episode_action_download_subtitle) to ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR,\n                        txt(R.string.episode_action_reload_links) to ACTION_RELOAD_EPISODE,\n                    )\n                )\n\n                options.addAll(\n                    VideoClickActionHolder.makeOptionMap(activity, click.data)\n                )\n\n                // Do not add mark as watched on movies\n                if (!listOf(TvType.Movie, TvType.AnimeMovie).contains(click.data.tvType)) {\n                    val isWatched =\n                        getVideoWatchState(click.data.id) == VideoWatchState.Watched\n\n                    val watchedText = if (isWatched) R.string.action_remove_from_watched\n                    else R.string.action_mark_as_watched\n\n                    val markUpToText =\n                        if (isWatched) R.string.action_remove_mark_watched_up_to_this_episode\n                        else R.string.action_mark_watched_up_to_this_episode\n\n                    options.add(txt(watchedText) to ACTION_MARK_AS_WATCHED)\n\n                    options.add(txt(markUpToText) to ACTION_MARK_WATCHED_UP_TO_THIS_EPISODE)\n                }\n                postPopup(\n                    txt(\n                        activity?.getNameFull(\n                            click.data.name,\n                            click.data.episode,\n                            click.data.season\n                        ) ?: \"\"\n                    ), // TODO FIX\n                    options\n                ) { result ->\n                    handleEpisodeClickEvent(\n                        click.copy(action = result ?: return@postPopup)\n                    )\n                }\n            }\n\n            ACTION_CLICK_DEFAULT -> {\n                activity?.let { ctx ->\n                    if (ctx.isConnectedToChromecast()) {\n                        handleEpisodeClickEvent(\n                            click.copy(action = ACTION_CHROME_CAST_EPISODE)\n                        )\n                    } else {\n                        val action = getPlayerAction(ctx)\n                        handleEpisodeClickEvent(\n                            click.copy(action = action)\n                        )\n                    }\n                }\n            }\n\n            ACTION_SHOW_DESCRIPTION -> {\n                _episodeSynopsis.postValue(click.data.description)\n            }\n\n            /* not implemented, not used\n            ACTION_DOWNLOAD_EPISODE_SUBTITLE -> {\n                loadLinks(click.data, isVisible =  false, isCasting = false) { links ->\n                    downloadSubtitle(activity,links.subs,)\n                }\n            }*/\n            ACTION_DOWNLOAD_EPISODE_SUBTITLE_MIRROR -> {\n                val response = currentResponse ?: return\n\n                acquireSingleSubtitle(\n                    click.data,\n                    txt(R.string.episode_action_download_subtitle)\n                ) { (links, index) ->\n                    downloadSubtitle(\n                        activity,\n                        links.subs[index],\n                        getMeta(\n                            click.data,\n                            response.name,\n                            response.apiName,\n                            response.posterUrl,\n                            response.isMovie(),\n                            response.type\n                        )\n                    )\n                    showToast(\n                        R.string.download_started,\n                        Toast.LENGTH_SHORT\n                    )\n                }\n            }\n\n            ACTION_SHOW_TOAST -> {\n                showToast(R.string.play_episode_toast, Toast.LENGTH_SHORT)\n            }\n\n            ACTION_DOWNLOAD_EPISODE -> {\n                val response = currentResponse ?: return\n                DownloadQueueManager.addToQueue(\n                    DownloadObjects.DownloadQueueItem(\n                        click.data,\n                        response.isMovie(),\n                        response.name,\n                        response.type,\n                        response.posterUrl,\n                        response.apiName,\n                        response.getId(),\n                        response.url,\n                    ).toWrapper()\n                )\n            }\n\n            ACTION_DOWNLOAD_MIRROR -> {\n                val response = currentResponse ?: return\n                acquireSingleLink(\n                    click.data,\n                    LOADTYPE_INAPP_DOWNLOAD,\n                    txt(R.string.episode_action_download_mirror)\n                ) { (result, index) ->\n                    DownloadQueueManager.addToQueue(\n                        DownloadObjects.DownloadQueueItem(\n                            click.data,\n                            response.isMovie(),\n                            response.name,\n                            response.type,\n                            response.posterUrl,\n                            response.apiName,\n                            response.getId(),\n                            response.url,\n                            listOf(result.links[index]),\n                            result.subs,\n                        ).toWrapper()\n                    )\n                    showToast(\n                        R.string.download_started,\n                        Toast.LENGTH_SHORT\n                    )\n                }\n            }\n\n            ACTION_RELOAD_EPISODE -> {\n                ioSafe {\n                    loadLinks(\n                        click.data,\n                        isVisible = false,\n                        LOADTYPE_INAPP,\n                        clearCache = true\n                    )\n                }\n                showToast(\n                    R.string.links_reloaded_toast,\n                    Toast.LENGTH_SHORT\n                )\n            }\n\n            ACTION_CHROME_CAST_MIRROR -> {\n                acquireSingleLink(\n                    click.data,\n                    LOADTYPE_CHROMECAST,\n                    txt(R.string.episode_action_chromecast_mirror),\n                    isCasting = true\n                ) { (result, index) ->\n                    startChromecast(activity, click.data, result.links, result.subs, index)\n                }\n            }\n\n            ACTION_CHROME_CAST_EPISODE -> {\n                startChromecast(activity, click.data)\n            }\n\n            ACTION_PLAY_EPISODE_IN_PLAYER -> {\n                val list = HashMap<String, String>(currentResponse?.syncData ?: emptyMap())\n\n                generator?.also {\n                    it.getAll() // I know kinda shit to iterate all, but it is 100% sure to work\n                        ?.indexOfFirst { value -> value is ResultEpisode && value.id == click.data.id }\n                        ?.let { index ->\n                            if (index >= 0)\n                                it.goto(index)\n                        }\n                }\n                if (currentResponse?.type == TvType.CustomMedia) {\n                    generator?.generateLinks(\n                        clearCache = true,\n                        LOADTYPE_ALL,\n                        callback = {},\n                        subtitleCallback = {})\n                } else {\n                    activity?.navigate(\n                        R.id.global_to_navigation_player,\n                        GeneratorPlayer.newInstance(\n                            generator ?: return, list\n                        )\n                    )\n                }\n            }\n\n            ACTION_MARK_AS_WATCHED -> {\n                val isWatched =\n                    getVideoWatchState(click.data.id) == VideoWatchState.Watched\n                if (isWatched) {\n                    setVideoWatchState(click.data.id, VideoWatchState.None)\n                } else {\n                    setVideoWatchState(click.data.id, VideoWatchState.Watched)\n                }\n                // Kinda dirty to reload all episodes :(\n                reloadEpisodes()\n            }\n\n            ACTION_MARK_WATCHED_UP_TO_THIS_EPISODE -> ioSafe {\n                val editor = context?.let { it1 -> editor(it1, false) }\n\n                if (editor != null) {\n                    val (clickSeason, clickEpisode) = click.data.let {\n                        (it.season ?: 0) to it.episode\n                    }\n                    val watchState =\n                        if (getVideoWatchState(click.data.id) == VideoWatchState.Watched) VideoWatchState.None else VideoWatchState.Watched\n                    val seasons = getEpisodesIdsBySeason(clickSeason)\n\n                    seasons.keys.forEach { currentSeason ->\n                        var episodeIds = seasons[currentSeason] ?: emptyArray()\n                        if (currentSeason == clickSeason) episodeIds =\n                            episodeIds.sliceArray(0 until clickEpisode)\n                        markEpisodes(editor, episodeIds, watchState)\n                    }\n                    editor.apply()\n                    reloadEpisodes()\n                }\n            }\n\n            else -> {\n                val action = VideoClickActionHolder.getActionById(click.action) ?: return\n\n                // Special handling for AlwaysAskAction - show player selection dialog\n                if (action is AlwaysAskAction) {\n                    activity?.let { ctx ->\n                        // Show player selection dialog\n                        val players = VideoClickActionHolder.getPlayers(ctx)\n                        val options = mutableListOf<Pair<UiText, Int>>()\n\n                        // Add internal player option\n                        options.add(txt(R.string.episode_action_play_in_app) to ACTION_PLAY_EPISODE_IN_PLAYER)\n\n                        // Add external player options \n                        options.addAll(players.filter { it !is AlwaysAskAction }.map { player ->\n                            player.name to (VideoClickActionHolder.uniqueIdToId(player.uniqueId())\n                                ?: ACTION_PLAY_EPISODE_IN_PLAYER)\n                        })\n\n                        postPopup(\n                            txt(R.string.player_pref),\n                            options\n                        ) { selectedAction ->\n                            if (selectedAction != null) {\n                                handleEpisodeClickEvent(\n                                    click.copy(action = selectedAction)\n                                )\n                            }\n                        }\n                    }\n                    return\n                }\n\n                activity?.setKey(\"last_click_action\", action.uniqueId())\n                if (action.oneSource) {\n                    acquireSingleLink(\n                        click.data,\n                        action.sourceTypes,\n                        action.name\n                    ) { (result, index) ->\n                        action.runActionSafe(\n                            activity,\n                            click.data,\n                            result,\n                            index\n                        )\n                    }\n                } else {\n                    loadLinks(click.data, isVisible = true, action.sourceTypes) { links ->\n                        action.runActionSafe(\n                            activity,\n                            click.data,\n                            links,\n                            null\n                        )\n                    }\n                }\n            }\n        }\n    }\n\n    private suspend fun applyMeta(\n        resp: LoadResponse,\n        meta: SyncAPI.SyncResult?,\n        syncs: Map<String, String>? = null\n    ): Pair<LoadResponse, Boolean> {\n        //if (meta == null) return resp to false\n        var updateEpisodes = false\n        val out = resp.apply {\n            Log.i(TAG, \"applyMeta\")\n\n            if (meta != null) {\n                duration = duration ?: meta.duration\n                score = score ?: meta.publicScore\n                tags = tags ?: meta.genres\n                plot = if (plot.isNullOrBlank()) meta.synopsis else plot\n                posterUrl = posterUrl ?: meta.posterUrl ?: meta.backgroundPosterUrl\n                actors = actors ?: meta.actors\n\n                if (this is EpisodeResponse) {\n                    nextAiring = nextAiring ?: meta.nextAiring\n                }\n\n                val realRecommendations = ArrayList<SearchResponse>()\n                val apiNames = synchronized(apis) {\n                    apis.filter {\n                        it.name.contains(\"gogoanime\", true) ||\n                                it.name.contains(\"9anime\", true)\n                    }.map {\n                        it.name\n                    }\n                }\n                meta.recommendations?.forEach { rec ->\n                    apiNames.forEach { name ->\n                        realRecommendations.add(rec.copy(apiName = name))\n                    }\n                }\n\n                recommendations = recommendations?.union(realRecommendations)?.toList()\n                    ?: realRecommendations\n            }\n\n            for ((k, v) in syncs ?: emptyMap()) {\n                syncData[k] = v\n            }\n\n            runAllAsync(\n                {\n                    if (this !is AnimeLoadResponse) return@runAllAsync\n                    // already exist, no need to run getTracker\n                    if (this.getAniListId() != null && this.getKitsuId() != null && this.getMalId() != null) return@runAllAsync\n\n                    val res = APIHolder.getTracker(\n                        listOfNotNull(\n                            this.engName,\n                            this.name,\n                            this.japName\n                        ).filter { it.length > 2 }\n                            .distinct().map {\n                                // this actually would be nice if we improved a bit as 3rd season == season 3 == III ect\n                                // right now it just removes the dubbed status\n                                it.lowercase().replace(Regex(\"\"\"\\(?[ds]ub(bed)?\\)?(\\s|$)\"\"\"), \"\")\n                                    .trim()\n                            },\n                        TrackerType.getTypes(this.type),\n                        this.year\n                    )\n\n                    val kitsuId = AccountManager.kitsuApi.getAnimeIdByTitle(this.name)\n\n                    val ids = arrayOf(\n                        AccountManager.malApi.idPrefix to res?.malId?.toString(),\n                        AccountManager.aniListApi.idPrefix to res?.aniId,\n                        AccountManager.kitsuApi.idPrefix to kitsuId\n                    )\n\n                    if (ids.any { (id, new) ->\n                            val current = syncData[id]\n                            new != null && current != null && current != new\n                        }\n                    ) {\n                        // getTracker fucked up as it conflicts with current implementation\n                        return@runAllAsync\n                    }\n\n                    // set all the new data, prioritise old correct data\n                    ids.forEach { (id, new) ->\n                        new?.let {\n                            syncData[id] = syncData[id] ?: it\n                        }\n                    }\n\n                    // set posters, might fuck up due to headers idk\n                    posterUrl = posterUrl ?: res?.image\n                    backgroundPosterUrl = backgroundPosterUrl ?: res?.cover\n                    logoUrl = logoUrl\n                },\n                {\n                    if (meta == null) return@runAllAsync\n                    addTrailer(meta.trailers)\n                }, {\n                    if (this !is AnimeLoadResponse) return@runAllAsync\n                    val map =\n                        Kitsu.getEpisodesDetails(\n                            getMalId(),\n                            getAniListId(),\n                            isResponseRequired = false\n                        )\n                    if (map.isNullOrEmpty()) return@runAllAsync\n                    updateEpisodes = DubStatus.entries.map { dubStatus ->\n                        val current =\n                            this.episodes[dubStatus]?.mapIndexed { index, episode ->\n                                episode.apply {\n                                    this.episode = this.episode ?: (index + 1)\n                                }\n                            }?.sortedBy { it.episode ?: 0 }?.toMutableList()\n                        if (current.isNullOrEmpty()) return@map false\n                        val episodeNumbers = current.map { ep -> ep.episode!! }\n                        var updateCount = 0\n                        map.forEach { (episode, node) ->\n                            episodeNumbers.binarySearch(episode).let { index ->\n                                current.getOrNull(index)?.let { currentEp ->\n                                    current[index] = currentEp.apply {\n                                        updateCount++\n                                        this.description = this.description ?: node.description?.en\n                                        this.name = this.name ?: node.titles?.canonical\n                                        this.episode =\n                                            this.episode ?: node.num ?: episodeNumbers[index]\n                                        this.posterUrl =\n                                            this.posterUrl ?: node.thumbnail?.original?.url\n                                    }\n                                }\n                            }\n                        }\n                        this.episodes[dubStatus] = current\n                        updateCount > 0\n                    }.any { it }\n                })\n        }\n        return out to updateEpisodes\n    }\n\n    fun setMeta(meta: SyncAPI.SyncResult, syncs: Map<String, String>?) {\n        // I dont want to update everything if the metadata is not relevant\n        if (currentMeta == meta && currentSync == syncs) {\n            Log.i(TAG, \"setMeta same\")\n            return\n        }\n        Log.i(TAG, \"setMeta\")\n        viewModelScope.launchSafe {\n            currentMeta = meta\n            currentSync = syncs\n            val (value, updateEpisodes) = ioWork {\n                currentResponse?.let { resp ->\n                    return@ioWork applyMeta(resp, meta, syncs)\n                }\n                return@ioWork null to null\n            }\n\n            postSuccessful(\n                value ?: return@launchSafe,\n                currentId ?: return@launchSafe,\n                currentRepo ?: return@launchSafe,\n                updateEpisodes ?: return@launchSafe,\n                false\n            )\n        }\n    }\n\n\n    private suspend fun updateFillers(name: String) {\n        fillers =\n            ioWorkSafe {\n                FillerEpisodeCheck.getFillerEpisodes(name)\n            } ?: emptyMap()\n    }\n\n    fun changeDubStatus(status: DubStatus) {\n        postEpisodeRange(\n            currentIndex?.copy(dubStatus = status),\n            currentRange,\n            currentSorting ?: DataStoreHelper.resultsSortingMode\n        )\n    }\n\n    fun changeRange(range: EpisodeRange) {\n        postEpisodeRange(currentIndex, range, currentSorting ?: DataStoreHelper.resultsSortingMode)\n    }\n\n    fun changeSeason(season: Int) {\n        postEpisodeRange(\n            currentIndex?.copy(season = season),\n            currentRange,\n            currentSorting ?: DataStoreHelper.resultsSortingMode\n        )\n    }\n\n    fun setSort(sortType: EpisodeSortType) {\n        // we only update here as postEpisodeRange might change the sorting mode if it does not fit\n        DataStoreHelper.resultsSortingMode = sortType\n        postEpisodeRange(currentIndex, currentRange, sortType)\n    }\n\n    private fun getMovie(): ResultEpisode? {\n        return currentEpisodes.entries.firstOrNull()?.value?.firstOrNull()?.let { ep ->\n            val posDur = getViewPos(ep.id)\n            ep.copy(position = posDur?.position ?: 0, duration = posDur?.duration ?: 0)\n        }\n    }\n\n    private fun getEpisodes(\n        indexer: EpisodeIndexer,\n        range: EpisodeRange,\n    ): List<ResultEpisode> {\n        return currentEpisodes[indexer]?.let { list ->\n            val start = minOf(list.size, range.startIndex)\n            val end = minOf(list.size, start + range.length)\n            list.subList(start, end).map {\n                val posDur = getViewPos(it.id)\n                val watchState = getVideoWatchState(it.id) ?: VideoWatchState.None\n                it.copy(\n                    position = posDur?.position ?: 0,\n                    duration = posDur?.duration ?: 0,\n                    videoWatchState = watchState\n                )\n            }\n        } ?: emptyList()\n    }\n\n    private fun getSortedEpisodes(\n        episodes: List<ResultEpisode>,\n        sorting: EpisodeSortType\n    ): List<ResultEpisode> {\n        return when (sorting) {\n            EpisodeSortType.NUMBER_ASC -> episodes.sortedBy { it.episode }\n            EpisodeSortType.NUMBER_DESC -> episodes.sortedByDescending { it.episode }\n            EpisodeSortType.RATING_HIGH_LOW -> episodes.sortedByDescending {\n                it.score?.toDouble() ?: 0.0\n            }\n\n            EpisodeSortType.RATING_LOW_HIGH -> episodes.sortedBy { it.score?.toDouble() ?: 0.0 }\n            EpisodeSortType.DATE_NEWEST -> episodes.sortedByDescending { it.airDate }\n            EpisodeSortType.DATE_OLDEST -> episodes.sortedBy { it.airDate }\n        }\n    }\n\n    private fun postMovie() {\n        val response = currentResponse\n        _episodes.postValue(null)\n\n        if (response == null) {\n            _movie.postValue(null)\n            return\n        }\n\n        val text = txt(\n            when (response.type) {\n                TvType.Torrent -> R.string.play_torrent_button\n                TvType.TvSeries -> R.string.play_full_series_button\n                else -> {\n                    if (response.type.isLiveStream())\n                        R.string.play_livestream_button\n                    else if (response.isMovie()) // this wont break compatibility as you only need to override isMovieType\n                        R.string.play_movie_button\n                    else null\n                }\n            }\n        )\n        val data = getMovie()\n        _episodes.postValue(null)\n        if (text == null || data == null) {\n            _movie.postValue(null)\n        } else {\n            _movie.postValue(Resource.Success(text to data))\n        }\n    }\n\n    fun reloadEpisodes() {\n        if (currentResponse?.isMovie() == true) {\n            postMovie()\n        } else {\n            _episodes.postValue(\n                Resource.Success(\n                    getSortedEpisodes(\n                        getEpisodes(\n                            currentIndex ?: return,\n                            currentRange ?: return,\n                        ), currentSorting ?: return\n                    )\n                )\n            )\n            _movie.postValue(null)\n        }\n        postResume()\n    }\n\n    private fun postSubscription(loadResponse: LoadResponse) {\n        val id = loadResponse.getId()\n        val data = getSubscribedData(id)\n        if (loadResponse.isEpisodeBased()) {\n            updateSubscribedData(id, data, loadResponse as? EpisodeResponse)\n            _subscribeStatus.postValue(data != null)\n        }\n        // lets say that we have subscribed, then we must be able to unsubscribe no matter what\n        else if (data != null) {\n            _subscribeStatus.postValue(true)\n        } else _subscribeStatus.postValue(null)\n    }\n\n    private fun postFavorites(loadResponse: LoadResponse) {\n        val id = loadResponse.getId()\n        val isFavorite = getFavoritesData(id) != null\n        _favoriteStatus.postValue(isFavorite)\n    }\n\n    private fun shouldEnableSort(type: EpisodeSortType, episodes: List<ResultEpisode>?): Boolean {\n        if (episodes.isNullOrEmpty()) return false\n        return when (type) {\n            EpisodeSortType.NUMBER_ASC, EpisodeSortType.NUMBER_DESC -> true\n            EpisodeSortType.RATING_HIGH_LOW, EpisodeSortType.RATING_LOW_HIGH ->\n                episodes.any { it.score != null }\n\n            EpisodeSortType.DATE_NEWEST, EpisodeSortType.DATE_OLDEST ->\n                episodes.any { it.airDate != null }\n        }\n    }\n\n    private fun postEpisodeRange(\n        indexer: EpisodeIndexer?,\n        range: EpisodeRange?,\n        sorting: EpisodeSortType?\n    ) {\n        if (range == null || indexer == null || sorting == null) {\n            return\n        }\n\n        val ranges = currentRanges[indexer]\n\n        if (ranges?.contains(range) != true) {\n            // if the current ranges does not include the range then select the range with the closest matching start episode\n            // this usually happens when dub has less episodes then sub -> the range does not exist\n            ranges?.minByOrNull { kotlin.math.abs(it.startEpisode - range.startEpisode) }\n                ?.let { r ->\n                    postEpisodeRange(indexer, r, sorting)\n                    return\n                }\n        }\n\n        val isMovie = currentResponse?.isMovie() == true\n        currentIndex = indexer\n        currentRange = range\n\n        _rangeSelections.postValue(ranges?.map { r ->\n            val text = txt(R.string.episodes_range, r.startEpisode, r.endEpisode)\n            text to r\n        } ?: emptyList())\n\n        val size = currentEpisodes[indexer]?.size\n        _episodesCountText.postValue(\n\n            if (isMovie) null else\n                txt(\n                    R.string.episode_format,\n                    size,\n                    txt(if (size == 1) R.string.episode else R.string.episodes),\n                )\n\n        )\n\n        _selectedSeasonIndex.postValue(\n            currentSeasons.indexOf(indexer.season)\n        )\n\n        _selectedSeason.postValue(\n            if (isMovie || currentSeasons.size <= 1) null else\n                (currentResponse as? EpisodeResponse)?.seasonNames.getSeasonTxt(indexer.season)\n        )\n\n        _selectedRangeIndex.postValue(\n            ranges?.indexOf(range) ?: -1\n        )\n\n        _selectedRange.postValue(\n\n            if (isMovie) null else if ((currentRanges[indexer]?.size ?: 0) > 1) {\n                txt(R.string.episodes_range, range.startEpisode, range.endEpisode)\n            } else {\n                null\n            }\n\n        )\n\n        _selectedDubStatusIndex.postValue(\n            currentDubStatus.indexOf(indexer.dubStatus)\n        )\n\n        _selectedDubStatus.postValue(\n\n            if (isMovie || currentDubStatus.size <= 1) null else\n                txt(indexer.dubStatus)\n\n        )\n\n        currentId?.let { id ->\n            setDub(id, indexer.dubStatus)\n            setResultSeason(id, indexer.season)\n            setResultEpisode(id, range.startEpisode)\n        }\n\n        preferStartEpisode = range.startEpisode\n        preferStartSeason = indexer.season\n        preferDubStatus = indexer.dubStatus\n\n        generator = if (isMovie) {\n            getMovie()?.let { RepoLinkGenerator(listOf(it), page = currentResponse) }\n        } else {\n            val episodes = currentEpisodes.filter { it.key.dubStatus == indexer.dubStatus }\n                .toList()\n                .sortedBy { it.first.season }\n                .flatMap { it.second }\n\n            RepoLinkGenerator(episodes, page = currentResponse)\n        }\n\n        if (isMovie) {\n            _sortSelections.postValue(emptyList())\n            _selectedSortingIndex.postValue(-1)\n            _selectedSorting.postValue(null)\n\n            postMovie()\n        } else {\n            val ret = getEpisodes(indexer, range)\n\n            if (ret.size <= 1) {\n                // we cant sort on an empty list or a list with only 1 episode\n                _sortSelections.postValue(emptyList())\n                _selectedSortingIndex.postValue(-1)\n                _selectedSorting.postValue(null)\n                _episodes.postValue(Resource.Success(ret))\n            } else {\n                val sortOptions = mutableListOf<Pair<UiText, EpisodeSortType>>().apply {\n                    // Episode number sorting is always available\n                    add(txt(R.string.sort_episodes_number_asc) to EpisodeSortType.NUMBER_ASC)\n                    add(txt(R.string.sort_episodes_number_desc) to EpisodeSortType.NUMBER_DESC)\n\n                    // Only add rating options if any episodes have ratings\n                    if (shouldEnableSort(EpisodeSortType.RATING_HIGH_LOW, ret)) {\n                        add(txt(R.string.sort_episodes_rating_high_low) to EpisodeSortType.RATING_HIGH_LOW)\n                        add(txt(R.string.sort_episodes_rating_low_high) to EpisodeSortType.RATING_LOW_HIGH)\n                    }\n\n                    // Only add air date options if any episodes have air dates\n                    if (shouldEnableSort(EpisodeSortType.DATE_NEWEST, ret)) {\n                        add(txt(R.string.sort_episodes_date_newest) to EpisodeSortType.DATE_NEWEST)\n                        add(txt(R.string.sort_episodes_date_oldest) to EpisodeSortType.DATE_OLDEST)\n                    }\n                }\n\n                var sortIndex = sortOptions.indexOfFirst { it.second == sorting }\n\n                // correct the sorting order so if we have a selected that is not possible we just choose the default NUMBER_ASC\n                val correctedSorting = if (sortIndex == -1) {\n                    sortIndex = 0\n                    EpisodeSortType.NUMBER_ASC\n                } else {\n                    sorting\n                }\n\n                currentSorting = correctedSorting\n                _sortSelections.postValue(sortOptions)\n                _selectedSortingIndex.postValue(sortIndex)\n                _selectedSorting.postValue(\n                    when (correctedSorting) {\n                        EpisodeSortType.NUMBER_ASC -> txt(R.string.sort_button_episode, \"↑\")\n                        EpisodeSortType.NUMBER_DESC -> txt(R.string.sort_button_episode, \"↓\")\n                        EpisodeSortType.RATING_HIGH_LOW -> txt(R.string.sort_button_rating, \"↓\")\n                        EpisodeSortType.RATING_LOW_HIGH -> txt(R.string.sort_button_rating, \"↑\")\n                        EpisodeSortType.DATE_NEWEST -> txt(R.string.sort_button_date, \"↓\")\n                        EpisodeSortType.DATE_OLDEST -> txt(R.string.sort_button_date, \"↑\")\n                    }\n                )\n                _episodes.postValue(Resource.Success(getSortedEpisodes(ret, correctedSorting)))\n            }\n        }\n    }\n\n    private suspend fun postSuccessful(\n        loadResponse: LoadResponse,\n        mainId: Int,\n        apiRepository: APIRepository,\n        updateEpisodes: Boolean,\n        updateFillers: Boolean,\n    ) {\n        currentId = mainId\n        currentResponse = loadResponse\n        postPage(loadResponse, apiRepository)\n        postSubscription(loadResponse)\n        postFavorites(loadResponse)\n        _watchStatus.postValue(getResultWatchState(mainId))\n\n        if (updateEpisodes)\n            postEpisodes(loadResponse, mainId, updateFillers)\n    }\n\n    private suspend fun postEpisodes(\n        loadResponse: LoadResponse,\n        mainId: Int,\n        updateFillers: Boolean\n    ) {\n        _episodes.postValue(Resource.Loading())\n\n        if (updateFillers && loadResponse is AnimeLoadResponse) {\n            updateFillers(loadResponse.name)\n        }\n\n        val allEpisodes = when (loadResponse) {\n            is AnimeLoadResponse -> {\n                val existingEpisodes = HashSet<Int>()\n                val episodes: MutableMap<EpisodeIndexer, MutableList<ResultEpisode>> =\n                    mutableMapOf()\n                loadResponse.episodes.map { ep ->\n                    val idIndex = ep.key.id\n                    for ((index, i) in ep.value.withIndex()) {\n                        val episode = i.episode ?: (index + 1)\n                        val id =\n                            mainId + episode + idIndex * 1_000_000 + (i.season?.times(10_000)\n                                ?: 0)\n\n                        val totalIndex =\n                            i.season?.let { season ->\n                                loadResponse.getTotalEpisodeIndex(\n                                    episode,\n                                    season\n                                )\n                            }\n\n                        if (!existingEpisodes.contains(id)) {\n                            existingEpisodes.add(id)\n                            val seasonData = loadResponse.seasonNames.getSeason(i.season)\n                            val eps =\n                                buildResultEpisode(\n                                    loadResponse.name,\n                                    filterName(i.name),\n                                    i.posterUrl,\n                                    episode,\n                                    i.season,\n                                    if (seasonData != null) seasonData.displaySeason else i.season,\n                                    i.data,\n                                    loadResponse.apiName,\n                                    id,\n                                    index,\n                                    i.score,\n                                    i.description,\n                                    fillers.getOrDefault(episode, false),\n                                    loadResponse.type,\n                                    mainId,\n                                    totalIndex,\n                                    airDate = i.date,\n                                    runTime = i.runTime,\n                                    seasonData = seasonData,\n                                )\n\n                            val season = eps.seasonIndex ?: 0\n                            val indexer = EpisodeIndexer(ep.key, season)\n                            episodes[indexer]?.add(eps) ?: run {\n                                episodes[indexer] = mutableListOf(eps)\n                            }\n                        }\n                    }\n                }\n                episodes\n            }\n\n            is TvSeriesLoadResponse -> {\n                val episodes: MutableMap<EpisodeIndexer, MutableList<ResultEpisode>> =\n                    mutableMapOf()\n                val existingEpisodes = HashSet<Int>()\n                for ((index, episode) in loadResponse.episodes.sortedBy {\n                    (it.season?.times(10_000) ?: 0) + (it.episode ?: 0)\n                }.withIndex()) {\n                    val episodeIndex = episode.episode ?: (index + 1)\n                    val id =\n                        mainId + (episode.season?.times(100_000) ?: 0) + episodeIndex + 1\n                    if (!existingEpisodes.contains(id)) {\n                        existingEpisodes.add(id)\n                        val seasonData =\n                            loadResponse.seasonNames.getSeason(episode.season)\n\n                        val totalIndex =\n                            episode.season?.let { season ->\n                                loadResponse.getTotalEpisodeIndex(\n                                    episodeIndex,\n                                    season\n                                )\n                            }\n\n                        val ep =\n                            buildResultEpisode(\n                                loadResponse.name,\n                                filterName(episode.name),\n                                episode.posterUrl,\n                                episodeIndex,\n                                episode.season,\n                                if (seasonData != null) seasonData.displaySeason else episode.season,\n                                episode.data,\n                                loadResponse.apiName,\n                                id,\n                                index,\n                                episode.score,\n                                episode.description,\n                                null,\n                                loadResponse.type,\n                                mainId,\n                                totalIndex,\n                                airDate = episode.date,\n                                runTime = episode.runTime,\n                                seasonData = seasonData,\n                            )\n\n                        val season = ep.seasonIndex ?: 0\n                        val indexer = EpisodeIndexer(DubStatus.None, season)\n\n                        episodes[indexer]?.add(ep) ?: kotlin.run {\n                            episodes[indexer] = mutableListOf(ep)\n                        }\n                    }\n                }\n                episodes\n            }\n\n            is MovieLoadResponse -> {\n                singleMap(\n                    buildResultEpisode(\n                        loadResponse.name,\n                        loadResponse.name,\n                        null,\n                        0,\n                        null,\n                        null,\n                        loadResponse.dataUrl,\n                        loadResponse.apiName,\n                        (mainId), // HAS SAME ID\n                        0,\n                        null,\n                        null,\n                        null,\n                        loadResponse.type,\n                        mainId,\n                        null,\n                    )\n                )\n            }\n\n            is LiveStreamLoadResponse -> {\n                singleMap(\n                    buildResultEpisode(\n                        loadResponse.name,\n                        loadResponse.name,\n                        null,\n                        0,\n                        null,\n                        null,\n                        loadResponse.dataUrl,\n                        loadResponse.apiName,\n                        (mainId), // HAS SAME ID\n                        0,\n                        null,\n                        null,\n                        null,\n                        loadResponse.type,\n                        mainId,\n                        null\n                    )\n                )\n            }\n\n            is TorrentLoadResponse -> {\n                singleMap(\n                    buildResultEpisode(\n                        loadResponse.name,\n                        loadResponse.name,\n                        null,\n                        0,\n                        null,\n                        null,\n                        loadResponse.torrent ?: loadResponse.magnet ?: \"\",\n                        loadResponse.apiName,\n                        (mainId), // HAS SAME ID\n                        0,\n                        null,\n                        null,\n                        null,\n                        loadResponse.type,\n                        mainId,\n                        null\n                    )\n                )\n            }\n\n            else -> {\n                mapOf()\n            }\n        }\n\n        val seasonsSelection = mutableSetOf<Int>()\n        val dubSelection = mutableSetOf<DubStatus>()\n        allEpisodes.keys.forEach { key ->\n            seasonsSelection += key.season\n            dubSelection += key.dubStatus\n        }\n        currentDubStatus = dubSelection.toList()\n        currentSeasons = seasonsSelection.toList()\n        _dubSubSelections.postValue(dubSelection.map { txt(it) to it })\n        if (loadResponse is EpisodeResponse) {\n            _seasonSelections.postValue(seasonsSelection.map { seasonNumber ->\n                loadResponse.seasonNames.getSeasonTxt(seasonNumber) to seasonNumber\n            })\n        }\n\n        currentEpisodes = allEpisodes\n        val ranges = getRanges(allEpisodes, EPISODE_RANGE_SIZE)\n        currentRanges = ranges\n\n\n        // this takes the indexer most preferable by the user given the current sorting\n        val min = ranges.keys.minByOrNull { index ->\n            kotlin.math.abs(\n                index.season - (preferStartSeason ?: 1)\n            ) + if (index.dubStatus == preferDubStatus) 0 else 100000\n        }\n\n        // this takes the range most preferable by the user given the current sorting\n        val ranger = ranges[min]\n        val range = ranger?.firstOrNull {\n            it.startEpisode >= (preferStartEpisode ?: 0)\n        } ?: ranger?.lastOrNull()\n\n        postEpisodeRange(min, range, DataStoreHelper.resultsSortingMode)\n        postResume()\n    }\n\n    private fun postResume() {\n        _resumeWatching.postValue(resume())\n    }\n\n    private fun resume(): ResumeWatchingStatus? {\n        val correctId = currentId ?: return null\n        val resume = getLastWatched(correctId)\n        val resumeParentId = resume?.parentId\n        if (resumeParentId != correctId) return null // is null or smth went wrong with getLastWatched\n        val resumeId = resume.episodeId ?: return null// invalid episode id\n        val response = currentResponse ?: return null\n        // kinda ugly ik\n        val episode =\n            currentEpisodes.values.flatten().firstOrNull { it.id == resumeId } ?: return null\n\n        val isMovie = response.isMovie()\n\n        val progress = getViewPos(resume.episodeId)?.let { viewPos ->\n            ResumeProgress(\n                progress = (viewPos.position / 1000).toInt(),\n                maxProgress = (viewPos.duration / 1000).toInt(),\n                txt(\n                    R.string.resume_remaining,\n                    secondsToReadable(\n                        ((viewPos.duration - viewPos.position) / 1_000).toInt(),\n                        \"0 mins\"\n                    )\n                )\n            )\n        }\n\n        return ResumeWatchingStatus(progress = progress, isMovie = isMovie, result = episode)\n    }\n\n    private fun loadTrailers(loadResponse: LoadResponse) = ioSafe {\n        _trailers.postValue(\n            getTrailers(\n                loadResponse,\n                3\n            )\n        ) // we dont want to fetch too many trailers\n    }\n\n    private suspend fun getTrailers(\n        loadResponse: LoadResponse,\n        limit: Int = 0\n    ): List<ExtractedTrailerData> =\n        coroutineScope {\n            val returnlist = ArrayList<ExtractedTrailerData>()\n            loadResponse.trailers.windowed(limit, limit, true).takeWhile { list ->\n                list.amap { trailerData ->\n                    try {\n                        val links = arrayListOf<Pair<ExtractorLink,String>>()\n                        val subs = arrayListOf<SubtitleFile>()\n                        if (!loadExtractor(\n                                trailerData.extractorUrl,\n                                trailerData.referer,\n                                { subs.add(it) },\n                                { links.add(Pair(it,trailerData.extractorUrl))}) && trailerData.raw\n                        ) {\n                            arrayListOf(\n                                Pair(\n                                    newExtractorLink(\n                                    \"\",\n                                    \"Trailer\",\n                                    trailerData.extractorUrl,\n                                    type = INFER_TYPE\n                                ) {\n                                    this.referer = trailerData.referer ?: \"\"\n                                    this.quality = Qualities.Unknown.value\n                                    this.headers = trailerData.headers\n                                },trailerData.extractorUrl)\n                            ) to arrayListOf()\n                        } else {\n                            links to subs\n                        }\n                    } catch (e: Throwable) {\n                        logError(e)\n                        null\n                    }\n                }.filterNotNull().map { (links, subs) -> ExtractedTrailerData(links, subs) }.let {\n                    returnlist.addAll(it)\n                }\n\n                returnlist.size < limit\n            }\n            return@coroutineScope returnlist\n        }\n\n\n    // this instantly updates the metadata on the page\n    private fun postPage(loadResponse: LoadResponse, apiRepository: APIRepository) {\n        _recommendations.postValue(loadResponse.recommendations ?: emptyList())\n        _page.postValue(Resource.Success(loadResponse.toResultData(apiRepository)))\n    }\n\n    fun hasLoaded() = currentResponse != null\n\n    private fun handleAutoStart(activity: Activity?, autostart: AutoResume?) =\n        viewModelScope.launchSafe {\n            if (autostart == null || activity == null) return@launchSafe\n\n            when (autostart.startAction) {\n                START_ACTION_RESUME_LATEST -> {\n                    currentEpisodes[currentIndex]?.let { currentRange ->\n                        for (ep in currentRange) {\n                            if (ep.getWatchProgress() > 0.9) continue\n                            handleAction(\n                                EpisodeClickEvent(\n                                    getPlayerAction(activity),\n                                    ep\n                                )\n                            )\n                            break\n                        }\n                    }\n                }\n\n                START_ACTION_LOAD_EP -> {\n                    val all = currentEpisodes.values.flatten()\n                    val episode =\n                        autostart.id?.let { id -> all.firstOrNull { it.id == id } }\n                            ?: autostart.episode?.let { ep ->\n                                currentEpisodes[currentIndex]?.firstOrNull { it.episode == ep && it.season == autostart.episode }\n                                    ?: all.firstOrNull { it.episode == ep && it.season == autostart.episode }\n                            }\n                            ?: return@launchSafe\n                    handleAction(\n                        EpisodeClickEvent(\n                            getPlayerAction(activity),\n                            episode\n                        )\n                    )\n                }\n            }\n        }\n\n    data class LoadResponseFromSearch(\n        override var name: String,\n        override var url: String,\n        override var apiName: String,\n        override var type: TvType,\n        override var posterUrl: String?,\n        override var year: Int? = null,\n        override var plot: String? = null,\n        override var score: Score? = null,\n        override var tags: List<String>? = null,\n        override var duration: Int? = null,\n        override var trailers: MutableList<TrailerData> = mutableListOf(),\n        override var recommendations: List<SearchResponse>? = null,\n        override var actors: List<ActorData>? = null,\n        override var comingSoon: Boolean = false,\n        override var syncData: MutableMap<String, String> = mutableMapOf(),\n        override var posterHeaders: Map<String, String>? = null,\n        override var backgroundPosterUrl: String? = null,\n        override var logoUrl: String? = null,\n        override var contentRating: String? = null,\n        override var uniqueUrl: String = url,\n        val id: Int?,\n    ) : LoadResponse\n\n    fun loadSmall(searchResponse: SearchResponse) = ioSafe {\n        val url = searchResponse.url\n        _page.postValue(Resource.Loading(url))\n        _episodes.postValue(Resource.Loading())\n        val api =\n            APIHolder.getApiFromNameNull(searchResponse.apiName) ?: APIHolder.getApiFromUrlNull(\n                searchResponse.url\n            ) ?: APIRepository.noneApi\n        val repo = APIRepository(api)\n        val response = LoadResponseFromSearch(\n            name = searchResponse.name,\n            url = searchResponse.url,\n            apiName = api.name,\n            type = searchResponse.type ?: TvType.Others,\n            posterUrl = searchResponse.posterUrl,\n            id = searchResponse.id\n        ).apply {\n            if (searchResponse is SyncAPI.LibraryItem) {\n                this.plot = searchResponse.plot\n                this.score = searchResponse.personalRating ?: searchResponse.score\n                this.tags = searchResponse.tags\n            }\n            if (searchResponse is DataStoreHelper.BookmarkedData) {\n                this.plot = searchResponse.plot\n                this.score = searchResponse.score\n                this.tags = searchResponse.tags\n            }\n        }\n        val mainId = response.getId()\n\n        postSuccessful(\n            loadResponse = response,\n            mainId = mainId,\n            apiRepository = repo,\n            updateEpisodes = false,\n            updateFillers = false\n        )\n    }\n\n    fun load(\n        activity: Activity?,\n        url: String,\n        apiName: String,\n        showFillers: Boolean,\n        dubStatus: DubStatus,\n        autostart: AutoResume?,\n        loadTrailers: Boolean = true,\n    ) =\n        ioSafe {\n            _page.postValue(Resource.Loading(url))\n            _episodes.postValue(Resource.Loading())\n\n            preferDubStatus = dubStatus\n            currentShowFillers = showFillers\n\n            // set api\n            val api = APIHolder.getApiFromNameNull(apiName) ?: APIHolder.getApiFromUrlNull(url)\n            if (api == null) {\n                _page.postValue(\n                    Resource.Failure(\n                        false,\n                        \"This provider does not exist\"\n                    )\n                )\n                return@ioSafe\n            }\n\n\n            // validate url\n            val validUrlResource = safeApiCall {\n                SyncRedirector.redirect(\n                    url,\n                    api\n                )\n            }\n\n            if (validUrlResource !is Resource.Success) {\n                if (validUrlResource is Resource.Failure) {\n                    _page.postValue(validUrlResource)\n                }\n\n                return@ioSafe\n            }\n\n            val validUrl = validUrlResource.value\n            val repo = APIRepository(api)\n            currentRepo = repo\n\n            when (val data = repo.load(validUrl)) {\n                is Resource.Failure -> {\n                    _page.postValue(data)\n                }\n\n                is Resource.Success -> {\n                    if (!isActive) return@ioSafe\n                    val loadResponse = ioWork {\n                        applyMeta(data.value, currentMeta, currentSync).first\n                    }\n                    if (!isActive) return@ioSafe\n                    val mainId = loadResponse.getId()\n\n                    preferDubStatus = getDub(mainId) ?: preferDubStatus\n                    preferStartEpisode = getResultEpisode(mainId)\n                    preferStartSeason = getResultSeason(mainId) ?: 1\n\n                    setKey(\n                        DOWNLOAD_HEADER_CACHE,\n                        mainId.toString(),\n                        DownloadObjects.DownloadHeaderCached(\n                            apiName = apiName,\n                            url = validUrl,\n                            type = loadResponse.type,\n                            name = loadResponse.name,\n                            poster = loadResponse.posterUrl,\n                            id = mainId,\n                            cacheTime = System.currentTimeMillis(),\n                        )\n                    )\n                    if (loadTrailers)\n                        loadTrailers(data.value)\n                    postSuccessful(\n                        data.value,\n                        mainId,\n                        updateEpisodes = true,\n                        updateFillers = showFillers,\n                        apiRepository = repo\n                    )\n                    if (!isActive) return@ioSafe\n                    handleAutoStart(activity, autostart)\n                }\n\n                is Resource.Loading -> {\n                    debugException { \"Invalid load result\" }\n                }\n            }\n        }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/SelectAdaptor.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.recyclerview.widget.RecyclerView\nimport com.lagradost.cloudstream3.databinding.ResultSelectionBinding\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.UiText\nimport com.lagradost.cloudstream3.utils.setText\n\ntypealias SelectData = Pair<UiText?, Any>\n\nclass SelectAdaptor(val callback: (Any) -> Unit) :\n    NoStateAdapter<SelectData>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n        a.second == b.second\n    }, contentSame = { a, b ->\n        a == b\n    })) {\n    private var selectedIndex: Int = -1\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            ResultSelectionBinding.inflate(\n                LayoutInflater.from(parent.context),\n                parent,\n                false\n            )\n        )\n    }\n\n    override fun onBindContent(holder: ViewHolderState<Any>, item: SelectData, position: Int) {\n        when (val binding = holder.view) {\n            is ResultSelectionBinding -> {\n                binding.root.apply {\n                    if (isLayout(TV)) {\n                        isFocusable = true\n                        isFocusableInTouchMode = true\n                    }\n\n                    isSelected = position == selectedIndex\n                    setText(item.first)\n                    setOnClickListener {\n                        callback.invoke(item.second)\n                    }\n                }\n            }\n        }\n    }\n\n    override fun onViewDetachedFromWindow(holder: ViewHolderState<Any>) {\n        if (holder.itemView.hasFocus()) {\n            holder.itemView.clearFocus()\n        }\n    }\n\n    fun select(newIndex: Int, recyclerView: RecyclerView?) {\n        if (recyclerView == null) return\n        if (newIndex == selectedIndex) return\n        val oldIndex = selectedIndex\n        selectedIndex = newIndex\n\n        notifyItemChanged(selectedIndex)\n        notifyItemChanged(oldIndex)\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/result/SyncViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.result\n\nimport android.util.Log\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.throwAbleToResource\nimport com.lagradost.cloudstream3.syncproviders.AccountManager\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.aniListApi\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.kitsuApi\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.malApi\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.simklApi\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.ui.SyncWatchType\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.SyncUtil\nimport java.util.*\n\n\ndata class CurrentSynced(\n    val name: String,\n    val idPrefix: String,\n    val isSynced: Boolean,\n    val hasAccount: Boolean,\n    val icon: Int?,\n)\n\nclass SyncViewModel : ViewModel() {\n    companion object {\n        const val TAG = \"SYNCVM\"\n    }\n\n    private val repos = AccountManager.syncApis\n\n    private val _metaResponse: MutableLiveData<Resource<SyncAPI.SyncResult>?> =\n        MutableLiveData(null)\n\n    val metadata: LiveData<Resource<SyncAPI.SyncResult>?> = _metaResponse\n\n    private val _userDataResponse: MutableLiveData<Resource<SyncAPI.AbstractSyncStatus>?> =\n        MutableLiveData(null)\n\n    val userData: LiveData<Resource<SyncAPI.AbstractSyncStatus>?> = _userDataResponse\n\n    // prefix, id\n    private val syncs = mutableMapOf<String, String>()\n    //private val _syncIds: MutableLiveData<MutableMap<String, String>> =\n    //    MutableLiveData(mutableMapOf())\n    //val syncIds: LiveData<MutableMap<String, String>> get() = _syncIds\n\n    fun getSyncs(): Map<String, String> {\n        return syncs\n    }\n\n    private val _currentSynced: MutableLiveData<List<CurrentSynced>> =\n        MutableLiveData(getMissing())\n\n    // pair of name idPrefix isSynced\n    val synced: LiveData<List<CurrentSynced>> = _currentSynced\n\n    private fun getMissing(): List<CurrentSynced> {\n        return repos.map {\n            CurrentSynced(\n                it.name,\n                it.idPrefix,\n                syncs.containsKey(it.idPrefix),\n                it.authUser() != null,\n                it.icon,\n            )\n        }\n    }\n\n    fun updateSynced() {\n        Log.i(TAG, \"updateSynced\")\n        _currentSynced.postValue(getMissing())\n    }\n\n    private fun addSync(idPrefix: String, id: String): Boolean {\n        if (syncs[idPrefix] == id) return false\n        Log.i(TAG, \"addSync $idPrefix = $id\")\n\n        syncs[idPrefix] = id\n        //_syncIds.postValue(syncs)\n        return true\n    }\n\n    fun addSyncs(map: Map<String, String>?): Boolean {\n        var isValid = false\n\n        map?.forEach { (prefix, id) ->\n            isValid = addSync(prefix, id) || isValid\n        }\n        return isValid\n    }\n\n    private fun setMalId(id: String?): Boolean {\n        return addSync(malApi.idPrefix, id ?: return false)\n    }\n\n    private fun setAniListId(id: String?): Boolean {\n        return addSync(aniListApi.idPrefix, id ?: return false)\n    }\n\n    var hasAddedFromUrl: HashSet<String> = hashSetOf()\n\n    fun addFromUrl(url: String?) = ioSafe {\n        Log.i(TAG, \"addFromUrl = $url\")\n\n        if (url == null || hasAddedFromUrl.contains(url)) return@ioSafe\n        if (!url.startsWith(\"http\")) return@ioSafe\n\n        SyncUtil.getIdsFromUrl(url)?.let { (malId, aniListId) ->\n            hasAddedFromUrl.add(url)\n\n            setMalId(malId)\n            setAniListId(aniListId)\n            updateSynced()\n            if (malId != null || aniListId != null) {\n                Log.i(TAG, \"addFromUrl->updateMetaAndUser $malId $aniListId\")\n                updateMetaAndUser()\n            }\n        }\n    }\n\n    fun setEpisodesDelta(delta: Int) {\n        Log.i(TAG, \"setEpisodesDelta = $delta\")\n\n        val user = userData.value\n        if (user is Resource.Success) {\n            user.value.watchedEpisodes?.plus(\n                delta\n            )?.let { episode ->\n                setEpisodes(episode)\n            }\n        }\n    }\n\n    fun setEpisodes(episodes: Int) {\n        Log.i(TAG, \"setEpisodes = $episodes\")\n\n        if (episodes < 0) return\n        val meta = metadata.value\n        if (meta is Resource.Success) {\n            meta.value.totalEpisodes?.let { max ->\n                if (episodes > max) {\n                    setEpisodes(max)\n                    return\n                }\n            }\n        }\n\n        val user = userData.value\n        if (user is Resource.Success) {\n            user.value.watchedEpisodes = episodes\n            _userDataResponse.postValue(Resource.Success(user.value))\n        }\n    }\n\n    fun setScore(score: Score?) {\n        Log.i(TAG, \"setScore = $score\")\n        val user = userData.value\n        if (user is Resource.Success) {\n            user.value.score = score\n            _userDataResponse.postValue(Resource.Success(user.value))\n        }\n    }\n\n    fun setStatus(which: Int) {\n        Log.i(TAG, \"setStatus = $which\")\n        if (which < -1 || which > 5) return // validate input\n        val user = userData.value\n        if (user is Resource.Success) {\n            user.value.status = SyncWatchType.fromInternalId(which)\n            _userDataResponse.postValue(Resource.Success(user.value))\n        }\n    }\n\n    fun publishUserData() = ioSafe {\n        Log.i(TAG, \"publishUserData\")\n        val user = userData.value\n        if (user is Resource.Success) {\n            syncs.forEach { (prefix, id) ->\n                repos.firstOrNull { it.idPrefix == prefix }?.updateStatus(id, user.value)\n            }\n        }\n        updateUserData()\n    }\n\n    fun modifyMaxEpisode(episodeNum: Int) {\n        Log.i(TAG, \"modifyMaxEpisode = $episodeNum\")\n        modifyData { status ->\n            status.watchedEpisodes = maxOf(\n                episodeNum,\n                status.watchedEpisodes ?: return@modifyData null\n            )\n            status\n        }\n    }\n\n    /// modifies the current sync data, return null if you don't want to change it\n    private fun modifyData(update: ((SyncAPI.AbstractSyncStatus) -> (SyncAPI.AbstractSyncStatus?))) =\n        ioSafe {\n            syncs.amap { (prefix, id) ->\n                repos.firstOrNull { it.idPrefix == prefix }?.let { repo ->\n                    val result =\n                        update(repo.status(id).getOrNull() ?: return@let null) ?: return@let null\n                    Log.i(TAG, \"modifyData ${repo.name} => $result\")\n                    repo.updateStatus(id, result)\n                }\n            }\n        }\n\n    fun updateUserData() = ioSafe {\n        Log.i(TAG, \"updateUserData\")\n        _userDataResponse.postValue(Resource.Loading())\n\n        val status = syncs.firstNotNullOfOrNull { (prefix, id) ->\n            repos.firstOrNull { it.idPrefix == prefix }\n                ?.status(id)?.getOrNull()\n        }\n\n        if (status == null) {\n            _userDataResponse.postValue(Resource.Failure(false, \"No data\"))\n        } else {\n            _userDataResponse.postValue(Resource.Success(status))\n        }\n    }\n\n    private fun updateMetadata() = ioSafe {\n        Log.i(TAG, \"updateMetadata\")\n\n        _metaResponse.postValue(Resource.Loading())\n        var lastError: Resource<SyncAPI.SyncResult> = Resource.Failure(false, \"No data\")\n        val current = ArrayList(syncs.toList())\n\n        // shitty way to sort anilist first, as it has trailers while mal does not\n        if (syncs.containsKey(aniListApi.idPrefix)) {\n            try { // swap can throw error\n                Collections.swap(\n                    current,\n                    current.indexOfFirst { it.first == aniListApi.idPrefix },\n                    0\n                )\n            } catch (t: Throwable) {\n                logError(t)\n            }\n        }\n\n        current.forEach { (prefix, id) ->\n            repos.firstOrNull { it.idPrefix == prefix }?.let { repo ->\n                Log.i(TAG, \"updateMetadata loading ${repo.idPrefix}\")\n                val result = repo.load(id)\n                val resultValue = result.getOrNull()\n                val resultError = result.exceptionOrNull()\n                if (resultValue != null) {\n                    _metaResponse.postValue(Resource.Success(resultValue))\n                    return@ioSafe\n                } else if (resultError != null) {\n\n                    /*Log.e(\n                        TAG,\n                        \"updateMetadata error $id at ${repo.idPrefix} ${result.errorString}\"\n                    )*/\n                    lastError = throwAbleToResource(resultError)\n                }\n            }\n        }\n        _metaResponse.postValue(lastError)\n        setEpisodesDelta(0)\n    }\n\n    fun syncName(syncName: String): String? {\n        // fix because of bad old data :pensive:\n        val realName = when (syncName) {\n            \"MAL\" -> malApi.idPrefix\n            \"Kitsu\" -> kitsuApi.idPrefix\n            \"Simkl\" -> simklApi.idPrefix\n            \"AniList\" -> aniListApi.idPrefix\n            else -> syncName\n        }\n        return repos.firstOrNull { it.idPrefix == realName }?.idPrefix\n    }\n\n    fun setSync(syncName: String, syncId: String) {\n        syncs.clear()\n        syncs[syncName] = syncId\n    }\n\n    fun clear() {\n        syncs.clear()\n        _metaResponse.postValue(null)\n        _currentSynced.postValue(getMissing())\n        _userDataResponse.postValue(null)\n    }\n\n    fun updateMetaAndUser() {\n        _userDataResponse.postValue(Resource.Loading())\n        _metaResponse.postValue(Resource.Loading())\n\n        Log.i(TAG, \"updateMetaAndUser\")\n        updateMetadata()\n        updateUserData()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt",
    "content": "package com.lagradost.cloudstream3.ui.search\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.widget.FrameLayout\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.databinding.SearchResultGridBinding\nimport com.lagradost.cloudstream3.databinding.SearchResultGridExpandedBinding\nimport com.lagradost.cloudstream3.ui.AutofitRecyclerView\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.newSharedPool\nimport com.lagradost.cloudstream3.utils.UIHelper.isBottomLayout\nimport kotlin.math.roundToInt\n\n/** Click */\nconst val SEARCH_ACTION_LOAD = 0\n\n/** Long press */\nconst val SEARCH_ACTION_SHOW_METADATA = 1\nconst val SEARCH_ACTION_PLAY_FILE = 2\nconst val SEARCH_ACTION_FOCUSED = 4\n\nclass SearchClickCallback(\n    val action: Int,\n    val view: View,\n    val position: Int,\n    val card: SearchResponse\n)\n\nclass SearchAdapter(\n    private val resView: AutofitRecyclerView,\n    private val isHorizontal:Boolean = false,\n    private val clickCallback: (SearchClickCallback) -> Unit,\n) : NoStateAdapter<SearchResponse>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n    if (a.id != null || b.id != null) {\n        a.id == b.id\n    } else {\n        a.name == b.name\n    }\n})) {\n    companion object {\n        val sharedPool =\n            newSharedPool { setMaxRecycledViews(CONTENT, 10) }\n    }\n\n    var hasNext: Boolean = false\n\n    private val coverRatio = if(isHorizontal) 1.8 else 0.68\n\n    private val coverHeight: Int get() = (resView.itemWidth / coverRatio).roundToInt()\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        val inflater = LayoutInflater.from(parent.context)\n\n        val layout =\n            if (parent.context.isBottomLayout()) SearchResultGridExpandedBinding.inflate(\n                inflater,\n                parent,\n                false\n            ) else SearchResultGridBinding.inflate(\n                inflater,\n                parent,\n                false\n            )\n        return ViewHolderState(layout)\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        clearImage(\n            when (val binding = holder.view) {\n                is SearchResultGridExpandedBinding -> binding.imageView\n                is SearchResultGridBinding -> binding.imageView\n                else -> null\n            }\n        )\n    }\n\n    override fun onBindContent(holder: ViewHolderState<Any>, item: SearchResponse, position: Int) {\n        val imageView = when (val binding = holder.view) {\n            is SearchResultGridExpandedBinding -> binding.imageView\n            is SearchResultGridBinding -> binding.imageView\n            else -> null\n        }\n\n        if (imageView != null) {\n            val params = FrameLayout.LayoutParams(\n                ViewGroup.LayoutParams.MATCH_PARENT,\n                coverHeight\n            )\n            if (imageView.layoutParams.width != params.width || imageView.layoutParams.height != params.height) {\n                imageView.layoutParams = params\n            }\n        }\n        SearchResultBuilder.bind(clickCallback, item, position, holder.view.root)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.search\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.content.DialogInterface\nimport android.speech.RecognizerIntent\nimport android.speech.SpeechRecognizer\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.WindowManager\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport android.widget.ImageView\nimport android.widget.ListView\nimport android.widget.TextView\nimport androidx.appcompat.app.AlertDialog\nimport androidx.appcompat.widget.SearchView\nimport androidx.core.view.isVisible\nimport androidx.fragment.app.activityViewModels\nimport androidx.preference.PreferenceManager\nimport androidx.recyclerview.widget.GridLayoutManager\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.activity.result.contract.ActivityResultContracts\nimport com.google.android.material.bottomsheet.BottomSheetBehavior\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.google.android.material.button.MaterialButton\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.AllLanguagesName\nimport com.lagradost.cloudstream3.AnimeSearchResponse\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKeys\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.HomePageList\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.databinding.FragmentSearchBinding\nimport com.lagradost.cloudstream3.databinding.HomeSelectMainpageBinding\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.ui.APIRepository\nimport com.lagradost.cloudstream3.ui.BaseAdapter\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.home.HomeFragment\nimport com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.bindChips\nimport com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.currentSpan\nimport com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.loadHomepageList\nimport com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.updateChips\nimport com.lagradost.cloudstream3.ui.home.HomeViewModel\nimport com.lagradost.cloudstream3.ui.home.ParentItemAdapter\nimport com.lagradost.cloudstream3.ui.result.FOCUS_SELF\nimport com.lagradost.cloudstream3.ui.result.setLinearListLayout\nimport com.lagradost.cloudstream3.ui.setRecycledViewPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.filterProviderByPreferredMedia\nimport com.lagradost.cloudstream3.utils.AppContextUtils.filterSearchResultByFilmQuality\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiProviderLangSettings\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiSettings\nimport com.lagradost.cloudstream3.utils.AppContextUtils.ownHide\nimport com.lagradost.cloudstream3.utils.AppContextUtils.ownShow\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount\nimport com.lagradost.cloudstream3.utils.SubtitleHelper\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.attachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.detachBackPressedCallback\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.getSpanCount\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport java.util.Locale\nimport java.util.concurrent.locks.ReentrantLock\n\nclass SearchFragment : BaseFragment<FragmentSearchBinding>(\n    BaseFragment.BindingCreator.Bind(FragmentSearchBinding::bind)\n) {\n    companion object {\n        fun List<SearchResponse>.filterSearchResponse(): List<SearchResponse> {\n            return this.filter { response ->\n                if (response is AnimeSearchResponse) {\n                    val status = response.dubStatus\n                    (status.isNullOrEmpty()) || (status.any {\n                        APIRepository.dubStatusActive.contains(it)\n                    })\n                } else {\n                    true\n                }\n            }\n        }\n\n        const val SEARCH_QUERY = \"search_query\"\n\n        fun newInstance(query: String): Bundle {\n            return Bundle().apply {\n                if (query.isNotBlank()) putString(SEARCH_QUERY, query)\n            }\n        }\n    }\n\n    private val searchViewModel: SearchViewModel by activityViewModels()\n    private var bottomSheetDialog: BottomSheetDialog? = null\n\n    private val speechRecognizerLauncher =\n        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->\n            if (result.resultCode == Activity.RESULT_OK) {\n                val data: Intent? = result.data\n                val matches = data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)\n                if (!matches.isNullOrEmpty()) {\n                    val recognizedText = matches[0]\n                    binding?.mainSearch?.setQuery(recognizedText, true)\n                }\n            }\n        }\n\n    override fun pickLayout(): Int? =\n        if (isLayout(TV or EMULATOR)) R.layout.fragment_search_tv else R.layout.fragment_search\n\n    override fun onCreateView(\n        inflater: LayoutInflater,\n        container: ViewGroup?,\n        savedInstanceState: Bundle?,\n    ): View? {\n        activity?.window?.setSoftInputMode(\n            WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE\n        )\n        bottomSheetDialog?.ownShow()\n        return super.onCreateView(inflater, container, savedInstanceState)\n    }\n\n    override fun onDestroyView() {\n        hideKeyboard()\n        bottomSheetDialog?.ownHide()\n        activity?.detachBackPressedCallback(\"SearchFragment\")\n        super.onDestroyView()\n    }\n\n    override fun onResume() {\n        super.onResume()\n        afterPluginsLoadedEvent += ::reloadRepos\n    }\n\n    override fun onStop() {\n        super.onStop()\n        afterPluginsLoadedEvent -= ::reloadRepos\n    }\n\n    var selectedSearchTypes = mutableListOf<TvType>()\n    var selectedApis = mutableSetOf<String>()\n\n    /**\n     * Will filter all providers by preferred media and selectedSearchTypes.\n     * If that results in no available providers then only filter\n     * providers by preferred media\n     **/\n    fun search(query: String?) {\n        if (query == null) return\n        // don't resume state from prev search\n        (binding?.searchMasterRecycler?.adapter as? BaseAdapter<*, *>)?.clearState()\n        context?.let { ctx ->\n            val default = enumValues<TvType>().sorted().filter { it != TvType.NSFW }\n                .map { it.ordinal.toString() }.toSet()\n            val preferredTypes = (PreferenceManager.getDefaultSharedPreferences(ctx)\n                .getStringSet(this.getString(R.string.prefer_media_type_key), default)\n                ?.ifEmpty { default } ?: default)\n                .mapNotNull { it.toIntOrNull() ?: return@mapNotNull null }\n\n            val settings = ctx.getApiSettings()\n\n            val notFilteredBySelectedTypes = selectedApis.filter { name ->\n                settings.contains(name)\n            }.map { name ->\n                name to getApiFromNameNull(name)?.supportedTypes\n            }.filter { (_, types) ->\n                types?.any { preferredTypes.contains(it.ordinal) } == true\n            }\n\n            searchViewModel.searchAndCancel(\n                query = query,\n                providersActive = notFilteredBySelectedTypes.filter { (_, types) ->\n                    types?.any { selectedSearchTypes.contains(it) } == true\n                }.ifEmpty { notFilteredBySelectedTypes }.map { it.first }.toSet()\n            )\n        }\n    }\n\n    // Null if defined as a variable\n    // This needs to be run after view created\n\n    private fun reloadRepos(success: Boolean = false) = main {\n        searchViewModel.reloadRepos()\n        context?.filterProviderByPreferredMedia()?.let { validAPIs ->\n            bindChips(\n                binding?.tvtypesChipsScroll?.tvtypesChips,\n                selectedSearchTypes,\n                validAPIs.flatMap { api -> api.supportedTypes }.distinct()\n            ) { list ->\n                if (selectedSearchTypes.toSet() != list.toSet()) {\n                    DataStoreHelper.searchPreferenceTags = list\n                    selectedSearchTypes.clear()\n                    selectedSearchTypes.addAll(list)\n                    search(binding?.mainSearch?.query?.toString())\n                }\n            }\n        }\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padBottom = isLandscape(),\n            padLeft = isLayout(TV or EMULATOR)\n        )\n\n        // Fix grid\n        currentSpan = view.context.getSpanCount()\n        binding?.searchAutofitResults?.spanCount = currentSpan\n        HomeFragment.configEvent.invoke()\n    }\n\n    override fun onBindingCreated(\n        binding: FragmentSearchBinding,\n        savedInstanceState: Bundle?\n    ) {\n        reloadRepos()\n        binding.apply {\n            val adapter =\n                SearchAdapter(\n                    searchAutofitResults,\n                ) { callback ->\n                    SearchHelper.handleSearchClickCallback(callback)\n                }\n\n            searchRoot.findViewById<TextView>(androidx.appcompat.R.id.search_src_text)?.tag =\n                \"tv_no_focus_tag\"\n            searchAutofitResults.setRecycledViewPool(SearchAdapter.sharedPool)\n            searchAutofitResults.adapter = adapter\n            searchLoadingBar.alpha = 0f\n        }\n\n        binding.voiceSearch.setOnClickListener { searchView ->\n            searchView?.context?.let { ctx ->\n                try {\n                    if (!SpeechRecognizer.isRecognitionAvailable(ctx)) {\n                        showToast(R.string.speech_recognition_unavailable)\n                    } else {\n                        val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {\n                            putExtra(\n                                RecognizerIntent.EXTRA_LANGUAGE_MODEL,\n                                RecognizerIntent.LANGUAGE_MODEL_FREE_FORM\n                            )\n                            putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())\n                            putExtra(\n                                RecognizerIntent.EXTRA_PROMPT,\n                                ctx.getString(R.string.begin_speaking)\n                            )\n                        }\n                        speechRecognizerLauncher.launch(intent)\n                    }\n                } catch (_: Throwable) {\n                    // launch may throw\n                    showToast(R.string.speech_recognition_unavailable)\n                }\n            }\n        }\n\n        val searchExitIcon =\n            binding.mainSearch.findViewById<ImageView>(androidx.appcompat.R.id.search_close_btn)\n\n        selectedApis = DataStoreHelper.searchPreferenceProviders.toMutableSet()\n\n        binding.searchFilter.setOnClickListener { searchView ->\n            searchView?.context?.let { ctx ->\n                val validAPIs = ctx.filterProviderByPreferredMedia(hasHomePageIsRequired = false)\n                var currentValidApis = listOf<MainAPI>()\n                val currentSelectedApis = if (selectedApis.isEmpty()) validAPIs.map { it.name }\n                    .toMutableSet() else selectedApis\n\n                val builder =\n                    BottomSheetDialog(ctx)\n\n                builder.behavior.state = BottomSheetBehavior.STATE_EXPANDED\n\n                val selectMainpageBinding: HomeSelectMainpageBinding =\n                    HomeSelectMainpageBinding.inflate(\n                        builder.layoutInflater,\n                        null,\n                        false\n                    )\n                builder.setContentView(selectMainpageBinding.root)\n                builder.show()\n                builder.let { dialog ->\n                    val previousSelectedApis = selectedApis.toSet()\n                    val previousSelectedSearchTypes = selectedSearchTypes.toSet()\n\n                    val isMultiLang = ctx.getApiProviderLangSettings().let { set ->\n                        set.size > 1 || set.contains(AllLanguagesName)\n                    }\n\n                    val cancelBtt = dialog.findViewById<MaterialButton>(R.id.cancel_btt)\n                    val applyBtt = dialog.findViewById<MaterialButton>(R.id.apply_btt)\n\n                    val listView = dialog.findViewById<ListView>(R.id.listview1)\n                    val arrayAdapter = ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)\n                    listView?.adapter = arrayAdapter\n                    listView?.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE\n\n                    listView?.setOnItemClickListener { _, _, i, _ ->\n                        if (currentValidApis.isNotEmpty()) {\n                            val api = currentValidApis[i].name\n                            if (currentSelectedApis.contains(api)) {\n                                listView.setItemChecked(i, false)\n                                currentSelectedApis -= api\n                            } else {\n                                listView.setItemChecked(i, true)\n                                currentSelectedApis += api\n                            }\n                        }\n                    }\n\n                    fun updateList(types: List<TvType>) {\n                        DataStoreHelper.searchPreferenceTags = types\n\n                        arrayAdapter.clear()\n                        currentValidApis = validAPIs.filter { api ->\n                            api.supportedTypes.any {\n                                types.contains(it)\n                            }\n                        }.sortedBy { it.name.lowercase() }\n\n                        val names = currentValidApis.map {\n                            if (isMultiLang) \"${\n                                SubtitleHelper.getFlagFromIso(\n                                    it.lang\n                                )?.plus(\" \") ?: \"\"\n                            }${it.name}\" else it.name\n                        }\n                        for ((index, api) in currentValidApis.map { it.name }.withIndex()) {\n                            listView?.setItemChecked(index, currentSelectedApis.contains(api))\n                        }\n\n                        //arrayAdapter.notifyDataSetChanged()\n                        arrayAdapter.addAll(names)\n                        arrayAdapter.notifyDataSetChanged()\n                    }\n\n                    bindChips(\n                        selectMainpageBinding.tvtypesChipsScroll.tvtypesChips,\n                        selectedSearchTypes,\n                        validAPIs.flatMap { api -> api.supportedTypes }.distinct()\n                    ) { list ->\n                        updateList(list)\n\n                        // refresh selected chips in main chips\n                        if (selectedSearchTypes.toSet() != list.toSet()) {\n                            selectedSearchTypes.clear()\n                            selectedSearchTypes.addAll(list)\n                            updateChips(\n                                binding.tvtypesChipsScroll.tvtypesChips,\n                                selectedSearchTypes\n                            )\n\n                        }\n                    }\n\n\n                    cancelBtt?.setOnClickListener {\n                        dialog.dismissSafe()\n                    }\n\n                    cancelBtt?.setOnClickListener {\n                        dialog.dismissSafe()\n                    }\n\n                    applyBtt?.setOnClickListener {\n                        //if (currentApiName != selectedApiName) {\n                        //    currentApiName?.let(callback)\n                        //}\n                        dialog.dismissSafe()\n                    }\n\n                    dialog.setOnDismissListener {\n                        DataStoreHelper.searchPreferenceProviders = currentSelectedApis.toList()\n                        selectedApis = currentSelectedApis\n\n                        // run search when dialog is close\n                        if (previousSelectedApis != selectedApis.toSet() || previousSelectedSearchTypes != selectedSearchTypes.toSet()) {\n                            search(binding.mainSearch.query.toString())\n                        }\n                    }\n                    updateList(selectedSearchTypes.toList())\n                }\n            }\n        }\n\n        val settingsManager = context?.let { PreferenceManager.getDefaultSharedPreferences(it) }\n        val isAdvancedSearch = settingsManager?.getBoolean(\"advanced_search\", true) ?: true\n        val isSearchSuggestionsEnabled = settingsManager?.getBoolean(\"search_suggestions_enabled\", true) ?: true\n\n        selectedSearchTypes = DataStoreHelper.searchPreferenceTags.toMutableList()\n\n        if (!isLayout(PHONE)) {\n            binding.searchFilter.isFocusable = true\n            binding.searchFilter.isFocusableInTouchMode = true\n        }\n        \n        // Hide suggestions when search view loses focus (phone only)\n        if (isLayout(PHONE)) {\n            binding.mainSearch.setOnQueryTextFocusChangeListener { _, hasFocus ->\n                if (!hasFocus) {\n                    searchViewModel.clearSuggestions()\n                }\n            }\n        }\n\n\n        binding.mainSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener {\n            override fun onQueryTextSubmit(query: String): Boolean {\n                search(query)\n                searchViewModel.clearSuggestions()\n\n                binding.mainSearch.let {\n                    hideKeyboard(it)\n                }\n\n                return true\n            }\n\n            override fun onQueryTextChange(newText: String): Boolean {\n                //searchViewModel.quickSearch(newText)\n                val showHistory = newText.isBlank()\n                if (showHistory) {\n                    searchViewModel.clearSearch()\n                    searchViewModel.updateHistory()\n                    searchViewModel.clearSuggestions()\n                } else {\n                    // Fetch suggestions when user is typing (if enabled)\n                    if (isSearchSuggestionsEnabled) {\n                        searchViewModel.fetchSuggestions(newText)\n                    }\n                }\n                binding.apply {\n                    searchHistoryRecycler.isVisible = showHistory\n                    searchMasterRecycler.isVisible = !showHistory && isAdvancedSearch\n                    searchAutofitResults.isVisible = !showHistory && !isAdvancedSearch\n                    // Hide suggestions when showing history or showing search results\n                    searchSuggestionsRecycler.isVisible = !showHistory && isSearchSuggestionsEnabled\n                }\n\n                return true\n            }\n        })\n\n        observe(searchViewModel.searchResponse) {\n            when (it) {\n                is Resource.Success -> {\n                    it.value.let { data ->\n                        val list = data.list\n                        if (list.isNotEmpty()) {\n                            (binding.searchAutofitResults.adapter as? SearchAdapter)?.submitList(\n                                list\n                            )\n                        }\n                    }\n                    searchExitIcon?.alpha = 1f\n                    binding.searchLoadingBar.alpha = 0f\n                }\n\n                is Resource.Failure -> {\n                    // Toast.makeText(activity, \"Server error\", Toast.LENGTH_LONG).show()\n                    searchExitIcon?.alpha = 1f\n                    binding.searchLoadingBar.alpha = 0f\n                }\n\n                is Resource.Loading -> {\n                    searchExitIcon?.alpha = 0f\n                    binding.searchLoadingBar.alpha = 1f\n                }\n            }\n        }\n\n        val listLock = ReentrantLock()\n        observe(searchViewModel.currentSearch) { list ->\n            try {\n                // https://stackoverflow.com/questions/6866238/concurrent-modification-exception-adding-to-an-arraylist\n                listLock.lock()\n\n                val pinnedOrder = DataStoreHelper.pinnedProviders.reversedArray()\n\n                val sortedList = list.toList().sortedWith(compareBy { (providerName, _) ->\n                    val index = pinnedOrder.indexOf(providerName)\n                    if (index == -1) Int.MAX_VALUE else index\n                })\n\n                (binding.searchMasterRecycler.adapter as? ParentItemAdapter)?.apply {\n                    val newItems = sortedList.map { (providerName, providerData) ->\n                        val dataList = providerData.list\n                        val dataListFiltered =\n                            context?.filterSearchResultByFilmQuality(dataList) ?: dataList\n\n                        val homePageList = HomePageList(\n                            providerName,\n                            dataListFiltered\n                        )\n\n                        HomeViewModel.ExpandableHomepageList(\n                            homePageList,\n                            providerData.currentPage,\n                            providerData.hasNext\n                        )\n                    }\n\n                    submitList(newItems)\n                    //notifyDataSetChanged()\n                }\n            } catch (e: Exception) {\n                logError(e)\n            } finally {\n                listLock.unlock()\n            }\n        }\n\n\n        /*main_search.setOnQueryTextFocusChangeListener { _, b ->\n            if (b) {\n                // https://stackoverflow.com/questions/12022715/unable-to-show-keyboard-automatically-in-the-searchview\n                showInputMethod(view.findFocus())\n            }\n        }*/\n        //main_search.onActionViewExpanded()*/\n\n        val masterAdapter =\n            ParentItemAdapter(id = \"masterAdapter\".hashCode(), { callback ->\n                SearchHelper.handleSearchClickCallback(callback)\n            }, { item ->\n                bottomSheetDialog = activity?.loadHomepageList(item, dismissCallback = {\n                    bottomSheetDialog = null\n                }, expandCallback = { name -> searchViewModel.expandAndReturn(name) })\n            }, expandCallback = { name ->\n                ioSafe {\n                    searchViewModel.expandAndReturn(name)\n                }\n            })\n\n        val historyAdapter = SearchHistoryAdaptor { click ->\n            val searchItem = click.item\n            when (click.clickAction) {\n                SEARCH_HISTORY_OPEN -> {\n                    if (searchItem == null) return@SearchHistoryAdaptor\n                    searchViewModel.clearSearch()\n                    if (searchItem.type.isNotEmpty())\n                        updateChips(\n                            binding.tvtypesChipsScroll.tvtypesChips,\n                            searchItem.type.toMutableList()\n                        )\n                    binding.mainSearch.setQuery(searchItem.searchText, true)\n                }\n\n                SEARCH_HISTORY_REMOVE -> {\n                    if (searchItem == null) return@SearchHistoryAdaptor\n                    removeKey(\"$currentAccount/$SEARCH_HISTORY_KEY\", searchItem.key)\n                    searchViewModel.updateHistory()\n                }\n                \n                SEARCH_HISTORY_CLEAR -> {\n                    // Show confirmation dialog (from footer button)\n                    activity?.let { ctx ->\n                        val builder: AlertDialog.Builder = AlertDialog.Builder(ctx)\n                        val dialogClickListener =\n                            DialogInterface.OnClickListener { _, which ->\n                                when (which) {\n                                    DialogInterface.BUTTON_POSITIVE -> {\n                                        removeKeys(\"$currentAccount/$SEARCH_HISTORY_KEY\")\n                                        searchViewModel.updateHistory()\n                                    }\n\n                                    DialogInterface.BUTTON_NEGATIVE -> {\n                                    }\n                                }\n                            }\n\n                        try {\n                            builder.setTitle(R.string.clear_history).setMessage(\n                                ctx.getString(R.string.delete_message).format(\n                                    ctx.getString(R.string.history)\n                                )\n                            )\n                                .setPositiveButton(R.string.sort_clear, dialogClickListener)\n                                .setNegativeButton(R.string.cancel, dialogClickListener)\n                                .show().setDefaultFocus()\n                        } catch (e: Exception) {\n                            logError(e)\n                        }\n                    }\n                }\n\n                else -> {\n                    // wth are you doing???\n                }\n            }\n        }\n\n        val suggestionAdapter = SearchSuggestionAdapter { callback ->\n            when (callback.clickAction) {\n                SEARCH_SUGGESTION_CLICK -> {\n                    // Search directly\n                    binding.mainSearch.setQuery(callback.suggestion, true)\n                    searchViewModel.clearSuggestions()\n                }\n                SEARCH_SUGGESTION_FILL -> {\n                    // Fill the search box without searching\n                    binding.mainSearch.setQuery(callback.suggestion, false)\n                }\n                SEARCH_SUGGESTION_CLEAR -> {\n                    // Clear suggestions (from footer button)\n                    searchViewModel.clearSuggestions()\n                }\n            }\n        }\n\n        binding.apply {\n            searchHistoryRecycler.adapter = historyAdapter\n            searchHistoryRecycler.setLinearListLayout(isHorizontal = false, nextRight = FOCUS_SELF)\n            //searchHistoryRecycler.layoutManager = GridLayoutManager(context, 1)\n\n            // Setup suggestions RecyclerView\n            searchSuggestionsRecycler.adapter = suggestionAdapter\n            searchSuggestionsRecycler.layoutManager = LinearLayoutManager(context)\n\n            searchMasterRecycler.setRecycledViewPool(ParentItemAdapter.sharedPool)\n            searchMasterRecycler.adapter = masterAdapter\n            //searchMasterRecycler.setLinearListLayout(isHorizontal = false, nextRight = FOCUS_SELF)\n\n            searchMasterRecycler.layoutManager = GridLayoutManager(context, 1)\n\n            // Automatically search the specified query, this allows the app search to launch from intent\n            var sq =\n                arguments?.getString(SEARCH_QUERY) ?: savedInstanceState?.getString(SEARCH_QUERY)\n            if (sq.isNullOrBlank()) {\n                sq = MainActivity.nextSearchQuery\n            }\n\n            sq?.let { query ->\n                if (query.isBlank()) return@let\n                mainSearch.setQuery(query, true)\n                // Clear the query as to not make it request the same query every time the page is opened\n                arguments?.remove(SEARCH_QUERY)\n                savedInstanceState?.remove(SEARCH_QUERY)\n                MainActivity.nextSearchQuery = null\n            }\n        }\n\n        observe(searchViewModel.currentHistory) { list ->\n            (binding.searchHistoryRecycler.adapter as? SearchHistoryAdaptor?)?.submitList(list)\n             // Scroll to top to show newest items (list is sorted by newest first)\n            if (list.isNotEmpty()) {\n                binding.searchHistoryRecycler.scrollToPosition(0)\n            }\n        }\n\n        // Observe search suggestions\n        observe(searchViewModel.searchSuggestions) { suggestions ->\n            val hasSuggestions = suggestions.isNotEmpty()\n            binding.searchSuggestionsRecycler.isVisible = hasSuggestions\n            (binding.searchSuggestionsRecycler.adapter as? SearchSuggestionAdapter?)?.submitList(suggestions)\n            \n            // On non-phone layouts, redirect focus and handle back button\n            if (!isLayout(PHONE)) {\n                if (hasSuggestions) {\n                    binding.tvtypesChipsScroll.tvtypesChips.root.nextFocusDownId = R.id.search_suggestions_recycler\n                    // Attach back button callback to clear suggestions\n                    activity?.attachBackPressedCallback(\"SearchFragment\") {\n                        searchViewModel.clearSuggestions()\n                    }\n                } else {\n                    // Reset to default focus target (history)\n                    binding.tvtypesChipsScroll.tvtypesChips.root.nextFocusDownId = R.id.search_history_recycler\n                    // Detach back button callback when no suggestions\n                    activity?.detachBackPressedCallback(\"SearchFragment\")\n                }\n            }\n        }\n\n        searchViewModel.updateHistory()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHelper.kt",
    "content": "package com.lagradost.cloudstream3.ui.search\n\nimport android.widget.Toast\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_PLAY_FILE\nimport com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick\nimport com.lagradost.cloudstream3.ui.download.DownloadClickEvent\nimport com.lagradost.cloudstream3.ui.result.START_ACTION_LOAD_EP\nimport com.lagradost.cloudstream3.utils.AppContextUtils.loadSearchResult\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\n\nobject SearchHelper {\n    fun handleSearchClickCallback(callback: SearchClickCallback) {\n        val card = callback.card\n        when (callback.action) {\n            SEARCH_ACTION_LOAD -> {\n                loadSearchResult(card)\n            }\n\n            SEARCH_ACTION_PLAY_FILE -> {\n                if (card is DataStoreHelper.ResumeWatchingResult) {\n                    val id = card.id\n                    if (id == null) {\n                        showToast(R.string.error_invalid_id, Toast.LENGTH_SHORT)\n                    } else {\n                        if (card.isFromDownload) {\n                            handleDownloadClick(\n                                DownloadClickEvent(\n                                    DOWNLOAD_ACTION_PLAY_FILE,\n                                    DownloadObjects.DownloadEpisodeCached(\n                                        name = card.name,\n                                        poster = card.posterUrl,\n                                        episode = card.episode ?: 0,\n                                        season = card.season,\n                                        id = id,\n                                        parentId = card.parentId ?: return,\n                                        score = null,\n                                        description = null,\n                                        cacheTime = System.currentTimeMillis(),\n                                    )\n                                )\n                            )\n                        } else {\n                            loadSearchResult(card, START_ACTION_LOAD_EP, id)\n                        }\n                    }\n                } else {\n                    handleSearchClickCallback(\n                        SearchClickCallback(SEARCH_ACTION_LOAD, callback.view, -1, callback.card)\n                    )\n                }\n            }\n\n            SEARCH_ACTION_SHOW_METADATA -> {\n                (activity as? MainActivity?)?.apply {\n                    loadPopup(callback.card)\n                } ?: kotlin.run {\n                    showToast(callback.card.name, Toast.LENGTH_SHORT)\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHistoryAdaptor.kt",
    "content": "package com.lagradost.cloudstream3.ui.search\n\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.core.view.isGone\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.databinding.SearchHistoryFooterBinding\nimport com.lagradost.cloudstream3.databinding.SearchHistoryItemBinding\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\n\ndata class SearchHistoryItem(\n    @JsonProperty(\"searchedAt\") val searchedAt: Long,\n    @JsonProperty(\"searchText\") val searchText: String,\n    @JsonProperty(\"type\") val type: List<TvType>,\n    @JsonProperty(\"key\") val key: String,\n)\n\ndata class SearchHistoryCallback(\n    val item: SearchHistoryItem?,\n    val clickAction: Int,\n)\n\nconst val SEARCH_HISTORY_OPEN = 0\nconst val SEARCH_HISTORY_REMOVE = 1\nconst val SEARCH_HISTORY_CLEAR = 2\n\nclass SearchHistoryAdaptor(\n    private val clickCallback: (SearchHistoryCallback) -> Unit,\n) : NoStateAdapter<SearchHistoryItem>(diffCallback = BaseDiffCallback(itemSame = { a,b ->\n    a.searchedAt == b.searchedAt && a.searchText == b.searchText\n})) {\n    \n    // Add footer for all layouts\n    override val footers = 1\n    \n    override fun submitList(list: Collection<SearchHistoryItem>?, commitCallback: Runnable?) {\n        super.submitList(list, commitCallback)\n        // Notify footer to rebind when list changes to update visibility\n        if (footers > 0) {\n            notifyItemChanged(itemCount - 1)\n        }\n    }\n    \n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            SearchHistoryItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),\n        )\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Any>,\n        item: SearchHistoryItem,\n        position: Int\n    ) {\n        val binding = holder.view as? SearchHistoryItemBinding ?: return\n        binding.apply {\n            homeHistoryTitle.text = item.searchText\n\n            homeHistoryRemove.setOnClickListener {\n                clickCallback.invoke(SearchHistoryCallback(item, SEARCH_HISTORY_REMOVE))\n            }\n            homeHistoryTab.setOnClickListener {\n                clickCallback.invoke(SearchHistoryCallback(item, SEARCH_HISTORY_OPEN))\n            }\n        }\n    }\n    \n    override fun onCreateFooter(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            SearchHistoryFooterBinding.inflate(LayoutInflater.from(parent.context), parent, false)\n        )\n    }\n    \n    override fun onBindFooter(holder: ViewHolderState<Any>) {\n        val binding = holder.view as? SearchHistoryFooterBinding ?: return\n        // Hide footer when list is empty\n        binding.searchClearCallHistory.apply {\n            isGone = immutableCurrentList.isEmpty()\n            if (isLayout(TV or EMULATOR)) {\n                isFocusable = true\n                isFocusableInTouchMode = true\n            }\n            setOnClickListener {\n                clickCallback.invoke(SearchHistoryCallback(null, SEARCH_HISTORY_CLEAR))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchResultBuilder.kt",
    "content": "package com.lagradost.cloudstream3.ui.search\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.content.res.ColorStateList\nimport android.view.View\nimport android.widget.ImageView\nimport android.widget.ProgressBar\nimport android.widget.TextView\nimport androidx.cardview.widget.CardView\nimport androidx.core.view.isVisible\nimport androidx.palette.graphics.Palette\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.AnimeSearchResponse\nimport com.lagradost.cloudstream3.DubStatus\nimport com.lagradost.cloudstream3.LiveSearchResponse\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchQuality\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.isMovieType\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getShortSeasonText\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.SubtitleHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.getImageFromDrawable\n\nobject SearchResultBuilder {\n    private val showCache: MutableMap<String, Boolean> = mutableMapOf()\n\n    fun updateCache(context: Context?) {\n        if (context == null) return\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)\n\n        for (k in context.resources.getStringArray(R.array.poster_ui_options_values)) {\n            showCache[k] = settingsManager.getBoolean(k, showCache[k] ?: true)\n        }\n    }\n\n    @SuppressLint(\"StringFormatInvalid\")\n    fun bind(\n        clickCallback: (SearchClickCallback) -> Unit,\n        card: SearchResponse,\n        position: Int,\n        itemView: View,\n        nextFocusUp: Int? = null,\n        nextFocusDown: Int? = null,\n        colorCallback: ((Palette) -> Unit)? = null\n    ) {\n        val cardView: ImageView = itemView.findViewById(R.id.imageView)\n        val cardText: TextView? = itemView.findViewById(R.id.imageText)\n\n        val textIsDub: TextView? = itemView.findViewById(R.id.text_is_dub)\n        val textIsSub: TextView? = itemView.findViewById(R.id.text_is_sub)\n        val textFlag: TextView? = itemView.findViewById(R.id.text_flag)\n        val rating: TextView? = itemView.findViewById(R.id.text_rating)\n\n        val textQuality: TextView? = itemView.findViewById(R.id.text_quality)\n        val shadow: View? = itemView.findViewById(R.id.title_shadow)\n\n        val bg: CardView = itemView.findViewById(R.id.background_card)\n\n        val bar: ProgressBar? = itemView.findViewById(R.id.watchProgress)\n        val playImg: ImageView? = itemView.findViewById(R.id.search_item_download_play)\n        val episodeText: TextView? = itemView.findViewById(R.id.episode_text)\n\n        // Do logic\n\n        bar?.isVisible = false\n        playImg?.isVisible = false\n        textIsDub?.isVisible = false\n        textIsSub?.isVisible = false\n        textFlag?.isVisible = false\n        rating?.isVisible = false\n        episodeText?.isVisible = false\n\n        val showSub = showCache[textIsDub?.context?.getString(R.string.show_sub_key)] ?: false\n        val showDub = showCache[textIsDub?.context?.getString(R.string.show_dub_key)] ?: false\n        val showTitle = showCache[cardText?.context?.getString(R.string.show_title_key)] ?: false\n        val showEpisodeText = showCache[cardText?.context?.getString(R.string.show_episode_text_key)] ?: false\n        val showHd = showCache[textQuality?.context?.getString(R.string.show_hd_key)] ?: false\n        val showRatingView =\n            showCache[textQuality?.context?.getString(R.string.show_rating_key)] ?: false\n        if (card is SyncAPI.LibraryItem) {\n            val ratingText = card.personalRating?.toStringNull(0.1, 10, 1)\n            val showRating = !ratingText.isNullOrBlank()\n            rating?.isVisible = showRating\n            if (showRating) {\n                rating?.text = ratingText\n            }\n        } else if (showRatingView) {\n            val ratingText = card.score?.toStringNull(0.1, 10, 1)\n            val showRating = !ratingText.isNullOrBlank()\n            rating?.isVisible = showRating\n            if (showRating) {\n                rating?.text = ratingText\n            }\n        }\n\n        shadow?.isVisible = showTitle\n\n        when (card.quality) {\n            SearchQuality.BlueRay -> R.string.quality_blueray\n            SearchQuality.Cam -> R.string.quality_cam\n            SearchQuality.CamRip -> R.string.quality_cam_rip\n            SearchQuality.DVD -> R.string.quality_dvd\n            SearchQuality.HD -> R.string.quality_hd\n            SearchQuality.HQ -> R.string.quality_hq\n            SearchQuality.HdCam -> R.string.quality_cam_hd\n            SearchQuality.Telecine -> R.string.quality_tc\n            SearchQuality.Telesync -> R.string.quality_ts\n            SearchQuality.WorkPrint -> R.string.quality_workprint\n            SearchQuality.SD -> R.string.quality_sd\n            SearchQuality.FourK -> R.string.quality_4k\n            SearchQuality.UHD -> R.string.quality_uhd\n            SearchQuality.SDR -> R.string.quality_sdr\n            SearchQuality.HDR -> R.string.quality_hdr\n            SearchQuality.WebRip -> R.string.quality_webrip\n            null -> null\n        }?.let { textRes ->\n            textQuality?.setText(textRes)\n            textQuality?.isVisible = showHd\n        } ?: run {\n            textQuality?.isVisible = false\n        }\n\n        cardText?.text = card.name\n        cardText?.isVisible = showTitle\n        cardView.isVisible = true\n        if (!card.posterUrl.isNullOrEmpty()) {\n            cardView.loadImage(card.posterUrl, card.posterHeaders) {\n                error { getImageFromDrawable(itemView.context, R.drawable.default_cover) }\n            }\n        } else cardView.loadImage(R.drawable.default_cover)\n\n        fun click(view: View?) {\n            clickCallback.invoke(\n                SearchClickCallback(\n                    if (card is DataStoreHelper.ResumeWatchingResult) SEARCH_ACTION_PLAY_FILE else SEARCH_ACTION_LOAD,\n                    view ?: return,\n                    position,\n                    card\n                )\n            )\n        }\n\n        fun longClick(view: View?) {\n            clickCallback.invoke(\n                SearchClickCallback(\n                    SEARCH_ACTION_SHOW_METADATA,\n                    view ?: return,\n                    position,\n                    card\n                )\n            )\n        }\n\n        fun focus(view: View?, focus: Boolean) {\n            if (focus) {\n                clickCallback.invoke(\n                    SearchClickCallback(\n                        SEARCH_ACTION_FOCUSED,\n                        view ?: return,\n                        position,\n                        card\n                    )\n                )\n            }\n        }\n\n        bg.isFocusable = false\n        bg.isFocusableInTouchMode = false\n        if (!isLayout(TV)) {\n            bg.setOnClickListener {\n                click(it)\n            }\n            bg.setOnLongClickListener {\n                longClick(it)\n                return@setOnLongClickListener true\n            }\n        }\n        //\n        //\n        //\n\n        itemView.setOnClickListener {\n            click(it)\n        }\n        if (nextFocusUp != null) {\n            itemView.nextFocusUpId = nextFocusUp\n        }\n\n        if (nextFocusDown != null) {\n            itemView.nextFocusDownId = nextFocusDown\n        }\n\n        /*when (nextFocusBehavior) {\n            true -> itemView.nextFocusLeftId = bg.id\n            false -> itemView.nextFocusRightId = bg.id\n            null -> {\n                bg.nextFocusRightId = -1\n                bg.nextFocusLeftId = -1\n            }\n        }*/\n\n        /*if (nextFocusUp != null) {\n            bg.nextFocusUpId = nextFocusUp\n        }\n\n        if (nextFocusDown != null) {\n            bg.nextFocusDownId = nextFocusDown\n        }\n\n        */\n\n        if (isLayout(TV)) {\n            // bg.isFocusable = true\n            // bg.isFocusableInTouchMode = true\n            // bg.touchscreenBlocksFocus = false\n            itemView.isFocusableInTouchMode = true\n            itemView.isFocusable = true\n        }\n\n        /**/\n\n        itemView.setOnLongClickListener {\n            longClick(it)\n            return@setOnLongClickListener true\n        }\n\n        /*bg.setOnFocusChangeListener { view, b ->\n            focus(view, b)\n        }*/\n\n        itemView.setOnFocusChangeListener { view, b ->\n            focus(view, b)\n        }\n\n        when (card) {\n            is LiveSearchResponse -> {\n                SubtitleHelper.getFlagFromIso(card.lang)?.let { flagEmoji ->\n                    textFlag?.apply {\n                        isVisible = true\n                        text = flagEmoji\n                    }\n                }\n            }\n\n            is DataStoreHelper.ResumeWatchingResult -> {\n                val pos = card.watchPos?.fixVisual()\n                if (pos != null) {\n                    bar?.max = (pos.duration / 1000).toInt()\n                    bar?.progress = (pos.position / 1000).toInt()\n                    bar?.visibility = View.VISIBLE\n                }\n                playImg?.visibility = View.VISIBLE\n                if (card.type?.isMovieType() == false && showEpisodeText) {\n                    episodeText?.context?.getShortSeasonText(card.episode, card.season)?.let {text->\n                        episodeText.text = text\n                        episodeText.isVisible = true\n                    }\n                }\n            }\n\n            is AnimeSearchResponse -> {\n                val dubStatus = card.dubStatus\n                if (!dubStatus.isNullOrEmpty()) {\n                    if (dubStatus.contains(DubStatus.Dubbed)) {\n                        textIsDub?.isVisible = showDub\n                    }\n                    if (dubStatus.contains(DubStatus.Subbed)) {\n                        textIsSub?.isVisible = showSub\n                    }\n                }\n\n                val dubEpisodes = card.episodes[DubStatus.Dubbed]\n                val subEpisodes = card.episodes[DubStatus.Subbed]\n\n                textIsDub?.apply {\n                    val dubText = context.getString(R.string.app_dubbed_text)\n                    text = if (dubEpisodes != null && dubEpisodes > 0) {\n                        context.getString(R.string.app_dub_sub_episode_text_format)\n                            .format(dubText, dubEpisodes)\n                    } else {\n                        dubText\n                    }\n                }\n\n                textIsSub?.apply {\n                    val subText = context.getString(R.string.app_subbed_text)\n                    text = if (subEpisodes != null && subEpisodes > 0) {\n                        context.getString(R.string.app_dub_sub_episode_text_format)\n                            .format(subText, subEpisodes)\n                    } else {\n                        subText\n                    }\n                }\n            }\n        }\n\n        // This is the logic for making the rounded corners more round on the top and bottom element\n        // a bit dirty to do memory allocation, but it makes it more extensible and is easier to reason about\n        // then a large if statement\n\n        // Requires that the ordering here is the same as in the xml\n        val boxes = arrayListOf<TextView>()\n        for (view in arrayOf(textIsDub, textIsSub, rating)) {\n            if (view?.isVisible == true) {\n                boxes.add(view)\n            }\n        }\n        if (boxes.size == 1) {\n            boxes[0].setBackgroundResource(R.drawable.bg_color_both)\n        } else if (boxes.size > 1) {\n            boxes[0].setBackgroundResource(R.drawable.bg_color_top)\n            for (i in 1 until boxes.size) {\n                boxes[i].setBackgroundResource(R.drawable.bg_color_center)\n            }\n            boxes[boxes.size - 1].setBackgroundResource(R.drawable.bg_color_bottom)\n        }\n        textIsDub?.apply {\n            backgroundTintList = ColorStateList.valueOf(context.colorFromAttribute(R.attr.textColor))\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchSuggestionAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.search\n\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.core.view.isGone\nimport com.lagradost.cloudstream3.databinding.SearchSuggestionFooterBinding\nimport com.lagradost.cloudstream3.databinding.SearchSuggestionItemBinding\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\n\nconst val SEARCH_SUGGESTION_CLICK = 0\nconst val SEARCH_SUGGESTION_FILL = 1\nconst val SEARCH_SUGGESTION_CLEAR = 2\n\ndata class SearchSuggestionCallback(\n    val suggestion: String,\n    val clickAction: Int,\n)\n\nclass SearchSuggestionAdapter(\n    private val clickCallback: (SearchSuggestionCallback) -> Unit,\n) : NoStateAdapter<String>(diffCallback = BaseDiffCallback(itemSame = { a, b -> a == b })) {\n    \n    // Add footer for all layouts\n    override val footers = 1\n    \n    override fun submitList(list: Collection<String>?, commitCallback: Runnable?) {\n        super.submitList(list, commitCallback)\n        // Notify footer to rebind when list changes to update visibility\n        if (footers > 0) {\n            notifyItemChanged(itemCount - 1)\n        }\n    }\n    \n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            SearchSuggestionItemBinding.inflate(LayoutInflater.from(parent.context), parent, false),\n        )\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Any>,\n        item: String,\n        position: Int\n    ) {\n        val binding = holder.view as? SearchSuggestionItemBinding ?: return\n        binding.apply {\n            suggestionText.text = item\n            \n            // Click on the whole item to search\n            suggestionItem.setOnClickListener {\n                clickCallback.invoke(SearchSuggestionCallback(item, SEARCH_SUGGESTION_CLICK))\n            }\n            \n            // Click on the arrow to fill the search box without searching\n            suggestionFill.setOnClickListener {\n                clickCallback.invoke(SearchSuggestionCallback(item, SEARCH_SUGGESTION_FILL))\n            }\n        }\n    }\n    \n    override fun onCreateFooter(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            SearchSuggestionFooterBinding.inflate(LayoutInflater.from(parent.context), parent, false)\n        )\n    }\n    \n    override fun onBindFooter(holder: ViewHolderState<Any>) {\n        val binding = holder.view as? SearchSuggestionFooterBinding ?: return\n        binding.clearSuggestionsButton.apply {\n            isGone = immutableCurrentList.isEmpty()\n            if (isLayout(TV or EMULATOR)) {\n                isFocusable = true\n                isFocusableInTouchMode = true\n            }\n            setOnClickListener {\n                clickCallback.invoke(SearchSuggestionCallback(\"\", SEARCH_SUGGESTION_CLEAR))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchSuggestionApi.kt",
    "content": "package com.lagradost.cloudstream3.ui.search\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.nicehttp.NiceResponse\n\n/**\n * API for fetching search suggestions from external sources.\n * Uses TheMovieDB API to provide movie/show/anime related suggestions.\n */\nobject SearchSuggestionApi {\n    private const val TMDB_API_URL = \"https://api.themoviedb.org/3/search/multi\"\n    private const val TMDB_API_KEY = \"e6333b32409e02a4a6eba6fb7ff866bb\"\n    \n    data class TmdbSearchResult(\n        @JsonProperty(\"results\") val results: List<TmdbSearchItem>?\n    )\n    \n    data class TmdbSearchItem(\n        @JsonProperty(\"media_type\") val mediaType: String?,\n        @JsonProperty(\"title\") val title: String?,\n        @JsonProperty(\"name\") val name: String?,\n        @JsonProperty(\"original_title\") val originalTitle: String?,\n        @JsonProperty(\"original_name\") val originalName: String?\n    )\n    \n    /**\n     * Fetches search suggestions from TheMovieDB multi search API.\n     * Returns suggestions for movies, TV series, and anime.\n     * \n     * @param query The search query to get suggestions for\n     * @return List of suggestion strings, empty list on failure\n     */\n    suspend fun getSuggestions(query: String): List<String> {\n        if (query.isBlank() || query.length < 2) return emptyList()\n        \n        return try {\n            val response = app.get(\n                TMDB_API_URL,\n                params = mapOf(\n                    \"api_key\" to TMDB_API_KEY,\n                    \"query\" to query,\n                    \"language\" to \"en-US\"\n                ),\n                cacheTime = 60 * 24  // Cache for 1 day (cacheUnit default is Minutes)\n            )\n            \n            parseSuggestions(response)\n        } catch (e: Exception) {\n            logError(e)\n            emptyList()\n        }\n    }\n    \n    /**\n     * Parses the TMDB search response and extracts movie/TV show titles.\n     * Filters to only include movies, TV shows, and anime.\n     */\n    private fun parseSuggestions(response: NiceResponse): List<String> {\n        return try {\n            val parsed = response.parsed<TmdbSearchResult>()\n            parsed.results\n                ?.filter { it.mediaType == \"movie\" || it.mediaType == \"tv\" }\n                ?.mapNotNull { it.title ?: it.name }\n                ?.distinct()\n                ?.take(10)\n                ?: emptyList()\n        } catch (e: Exception) {\n            logError(e)\n            emptyList()\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.search\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport com.lagradost.cloudstream3.APIHolder.apis\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.HomePageList\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.mvvm.Resource\nimport com.lagradost.cloudstream3.mvvm.debugAssert\nimport com.lagradost.cloudstream3.mvvm.debugWarning\nimport com.lagradost.cloudstream3.mvvm.launchSafe\nimport com.lagradost.cloudstream3.ui.APIRepository\nimport com.lagradost.cloudstream3.ui.home.HomeViewModel\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.currentAccount\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.withContext\n\n\ndata class ExpandableSearchList(\n    var list: List<SearchResponse>, var currentPage: Int, var hasNext: Boolean,\n)\n\nconst val SEARCH_HISTORY_KEY = \"search_history\"\n\nclass SearchViewModel : ViewModel() {\n    private val _searchResponse: MutableLiveData<Resource<ExpandableSearchList>> =\n        MutableLiveData()\n    val searchResponse: LiveData<Resource<ExpandableSearchList>> get() = _searchResponse\n\n    private val _currentSearch: MutableLiveData<Map<String, ExpandableSearchList>> =\n        MutableLiveData()\n    val currentSearch: LiveData<Map<String, ExpandableSearchList>> get() = _currentSearch\n\n    private val _currentHistory: MutableLiveData<List<SearchHistoryItem>> = MutableLiveData()\n    val currentHistory: LiveData<List<SearchHistoryItem>> get() = _currentHistory\n\n    private val _searchSuggestions: MutableLiveData<List<String>> = MutableLiveData()\n    val searchSuggestions: LiveData<List<String>> get() = _searchSuggestions\n\n    private var suggestionJob: Job? = null\n\n    private var repos = synchronized(apis) { apis.map { APIRepository(it) } }\n\n    fun clearSearch() {\n        _searchResponse.postValue(Resource.Success(ExpandableSearchList(emptyList(), 0, false)))\n        _currentSearch.postValue(emptyMap())\n        expandableSearches.clear()\n    }\n\n    var lastQuery: String? = null\n\n    /** Save which providers can searched again and which search result page they are on.\n     * Maps provider name to search list.\n     * @see [HomeViewModel.expandable] */\n    private val expandableSearches: MutableMap<String, ExpandableSearchList> = mutableMapOf()\n\n    private var currentSearchIndex = 0\n    private var onGoingSearch: Job? = null\n\n    fun reloadRepos() {\n        repos = synchronized(apis) { apis.map { APIRepository(it) } }\n    }\n\n    fun searchAndCancel(\n        query: String,\n        providersActive: Set<String> = setOf(),\n        ignoreSettings: Boolean = false,\n        isQuickSearch: Boolean = false,\n    ) {\n        currentSearchIndex++\n        onGoingSearch?.cancel()\n        onGoingSearch = search(query, providersActive, ignoreSettings, isQuickSearch)\n    }\n\n    fun updateHistory() = ioSafe {\n        val items = getKeys(\"$currentAccount/$SEARCH_HISTORY_KEY\")?.mapNotNull {\n            getKey<SearchHistoryItem>(it)\n        }?.sortedByDescending { it.searchedAt } ?: emptyList()\n        _currentHistory.postValue(items)\n    }\n\n    /**\n     * Fetches search suggestions with debouncing.\n     * Waits 300ms before making the API call to avoid too many requests.\n     * \n     * @param query The search query to get suggestions for\n     */\n    fun fetchSuggestions(query: String) {\n        suggestionJob?.cancel()\n        \n        if (query.isBlank() || query.length < 2) {\n            _searchSuggestions.postValue(emptyList())\n            return\n        }\n        \n        suggestionJob = ioSafe {\n            delay(300) // Debounce\n            val suggestions = SearchSuggestionApi.getSuggestions(query)\n            _searchSuggestions.postValue(suggestions)\n        }\n    }\n\n    /**\n     * Clears the current search suggestions.\n     */\n    fun clearSuggestions() {\n        suggestionJob?.cancel()\n        _searchSuggestions.postValue(emptyList())\n    }\n\n    private val lock: MutableSet<String> = mutableSetOf()\n\n    // ExpandableHomepageList because the home adapter is reused in the search fragment\n    suspend fun expandAndReturn(name: String): HomeViewModel.ExpandableHomepageList? {\n        if (lock.contains(name)) return null\n        val query = lastQuery ?: return null\n        val repo = repos.find { it.name == name } ?: return null\n\n        lock += name\n\n        expandableSearches[name]?.let { current ->\n            debugAssert({ !current.hasNext }) {\n                \"Expand called when not needed\"\n            }\n\n            val nextPage = current.currentPage + 1\n            val next = repo.search(query, nextPage)\n            if (next is Resource.Success) {\n                val nextValue = next.value\n                expandableSearches[name]?.apply {\n                    this.hasNext = nextValue.hasNext\n                    this.currentPage = nextPage\n\n                    debugWarning({ nextValue.items.any { outer -> this.list.any { it.url == outer.url } } }) {\n                        \"Expanded search contained an item that was previously already in the list.\\nQuery = $query, ${nextValue.items} = ${this.list}\"\n                    }\n\n                    // just to be sure we are not adding the same shit for some reason\n                    // Avoids weird behavior in the recyclerview by recreating the list\n                    this.list = (this.list + nextValue.items).distinctBy { it.url }\n                } ?: debugWarning {\n                    \"Expanded an item not in search load named $name, current list is ${expandableSearches.keys}\"\n                }\n            } else {\n                current.hasNext = false\n            }\n\n            _searchResponse.postValue(Resource.Success(bundleSearch(expandableSearches)))\n            _currentSearch.postValue(expandableSearches)\n        }\n\n        lock -= name\n\n        val item = expandableSearches[name] ?: return null\n        return HomeViewModel.ExpandableHomepageList(\n            HomePageList(name, item.list),\n            item.currentPage,\n            item.hasNext\n        )\n    }\n\n    private fun bundleSearch(lists: MutableMap<String, ExpandableSearchList>): ExpandableSearchList {\n        if (lists.size == 1) {\n            return lists.values.first()\n        }\n\n        val list = ArrayList<SearchResponse>()\n        val nestedList =\n            lists.map { it.value.list }\n\n        // I do it this way to move the relevant search results to the top\n        var index = 0\n        while (true) {\n            var added = 0\n            for (sublist in nestedList) {\n                if (sublist.size > index) {\n                    list.add(sublist[index])\n                    added++\n                }\n            }\n            if (added == 0) break\n            index++\n        }\n\n        return ExpandableSearchList(list, 1, false)\n    }\n\n    private fun search(\n        query: String,\n        providersActive: Set<String>,\n        ignoreSettings: Boolean = false,\n        isQuickSearch: Boolean = false,\n    ) =\n        viewModelScope.launchSafe {\n            val currentIndex = currentSearchIndex\n            if (query.length <= 1) {\n                clearSearch()\n                return@launchSafe\n            }\n\n            if (!isQuickSearch) {\n                val key = query.hashCode().toString()\n                setKey(\n                    \"$currentAccount/$SEARCH_HISTORY_KEY\",\n                    key,\n                    SearchHistoryItem(\n                        searchedAt = System.currentTimeMillis(),\n                        searchText = query,\n                        type = emptyList(), // TODO implement tv type\n                        key = key,\n                    )\n                )\n            }\n\n            _searchResponse.postValue(Resource.Loading())\n            _currentSearch.postValue(emptyMap())\n            expandableSearches.clear()\n\n            lastQuery = query\n\n            withContext(Dispatchers.IO) { // This interrupts UI otherwise\n                repos.filter { a ->\n                    (ignoreSettings || (providersActive.isEmpty() || providersActive.contains(a.name))) && (!isQuickSearch || a.hasQuickSearch)\n                }.amap { a -> // Parallel\n                    val search = if (isQuickSearch) a.quickSearch(query) else a.search(query, 1)\n                    if (currentSearchIndex != currentIndex) return@amap\n                    if (search is Resource.Success) {\n                        val searchValue = search.value\n                        expandableSearches[a.name] =\n                            ExpandableSearchList(searchValue.items, 1, searchValue.hasNext)\n                    }\n\n                    _currentSearch.postValue(expandableSearches)\n                }\n\n                if (currentSearchIndex != currentIndex) return@withContext // this should prevent rewrite of existing data bug\n\n                _currentSearch.postValue(expandableSearches)\n                val list = bundleSearch(expandableSearches)\n\n                _searchResponse.postValue(Resource.Success(list))\n            }\n        }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/search/SyncSearchViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.search\n\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.SearchQuality\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.TvType\n\n//TODO Relevance of this class since it's not used\nclass SyncSearchViewModel {\n    data class SyncSearchResultSearchResponse(\n        override val name: String,\n        override val url: String,\n        override val apiName: String,\n        override var type: TvType?,\n        override var posterUrl: String?,\n        override var id: Int?,\n        override var quality: SearchQuality? = null,\n        override var posterHeaders: Map<String, String>? = null,\n        override var score: Score? = null,\n    ) : SearchResponse\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/AccountAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\n\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport androidx.core.view.isVisible\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.AccountSingleBinding\nimport com.lagradost.cloudstream3.syncproviders.AuthData\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\n\nclass AccountClickCallback(val action: Int, val view: View, val card: AuthData)\n\nclass AccountAdapter(\n    private val clickCallback: (AccountClickCallback) -> Unit\n) :\n    NoStateAdapter<AuthData>(\n        diffCallback = BaseDiffCallback(itemSame = { a, b ->\n            a.user.id == b.user.id\n        })\n    ) {\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            AccountSingleBinding.inflate(\n                LayoutInflater.from(parent.context),\n                parent,\n                false\n            )\n        )\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        val binding = holder.view as? AccountSingleBinding ?: return\n        clearImage(binding.accountProfilePicture)\n    }\n\n    override fun onBindContent(holder: ViewHolderState<Any>, item: AuthData, position: Int) {\n        val binding = holder.view as? AccountSingleBinding ?: return\n        binding.apply {\n            accountName.text = item.user.name\n                ?: \"${binding.accountName.context.getString(R.string.account)} ${position + 1}\"\n            accountProfilePicture.isVisible = true\n            accountProfilePicture.loadImage(\n                item.user.profilePicture,\n                headers = item.user.profilePictureHeaders\n            )\n\n            root.setOnClickListener {\n                clickCallback.invoke(AccountClickCallback(0, root, item))\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/Globals.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\n\nimport android.app.UiModeManager\nimport android.content.Context\nimport android.content.res.Configuration\nimport android.content.res.Resources\nimport android.os.Build\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.R\n\nobject Globals {\n    var beneneCount = 0\n\n    const val PHONE : Int = 0b001\n    const val TV : Int = 0b010\n    const val EMULATOR : Int = 0b100\n    private const val INVALID = -1\n    private var layoutId = INVALID\n\n    private fun Context.getLayoutInt(): Int {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        return settingsManager.getInt(this.getString(R.string.app_layout_key), -1)\n    }\n\n    private fun Context.isAutoTv(): Boolean {\n        val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager?\n        // AFT = Fire TV\n        val model = Build.MODEL.lowercase()\n        return uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION || Build.MODEL.contains(\n            \"AFT\"\n        ) || model.contains(\"firestick\") || model.contains(\"fire tv\") || model.contains(\"chromecast\")\n    }\n\n    private fun Context.layoutIntCorrected(): Int {\n        return when(getLayoutInt()) {\n            -1 -> if (isAutoTv()) TV else PHONE\n            0 -> PHONE\n            1 -> TV\n            2 -> EMULATOR\n            else -> PHONE\n        }\n    }\n\n    fun Context.updateTv() {\n        layoutId = layoutIntCorrected()\n    }\n\n    /** Returns true if the current orientation is landscape. */\n    fun isLandscape(): Boolean =\n        isLayout(TV or EMULATOR) ||\n            Resources.getSystem().configuration.orientation == Configuration.ORIENTATION_LANDSCAPE\n\n    /** Returns true if the layout is any of the flags,\n     * so isLayout(TV or EMULATOR) is a valid statement for checking if the layout is in the emulator\n     * or tv. Auto will become the \"TV\" or the \"PHONE\" layout.\n     *\n     * Valid flags are: PHONE, TV, EMULATOR\n     * */\n    fun isLayout(flags: Int) : Boolean {\n        return (layoutId and flags) != 0\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/LogcatAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\r\n\r\nimport android.view.LayoutInflater\r\nimport android.view.ViewGroup\r\nimport com.lagradost.cloudstream3.databinding.ItemLogcatBinding\r\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\r\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\r\nimport com.lagradost.cloudstream3.ui.ViewHolderState\r\n\r\nclass LogcatAdapter() : NoStateAdapter<String>(\r\n    diffCallback = BaseDiffCallback(\r\n        itemSame = String::equals,\r\n        contentSame = String::equals\r\n    )\r\n) {\r\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\r\n        return ViewHolderState(\r\n            ItemLogcatBinding.inflate(\r\n                LayoutInflater.from(parent.context),\r\n                parent,\r\n                false\r\n            )\r\n        )\r\n    }\r\n\r\n    override fun onBindContent(holder: ViewHolderState<Any>, item: String, position: Int) {\r\n        (holder.view as? ItemLogcatBinding)?.apply {\r\n            logText.text = item\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\n\nimport android.annotation.SuppressLint\nimport android.graphics.Bitmap\nimport android.os.Bundle\nimport android.os.CountDownTimer\nimport android.view.View\nimport android.view.View.FOCUS_DOWN\nimport android.view.inputmethod.EditorInfo\nimport android.widget.TextView\nimport androidx.annotation.UiThread\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.edit\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.fragment.app.FragmentActivity\nimport androidx.preference.PreferenceManager\nimport androidx.preference.SwitchPreference\nimport androidx.recyclerview.widget.RecyclerView\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser\nimport com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.AccountManagmentBinding\nimport com.lagradost.cloudstream3.databinding.AccountSwitchBinding\nimport com.lagradost.cloudstream3.databinding.AddAccountInputBinding\nimport com.lagradost.cloudstream3.databinding.DeviceAuthBinding\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.aniListApi\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.malApi\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.kitsuApi\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.openSubtitlesApi\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.simklApi\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.subDlApi\nimport com.lagradost.cloudstream3.syncproviders.AuthLoginResponse\nimport com.lagradost.cloudstream3.syncproviders.AuthRepo\nimport com.lagradost.cloudstream3.syncproviders.AuthUser\nimport com.lagradost.cloudstream3.syncproviders.SubtitleRepo\nimport com.lagradost.cloudstream3.syncproviders.SyncRepo\nimport com.lagradost.cloudstream3.ui.BasePreferenceFragmentCompat\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.hideOn\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\nimport com.lagradost.cloudstream3.utils.BackupUtils\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.BiometricCallback\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.authCallback\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.biometricPrompt\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.deviceHasPasswordPinLock\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.isAuthEnabled\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.promptInfo\nimport com.lagradost.cloudstream3.utils.BiometricAuthenticator.startBiometricAuthentication\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialogText\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport com.lagradost.cloudstream3.utils.setText\nimport com.lagradost.cloudstream3.utils.txt\nimport qrcode.QRCode\n\nclass SettingsAccount : BasePreferenceFragmentCompat(), BiometricCallback {\n    companion object {\n        /** Used by nginx plugin too */\n        @SuppressLint(\"StringFormatInvalid\")\n        fun showLoginInfo(\n            activity: FragmentActivity?,\n            api: AuthRepo,\n            info: AuthUser?,\n            index: Int,\n        ) {\n            if (activity == null) return\n            val binding: AccountManagmentBinding =\n                AccountManagmentBinding.inflate(activity.layoutInflater, null, false)\n            val builder =\n                AlertDialog.Builder(activity, R.style.AlertDialogCustom)\n                    .setView(binding.root)\n            val dialog = builder.show()\n\n            binding.accountMainProfilePictureHolder.isVisible =\n                !info?.profilePicture.isNullOrEmpty()\n            binding.accountMainProfilePicture.loadImage(info?.profilePicture)\n\n            binding.accountLogout.isVisible = info != null\n            binding.accountLogout.setOnClickListener {\n                if (info != null) {\n                    ioSafe { api.logout(info) }\n                }\n                dialog.dismissSafe(activity)\n            }\n\n            dialog.findViewById<TextView>(R.id.account_name)?.text = if (info != null) {\n                info.name ?: \"%s %d\".format(\n                    activity.getString(R.string.account),\n                    index + 1\n                )\n            } else {\n                activity.getString(R.string.no_account)\n            }\n\n            binding.accountSite.text = api.name\n            binding.accountSwitchAccount.setOnClickListener {\n                dialog.dismissSafe(activity)\n                showAccountSwitch(activity, api)\n            }\n\n            if (isLayout(TV or EMULATOR)) {\n                binding.accountSwitchAccount.requestFocus()\n            }\n        }\n\n        private fun showAccountSwitch(activity: FragmentActivity, api: AuthRepo) {\n            val accounts = api.accounts\n            val binding: AccountSwitchBinding =\n                AccountSwitchBinding.inflate(activity.layoutInflater, null, false)\n\n            val builder =\n                AlertDialog.Builder(activity, R.style.AlertDialogCustom)\n                    .setView(binding.root)\n            val dialog = builder.show()\n\n            binding.accountAdd.setOnClickListener {\n                addAccount(activity, api)\n                dialog?.dismissSafe(activity)\n            }\n\n            binding.accountNone.setOnClickListener {\n                api.accountId = -1\n                dialog?.dismissSafe(activity)\n            }\n\n            val adapter = AccountAdapter {\n                dialog?.dismissSafe(activity)\n                api.accountId = it.card.user.id\n            }.apply {\n                submitList(accounts.toList())\n            }\n            val list = dialog.findViewById<RecyclerView>(R.id.account_list)\n            list?.adapter = adapter\n        }\n\n\n        @UiThread\n        fun showPin(activity: FragmentActivity, api: AuthRepo) {\n            val binding: DeviceAuthBinding =\n                DeviceAuthBinding.inflate(activity.layoutInflater, null, false)\n\n            val builder =\n                AlertDialog.Builder(activity)\n                    .setView(binding.root)\n\n            builder.apply {\n                setNegativeButton(R.string.cancel) { _, _ -> }\n                if (api.hasOAuth2) {\n                    setPositiveButton(R.string.auth_locally) { _, _ ->\n                        api.openOAuth2PageWithToast()\n                    }\n                }\n            }\n\n            val dialog = builder.create()\n\n            ioSafe {\n                val pinCodeData = try {\n                    api.pinRequest()\n                } catch (e: ErrorLoadingException) {\n                    if (e.message != null) {\n                        showToast(e.message)\n                        null\n                    } else {\n                        throw e\n                    }\n                } catch (t: Throwable) {\n                    logError(t)\n                    null\n                }\n                if (pinCodeData == null) {\n                    if (api.hasOAuth2) {\n                        showToast(R.string.device_pin_error_message)\n                        api.openOAuth2PageWithToast()\n                    } else {\n                        showToast(\n                            txt(\n                                R.string.authenticated_user_fail,\n                                api.name\n                            )\n                        )\n                    }\n                    return@ioSafe\n                }\n\n                /*val logoBytes = ContextCompat.getDrawable(\n                    activity,\n                    R.drawable.cloud_2_solid\n                )?.toBitmapOrNull()?.let { bitmap ->\n                    val csLogo = ByteArrayOutputStream()\n                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, csLogo)\n                    csLogo.toByteArray()\n                }*/\n\n                val qrCodeImage = QRCode.ofRoundedSquares()\n                    .withColor(activity.colorFromAttribute(R.attr.textColor))\n                    .withBackgroundColor(activity.colorFromAttribute(R.attr.primaryBlackBackground))\n                    //.withLogo(logoBytes, 200.toPx, 200.toPx) //For later if logo needed anytime\n                    .build(pinCodeData.verificationUrl)\n                    .render().nativeImage() as Bitmap\n\n                activity.runOnUiThread {\n                    dialog.show()\n                    binding.apply {\n                        devicePinCode.setText(txt(pinCodeData.userCode))\n                        deviceAuthMessage.setText(\n                            txt(\n                                R.string.device_pin_url_message,\n                                pinCodeData.verificationUrl\n                            )\n                        )\n                        deviceAuthQrcode.loadImage(qrCodeImage)\n                    }\n\n                    val expirationMillis =\n                        pinCodeData.expiresIn.times(1000).toLong()\n\n                    object : CountDownTimer(expirationMillis, 1000) {\n                        override fun onTick(millisUntilFinished: Long) {\n                            val secondsUntilFinished =\n                                millisUntilFinished.div(1000).toInt()\n\n                            binding.deviceAuthValidationCounter.setText(\n                                txt(\n                                    R.string.device_pin_counter_text,\n                                    secondsUntilFinished.div(60),\n                                    secondsUntilFinished.rem(60)\n                                )\n                            )\n\n                            ioSafe {\n                                if (secondsUntilFinished.rem(pinCodeData.interval) == 0 && api.login(\n                                        pinCodeData\n                                    )\n                                ) {\n                                    showToast(\n                                        txt(\n                                            R.string.authenticated_user,\n                                            api.name\n                                        )\n                                    )\n                                    dialog.dismissSafe(activity)\n                                    cancel()\n                                }\n                            }\n                        }\n\n                        override fun onFinish() {\n                            showToast(R.string.device_pin_expired_message)\n                            dialog.dismissSafe(activity)\n                        }\n                    }.start()\n                }\n            }\n        }\n\n\n        fun showAppLogin(activity: FragmentActivity, api: AuthRepo) {\n\n            val binding: AddAccountInputBinding =\n                AddAccountInputBinding.inflate(activity.layoutInflater, null, false)\n            val builder =\n                AlertDialog.Builder(activity, R.style.AlertDialogCustom)\n                    .setView(binding.root)\n            val dialog = builder.show()\n            val req =\n                api.inAppLoginRequirement ?: throw ErrorLoadingException(\"Missing LoginRequirement\")\n            val visibilityMap = listOf(\n                binding.loginEmailInput to req.email,\n                binding.loginPasswordInput to req.password,\n                binding.loginServerInput to req.server,\n                binding.loginUsernameInput to req.username\n            )\n\n            if (isLayout(TV or EMULATOR)) {\n                visibilityMap.forEach { (input, isVisible) ->\n                    input.isVisible = isVisible\n\n                    // Band-aid for weird FireTV behavior causing crashes because keyboard covers the screen\n                    input.setOnEditorActionListener { textView, actionId, _ ->\n                        if (actionId == EditorInfo.IME_ACTION_NEXT) {\n                            val view = textView.focusSearch(FOCUS_DOWN)\n                            return@setOnEditorActionListener view?.requestFocus(\n                                FOCUS_DOWN\n                            ) == true\n                        }\n                        return@setOnEditorActionListener true\n                    }\n                }\n            } else {\n                visibilityMap.forEach { (input, isVisible) ->\n                    input.isVisible = isVisible\n                }\n            }\n\n            binding.createAccount.isGone = api.createAccountUrl.isNullOrBlank()\n            binding.createAccount.setOnClickListener {\n                openBrowser(\n                    api.createAccountUrl ?: return@setOnClickListener,\n                    activity\n                )\n                dialog.dismissSafe()\n            }\n\n            val displayedItems = listOf(\n                binding.loginUsernameInput,\n                binding.loginEmailInput,\n                binding.loginServerInput,\n                binding.loginPasswordInput\n            ).filter { it.isVisible }\n\n            displayedItems.foldRight(displayedItems.firstOrNull()) { item, previous ->\n                item.id.let { previous?.nextFocusDownId = it }\n                previous?.id?.let { item.nextFocusUpId = it }\n                item\n            }\n\n            displayedItems.firstOrNull()?.let {\n                binding.createAccount.nextFocusDownId = it.id\n                it.nextFocusUpId = binding.createAccount.id\n            }\n            binding.applyBtt.id.let {\n                displayedItems.lastOrNull()?.nextFocusDownId = it\n            }\n\n            binding.text1.text = api.name\n\n            binding.applyBtt.setOnClickListener {\n                val loginData = AuthLoginResponse(\n                    username = if (req.username) binding.loginUsernameInput.text?.toString() else null,\n                    password = if (req.password) binding.loginPasswordInput.text?.toString() else null,\n                    email = if (req.email) binding.loginEmailInput.text?.toString() else null,\n                    server = if (req.server) binding.loginServerInput.text?.toString() else null,\n                )\n                ioSafe {\n                    try {\n                        if (api.login(loginData)) {\n                            showToast(\n                                txt(\n                                    R.string.authenticated_user,\n                                    api.name\n                                )\n                            )\n                            dialog.dismissSafe(activity)\n                        } else {\n                            showToast(\n                                txt(\n                                    R.string.authenticated_user_fail,\n                                    api.name\n                                )\n                            )\n                        }\n                    } catch (t: Throwable) {\n                        if (t is ErrorLoadingException && t.message != null) {\n                            showToast(t.message)\n                            return@ioSafe\n                        }\n                        showToast(\n                            txt(\n                                R.string.authenticated_user_fail,\n                                api.name\n                            )\n                        )\n                    }\n                }\n            }\n            binding.cancelBtt.setOnClickListener {\n                dialog.dismissSafe(activity)\n            }\n        }\n\n        @UiThread\n        fun addAccount(activity: FragmentActivity, api: AuthRepo) {\n            try {\n                if (api.hasPin && !isLayout(PHONE)) {\n                    showPin(activity, api)\n                } else if (api.hasOAuth2) {\n                    api.openOAuth2PageWithToast()\n                } else if (api.hasInApp) {\n                    showAppLogin(activity, api)\n                } else {\n                    throw NotImplementedError(\"The api ${api.name} has no login\")\n                }\n            } catch (t: Throwable) {\n                showToast(txt(R.string.authenticated_user_fail, api.name))\n                logError(t)\n            }\n        }\n    }\n\n    private fun updateAuthPreference(enabled: Boolean) {\n        val biometricKey = getString(R.string.biometric_key)\n\n        PreferenceManager.getDefaultSharedPreferences(context ?: return).edit {\n            putBoolean(biometricKey, enabled)\n        }\n        findPreference<SwitchPreference>(biometricKey)?.isChecked = enabled\n    }\n\n    override fun onAuthenticationError() {\n        updateAuthPreference(!isAuthEnabled(context ?: return))\n    }\n\n    override fun onAuthenticationSuccess() {\n        if (isAuthEnabled(context ?: return)) {\n            updateAuthPreference(true)\n            BackupUtils.backup(activity)\n            activity?.showBottomDialogText(\n                getString(R.string.biometric_setting),\n                getString(R.string.biometric_warning).html()\n            ) { onDialogDismissedEvent }\n        } else {\n            updateAuthPreference(false)\n        }\n    }\n\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        setUpToolbar(R.string.category_account)\n        setPaddingBottom()\n        setToolBarScrollFlags()\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        hideKeyboard()\n        setPreferencesFromResource(R.xml.settings_account, rootKey)\n\n        //Hides the security  category on TV as it's only Biometric for now\n        getPref(R.string.pref_category_security_key)?.hideOn(TV or EMULATOR)\n\n        getPref(R.string.biometric_key)?.hideOn(TV or EMULATOR)?.setOnPreferenceClickListener {\n            val ctx = context ?: return@setOnPreferenceClickListener false\n\n            if (deviceHasPasswordPinLock(ctx)) {\n                startBiometricAuthentication(\n                    activity ?: return@setOnPreferenceClickListener false,\n                    R.string.biometric_authentication_title,\n                    false\n                )\n                promptInfo?.let {\n                    authCallback = this\n                    biometricPrompt?.authenticate(it)\n                }\n            }\n\n            false\n        }\n\n        val syncApis =\n            listOf(\n                R.string.mal_key to SyncRepo(malApi),\n                R.string.kitsu_key to SyncRepo(kitsuApi),\n                R.string.anilist_key to SyncRepo(aniListApi),\n                R.string.simkl_key to SyncRepo(simklApi),\n                R.string.opensubtitles_key to SubtitleRepo(openSubtitlesApi),\n                R.string.subdl_key to SubtitleRepo(subDlApi),\n            )\n\n        for ((key, api) in syncApis) {\n            getPref(key)?.apply {\n                title = api.name\n                setOnPreferenceClickListener {\n                    val activity = activity ?: return@setOnPreferenceClickListener false\n                    val info = api.authUser()\n                    val index = api.accounts.indexOfFirst { account -> account.user.id == info?.id }\n                    if (api.accounts.isNotEmpty()) {\n                        showLoginInfo(activity, api, info, index)\n                    } else {\n                        addAccount(activity, api)\n                    }\n                    return@setOnPreferenceClickListener true\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\n\nimport android.os.Bundle\nimport android.util.Log\nimport android.view.View\nimport android.widget.ImageView\nimport androidx.annotation.StringRes\nimport androidx.core.view.children\nimport androidx.core.view.updateLayoutParams\nimport androidx.fragment.app.Fragment\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompat\nimport com.google.android.material.appbar.AppBarLayout\nimport com.google.android.material.appbar.MaterialToolbar\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.MainSettingsBinding\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.syncproviders.AccountManager\nimport com.lagradost.cloudstream3.syncproviders.AuthRepo\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.errorProfilePic\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\nimport com.lagradost.cloudstream3.utils.getImageFromDrawable\nimport com.lagradost.cloudstream3.utils.txt\nimport java.io.File\nimport java.text.DateFormat\nimport java.text.SimpleDateFormat\nimport java.util.Date\nimport java.util.Locale\nimport java.util.TimeZone\n\nclass SettingsFragment : BaseFragment<MainSettingsBinding>(\n    BaseFragment.BindingCreator.Inflate(MainSettingsBinding::inflate)\n) {\n    companion object {\n        fun PreferenceFragmentCompat?.getPref(id: Int): Preference? {\n            if (this == null) return null\n            return try {\n                findPreference(getString(id))\n            } catch (e: Exception) {\n                logError(e)\n                null\n            }\n        }\n\n        /**\n         * Hide many Preferences on selected layouts.\n         **/\n        fun PreferenceFragmentCompat?.hidePrefs(ids: List<Int>, layoutFlags: Int) {\n            if (this == null) return\n\n            try {\n                ids.forEach {\n                    getPref(it)?.isVisible = !isLayout(layoutFlags)\n                }\n            } catch (e: Exception) {\n                logError(e)\n            }\n        }\n\n        /**\n         * Hide the [Preference] on selected layouts.\n         * @return [Preference] if visible otherwise null.\n         *\n         * [hideOn] is usually followed by some actions on the preference which are mostly\n         * unnecessary when the preference is disabled for the said layout thus returning null.\n         **/\n        fun Preference?.hideOn(layoutFlags: Int): Preference? {\n            if (this == null) return null\n            this.isVisible = !isLayout(layoutFlags)\n            return if(this.isVisible) this else null\n        }\n\n        /**\n         * On TV you cannot properly scroll to the bottom of settings, this fixes that.\n         * */\n        fun PreferenceFragmentCompat.setPaddingBottom() {\n            if (isLayout(TV or EMULATOR)) {\n                listView?.setPadding(0, 0, 0, 100.toPx)\n            }\n        }\n\n        fun PreferenceFragmentCompat.setToolBarScrollFlags() {\n            if (isLayout(TV or EMULATOR)) {\n                val settingsAppbar = view?.findViewById<MaterialToolbar>(R.id.settings_toolbar)\n\n                settingsAppbar?.updateLayoutParams<AppBarLayout.LayoutParams> {\n                    scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL\n                }\n            }\n        }\n\n        fun Fragment?.setToolBarScrollFlags() {\n            if (isLayout(TV or EMULATOR)) {\n                val settingsAppbar = this?.view?.findViewById<MaterialToolbar>(R.id.settings_toolbar)\n\n                settingsAppbar?.updateLayoutParams<AppBarLayout.LayoutParams> {\n                    scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL\n                }\n            }\n        }\n\n        fun Fragment?.setUpToolbar(title: String) {\n            if (this == null) return\n            val settingsToolbar = view?.findViewById<MaterialToolbar>(R.id.settings_toolbar) ?: return\n\n            settingsToolbar.apply {\n                setTitle(title)\n                if (isLayout(PHONE or EMULATOR)) {\n                    setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)\n                    setNavigationOnClickListener {\n                        activity?.onBackPressedDispatcher?.onBackPressed()\n                    }\n                }\n            }\n        }\n\n        fun Fragment?.setUpToolbar(@StringRes title: Int) {\n            if (this == null) return\n            val settingsToolbar = view?.findViewById<MaterialToolbar>(R.id.settings_toolbar) ?: return\n\n            settingsToolbar.apply {\n                setTitle(title)\n                if (isLayout(PHONE or EMULATOR)) {\n                    setNavigationIcon(R.drawable.ic_baseline_arrow_back_24)\n                    children.firstOrNull { it is ImageView }?.tag = getString(R.string.tv_no_focus_tag)\n                    setNavigationOnClickListener {\n                        safe { activity?.onBackPressedDispatcher?.onBackPressed() }\n                    }\n                }\n            }\n        }\n\n        fun Fragment.setSystemBarsPadding() {\n            view?.let {\n                fixSystemBarsPadding(\n                    it,\n                    padLeft = isLayout(TV or EMULATOR),\n                    padBottom = isLandscape()\n                )\n            }\n        }\n\n        fun getFolderSize(dir: File): Long {\n            var size: Long = 0\n            dir.listFiles()?.let {\n                for (file in it) {\n                    size += if (file.isFile) {\n                        // System.out.println(file.getName() + \" \" + file.length());\n                        file.length()\n                    } else getFolderSize(file)\n                }\n            }\n\n            return size\n        }\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padBottom = isLandscape(),\n            padLeft = isLayout(TV or EMULATOR)\n        )\n    }\n\n    override fun onBindingCreated(binding: MainSettingsBinding) {\n        fun navigate(id: Int) {\n            activity?.navigate(id, Bundle())\n        }\n\n        /** used to debug leaks\n        showToast(activity,\"${VideoDownloadManager.downloadStatusEvent.size} :\n        ${VideoDownloadManager.downloadProgressEvent.size}\") **/\n\n        fun hasProfilePictureFromAccountManagers(accountManagers: Array<AuthRepo>): Boolean {\n            for (syncApi in accountManagers) {\n                val login = syncApi.authUser()\n                val pic = login?.profilePicture ?: continue\n\n                binding.settingsProfilePic.let { imageView ->\n                    imageView.loadImage(pic) {\n                        // Fallback to random error drawable\n                        error { getImageFromDrawable(context ?: return@error null, errorProfilePic) }\n                    }\n                }\n                binding.settingsProfileText.text = login.name\n                return true // sync profile exists\n            }\n            return false // not syncing\n        }\n\n        // display local account information if not syncing\n        if (!hasProfilePictureFromAccountManagers(AccountManager.allApis)) {\n            val activity = activity ?: return\n            val currentAccount = try {\n                DataStoreHelper.accounts.firstOrNull {\n                    it.keyIndex == DataStoreHelper.selectedKeyIndex\n                } ?: activity.let { DataStoreHelper.getDefaultAccount(activity) }\n\n            } catch (t: IllegalStateException) {\n                Log.e(\"AccountManager\", \"Activity not found\", t)\n                null\n            }\n\n            binding.settingsProfilePic.loadImage(currentAccount?.image)\n            binding.settingsProfileText.text = currentAccount?.name\n        }\n\n        binding.apply {\n            listOf(\n                settingsGeneral to R.id.action_navigation_global_to_navigation_settings_general,\n                settingsPlayer to R.id.action_navigation_global_to_navigation_settings_player,\n                settingsCredits to R.id.action_navigation_global_to_navigation_settings_account,\n                settingsUi to R.id.action_navigation_global_to_navigation_settings_ui,\n                settingsProviders to R.id.action_navigation_global_to_navigation_settings_providers,\n                settingsUpdates to R.id.action_navigation_global_to_navigation_settings_updates,\n                settingsExtensions to R.id.action_navigation_global_to_navigation_settings_extensions,\n            ).forEach { (view, navigationId) ->\n                view.apply {\n                    setOnClickListener {\n                        navigate(navigationId)\n                    }\n                    if (isLayout(TV)) {\n                        isFocusable = true\n                        isFocusableInTouchMode = true\n                    }\n                }\n            }\n\n            // Default focus on TV\n            if (isLayout(TV)) {\n                settingsGeneral.requestFocus()\n            }\n        }\n\n        val appVersion = BuildConfig.VERSION_NAME\n        val commitInfo = getString(R.string.commit_hash)\n        val buildTimestamp = SimpleDateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG,\n            Locale.getDefault()\n        ).apply { timeZone = TimeZone.getTimeZone(\"UTC\")\n        }.format(Date(BuildConfig.BUILD_DATE)).replace(\"UTC\", \"\")\n\n        binding.appVersion.text = appVersion\n        binding.buildDate.text = buildTimestamp\n        binding.appVersionInfo.setOnLongClickListener {\n            clipboardHelper(txt(R.string.extension_version), \"$appVersion $commitInfo $buildTimestamp\")\n            true\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\n\nimport android.content.Context\nimport android.net.Uri\nimport android.os.Bundle\nimport android.view.View\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.edit\nimport androidx.core.os.ConfigurationCompat\nimport androidx.preference.PreferenceManager\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder.allProviders\nimport com.lagradost.cloudstream3.CloudStreamApp\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.databinding.AddRemoveSitesBinding\nimport com.lagradost.cloudstream3.databinding.AddSiteInputBinding\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.network.initClient\nimport com.lagradost.cloudstream3.ui.BasePreferenceFragmentCompat\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.beneneCount\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.hideOn\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar\nimport com.lagradost.cloudstream3.ui.settings.utils.getChooseFolderLauncher\nimport com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.isAppRestricted\nimport com.lagradost.cloudstream3.utils.BatteryOptimizationChecker.showBatteryOptimizationDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog\nimport com.lagradost.cloudstream3.utils.SubtitleHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.USER_PROVIDER_API\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getBasePath\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager\nimport java.util.Locale\n\n// Change local language settings in the app.\nfun getCurrentLocale(context: Context): String {\n    val conf = context.resources.configuration\n    return ConfigurationCompat.getLocales(conf).get(0)?.toLanguageTag() ?: \"en\"\n}\n\n/**\n * List of app supported languages.\n * Language code shall be a IETF BCP 47 conformant tag\n *\n * See locales on:\n * https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/availableLocales.json\n * https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry\n * https://android.googlesource.com/platform/frameworks/base/+/android-16.0.0_r2/core/res/res/values/locale_config.xml\n * https://iso639-3.sil.org/code_tables/639/data/all\n*/\nval appLanguages = arrayListOf(\n    /* begin language list */\n    Pair(\"Afrikaans\", \"af\"),\n    Pair(\"Azərbaycan dili\", \"az\"),\n    Pair(\"Bahasa Indonesia\", \"in\"),\n    Pair(\"Bahasa Melayu\", \"ms\"),\n    Pair(\"Deutsch\", \"de\"),\n    Pair(\"English\", \"en\"),\n    Pair(\"Español\", \"es\"),\n    Pair(\"Esperanto\", \"eo\"),\n    Pair(\"Français\", \"fr\"),\n    Pair(\"Galego\", \"gl\"),\n    Pair(\"hrvatski\", \"hr\"),\n    Pair(\"Italiano\", \"it\"),\n    Pair(\"Latviešu valoda\", \"lv\"),\n    Pair(\"Lietuvių kalba\", \"lt\"),\n    Pair(\"Magyar\", \"hu\"),\n    Pair(\"Malti\", \"mt\"),\n    Pair(\"mmmm... monke\", \"qt\"),\n    Pair(\"Nederlands\", \"nl\"),\n    Pair(\"Norsk bokmål\", \"no\"),\n    Pair(\"Norsk nynorsk\", \"nn\"),\n    Pair(\"Polski\", \"pl\"),\n    Pair(\"Português\", \"pt\"),\n    Pair(\"Português (Brasil)\", \"pt-BR\"),\n    Pair(\"Română\", \"ro\"),\n    Pair(\"Slovenčina\", \"sk\"),\n    Pair(\"Soomaaliga\", \"so\"),\n    Pair(\"Svenska\", \"sv\"),\n    Pair(\"Tagalog\", \"tl\"),\n    Pair(\"Tiếng Việt\", \"vi\"),\n    Pair(\"Türkçe\", \"tr\"),\n    Pair(\"Wikang Filipino\", \"fil\"),\n    Pair(\"Čeština\", \"cs\"),\n    Pair(\"Ελληνικά\", \"el\"),\n    Pair(\"български\", \"bg\"),\n    Pair(\"македонски\", \"mk\"),\n    Pair(\"русский\", \"ru\"),\n    Pair(\"українська\", \"uk\"),\n    Pair(\"עברית\", \"iw\"),\n    Pair(\"اردو\", \"ur\"),\n    Pair(\"العربية\", \"ar\"),\n    Pair(\"اللهجة النجدية\", \"ars\"),\n    Pair(\"عربي شامي\", \"apc\"),\n    Pair(\"فارسی\", \"fa\"),\n    Pair(\"کوردیی ناوەندی\", \"ckb\"),\n    Pair(\"नेपाली\", \"ne\"),\n    Pair(\"हिन्दी\", \"hi\"),\n    Pair(\"অসমীয়া\", \"as\"),\n    Pair(\"বাংলা\", \"bn\"),\n    Pair(\"ଓଡ଼ିଆ\", \"or\"),\n    Pair(\"தமிழ்\", \"ta\"),\n    Pair(\"ಕನ್ನಡ\", \"kn\"),\n    Pair(\"മലയാളം\", \"ml\"),\n    Pair(\"ဗမာစာ\", \"my\"),\n    Pair(\"ትግርኛ\", \"ti\"),\n    Pair(\"አማርኛ\", \"am\"),\n    Pair(\"中文\", \"zh\"),\n    Pair(\"日本語 (にほんご)\", \"ja\"),\n    Pair(\"正體中文(臺灣)\", \"zh-TW\"),\n    Pair(\"한국어\", \"ko\"),\n/* end language list */\n).sortedBy { it.first.lowercase(Locale.ROOT) } // ye, we go alphabetical, so ppl don't put their lang on top\n\nfun Pair<String, String>.nameNextToFlagEmoji(): String {\n    // fallback to [A][A] -> [?] question mak flag\n    val flag = SubtitleHelper.getFlagFromIso(this.second) ?: \"\\ud83c\\udde6\\ud83c\\udde6\"\n\n    return \"$flag\\u00a0${this.first}\" // \\u00a0 non-breaking space\n}\n\nclass SettingsGeneral : BasePreferenceFragmentCompat() {\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        setUpToolbar(R.string.category_general)\n        setPaddingBottom()\n        setToolBarScrollFlags()\n    }\n\n    data class CustomSite(\n        @JsonProperty(\"parentJavaClass\") // javaClass.simpleName\n        val parentJavaClass: String,\n        @JsonProperty(\"name\")\n        val name: String,\n        @JsonProperty(\"url\")\n        val url: String,\n        @JsonProperty(\"lang\")\n        val lang: String,\n    )\n\n    private val pathPicker = getChooseFolderLauncher { uri, path ->\n        val context = context ?: CloudStreamApp.context ?: return@getChooseFolderLauncher\n        (path ?: uri.toString()).let {\n            PreferenceManager.getDefaultSharedPreferences(context).edit {\n                putString(getString(R.string.download_path_key), uri.toString())\n                putString(getString(R.string.download_path_key_visual), it)\n            }\n        }\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        hideKeyboard()\n        setPreferencesFromResource(R.xml.settings_general, rootKey)\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())\n\n        fun getCurrent(): MutableList<CustomSite> {\n            return getKey<Array<CustomSite>>(USER_PROVIDER_API)?.toMutableList()\n                ?: mutableListOf()\n        }\n\n        getPref(R.string.locale_key)?.setOnPreferenceClickListener { pref ->\n            val current = getCurrentLocale(pref.context)\n            val languageTagsIETF = appLanguages.map { it.second }\n            val languageNames = appLanguages.map { it.nameNextToFlagEmoji() }\n            val currentIndex = languageTagsIETF.indexOf(current)\n\n            activity?.showDialog(\n                languageNames, currentIndex, getString(R.string.app_language), true, { }\n            ) { selectedLangIndex ->\n                try {\n                    val langTagIETF = languageTagsIETF[selectedLangIndex]\n                    CommonActivity.setLocale(activity, langTagIETF)\n                    settingsManager.edit {\n                        putString(getString(R.string.locale_key), langTagIETF)\n                    }\n                    activity?.recreate()\n                } catch (e: Exception) {\n                    logError(e)\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.battery_optimisation_key)?.hideOn(TV or EMULATOR)?.setOnPreferenceClickListener {\n            val ctx = context ?: return@setOnPreferenceClickListener false\n\n            if (isAppRestricted(ctx)) {\n                ctx.showBatteryOptimizationDialog()\n            } else {\n                showToast(R.string.app_unrestricted_toast)\n            }\n\n            true\n        }\n\n        fun showAdd() {\n            val providers = synchronized(allProviders) { allProviders.distinctBy { it.javaClass }.sortedBy { it.name } }\n            activity?.showDialog(\n                providers.map { \"${it.name} (${it.mainUrl})\" },\n                -1,\n                context?.getString(R.string.add_site_pref) ?: return,\n                true,\n                {}) { selection ->\n                val provider = providers.getOrNull(selection) ?: return@showDialog\n\n                val binding : AddSiteInputBinding = AddSiteInputBinding.inflate(layoutInflater,null,false)\n\n                val builder =\n                    AlertDialog.Builder(context ?: return@showDialog, R.style.AlertDialogCustom)\n                        .setView(binding.root)\n\n                val dialog = builder.create()\n                dialog.show()\n\n                binding.text2.text = provider.name\n                binding.applyBtt.setOnClickListener {\n                    val name = binding.siteNameInput.text?.toString()\n                    val url = binding.siteUrlInput.text?.toString()\n                    val lang = binding.siteLangInput.text?.toString()\n                    val realLang = if (lang.isNullOrBlank()) provider.lang else lang\n                    if (url.isNullOrBlank() || name.isNullOrBlank()) {\n                        showToast(R.string.error_invalid_data, Toast.LENGTH_SHORT)\n                        return@setOnClickListener\n                    }\n\n                    val current = getCurrent()\n                    val newSite = CustomSite(provider.javaClass.simpleName, name, url, realLang)\n                    current.add(newSite)\n                    setKey(USER_PROVIDER_API, current.toTypedArray())\n                    // reload apis\n                    MainActivity.afterPluginsLoadedEvent.invoke(false)\n\n                    dialog.dismissSafe(activity)\n                }\n                binding.cancelBtt.setOnClickListener {\n                    dialog.dismissSafe(activity)\n                }\n            }\n        }\n\n        fun showDelete() {\n            val current = getCurrent()\n\n            activity?.showMultiDialog(\n                current.map { it.name },\n                listOf(),\n                context?.getString(R.string.remove_site_pref) ?: return,\n                {}) { indexes ->\n                current.removeAll(indexes.map { current[it] })\n                setKey(USER_PROVIDER_API, current.toTypedArray())\n            }\n        }\n\n        fun showAddOrDelete() {\n            val binding : AddRemoveSitesBinding = AddRemoveSitesBinding.inflate(layoutInflater,null,false)\n            val builder =\n                AlertDialog.Builder(context ?: return, R.style.AlertDialogCustom)\n                    .setView(binding.root)\n\n            val dialog = builder.create()\n            dialog.show()\n\n            binding.addSite.setOnClickListener {\n                showAdd()\n                dialog.dismissSafe(activity)\n            }\n            binding.removeSite.setOnClickListener {\n                showDelete()\n                dialog.dismissSafe(activity)\n            }\n        }\n\n        getPref(R.string.override_site_key)?.setOnPreferenceClickListener { _ ->\n\n            if (getCurrent().isEmpty()) {\n                showAdd()\n            } else {\n                showAddOrDelete()\n            }\n\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.legal_notice_key)?.setOnPreferenceClickListener {\n            val builder: AlertDialog.Builder =\n                AlertDialog.Builder(it.context, R.style.AlertDialogCustom)\n            builder.setTitle(R.string.legal_notice)\n            builder.setMessage(R.string.legal_notice_text)\n            builder.show()\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.dns_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.dns_pref)\n            val prefValues = resources.getIntArray(R.array.dns_pref_values)\n\n            val currentDns =\n                settingsManager.getInt(getString(R.string.dns_pref), 0)\n\n            activity?.showBottomDialog(\n                prefNames.toList(),\n                prefValues.indexOf(currentDns),\n                getString(R.string.dns_pref),\n                true,\n                {}) {\n                settingsManager.edit { putInt(getString(R.string.dns_pref), prefValues[it]) }\n                (context ?: CloudStreamApp.context)?.let { ctx -> app.initClient(ctx) }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        fun getDownloadDirs(): List<String> {\n            return safe {\n                context?.let { ctx ->\n                    val defaultDir = DownloadFileManagement.getDefaultDir(ctx)?.filePath()\n\n                    val first = listOf(defaultDir)\n                    (try {\n                        val currentDir = ctx.getBasePath().let { it.first?.filePath() ?: it.second }\n\n                        (first +\n                                ctx.getExternalFilesDirs(\"\").mapNotNull { it.path } +\n                                currentDir)\n                    } catch (e: Exception) {\n                        first\n                    }).filterNotNull().distinct()\n                }\n            } ?: emptyList()\n        }\n\n        settingsManager.edit { putBoolean(getString(R.string.jsdelivr_proxy_key), getKey(getString(R.string.jsdelivr_proxy_key), false) ?: false) }\n        getPref(R.string.jsdelivr_proxy_key)?.setOnPreferenceChangeListener { _, newValue ->\n            setKey(getString(R.string.jsdelivr_proxy_key), newValue)\n            return@setOnPreferenceChangeListener true\n        }\n\n        getPref(R.string.download_parallel_key)?.setOnPreferenceChangeListener { _, _ ->\n            // Notify that the queue logic has been changed\n            DownloadQueueManager.forceRefreshQueue()\n            return@setOnPreferenceChangeListener true\n        }\n\n        getPref(R.string.download_path_key)?.setOnPreferenceClickListener {\n            val dirs = getDownloadDirs()\n\n            val currentDir =\n                settingsManager.getString(getString(R.string.download_path_key_visual), null)\n                    ?: context?.let { ctx -> DownloadFileManagement.getDefaultDir(ctx)?.filePath() }\n\n            activity?.showBottomDialog(\n                dirs + listOf(getString(R.string.custom)),\n                dirs.indexOf(currentDir),\n                getString(R.string.download_path_pref),\n                true,\n                {}) {\n                // Last = custom\n                if (it == dirs.size) {\n                    try {\n                        pathPicker.launch(Uri.EMPTY)\n                    } catch (e: Exception) {\n                        logError(e)\n                    }\n                } else {\n                    // Sets both visual and actual paths.\n                    // key = used path\n                    // visual = visual path\n                    settingsManager.edit {\n                        putString(getString(R.string.download_path_key), dirs[it])\n                        putString(getString(R.string.download_path_key_visual), dirs[it])\n                    }\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        try {\n            beneneCount =\n                settingsManager.getInt(getString(R.string.benene_count), 0)\n            getPref(R.string.benene_count)?.let { pref ->\n                pref.summary =\n                    if (beneneCount <= 0) getString(R.string.benene_count_text_none) else getString(\n                        R.string.benene_count_text\n                    ).format(\n                        beneneCount\n                    )\n\n                pref.setOnPreferenceClickListener {\n                    try {\n                        beneneCount++\n                        if (beneneCount%20 == 0) {\n                            activity?.navigate(R.id.action_navigation_settings_general_to_easterEggMonkeFragment)\n                        }\n                        settingsManager.edit {\n                            putInt(\n                                getString(R.string.benene_count),\n                                beneneCount\n                            )\n                        }\n                        it.summary = getString(R.string.benene_count_text).format(beneneCount)\n                    } catch (e: Exception) {\n                        logError(e)\n                    }\n\n                    return@setOnPreferenceClickListener true\n                }\n            }\n        } catch (e: Exception) {\n            e.printStackTrace()\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\n\nimport android.os.Bundle\nimport android.text.format.Formatter.formatShortFileSize\nimport android.view.View\nimport androidx.core.content.edit\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.actions.VideoClickActionHolder\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.BasePreferenceFragmentCompat\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityProfileDialog\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getFolderSize\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.hideOn\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.hidePrefs\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar\nimport com.lagradost.cloudstream3.ui.subtitles.ChromecastSubtitlesFragment\nimport com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\n\nclass SettingsPlayer : BasePreferenceFragmentCompat() {\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        setUpToolbar(R.string.category_player)\n        setPaddingBottom()\n        setToolBarScrollFlags()\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        hideKeyboard()\n        setPreferencesFromResource(R.xml.settings_player, rootKey)\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())\n\n        //Hide specific prefs on TV/EMULATOR\n        hidePrefs(\n            listOf(\n                R.string.pref_category_gestures_key,\n                R.string.rotate_video_key,\n                R.string.auto_rotate_video_key,\n                R.string.speedup_key\n            ),\n            TV or EMULATOR\n        )\n\n        getPref(R.string.preview_seekbar_key)?.hideOn(TV)\n        getPref(R.string.pref_category_android_tv_key)?.hideOn(PHONE)\n\n        getPref(R.string.video_buffer_length_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.video_buffer_length_names)\n            val prefValues = resources.getIntArray(R.array.video_buffer_length_values)\n\n            val currentPrefSize =\n                settingsManager.getInt(getString(R.string.video_buffer_length_key), 0)\n\n            activity?.showDialog(\n                prefNames.toList(),\n                prefValues.indexOf(currentPrefSize),\n                getString(R.string.video_buffer_length_settings),\n                true,\n                {}\n            ) {\n                settingsManager.edit {\n                    putInt(getString(R.string.video_buffer_length_key), prefValues[it])\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.prefer_limit_title_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.limit_title_pref_names)\n            val prefValues = resources.getIntArray(R.array.limit_title_pref_values)\n            val current = settingsManager.getInt(getString(R.string.prefer_limit_title_key), 0)\n\n            activity?.showBottomDialog(\n                prefNames.toList(),\n                prefValues.indexOf(current),\n                getString(R.string.limit_title),\n                true,\n                {}\n            ) {\n                settingsManager.edit {\n                    putInt(getString(R.string.prefer_limit_title_key), prefValues[it])\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.software_decoding_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.software_decoding_switch)\n            val prefValues = resources.getIntArray(R.array.software_decoding_switch_values)\n            val current = settingsManager.getInt(getString(R.string.software_decoding_key), -1)\n\n            activity?.showBottomDialog(\n                prefNames.toList(),\n                prefValues.indexOf(current),\n                getString(R.string.software_decoding),\n                true,\n                {}\n            ) {\n                settingsManager.edit {\n                    putInt(getString(R.string.software_decoding_key), prefValues[it])\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.prefer_limit_show_player_info)?.setOnPreferenceClickListener {\n            val ctx = context ?: return@setOnPreferenceClickListener false\n\n            val prefNames = resources.getStringArray(R.array.title_info_pref_names)\n            val keys = resources.getStringArray(R.array.title_info_pref_values)\n\n            // Player defaults\n            val playerDefaults = mapOf(\n                ctx.getString(R.string.show_name_key) to true,\n                ctx.getString(R.string.show_resolution_key) to true,\n                ctx.getString(R.string.show_media_info_key) to false\n            )\n\n            val selectedIndices = keys.map { key ->\n                settingsManager.getBoolean(key, playerDefaults[key] ?: false)\n            }.mapIndexedNotNull { index, enabled ->\n                if (enabled) index else null\n            }\n\n            activity?.showMultiDialog(\n                prefNames.toList(),\n                selectedIndices,\n                getString(R.string.limit_title_rez),\n                {}\n            ) { selected ->\n                settingsManager.edit {\n                    for ((index, key) in keys.withIndex()) {\n                        putBoolean(key, selected.contains(index))\n                    }\n                }\n            }\n\n            true\n        }\n\n        getPref(R.string.hide_player_control_names_key)?.hideOn(TV)\n\n        getPref(R.string.quality_pref_key)?.setOnPreferenceClickListener {\n            val prefValues = Qualities.entries.map { it.value }.reversed().toMutableList()\n            prefValues.remove(Qualities.Unknown.value)\n\n            val prefNames = prefValues.map { Qualities.getStringByInt(it) }\n\n            val currentQuality =\n                settingsManager.getInt(\n                    getString(R.string.quality_pref_key),\n                    Qualities.entries.last().value\n                )\n\n            activity?.showBottomDialog(\n                prefNames.toList(),\n                prefValues.indexOf(currentQuality),\n                getString(R.string.watch_quality_pref),\n                true,\n                {}\n            ) {\n                settingsManager.edit {\n                    putInt(getString(R.string.quality_pref_key), prefValues[it])\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.quality_pref_mobile_data_key)?.setOnPreferenceClickListener {\n            val prefValues = Qualities.entries.map { it.value }.reversed().toMutableList()\n            prefValues.remove(Qualities.Unknown.value)\n\n            val prefNames = prefValues.map { Qualities.getStringByInt(it) }\n\n            val currentQuality =\n                settingsManager.getInt(\n                    getString(R.string.quality_pref_mobile_data_key),\n                    Qualities.entries.last().value\n                )\n\n            activity?.showBottomDialog(\n                prefNames.toList(),\n                prefValues.indexOf(currentQuality),\n                getString(R.string.watch_quality_pref_data),\n                true,\n                {}\n            ) {\n                settingsManager.edit {\n                    putInt(getString(R.string.quality_pref_mobile_data_key), prefValues[it])\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.player_default_key)?.setOnPreferenceClickListener {\n            val players = VideoClickActionHolder.getPlayers(activity)\n            val prefNames = buildList {\n                add(getString(R.string.player_settings_play_in_app))\n                addAll(players.map { it.name.asStringNull(activity) ?: it.javaClass.simpleName })\n            }\n            val prefValues = buildList {\n                add(\"\")\n                addAll(players.map { it.uniqueId() })\n            }\n            val current =\n                settingsManager.getString(getString(R.string.player_default_key), \"\") ?: \"\"\n\n            activity?.showBottomDialog(\n                prefNames.toList(),\n                prefValues.indexOf(current),\n                getString(R.string.player_pref),\n                true,\n                {}\n            ) {\n                settingsManager.edit {\n                    putString(getString(R.string.player_default_key), prefValues[it])\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.subtitle_settings_key)?.setOnPreferenceClickListener {\n            SubtitlesFragment.push(activity, false)\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.subtitle_settings_chromecast_key)?.setOnPreferenceClickListener {\n            ChromecastSubtitlesFragment.push(activity, false)\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.player_source_priority_key)?.setOnPreferenceClickListener {\n            ioSafe {\n                val defaultSources = QualityProfileDialog.getAllDefaultSources()\n                val activity = activity ?: return@ioSafe\n                activity.runOnUiThread {\n                    QualityProfileDialog(\n                        activity,\n                        R.style.DialogFullscreenPlayer,\n                        defaultSources,\n                    ).show()\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.video_buffer_disk_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.video_buffer_size_names)\n            val prefValues = resources.getIntArray(R.array.video_buffer_size_values)\n\n            val currentPrefSize =\n                settingsManager.getInt(getString(R.string.video_buffer_disk_key), 0)\n\n            activity?.showDialog(\n                prefNames.toList(),\n                prefValues.indexOf(currentPrefSize),\n                getString(R.string.video_buffer_disk_settings),\n                true,\n                {}\n            ) {\n                settingsManager.edit {\n                    putInt(getString(R.string.video_buffer_disk_key), prefValues[it])\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n        getPref(R.string.video_buffer_size_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.video_buffer_size_names)\n            val prefValues = resources.getIntArray(R.array.video_buffer_size_values)\n\n            val currentPrefSize =\n                settingsManager.getInt(getString(R.string.video_buffer_size_key), 0)\n\n            activity?.showDialog(\n                prefNames.toList(),\n                prefValues.indexOf(currentPrefSize),\n                getString(R.string.video_buffer_size_settings),\n                true,\n                {}\n            ) {\n                settingsManager.edit {\n                    putInt(getString(R.string.video_buffer_size_key), prefValues[it])\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.video_buffer_clear_key)?.let { pref ->\n            val cacheDir = context?.cacheDir ?: return@let\n\n            fun updateSummary() {\n                try {\n                    pref.summary = formatShortFileSize(pref.context, getFolderSize(cacheDir))\n                } catch (e: Exception) {\n                    logError(e)\n                }\n            }\n\n            updateSummary()\n\n            pref.setOnPreferenceClickListener {\n                try {\n                    cacheDir.deleteRecursively()\n                    updateSummary()\n                } catch (e: Exception) {\n                    logError(e)\n                }\n                return@setOnPreferenceClickListener true\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\n\nimport android.os.Bundle\nimport android.view.View\nimport androidx.core.content.edit\nimport androidx.navigation.fragment.findNavController\nimport androidx.navigation.NavOptions\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.ui.APIRepository\nimport com.lagradost.cloudstream3.ui.BasePreferenceFragmentCompat\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiDubstatusSettings\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiProviderLangSettings\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.getNameNextToFlagEmoji\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\n\nclass SettingsProviders : BasePreferenceFragmentCompat() {\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        setUpToolbar(R.string.category_providers)\n        setPaddingBottom()\n        setToolBarScrollFlags()\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        hideKeyboard()\n        setPreferencesFromResource(R.xml.settings_providers, rootKey)\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())\n\n        getPref(R.string.display_sub_key)?.setOnPreferenceClickListener {\n            activity?.getApiDubstatusSettings()?.let { current ->\n                val dublist = DubStatus.entries\n                val names = dublist.map { it.name }\n\n                val currentList = ArrayList<Int>()\n                for (i in current) {\n                    currentList.add(dublist.indexOf(i))\n                }\n\n                activity?.showMultiDialog(\n                    names,\n                    currentList,\n                    getString(R.string.display_subbed_dubbed_settings),\n                    {}\n                ) { selectedList ->\n                    APIRepository.dubStatusActive = selectedList.map { dublist[it] }.toHashSet()\n                    settingsManager.edit {\n                        putStringSet(\n                            getString(R.string.display_sub_key),\n                            selectedList.map { names[it] }.toMutableSet()\n                        )\n                    }\n                }\n            }\n\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.test_providers_key)?.setOnPreferenceClickListener {\n            // Somehow animations do not work without this.\n            val options = NavOptions.Builder()\n                .setEnterAnim(R.anim.enter_anim)\n                .setExitAnim(R.anim.exit_anim)\n                .setPopEnterAnim(R.anim.pop_enter)\n                .setPopExitAnim(R.anim.pop_exit)\n                .build()\n\n            this@SettingsProviders.findNavController()\n                .navigate(R.id.navigation_test_providers, null, options)\n            true\n        }\n\n        getPref(R.string.prefer_media_type_key)?.setOnPreferenceClickListener {\n            val names = enumValues<TvType>().sorted().map { it.name }\n            val default =\n                enumValues<TvType>().sorted().filter { it != TvType.NSFW }.map { it.ordinal }\n            val defaultSet = default.map { it.toString() }.toSet()\n            val currentList = try {\n                settingsManager.getStringSet(getString(R.string.prefer_media_type_key), defaultSet)\n                    ?.map {\n                        it.toInt()\n                    }\n            } catch (e: Throwable) {\n                null\n            } ?: default\n\n            activity?.showMultiDialog(\n                names,\n                currentList,\n                getString(R.string.preferred_media_settings),\n                {}\n            ) { selectedList ->\n                settingsManager.edit {\n                    putStringSet(\n                        getString(R.string.prefer_media_type_key),\n                        selectedList.map { it.toString() }.toMutableSet()\n                    )\n                }\n                DataStoreHelper.currentHomePage = null\n                //(context ?: CloudStreamApp.context)?.let { ctx -> app.initClient(ctx) }\n            }\n\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.provider_lang_key)?.setOnPreferenceClickListener {\n            activity?.getApiProviderLangSettings()?.let { currentLangTags ->\n                val languagesTagName = synchronized(APIHolder.apis) {\n                    listOf( Pair(AllLanguagesName, getString(R.string.all_languages_preference)) ) +\n                    APIHolder.apis.map { Pair(it.lang, getNameNextToFlagEmoji(it.lang) ?: it.lang) }\n                        .toSet().sortedBy { it.second.substringAfter(\"\\u00a0\").lowercase() } // name ignoring flag emoji\n                }\n\n                val currentIndexList = currentLangTags.map { langTag ->\n                    languagesTagName.indexOfFirst { lang -> lang.first == langTag }\n                }\n\n                activity?.showMultiDialog(\n                    languagesTagName.map { it.second },\n                    currentIndexList,\n                    getString(R.string.provider_lang_settings),\n                    {}\n                ) { selectedList ->\n                    settingsManager.edit {\n                        putStringSet(\n                            getString(R.string.provider_lang_key),\n                            selectedList.map { languagesTagName[it].first }.toSet()\n                        )\n                    }\n                    // APIRepository.providersActive = it.context.getApiSettings()\n                }\n            }\n\n            return@setOnPreferenceClickListener true\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUI.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\n\nimport android.os.Build\nimport android.os.Bundle\nimport android.view.View\nimport androidx.core.content.edit\nimport androidx.preference.PreferenceManager\nimport androidx.preference.SeekBarPreference\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchQuality\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.BasePreferenceFragmentCompat\nimport com.lagradost.cloudstream3.ui.clear\nimport com.lagradost.cloudstream3.ui.home.HomeChildItemAdapter\nimport com.lagradost.cloudstream3.ui.home.ParentItemAdapter\nimport com.lagradost.cloudstream3.ui.search.SearchAdapter\nimport com.lagradost.cloudstream3.ui.search.SearchResultBuilder\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.updateTv\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.hideOn\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\n\nclass SettingsUI : BasePreferenceFragmentCompat() {\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        setUpToolbar(R.string.category_ui)\n        setPaddingBottom()\n        setToolBarScrollFlags()\n    }\n\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        hideKeyboard()\n        setPreferencesFromResource(R.xml.settings_ui, rootKey)\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())\n\n        (getPref(R.string.overscan_key)?.hideOn(PHONE or EMULATOR) as? SeekBarPreference)?.setOnPreferenceChangeListener { pref, newValue ->\n            val padding = (newValue as? Int)?.toPx ?: return@setOnPreferenceChangeListener true\n            (pref.context.getActivity() as? MainActivity)?.binding?.homeRoot?.setPadding(padding, padding, padding, padding)\n            return@setOnPreferenceChangeListener true\n        }\n\n        getPref(R.string.bottom_title_key)?.setOnPreferenceChangeListener { _, _ ->\n            HomeChildItemAdapter.sharedPool.clear()\n            ParentItemAdapter.sharedPool.clear()\n            SearchAdapter.sharedPool.clear()\n            true\n        }\n\n        getPref(R.string.poster_size_key)?.setOnPreferenceChangeListener { _, newValue ->\n            HomeChildItemAdapter.sharedPool.clear()\n            ParentItemAdapter.sharedPool.clear()\n            SearchAdapter.sharedPool.clear()\n            context?.let { HomeChildItemAdapter.updatePosterSize(it, newValue as? Int) }\n            true\n        }\n\n        getPref(R.string.poster_ui_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.poster_ui_options)\n            val keys = resources.getStringArray(R.array.poster_ui_options_values)\n            val prefValues = keys.map {\n                settingsManager.getBoolean(it, true)\n            }.mapIndexedNotNull { index, b ->\n                if (b) {\n                    index\n                } else null\n            }\n\n            activity?.showMultiDialog(\n                prefNames.toList(),\n                prefValues,\n                getString(R.string.poster_ui_settings),\n                {}\n            ) { list ->\n                settingsManager.edit {\n                    for ((i, key) in keys.withIndex()) {\n                        putBoolean(key, list.contains(i))\n                    }\n                }\n                SearchResultBuilder.updateCache(it.context)\n            }\n\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.app_layout_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.app_layout)\n            val prefValues = resources.getIntArray(R.array.app_layout_values)\n\n            val currentLayout =\n                settingsManager.getInt(getString(R.string.app_layout_key), -1)\n\n            activity?.showBottomDialog(\n                items = prefNames.toList(),\n                selectedIndex = prefValues.indexOf(currentLayout),\n                name = getString(R.string.app_layout),\n                showApply = true,\n                dismissCallback = {},\n                callback = {\n                    try {\n                        settingsManager.edit {\n                            putInt(getString(R.string.app_layout_key), prefValues[it])\n                        }\n                        context?.updateTv()\n                        activity?.recreate()\n                    } catch (e: Exception) {\n                        logError(e)\n                    }\n                }\n            )\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.app_theme_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.themes_names).toMutableList()\n            val prefValues = resources.getStringArray(R.array.themes_names_values).toMutableList()\n            val removeIncompatible = { text: String ->\n                val toRemove = prefValues\n                    .mapIndexed { idx, s -> if (s.startsWith(text)) idx else null }\n                    .filterNotNull()\n                var offset = 0\n                toRemove.forEach { idx ->\n                    prefNames.removeAt(idx - offset)\n                    prefValues.removeAt(idx - offset)\n                    offset += 1\n                }\n            }\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { // remove monet on android 11 and less\n                removeIncompatible(\"Monet\")\n            }\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { // Remove system on android 9 and less\n                removeIncompatible(\"System\")\n            }\n\n            val currentLayout =\n                settingsManager.getString(getString(R.string.app_theme_key), prefValues.first())\n\n            activity?.showBottomDialog(\n                prefNames.toList(),\n                prefValues.indexOf(currentLayout),\n                getString(R.string.app_theme_settings),\n                true,\n                {}\n            ) {\n                try {\n                    settingsManager.edit {\n                        putString(getString(R.string.app_theme_key), prefValues[it])\n                    }\n                    activity?.recreate()\n                } catch (e: Exception) {\n                    logError(e)\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n        getPref(R.string.primary_color_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.themes_overlay_names).toMutableList()\n            val prefValues =\n                resources.getStringArray(R.array.themes_overlay_names_values).toMutableList()\n\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { // remove monet on android 11 and less\n                val toRemove = prefValues\n                    .mapIndexed { idx, s -> if (s.startsWith(\"Monet\")) idx else null }\n                    .filterNotNull()\n                var offset = 0\n                toRemove.forEach { idx ->\n                    prefNames.removeAt(idx - offset)\n                    prefValues.removeAt(idx - offset)\n                    offset += 1\n                }\n            }\n\n            val currentLayout =\n                settingsManager.getString(getString(R.string.primary_color_key), prefValues.first())\n\n            activity?.showDialog(\n                prefNames.toList(),\n                prefValues.indexOf(currentLayout),\n                getString(R.string.primary_color_settings),\n                true,\n                {}\n            ) {\n                try {\n                    settingsManager.edit {\n                        putString(getString(R.string.primary_color_key), prefValues[it])\n                    }\n                    activity?.recreate()\n                } catch (e: Exception) {\n                    logError(e)\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.pref_filter_search_quality_key)?.setOnPreferenceClickListener {\n            val names = enumValues<SearchQuality>().sorted().map { it.name }\n            val currentList = settingsManager.getStringSet(\n                getString(R.string.pref_filter_search_quality_key),\n                setOf()\n            )?.map {\n                it.toInt()\n            } ?: listOf()\n\n            activity?.showMultiDialog(\n                names,\n                currentList,\n                getString(R.string.pref_filter_search_quality),\n                {}\n            ) { selectedList ->\n                settingsManager.edit {\n                    putStringSet(\n                        getString(R.string.pref_filter_search_quality_key),\n                        selectedList.map { it.toString() }.toMutableSet()\n                    )\n                }\n            }\n\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.confirm_exit_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.confirm_exit)\n            val prefValues = resources.getIntArray(R.array.confirm_exit_values)\n            val confirmExit = settingsManager.getInt(getString(R.string.confirm_exit_key), -1)\n\n            activity?.showBottomDialog(\n                items = prefNames.toList(),\n                selectedIndex = prefValues.indexOf(confirmExit),\n                name = getString(R.string.confirm_before_exiting_title),\n                showApply = true,\n                dismissCallback = {},\n                callback = { selectedOption ->\n                    settingsManager.edit {\n                        putInt(getString(R.string.confirm_exit_key), prefValues[selectedOption])\n                    }\n                }\n            )\n            return@setOnPreferenceClickListener true\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings\n\nimport android.net.Uri\nimport android.os.Bundle\nimport android.view.View\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.edit\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.PreferenceManager\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport com.lagradost.cloudstream3.AutoDownloadMode\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.CloudStreamApp\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.databinding.LogcatBinding\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.network.initClient\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.services.BackupWorkManager\nimport com.lagradost.cloudstream3.ui.BasePreferenceFragmentCompat\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.hideOn\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setPaddingBottom\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar\nimport com.lagradost.cloudstream3.ui.settings.utils.getChooseFolderLauncher\nimport com.lagradost.cloudstream3.utils.BackupUtils\nimport com.lagradost.cloudstream3.utils.BackupUtils.restorePrompt\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.InAppUpdater.installPreReleaseIfNeeded\nimport com.lagradost.cloudstream3.utils.InAppUpdater.runAutoUpdate\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog\nimport com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager\nimport com.lagradost.cloudstream3.utils.txt\nimport java.io.BufferedReader\nimport java.io.InputStreamReader\nimport java.io.OutputStream\nimport java.lang.System.currentTimeMillis\nimport java.text.SimpleDateFormat\nimport java.util.Date\nimport java.util.Locale\n\nclass SettingsUpdates : BasePreferenceFragmentCompat() {\n    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        setUpToolbar(R.string.category_updates)\n        setPaddingBottom()\n        setToolBarScrollFlags()\n    }\n\n    private val pathPicker = getChooseFolderLauncher { uri, path ->\n        val context = context ?: CloudStreamApp.context ?: return@getChooseFolderLauncher\n        (path ?: uri.toString()).let {\n            PreferenceManager.getDefaultSharedPreferences(context).edit {\n                putString(getString(R.string.backup_path_key), uri.toString())\n                putString(getString(R.string.backup_dir_key), it)\n            }\n        }\n    }\n\n    @Suppress(\"DEPRECATION_ERROR\")\n    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {\n        hideKeyboard()\n        setPreferencesFromResource(R.xml.settings_updates, rootKey)\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())\n\n        getPref(R.string.backup_key)?.setOnPreferenceClickListener {\n            BackupUtils.backup(activity)\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.automatic_backup_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.periodic_work_names)\n            val prefValues = resources.getIntArray(R.array.periodic_work_values)\n            val current = settingsManager.getInt(getString(R.string.automatic_backup_key), 0)\n\n            activity?.showDialog(\n                prefNames.toList(),\n                prefValues.indexOf(current),\n                getString(R.string.backup_frequency),\n                true,\n                {}\n            ) { index ->\n                settingsManager.edit {\n                    putInt(getString(R.string.automatic_backup_key), prefValues[index])\n                }\n                BackupWorkManager.enqueuePeriodicWork(\n                    context ?: CloudStreamApp.context,\n                    prefValues[index].toLong()\n                )\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.redo_setup_key)?.setOnPreferenceClickListener {\n            findNavController().navigate(R.id.navigation_setup_language)\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.restore_key)?.setOnPreferenceClickListener {\n            activity?.restorePrompt()\n            return@setOnPreferenceClickListener true\n        }\n        getPref(R.string.backup_path_key)?.hideOn(EMULATOR)?.setOnPreferenceClickListener {\n            val dirs = getBackupDirsForDisplay()\n            val currentDir =\n                settingsManager.getString(getString(R.string.backup_dir_key), null)\n                    ?: context?.let { ctx -> BackupUtils.getDefaultBackupDir(ctx)?.filePath() }\n\n            activity?.showBottomDialog(\n                dirs + listOf(getString(R.string.custom)),\n                dirs.indexOf(currentDir),\n                getString(R.string.backup_path_title),\n                true,\n                {}\n            ) {\n                // Last = custom\n                if (it == dirs.size) {\n                    try {\n                        pathPicker.launch(Uri.EMPTY)\n                    } catch (e: Exception) {\n                        logError(e)\n                    }\n                } else {\n                    // Sets both visual and actual paths.\n                    // path = used uri\n                    // dir = dir path\n                    settingsManager.edit {\n                        putString(getString(R.string.backup_path_key), dirs[it])\n                        putString(getString(R.string.backup_dir_key), dirs[it])\n                    }\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.show_logcat_key)?.setOnPreferenceClickListener { pref ->\n            val builder = AlertDialog.Builder(pref.context, R.style.AlertDialogCustom)\n\n            val binding = LogcatBinding.inflate(layoutInflater, null, false)\n            builder.setView(binding.root)\n\n            val dialog = builder.create()\n            dialog.show()\n\n            val logList = mutableListOf<String>()\n            try {\n                // https://developer.android.com/studio/command-line/logcat\n                val process = Runtime.getRuntime().exec(\"logcat -d\")\n                val bufferedReader = BufferedReader(InputStreamReader(process.inputStream))\n                bufferedReader.lineSequence().forEach { logList.add(it) }\n            } catch (e: Exception) {\n                logError(e) // kinda ironic\n            }\n\n            val adapter = LogcatAdapter().apply { submitList(logList) }\n            binding.logcatRecyclerView.layoutManager = LinearLayoutManager(pref.context)\n            binding.logcatRecyclerView.adapter = adapter\n\n            binding.copyBtt.setOnClickListener {\n                clipboardHelper(txt(\"Logcat\"), logList.joinToString(\"\\n\"))\n                dialog.dismissSafe(activity)\n            }\n\n            binding.clearBtt.setOnClickListener {\n                Runtime.getRuntime().exec(\"logcat -c\")\n                dialog.dismissSafe(activity)\n            }\n\n            binding.saveBtt.setOnClickListener {\n                val date = SimpleDateFormat(\"yyyy_MM_dd_HH_mm\", Locale.getDefault()).format(Date(currentTimeMillis()))\n                var fileStream: OutputStream? = null\n                try {\n                    fileStream = VideoDownloadManager.setupStream(\n                        it.context,\n                        \"logcat_${date}\",\n                        null,\n                        \"txt\",\n                        false\n                    ).openNew()\n                    fileStream.writer().use { writer -> writer.write(logList.joinToString(\"\\n\")) }\n                    dialog.dismissSafe(activity)\n                } catch (t: Throwable) {\n                    logError(t)\n                    showToast(t.message)\n                }\n            }\n\n            binding.closeBtt.setOnClickListener {\n                dialog.dismissSafe(activity)\n            }\n\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.apk_installer_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.apk_installer_pref)\n            val prefValues = resources.getIntArray(R.array.apk_installer_values)\n\n            val currentInstaller =\n                settingsManager.getInt(getString(R.string.apk_installer_key), 0)\n\n            activity?.showBottomDialog(\n                prefNames.toList(),\n                prefValues.indexOf(currentInstaller),\n                getString(R.string.apk_installer_settings),\n                true,\n                {}\n            ) { num ->\n                try {\n                    settingsManager.edit {\n                        putInt(getString(R.string.apk_installer_key), prefValues[num])\n                    }\n                } catch (e: Exception) {\n                    logError(e)\n                }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.manual_check_update_key)?.let { pref ->\n            pref.summary = BuildConfig.VERSION_NAME\n            pref.setOnPreferenceClickListener {\n                ioSafe {\n                    if (activity?.runAutoUpdate(false) == false) {\n                        activity?.runOnUiThread {\n                            showToast(\n                                R.string.no_update_found,\n                                Toast.LENGTH_SHORT\n                            )\n                        }\n                    }\n                }\n                return@setOnPreferenceClickListener true\n            }\n        }\n        \n        getPref(R.string.install_prerelease_key)?.let { pref ->\n            pref.isVisible = BuildConfig.FLAVOR == \"stable\"\n            pref.setOnPreferenceClickListener {\n                activity?.installPreReleaseIfNeeded()\n                return@setOnPreferenceClickListener true\n            }\n        }\n\n        getPref(R.string.auto_download_plugins_key)?.setOnPreferenceClickListener {\n            val prefNames = resources.getStringArray(R.array.auto_download_plugin)\n            val prefValues =\n                enumValues<AutoDownloadMode>().sortedBy { x -> x.value }.map { x -> x.value }\n\n            val current = settingsManager.getInt(getString(R.string.auto_download_plugins_key), 0)\n\n            activity?.showBottomDialog(\n                prefNames.toList(),\n                prefValues.indexOf(current),\n                getString(R.string.automatic_plugin_download_mode_title),\n                true,\n                {}\n            ) { num ->\n                settingsManager.edit {\n                    putInt(getString(R.string.auto_download_plugins_key), prefValues[num])\n                }\n                (context ?: CloudStreamApp.context)?.let { ctx -> app.initClient(ctx) }\n            }\n            return@setOnPreferenceClickListener true\n        }\n\n        getPref(R.string.manual_update_plugins_key)?.setOnPreferenceClickListener {\n            ioSafe {\n                PluginManager.___DO_NOT_CALL_FROM_A_PLUGIN_manuallyReloadAndUpdatePlugins(activity ?: return@ioSafe)\n            }\n            return@setOnPreferenceClickListener true // Return true for the listener\n        }\n    }\n\n    private fun getBackupDirsForDisplay(): List<String> {\n        return safe {\n            context?.let { ctx ->\n                val defaultDir = BackupUtils.getDefaultBackupDir(ctx)?.filePath()\n                val first = listOf(defaultDir)\n                (runCatching {\n                    first + BackupUtils.getCurrentBackupDir(ctx).let {\n                                it.first?.filePath() ?: it.second\n                            }\n                }.getOrNull() ?: first).filterNotNull().distinct()\n            }\n        } ?: emptyList()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.extensions\n\nimport android.content.ClipboardManager\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.os.Build\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.widget.LinearLayout\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.core.view.marginBottom\nimport androidx.core.view.marginTop\nimport androidx.fragment.app.activityViewModels\nimport androidx.navigation.fragment.findNavController\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.AddRepoInputBinding\nimport com.lagradost.cloudstream3.databinding.FragmentExtensionsBinding\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.mvvm.observeNullable\nimport com.lagradost.cloudstream3.plugins.RepositoryManager\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.result.FOCUS_SELF\nimport com.lagradost.cloudstream3.ui.result.setLinearListLayout\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setSystemBarsPadding\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar\nimport com.lagradost.cloudstream3.utils.AppContextUtils.addRepositoryDialog\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.setText\n\nclass ExtensionsFragment : BaseFragment<FragmentExtensionsBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentExtensionsBinding::inflate)\n) {\n\n    private val extensionViewModel: ExtensionsViewModel by activityViewModels()\n\n    private fun View.setLayoutWidth(weight: Int) {\n        val param = LinearLayout.LayoutParams(\n            0,\n            LinearLayout.LayoutParams.MATCH_PARENT,\n            weight.toFloat()\n        )\n        this.layoutParams = param\n    }\n\n    override fun onResume() {\n        super.onResume()\n        afterRepositoryLoadedEvent += ::reloadRepositories\n    }\n\n    override fun onStop() {\n        super.onStop()\n        afterRepositoryLoadedEvent -= ::reloadRepositories\n    }\n\n    private fun reloadRepositories(success: Boolean = true) {\n        extensionViewModel.loadStats()\n        extensionViewModel.loadRepositories()\n    }\n\n    override fun fixLayout(view: View) {\n        setSystemBarsPadding()\n    }\n\n    override fun onBindingCreated(binding: FragmentExtensionsBinding) {\n        setUpToolbar(R.string.extensions)\n        setToolBarScrollFlags()\n\n        binding.repoRecyclerView.apply {\n            setLinearListLayout(\n                isHorizontal = false,\n                nextUp = R.id.settings_toolbar, // FOCUS_SELF, // back has no id so we cant :pensive:\n                nextDown = R.id.plugin_storage_appbar,\n                nextRight = FOCUS_SELF,\n                nextLeft = R.id.nav_rail_view\n            )\n\n            if (!isLayout(TV))\n                binding.addRepoButton.let { button ->\n                    button.post {\n                        setPadding(\n                            paddingLeft,\n                            paddingTop,\n                            paddingRight,\n                            button.measuredHeight + button.marginTop + button.marginBottom\n                        )\n                    }\n                }\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                setOnScrollChangeListener { _, _, scrollY, _, oldScrollY ->\n                    val dy = scrollY - oldScrollY\n                    if (dy > 0) { // check for scroll down\n                        binding.addRepoButton.shrink() // hide\n                    } else if (dy < -5) {\n                        binding.addRepoButton.extend() // show\n                    }\n                }\n            }\n            adapter = RepoAdapter(false, {\n                findNavController().navigate(\n                    R.id.navigation_settings_extensions_to_navigation_settings_plugins,\n                    PluginsFragment.newInstance(\n                        it.name,\n                        it.url,\n                        false\n                    )\n                )\n            }, { repo ->\n                // Prompt user before deleting repo\n                main {\n                    val builder = AlertDialog.Builder(context ?: binding.root.context)\n                    val dialogClickListener =\n                        DialogInterface.OnClickListener { _, which ->\n                            when (which) {\n                                DialogInterface.BUTTON_POSITIVE -> {\n                                    ioSafe {\n                                        RepositoryManager.removeRepository(binding.root.context, repo)\n                                        extensionViewModel.loadStats()\n                                        extensionViewModel.loadRepositories()\n                                    }\n                                }\n\n                                DialogInterface.BUTTON_NEGATIVE -> {}\n                            }\n                        }\n\n                    builder.setTitle(R.string.delete_repository)\n                        .setMessage(\n                            context?.getString(R.string.delete_repository_plugins)\n                        )\n                        .setPositiveButton(R.string.delete, dialogClickListener)\n                        .setNegativeButton(R.string.cancel, dialogClickListener)\n                        .show().setDefaultFocus()\n                }\n            })\n        }\n\n        observe(extensionViewModel.repositories) {\n            binding.repoRecyclerView.isVisible = it.isNotEmpty()\n            binding.blankRepoScreen.isVisible = it.isEmpty()\n            (binding.repoRecyclerView.adapter as? RepoAdapter)?.submitList(it.toList())\n        }\n\n        observeNullable(extensionViewModel.pluginStats) { value ->\n            binding.apply {\n                if (value == null) {\n                    pluginStorageAppbar.isVisible = false\n                    return@observeNullable\n                }\n\n                pluginStorageAppbar.isVisible = true\n                if (value.total == 0) {\n                    pluginDownload.setLayoutWidth(1)\n                    pluginDisabled.setLayoutWidth(0)\n                    pluginNotDownloaded.setLayoutWidth(0)\n                } else {\n                    pluginDownload.setLayoutWidth(value.downloaded)\n                    pluginDisabled.setLayoutWidth(value.disabled)\n                    pluginNotDownloaded.setLayoutWidth(value.notDownloaded)\n                }\n                pluginNotDownloadedTxt.setText(value.notDownloadedText)\n                pluginDisabledTxt.setText(value.disabledText)\n                pluginDownloadTxt.setText(value.downloadedText)\n            }\n        }\n\n        binding.pluginStorageAppbar.setOnClickListener {\n            findNavController().navigate(\n                R.id.navigation_settings_extensions_to_navigation_settings_plugins,\n                PluginsFragment.newInstance(\n                    getString(R.string.extensions),\n                    \"\",\n                    true\n                )\n            )\n        }\n\n        val addRepositoryClick = View.OnClickListener {\n            val ctx = context ?: return@OnClickListener\n            val binding = AddRepoInputBinding.inflate(LayoutInflater.from(ctx), null, false)\n            val builder =\n                AlertDialog.Builder(ctx, R.style.AlertDialogCustom)\n                    .setView(binding.root)\n\n            val dialog = builder.create()\n            dialog.show()\n            (activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager)?.primaryClip?.getItemAt(\n                0\n            )?.text?.toString()?.let { copiedText ->\n                if (copiedText.contains(RepoAdapter.SHAREABLE_REPO_SEPARATOR)) {\n                    // text is of format <repository name> : <repository url>\n                    val (name, url) = copiedText.split(RepoAdapter.SHAREABLE_REPO_SEPARATOR, limit = 2)\n                    binding.repoUrlInput.setText(url.trim())\n                    binding.repoNameInput.setText(name.trim())\n                } else {\n                    binding.repoUrlInput.setText(copiedText)\n                }\n            }\n\n            binding.applyBtt.setOnClickListener secondListener@{\n                val name = binding.repoNameInput.text?.toString()\n                ioSafe {\n                    val url = binding.repoUrlInput.text?.toString()\n                        ?.let { it1 -> RepositoryManager.parseRepoUrl(it1) }\n                    if (url.isNullOrBlank()) {\n                        main {\n                            showToast(R.string.error_invalid_data, Toast.LENGTH_SHORT)\n                        }\n                    } else {\n                        val repository = RepositoryManager.parseRepository(url)\n\n                        // Exit if wrong repository\n                        if (repository == null) {\n                            showToast(R.string.no_repository_found_error, Toast.LENGTH_LONG)\n                            return@ioSafe\n                        }\n\n                        val fixedName = if (!name.isNullOrBlank()) name\n                        else repository.name\n                        val newRepo = RepositoryData(repository.iconUrl,fixedName, url)\n                        RepositoryManager.addRepository(newRepo)\n                        extensionViewModel.loadStats()\n                        extensionViewModel.loadRepositories()\n\n                        val plugins = RepositoryManager.getRepoPlugins(url)\n                        if (plugins.isNullOrEmpty()) {\n                            showToast(R.string.no_plugins_found_error, Toast.LENGTH_LONG)\n                        } else {\n                            this@ExtensionsFragment.activity?.addRepositoryDialog(\n                                fixedName,\n                                url,\n                            )\n                        }\n                    }\n                }\n                dialog.dismissSafe(activity)\n            }\n            binding.cancelBtt.setOnClickListener {\n                dialog.dismissSafe(activity)\n            }\n        }\n\n        val isTv = isLayout(TV)\n        binding.apply {\n            addRepoButton.isGone = isTv\n            addRepoButtonImageviewHolder.isVisible = isTv\n\n            // Band-aid for Fire TV\n            pluginStorageAppbar.isFocusableInTouchMode = isTv\n            addRepoButtonImageview.isFocusableInTouchMode = isTv\n\n            addRepoButton.setOnClickListener(addRepositoryClick)\n            addRepoButtonImageview.setOnClickListener(addRepositoryClick)\n        }\n        reloadRepositories()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.extensions\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.mvvm.debugAssert\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.plugins.PluginManager.getPluginsOnline\nimport com.lagradost.cloudstream3.plugins.RepositoryManager\nimport com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES\nimport com.lagradost.cloudstream3.utils.UiText\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\n\ndata class RepositoryData(\n    @JsonProperty(\"iconUrl\") val iconUrl: String?,\n    @JsonProperty(\"name\") val name: String,\n    @JsonProperty(\"url\") val url: String\n){\n    constructor(name: String,url: String):this(null,name,url)\n}\n\nconst val REPOSITORIES_KEY = \"REPOSITORIES_KEY\"\n\nclass ExtensionsViewModel : ViewModel() {\n    data class PluginStats(\n        val total: Int,\n\n        val downloaded: Int,\n        val disabled: Int,\n        val notDownloaded: Int,\n\n        val downloadedText: UiText,\n        val disabledText: UiText,\n        val notDownloadedText: UiText,\n    )\n\n    private val _repositories = MutableLiveData<Array<RepositoryData>>()\n    val repositories: LiveData<Array<RepositoryData>> = _repositories\n\n    private val _pluginStats: MutableLiveData<PluginStats?> = MutableLiveData(null)\n    val pluginStats: LiveData<PluginStats?> = _pluginStats\n\n    //TODO CACHE GET REQUESTS\n    // DO not use viewModelScope.launchSafe, it will ANR on slow internet\n    fun loadStats() = ioSafe {\n        val urls = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY)\n            ?: emptyArray()) + PREBUILT_REPOSITORIES\n\n        val onlinePlugins = urls.toList().amap {\n            RepositoryManager.getRepoPlugins(it.url)?.toList() ?: emptyList()\n        }.flatten().distinctBy { it.second.url }\n\n        // Iterates over all offline plugins, compares to remote repo and returns the plugins which are outdated\n        val outdatedPlugins = getPluginsOnline().map { savedData ->\n            onlinePlugins.filter { onlineData -> savedData.internalName == onlineData.second.internalName }\n                .map { onlineData ->\n                    PluginManager.OnlinePluginData(savedData, onlineData)\n                }\n        }.flatten().distinctBy { it.onlineData.second.url }\n\n        val total = onlinePlugins.count()\n        val disabled = outdatedPlugins.count { it.isDisabled }\n        val downloadedTotal = outdatedPlugins.count()\n        val downloaded = downloadedTotal - disabled\n        val notDownloaded = total - downloadedTotal\n        val stats = PluginStats(\n            total,\n            downloaded,\n            disabled,\n            notDownloaded,\n            txt(R.string.plugins_downloaded, downloaded),\n            txt(R.string.plugins_disabled, disabled),\n            txt(R.string.plugins_not_downloaded, notDownloaded)\n        )\n        debugAssert({ stats.downloaded + stats.notDownloaded + stats.disabled != stats.total }) {\n            \"downloaded(${stats.downloaded}) + notDownloaded(${stats.notDownloaded}) + disabled(${stats.disabled}) != total(${stats.total})\"\n        }\n        _pluginStats.postValue(stats)\n    }\n\n    private fun repos() = (getKey<Array<RepositoryData>>(REPOSITORIES_KEY)\n        ?: emptyArray()) + PREBUILT_REPOSITORIES\n\n    fun loadRepositories() {\n        val urls = repos()\n        _repositories.postValue(urls)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.extensions\n\nimport android.annotation.SuppressLint\nimport android.text.format.Formatter.formatShortFileSize\nimport android.util.Log\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.viewbinding.ViewBinding\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity\nimport com.lagradost.cloudstream3.PROVIDER_STATUS_DOWN\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.databinding.RepositoryItemBinding\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.newSharedPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.getNameNextToFlagEmoji\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\nimport com.lagradost.cloudstream3.utils.getImageFromDrawable\nimport com.lagradost.cloudstream3.utils.setText\nimport com.lagradost.cloudstream3.utils.txt\nimport java.text.DecimalFormat\nimport kotlin.math.floor\nimport kotlin.math.log10\nimport kotlin.math.pow\n\ndata class PluginViewData(\n    val plugin: Plugin,\n    val isDownloaded: Boolean,\n)\n\nclass RepositoryViewHolderState(view: ViewBinding) : ViewHolderState<Any>(view) {\n    // Store how many times this has called recycled, this is used to correctly sync text in jobs\n    var recycleCount = 0\n}\n\nclass PluginAdapter(\n    val iconClickCallback: (Plugin) -> Unit\n) : NoStateAdapter<PluginViewData>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n    a.plugin.second.internalName == b.plugin.second.internalName && a.plugin.first == b.plugin.first\n})) {\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        val layout = if (isLayout(TV)) R.layout.repository_item_tv else R.layout.repository_item\n        val inflated = LayoutInflater.from(parent.context).inflate(layout, parent, false)\n\n        return RepositoryViewHolderState(\n            RepositoryItemBinding.bind(inflated) // may crash\n        )\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        if (holder is RepositoryViewHolderState) {\n            holder.recycleCount += 1\n        }\n        when (val binding = holder.view) {\n            is RepositoryItemBinding -> {\n                clearImage(binding.entryIcon)\n            }\n        }\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    override fun onBindContent(holder: ViewHolderState<Any>, item: PluginViewData, position: Int) {\n        val binding = holder.view as? RepositoryItemBinding ?: return\n        val itemView = holder.itemView\n\n        val metadata = item.plugin.second\n        val disabled = metadata.status == PROVIDER_STATUS_DOWN\n        val name = metadata.name.removeSuffix(\"Provider\")\n        val alpha = if (disabled) 0.6f else 1f\n        val isLocal = !item.plugin.second.url.startsWith(\"http\")\n        binding.mainText.alpha = alpha\n        binding.subText.alpha = alpha\n\n        val drawableInt = if (item.isDownloaded)\n            R.drawable.ic_baseline_delete_outline_24\n        else R.drawable.netflix_download\n\n        binding.nsfwMarker.isVisible = metadata.tvTypes?.contains(TvType.NSFW.name) ?: false\n        binding.actionButton.setImageResource(drawableInt)\n\n        binding.actionButton.setOnClickListener {\n            iconClickCallback.invoke(item.plugin)\n        }\n        itemView.setOnClickListener {\n            if (isLocal) return@setOnClickListener\n\n            val sheet = PluginDetailsFragment(item)\n            val activity = itemView.context.getActivity() as AppCompatActivity\n            sheet.show(activity.supportFragmentManager, \"PluginDetails\")\n        }\n        //if (itemView.context?.isTrueTvSettings() == false) {\n        //    val siteUrl = metadata.repositoryUrl\n        //    if (siteUrl != null && siteUrl.isNotBlank() && siteUrl != \"NONE\") {\n        //        itemView.setOnClickListener {\n        //            openBrowser(siteUrl)\n        //        }\n        //    }\n        //}\n\n        if (item.isDownloaded) {\n            // On local plugins page the filepath is provided instead of url.\n            val plugin =\n                (PluginManager.urlPlugins[metadata.url]\n                    ?: (PluginManager.plugins[metadata.url])) as? com.lagradost.cloudstream3.plugins.Plugin\n\n            if (plugin?.openSettings != null) {\n                binding.actionSettings.isVisible = true\n                binding.actionSettings.setOnClickListener {\n                    try {\n                        plugin.openSettings?.invoke(itemView.context)\n                    } catch (e: Throwable) {\n                        Log.e(\n                            \"PluginAdapter\",\n                            \"Failed to open $name settings: ${\n                                Log.getStackTraceString(e)\n                            }\"\n                        )\n                    }\n                }\n            } else {\n                binding.actionSettings.isVisible = false\n            }\n        } else {\n            binding.actionSettings.isVisible = false\n        }\n\n        val url = metadata.iconUrl?.replace(\n            \"%size%\",\n            \"$iconSize\"\n        )?.replace(\n            \"%exact_size%\",\n            \"$iconSizeExact\"\n        )\n\n        if (url.isNullOrBlank()) {\n            binding.entryIcon.loadImage(R.drawable.ic_baseline_extension_24)\n        } else {\n            binding.entryIcon.loadImage(\n                url\n            ) { error(getImageFromDrawable(itemView.context, R.drawable.ic_baseline_extension_24)) }\n        }\n\n        binding.extVersion.isVisible = true\n        binding.extVersion.text = \"v${metadata.version}\"\n\n        if (metadata.language.isNullOrBlank()) {\n            binding.langIcon.isVisible = false\n        } else {\n            binding.langIcon.isVisible = true\n            binding.langIcon.text = getNameNextToFlagEmoji(metadata.language) ?: metadata.language\n        }\n\n        //val oldRecycleCount = (holder as? RepositoryViewHolderState)?.recycleCount\n\n        binding.extVotes.isVisible = false\n\n        // Disable this for now as the vote api is down, this will also significantly improve the lag\n        // from doing all these network requests\n        /*if (!isLocal) {\n            ioSafe {\n                metadata.getVotes().main { votes ->\n                    val currentRecycleCount = (holder as? RepositoryViewHolderState)?.recycleCount\n\n                    // Only set the text if the view is correctly rendered\n                    if (currentRecycleCount == oldRecycleCount) {\n                        binding.extVotes.setText(txt(R.string.extension_rating, prettyCount(votes)))\n                        binding.extVotes.isVisible = true\n                    }\n                }\n            }\n        }*/\n\n        if (metadata.fileSize != null) {\n            binding.extFilesize.isVisible = true\n            binding.extFilesize.text = formatShortFileSize(itemView.context, metadata.fileSize)\n        } else {\n            binding.extFilesize.isVisible = false\n        }\n\n        binding.mainText.setText(\n            if (disabled) txt(\n                R.string.single_plugin_disabled,\n                name\n            ) else txt(name)\n        )\n\n        binding.subText.isGone = metadata.description.isNullOrBlank()\n        binding.subText.text = metadata.description.html()\n    }\n\n    companion object {\n        // A high count as we can render in the entire list as the same time\n        val sharedPool =\n            newSharedPool { setMaxRecycledViews(CONTENT, 15) }\n\n        private tailrec fun findClosestBase2(target: Int, current: Int = 16, max: Int = 512): Int {\n            if (current >= max) return max\n            if (current >= target) return current\n            return findClosestBase2(target, current * 2, max)\n        }\n\n        // DO NOT MOVE, as running this test will result in ExceptionInInitializerError on prerelease due to static variables using Resources.getSystem()\n        // this test function is only to show how the function works\n        /*@Test\n        fun testFindClosestBase2() {\n            Assert.assertEquals(16, findClosestBase2(0))\n            Assert.assertEquals(256, findClosestBase2(170))\n            Assert.assertEquals(256, findClosestBase2(256))\n            Assert.assertEquals(512, findClosestBase2(257))\n            Assert.assertEquals(512, findClosestBase2(700))\n        }*/\n\n        private val iconSizeExact = 32.toPx\n        private val iconSize by lazy {\n            findClosestBase2(iconSizeExact, 16, 512)\n        }\n\n        fun prettyCount(number: Number): String? {\n            val suffix = charArrayOf(' ', 'k', 'M', 'B', 'T', 'P', 'E')\n            val numValue = number.toLong()\n            val value = floor(log10(numValue.toDouble())).toInt()\n            val base = value / 3\n            return if (value >= 3 && base < suffix.size) {\n                DecimalFormat(\"#0.00\").format(\n                    numValue / 10.0.pow((base * 3).toDouble())\n                ) + suffix[base]\n            } else {\n                DecimalFormat().format(numValue)\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginDetailsFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.extensions\n\nimport android.content.res.ColorStateList\nimport android.text.format.Formatter.formatFileSize\nimport android.util.Log\nimport android.view.View\nimport androidx.core.view.isVisible\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser\nimport com.lagradost.cloudstream3.databinding.FragmentPluginDetailsBinding\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.plugins.VotingApi.canVote\nimport com.lagradost.cloudstream3.plugins.VotingApi.getVotes\nimport com.lagradost.cloudstream3.plugins.VotingApi.hasVoted\nimport com.lagradost.cloudstream3.plugins.VotingApi.vote\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.BaseBottomSheetDialogFragment\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.getImageFromDrawable\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.getNameNextToFlagEmoji\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\n\nclass PluginDetailsFragment(val data: PluginViewData) : BaseBottomSheetDialogFragment<FragmentPluginDetailsBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentPluginDetailsBinding::inflate)\n) {\n\n    companion object {\n        private tailrec fun findClosestBase2(target: Int, current: Int = 16, max: Int = 512): Int {\n            if (current >= max) return max\n            if (current >= target) return current\n            return findClosestBase2(target, current * 2, max)\n        }\n\n        private val iconSizeExact = 50.toPx\n        private val iconSize by lazy {\n            findClosestBase2(iconSizeExact, 16, 512)\n        }\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padBottom = isLandscape(),\n            padLeft = isLayout(TV or EMULATOR)\n        )\n    }\n\n    override fun onBindingCreated(binding: FragmentPluginDetailsBinding) {\n        val metadata = data.plugin.second\n        binding.apply {\n            pluginIcon.loadImage(metadata.iconUrl?.replace(\"%size%\", \"$iconSize\")\n                ?.replace(\"%exact_size%\", \"$iconSizeExact\")) {\n                error { getImageFromDrawable(context ?: return@error null , R.drawable.ic_baseline_extension_24) }\n            }\n            pluginName.text = metadata.name.removeSuffix(\"Provider\")\n            pluginVersion.text = metadata.version.toString()\n            pluginDescription.text = metadata.description ?: getString(R.string.no_data)\n            pluginSize.text =\n                if (metadata.fileSize == null) getString(R.string.no_data) else formatFileSize(\n                    context,\n                    metadata.fileSize\n                )\n            pluginAuthor.text =\n                if (metadata.authors.isEmpty()) getString(R.string.no_data) else metadata.authors.joinToString(\n                    \", \"\n                )\n            pluginStatus.text =\n                resources.getStringArray(R.array.extension_statuses)[metadata.status]\n            pluginTypes.text =\n                if (metadata.tvTypes.isNullOrEmpty()) getString(R.string.no_data) else metadata.tvTypes.joinToString(\n                    \", \"\n                )\n            pluginLang.text = if (metadata.language == null)\n                    getString(R.string.no_data)\n                else\n                    getNameNextToFlagEmoji(metadata.language) ?: metadata.language\n\n            githubBtn.setOnClickListener {\n                if (metadata.repositoryUrl != null) {\n                    openBrowser(metadata.repositoryUrl)\n                }\n            }\n\n            if (!metadata.canVote()) {\n                upvote.alpha = .6f\n            }\n\n            if (data.isDownloaded) {\n                // On local plugins page the filepath is provided instead of url.\n                val plugin =\n                    (PluginManager.urlPlugins[metadata.url] ?: PluginManager.plugins[metadata.url]) as? com.lagradost.cloudstream3.plugins.Plugin\n                if (plugin?.openSettings != null && context != null) {\n                    actionSettings.isVisible = true\n                    actionSettings.setOnClickListener {\n                        try {\n                            plugin.openSettings!!.invoke(requireContext())\n                        } catch (e: Throwable) {\n                            Log.e(\n                                \"PluginAdapter\",\n                                \"Failed to open ${metadata.name} settings: ${\n                                    Log.getStackTraceString(e)\n                                }\"\n                            )\n                        }\n                    }\n                } else {\n                    actionSettings.isVisible = false\n                }\n            } else {\n                actionSettings.isVisible = false\n            }\n\n            upvote.setOnClickListener {\n                ioSafe {\n                    metadata.vote().main {\n                        updateVoting(it)\n                    }\n                }\n            }\n\n            ioSafe {\n                metadata.getVotes().main {\n                    updateVoting(it)\n                }\n            }\n        }\n    }\n\n    private fun updateVoting(value: Int) {\n        val metadata = data.plugin.second\n        binding?.apply {\n            pluginVotes.text = value.toString()\n            if (metadata.hasVoted()) {\n                upvote.imageTintList = ColorStateList.valueOf(\n                    context?.colorFromAttribute(R.attr.colorPrimary) ?: R.color.colorPrimary\n                )\n            } else {\n                upvote.imageTintList = ColorStateList.valueOf(\n                    context?.colorFromAttribute(com.google.android.material.R.attr.colorOnSurface) ?: R.color.white\n                )\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginsFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.extensions\n\nimport android.os.Bundle\nimport android.view.View\nimport androidx.appcompat.widget.SearchView\nimport androidx.core.view.isVisible\nimport androidx.fragment.app.activityViewModels\nimport com.lagradost.cloudstream3.AllLanguagesName\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.databinding.FragmentPluginsBinding\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.home.HomeFragment.Companion.bindChips\nimport com.lagradost.cloudstream3.ui.result.FOCUS_SELF\nimport com.lagradost.cloudstream3.ui.result.setLinearListLayout\nimport com.lagradost.cloudstream3.ui.setRecycledViewPool\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setSystemBarsPadding\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiProviderLangSettings\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.getNameNextToFlagEmoji\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\n\nconst val PLUGINS_BUNDLE_NAME = \"name\"\nconst val PLUGINS_BUNDLE_URL = \"url\"\nconst val PLUGINS_BUNDLE_LOCAL = \"isLocal\"\n\nclass PluginsFragment : BaseFragment<FragmentPluginsBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentPluginsBinding::inflate)\n) {\n\n    private val pluginViewModel: PluginsViewModel by activityViewModels()\n\n    override fun onDestroyView() {\n        pluginViewModel.clear() // clear for the next observe\n        super.onDestroyView()\n    }\n\n    override fun fixLayout(view: View) {\n        setSystemBarsPadding()\n    }\n\n    override fun onBindingCreated(binding: FragmentPluginsBinding) {\n        // Since the ViewModel is getting reused the tvTypes must be cleared between uses\n        pluginViewModel.tvTypes.clear()\n        pluginViewModel.selectedLanguages = listOf()\n        pluginViewModel.clear()\n\n        // Filter by language set on preferred media\n        activity?.let {\n            val providerLangs = it.getApiProviderLangSettings().toList()\n            if (!providerLangs.contains(AllLanguagesName)) {\n                pluginViewModel.selectedLanguages = mutableListOf(\"none\") + providerLangs\n            }\n        }\n\n        val name = arguments?.getString(PLUGINS_BUNDLE_NAME)\n        val url = arguments?.getString(PLUGINS_BUNDLE_URL)\n        val isLocal = arguments?.getBoolean(PLUGINS_BUNDLE_LOCAL) == true\n        // download all extensions button\n        val downloadAllButton = binding.settingsToolbar.menu?.findItem(R.id.download_all)\n\n        if (url == null || name == null) {\n            dispatchBackPressed()\n            return\n        }\n\n        setToolBarScrollFlags()\n        setUpToolbar(name)\n        binding.settingsToolbar.apply {\n            setOnMenuItemClickListener { menuItem ->\n                when (menuItem?.itemId) {\n                    R.id.download_all -> {\n                        PluginsViewModel.downloadAll(activity, url, pluginViewModel)\n                    }\n\n                    R.id.lang_filter -> {\n                        val languagesTagName = pluginViewModel.pluginLanguages\n                            .map { langTag ->\n                                Pair(\n                                    langTag,\n                                    getNameNextToFlagEmoji(langTag) ?: langTag\n                                )\n                            }\n                            .sortedBy {\n                                it.second.substringAfter(\"\\u00a0\").lowercase()\n                            } // name ignoring flag emoji\n                            .toMutableList()\n\n                        // Move \"none\" to 1st position as it's special code to indicate unknown/missing language\n                        if (languagesTagName.remove(Pair(\"none\", \"none\"))) {\n                            languagesTagName.add(0, Pair(\"none\", getString(R.string.no_data)))\n                        }\n\n                        val currentIndexList = pluginViewModel.selectedLanguages.map { langTag ->\n                            languagesTagName.indexOfFirst { lang -> lang.first == langTag }\n                        }\n\n                        activity?.showMultiDialog(\n                            languagesTagName.map { it.second },\n                            currentIndexList,\n                            getString(R.string.provider_lang_settings),\n                            {}\n                        ) { selectedList ->\n                            pluginViewModel.selectedLanguages =\n                                selectedList.map { languagesTagName[it].first }\n                            pluginViewModel.updateFilteredPlugins()\n                        }\n                    }\n\n                    else -> {}\n                }\n                return@setOnMenuItemClickListener true\n            }\n\n            val searchView =\n                menu?.findItem(R.id.search_button)?.actionView as? SearchView\n\n            // Don't go back if active query\n            setNavigationOnClickListener {\n                if (searchView?.isIconified == false) {\n                    searchView.isIconified = true\n                } else {\n                    dispatchBackPressed()\n                }\n            }\n            searchView?.setOnQueryTextFocusChangeListener { _, hasFocus ->\n                if (!hasFocus) pluginViewModel.search(null)\n            }\n\n            searchView?.setOnQueryTextListener(object : SearchView.OnQueryTextListener {\n                override fun onQueryTextSubmit(query: String?): Boolean {\n                    pluginViewModel.search(query)\n                    return true\n                }\n\n                override fun onQueryTextChange(newText: String?): Boolean {\n                    pluginViewModel.search(newText)\n                    return true\n                }\n            })\n        }\n//        searchView?.onActionViewCollapsed = {\n//            pluginViewModel.search(null)\n//        }\n\n        // Because onActionViewCollapsed doesn't wanna work we need this workaround :(\n\n        binding.pluginRecyclerView.apply {\n            setLinearListLayout(\n                isHorizontal = false,\n                nextDown = FOCUS_SELF,\n                nextRight = FOCUS_SELF,\n            )\n            setRecycledViewPool(PluginAdapter.sharedPool)\n            adapter =\n                PluginAdapter {\n                    pluginViewModel.handlePluginAction(activity, url, it, isLocal)\n                }\n        }\n\n        if (isLayout(TV or EMULATOR)) {\n            // Scrolling down does not reveal the whole RecyclerView on TV, add to bypass that.\n            binding.pluginRecyclerView.setPadding(0, 0, 0, 200.toPx)\n        }\n\n        observe(pluginViewModel.filteredPlugins) { (scrollToTop, list) ->\n            (binding.pluginRecyclerView.adapter as? PluginAdapter)?.submitList(list)\n            if (scrollToTop) {\n                binding.pluginRecyclerView.scrollToPosition(0)\n            }\n        }\n\n        if (isLocal) {\n            // No download button and no categories on local\n            downloadAllButton?.isVisible = false\n            binding.settingsToolbar.menu?.findItem(R.id.lang_filter)?.isVisible = false\n            pluginViewModel.updatePluginListLocal()\n\n            binding.tvtypesChipsScroll.root.isVisible = false\n        } else {\n            pluginViewModel.updatePluginList(context, url)\n            binding.tvtypesChipsScroll.root.isVisible = true\n            // not needed for users but may be useful for devs\n            downloadAllButton?.isVisible = BuildConfig.DEBUG\n\n            bindChips(\n                binding.tvtypesChipsScroll.tvtypesChips,\n                emptyList(),\n                TvType.entries.toList(),\n                callback = { list ->\n                    pluginViewModel.tvTypes.clear()\n                    pluginViewModel.tvTypes.addAll(list.map { it.name })\n                    pluginViewModel.updateFilteredPlugins()\n                },\n                nextFocusDown = R.id.plugin_recycler_view,\n                nextFocusUp = null,\n            )\n        }\n    }\n\n    companion object {\n        fun newInstance(name: String, url: String, isLocal: Boolean): Bundle {\n            return Bundle().apply {\n                putString(PLUGINS_BUNDLE_NAME, name)\n                putString(PLUGINS_BUNDLE_URL, url)\n                putBoolean(PLUGINS_BUNDLE_LOCAL, isLocal)\n            }\n        }\n\n//        class RepoSearchView(context: Context) : android.widget.SearchView(context) {\n//            var onActionViewCollapsed = {}\n//\n//            override fun onActionViewCollapsed() {\n//                onActionViewCollapsed()\n//            }\n//        }\n\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginsViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.extensions\n\nimport android.app.Activity\nimport android.content.Context\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport androidx.lifecycle.viewModelScope\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.PROVIDER_STATUS_DOWN\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.mvvm.launchSafe\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.plugins.PluginManager.getPluginPath\nimport com.lagradost.cloudstream3.plugins.RepositoryManager\nimport com.lagradost.cloudstream3.plugins.SitePlugin\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread\nimport me.xdrop.fuzzywuzzy.FuzzySearch\nimport java.io.File\n\n// String => repository url\ntypealias Plugin = Pair<String, SitePlugin>\n/**\n * The boolean signifies if the plugin list should be scrolled to the top, used for searching.\n * */\ntypealias PluginViewDataUpdate = Pair<Boolean, List<PluginViewData>>\n\nclass PluginsViewModel : ViewModel() {\n\n    /** plugins is an unaltered list of plugins */\n    private var plugins: List<PluginViewData> = emptyList()\n        set(value) {\n            // Also set all the plugin languages for easier filtering\n            value.map { pluginViewData ->\n                val language = pluginViewData.plugin.second.language?.lowercase()\n                pluginLanguages.add(\n                    when {\n                        language.isNullOrBlank() -> \"none\"\n                        else -> language.lowercase()\n                    }\n                )\n                // not sorting as most likely this is a language tag instead of name\n            }\n            field = value\n        }\n    var pluginLanguages = mutableSetOf<String>() // set to avoid duplicates\n\n    /** filteredPlugins is a subset of plugins following the current search query and tv type selection */\n    private var _filteredPlugins = MutableLiveData<PluginViewDataUpdate>()\n    var filteredPlugins: LiveData<PluginViewDataUpdate> = _filteredPlugins\n\n    val tvTypes = mutableListOf<String>()\n    var selectedLanguages = listOf<String>()\n    private var currentQuery: String? = null\n\n    companion object {\n        private val repositoryCache: MutableMap<String, List<Plugin>> = mutableMapOf()\n        const val TAG = \"PLG\"\n\n        private fun isDownloaded(\n            context: Context,\n            pluginName: String,\n            repositoryUrl: String\n        ): Boolean {\n            return getPluginPath(context, pluginName, repositoryUrl).exists()\n        }\n\n        private suspend fun getPlugins(\n            repositoryUrl: String,\n            canUseCache: Boolean = true\n        ): List<Plugin> {\n            Log.i(TAG, \"getPlugins = $repositoryUrl\")\n            if (canUseCache && repositoryCache.containsKey(repositoryUrl)) {\n                repositoryCache[repositoryUrl]?.let {\n                    return it\n                }\n            }\n            return RepositoryManager.getRepoPlugins(repositoryUrl)\n                ?.also { repositoryCache[repositoryUrl] = it } ?: emptyList()\n        }\n\n        /**\n         * @param viewModel optional, updates the plugins livedata for that viewModel if included\n         * */\n        fun downloadAll(activity: Activity?, repositoryUrl: String, viewModel: PluginsViewModel?) =\n            ioSafe {\n                if (activity == null) return@ioSafe\n                val plugins = getPlugins(repositoryUrl)\n\n                plugins.filter { plugin ->\n                    !isDownloaded(\n                        activity,\n                        plugin.second.internalName,\n                        repositoryUrl\n                    )\n                }.also { list ->\n                    main {\n                        showToast(\n                            when {\n                                // No plugins at all\n                                plugins.isEmpty() -> txt(\n                                    R.string.no_plugins_found_error,\n                                )\n                                // All plugins downloaded\n                                list.isEmpty() -> txt(\n                                    R.string.batch_download_nothing_to_download_format,\n                                    txt(R.string.plugin)\n                                )\n\n                                else -> txt(\n                                    R.string.batch_download_start_format,\n                                    list.size,\n                                    txt(if (list.size == 1) R.string.plugin_singular else R.string.plugin)\n                                )\n                            },\n                            Toast.LENGTH_SHORT\n                        )\n                    }\n                }.amap { (repo, metadata) ->\n                    PluginManager.downloadPlugin(\n                        activity,\n                        metadata.url,\n                        metadata.internalName,\n                        repo,\n                        metadata.status != PROVIDER_STATUS_DOWN\n                    )\n                }.main { list ->\n                    if (list.any { it }) {\n                        showToast(\n                            txt(\n                                R.string.batch_download_finish_format,\n                                list.count { it },\n                                txt(if (list.size == 1) R.string.plugin_singular else R.string.plugin)\n                            ),\n                            Toast.LENGTH_SHORT\n                        )\n                        viewModel?.updatePluginListPrivate(activity, repositoryUrl)\n                    } else if (list.isNotEmpty()) {\n                        showToast(R.string.download_failed, Toast.LENGTH_SHORT)\n                    }\n                }\n            }\n    }\n\n    /**\n     * @param isLocal defines if the plugin data is from local data instead of repo\n     * Will only allow removal of plugins. Used for the local file management.\n     * */\n    fun handlePluginAction(\n        activity: Activity?,\n        repositoryUrl: String,\n        plugin: Plugin,\n        isLocal: Boolean\n    ) = ioSafe {\n        Log.i(TAG, \"handlePluginAction = $repositoryUrl, $plugin, $isLocal\")\n\n        if (activity == null) return@ioSafe\n        val (repo, metadata) = plugin\n\n        val file = if (isLocal) File(plugin.second.url) else getPluginPath(\n            activity,\n            plugin.second.internalName,\n            plugin.first\n        )\n\n        val (success, message) = if (file.exists()) {\n            PluginManager.deletePlugin(file) to R.string.plugin_deleted\n        } else {\n            val isEnabled = plugin.second.status != PROVIDER_STATUS_DOWN\n            val message = if (isEnabled) R.string.plugin_loaded else R.string.plugin_downloaded\n            PluginManager.downloadPlugin(\n                activity,\n                metadata.url,\n                metadata.internalName,\n                repo,\n                isEnabled\n            ) to message\n        }\n\n        runOnMainThread {\n            if (success)\n                showToast(message, Toast.LENGTH_SHORT)\n            else\n                showToast(R.string.error, Toast.LENGTH_SHORT)\n        }\n\n        if (success)\n            if (isLocal)\n                updatePluginListLocal()\n            else\n                updatePluginListPrivate(activity, repositoryUrl)\n    }\n\n    private suspend fun updatePluginListPrivate(context: Context, repositoryUrl: String) {\n        val isAdult = PreferenceManager.getDefaultSharedPreferences(context)\n            .getStringSet(context.getString(R.string.prefer_media_type_key), emptySet())\n            ?.contains(TvType.NSFW.ordinal.toString()) == true\n\n        val plugins = getPlugins(repositoryUrl)\n        val list = plugins.filter {\n            // Show all non-nsfw plugins or all if nsfw is enabled\n            it.second.tvTypes?.contains(TvType.NSFW.name) != true || isAdult\n        }.map { plugin ->\n            PluginViewData(plugin, isDownloaded(context, plugin.second.internalName, plugin.first))\n        }\n\n        this.plugins = list\n        _filteredPlugins.postValue(\n            false to list.filterTvTypes().filterLang().sortByQuery(currentQuery)\n        )\n    }\n\n    // Perhaps can be optimized?\n    private fun List<PluginViewData>.filterTvTypes(): List<PluginViewData> {\n        if (tvTypes.isEmpty()) return this\n        return this.filter {\n            (it.plugin.second.tvTypes?.any { type -> tvTypes.contains(type) } == true) ||\n                    (tvTypes.contains(TvType.Others.name) && (it.plugin.second.tvTypes\n                        ?: emptyList()).isEmpty())\n        }\n    }\n\n    private fun List<PluginViewData>.filterLang(): List<PluginViewData> {\n        if (selectedLanguages.isEmpty()) return this // do not filter\n        return this.filter {\n            if (it.plugin.second.language == null) {\n                return@filter selectedLanguages.contains(\"none\")\n            }\n            selectedLanguages.contains(it.plugin.second.language?.lowercase())\n        }\n    }\n\n    private fun List<PluginViewData>.sortByQuery(query: String?): List<PluginViewData> {\n        return if (query == null) {\n            // Return list to base state if no query\n            this.sortedBy { it.plugin.second.name }\n        } else {\n            this.sortedBy {\n                -FuzzySearch.partialRatio(\n                    it.plugin.second.name.lowercase(),\n                    query.lowercase()\n                )\n            }\n        }\n    }\n\n    fun updateFilteredPlugins() {\n        _filteredPlugins.postValue(\n            false to plugins.filterTvTypes().filterLang().sortByQuery(currentQuery)\n        )\n    }\n\n    fun clear() {\n        currentQuery = null\n        _filteredPlugins.postValue(\n            false to emptyList()\n        )\n    }\n\n    fun updatePluginList(context: Context?, repositoryUrl: String) = viewModelScope.launchSafe {\n        if (context == null) return@launchSafe\n        Log.i(TAG, \"updatePluginList = $repositoryUrl\")\n        updatePluginListPrivate(context, repositoryUrl)\n    }\n\n    fun search(query: String?) {\n        currentQuery = query\n        _filteredPlugins.postValue(\n            true to (filteredPlugins.value?.second?.sortByQuery(query) ?: emptyList())\n        )\n    }\n\n    /**\n     * Update the list but only with the local data. Used for file management.\n     * */\n    fun updatePluginListLocal() = viewModelScope.launchSafe {\n        Log.i(TAG, \"updatePluginList = local\")\n\n        val downloadedPlugins = (PluginManager.getPluginsOnline() + PluginManager.getPluginsLocal())\n            .distinctBy { it.filePath }\n            .map {\n                PluginViewData(\"\" to it.toSitePlugin(), true)\n            }\n\n        plugins = downloadedPlugins\n        _filteredPlugins.postValue(\n            false to downloadedPlugins.filterTvTypes().filterLang().sortByQuery(currentQuery)\n        )\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/RepoAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.extensions\n\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.RepositoryItemBinding\nimport com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding\nimport com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper\nimport com.lagradost.cloudstream3.utils.getImageFromDrawable\nimport com.lagradost.cloudstream3.utils.txt\n\nclass RepoAdapter(\n    val isSetup: Boolean,\n    val clickCallback: RepoAdapter.(RepositoryData) -> Unit,\n    val imageClickCallback: RepoAdapter.(RepositoryData) -> Unit,\n    /** In setup mode the trash icons will be replaced with download icons */\n) :\n    NoStateAdapter<RepositoryData>(diffCallback = BaseDiffCallback(itemSame = { a, b ->\n        a.url == b.url\n    })) {\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        val layout = if (isLayout(TV)) RepositoryItemTvBinding.inflate(\n            LayoutInflater.from(parent.context),\n            parent,\n            false\n        ) else RepositoryItemBinding.inflate(\n            LayoutInflater.from(parent.context),\n            parent,\n            false\n        )\n        return ViewHolderState(layout)\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        when (val binding = holder.view) {\n            is RepositoryItemBinding -> clearImage(binding.entryIcon)\n            is RepositoryItemTvBinding -> clearImage(binding.entryIcon)\n        }\n    }\n\n    override fun onBindContent(holder: ViewHolderState<Any>, item: RepositoryData, position: Int) {\n        val isPrebuilt = PREBUILT_REPOSITORIES.contains(item)\n        val drawable =\n            if (isSetup) R.drawable.netflix_download else R.drawable.ic_baseline_delete_outline_24\n        when (val binding = holder.view) {\n            is RepositoryItemTvBinding -> {\n                binding.apply {\n                    // Only shows icon if on setup or if it isn't a prebuilt repo.\n                    // No delete buttons on prebuilt repos.\n                    if (!isPrebuilt || isSetup) {\n                        actionButton.setImageResource(drawable)\n                    }\n\n                    actionButton.setOnClickListener {\n                        imageClickCallback(item)\n                    }\n\n                    repositoryItemRoot.setOnClickListener {\n                        clickCallback(item)\n                    }\n                    mainText.text = item.name\n                    subText.text = item.url\n                    if (!item.iconUrl.isNullOrEmpty()) {\n                        entryIcon.loadImage(item.iconUrl) {\n                            error(\n                                getImageFromDrawable(\n                                    binding.root.context,\n                                    R.drawable.ic_github_logo\n                                )\n                            )\n                        }\n                    } else {\n                        entryIcon.loadImage(R.drawable.ic_github_logo)\n                    }\n                }\n            }\n\n            is RepositoryItemBinding -> {\n                binding.apply {\n                    // Only shows icon if on setup or if it isn't a prebuilt repo.\n                    // No delete buttons on prebuilt repos.\n                    if (!isPrebuilt || isSetup) {\n                        actionButton.setImageResource(drawable)\n                    }\n\n                    actionButton.setOnClickListener {\n                        imageClickCallback(item)\n                    }\n\n                    repositoryItemRoot.setOnClickListener {\n                        clickCallback(item)\n                    }\n\n                    repositoryItemRoot.setOnLongClickListener {\n                        val shareableRepoData =\n                            \"${item.name}$SHAREABLE_REPO_SEPARATOR\\n ${item.url}\"\n                        clipboardHelper(txt(R.string.repo_copy_label), shareableRepoData)\n                        true\n                    }\n\n                    mainText.text = item.name\n                    subText.text = item.url\n                    if (!item.iconUrl.isNullOrEmpty()) {\n                        entryIcon.loadImage(item.iconUrl) {\n                            error(\n                                getImageFromDrawable(\n                                    binding.root.context,\n                                    R.drawable.ic_github_logo\n                                )\n                            )\n                        }\n                    } else {\n                        entryIcon.loadImage(R.drawable.ic_github_logo)\n                    }\n                }\n            }\n        }\n    }\n\n    companion object {\n        const val SHAREABLE_REPO_SEPARATOR = \" : \"\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.testing\n\nimport android.view.View\nimport androidx.fragment.app.activityViewModels\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.FragmentTestingBinding\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.mvvm.observe\nimport com.lagradost.cloudstream3.mvvm.observeNullable\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setSystemBarsPadding\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setToolBarScrollFlags\nimport com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar\n\nclass TestFragment : BaseFragment<FragmentTestingBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentTestingBinding::inflate)\n) {\n\n    private val testViewModel: TestViewModel by activityViewModels()\n\n    override fun fixLayout(view: View) {\n        setSystemBarsPadding()\n    }\n\n    override fun onBindingCreated(binding: FragmentTestingBinding) {\n        setUpToolbar(R.string.category_provider_test)\n        setToolBarScrollFlags()\n\n        binding.apply {\n            providerTestRecyclerView.adapter = TestResultAdapter()\n\n            testViewModel.init()\n            if (testViewModel.isRunningTest) {\n                providerTest.setState(TestView.TestState.Running)\n            }\n\n            observe(testViewModel.providerProgress) { (passed, failed, total) ->\n                providerTest.setProgress(passed, failed, total)\n            }\n\n            observeNullable(testViewModel.providerResults) {\n                safe {\n                    val newItems = it.sortedBy { api -> api.first.name }\n                    (providerTestRecyclerView.adapter as? TestResultAdapter)?.submitList(\n                        newItems\n                    )\n                }\n            }\n\n            providerTest.setOnPlayButtonListener { state ->\n                when (state) {\n                    TestView.TestState.Stopped -> testViewModel.stopTest()\n                    TestView.TestState.Running -> testViewModel.startTest()\n                    TestView.TestState.None -> testViewModel.startTest()\n                }\n            }\n\n            if (isLayout(TV)) {\n                providerTest.playPauseButton?.isFocusableInTouchMode = true\n                providerTest.playPauseButton?.requestFocus()\n            }\n\n            providerTest.playPauseButton?.setOnFocusChangeListener { _, hasFocus ->\n                if (hasFocus) {\n                    providerTestAppbar.setExpanded(true, true)\n                }\n            }\n\n            fun focusRecyclerView() {\n                // Hack to make it possible to focus the recyclerview.\n                if (isLayout(TV)) {\n                    providerTestRecyclerView.requestFocus()\n                    providerTestAppbar.setExpanded(false, true)\n                }\n            }\n\n            providerTest.setOnMainClick {\n                testViewModel.setFilterMethod(TestViewModel.ProviderFilter.All)\n                focusRecyclerView()\n            }\n            providerTest.setOnFailedClick {\n                testViewModel.setFilterMethod(TestViewModel.ProviderFilter.Failed)\n                focusRecyclerView()\n            }\n            providerTest.setOnPassedClick {\n                testViewModel.setFilterMethod(TestViewModel.ProviderFilter.Passed)\n                focusRecyclerView()\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestResultAdapter.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.testing\n\nimport android.app.AlertDialog\nimport android.view.LayoutInflater\nimport android.view.ViewGroup\nimport android.widget.ImageView\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.core.content.ContextCompat\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.ProviderTestItemBinding\nimport com.lagradost.cloudstream3.mvvm.getAllMessages\nimport com.lagradost.cloudstream3.mvvm.getStackTracePretty\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.ui.BaseDiffCallback\nimport com.lagradost.cloudstream3.ui.NoStateAdapter\nimport com.lagradost.cloudstream3.ui.ViewHolderState\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso\nimport com.lagradost.cloudstream3.utils.TestingUtils\nimport java.io.File\n\nclass TestResultAdapter() :\n    NoStateAdapter<Pair<MainAPI, TestingUtils.TestResultProvider>>(\n        diffCallback = BaseDiffCallback(\n            itemSame = { a, b ->\n                a.first.name == b.first.name && a.first.mainUrl == b.first.mainUrl\n            },\n            contentSame = { a, b ->\n                a == b\n            })\n    ) {\n    companion object {\n        private fun String.lastLine(): String? {\n            return this.lines().lastOrNull { it.isNotBlank() }\n        }\n    }\n\n    override fun onClearView(holder: ViewHolderState<Any>) {\n        val binding = holder.view as? ProviderTestItemBinding ?: return\n        clearImage(binding.actionButton)\n    }\n\n    override fun onCreateContent(parent: ViewGroup): ViewHolderState<Any> {\n        return ViewHolderState(\n            ProviderTestItemBinding.inflate(\n                LayoutInflater.from(parent.context),\n                parent,\n                false\n            )\n        )\n    }\n\n    override fun onBindContent(\n        holder: ViewHolderState<Any>,\n        item: Pair<MainAPI, TestingUtils.TestResultProvider>,\n        position: Int\n    ) {\n        val binding = holder.view as? ProviderTestItemBinding ?: return\n        val (api, result) = item\n\n        val itemView = holder.itemView\n\n        val languageText: TextView = binding.langIcon\n        val providerTitle: TextView = binding.mainText\n        val statusText: TextView = binding.passedFailedMarker\n        val failDescription: TextView = binding.failDescription\n        val logButton: ImageView = binding.actionButton\n\n        languageText.text = getFlagFromIso(api.lang)\n        providerTitle.text = api.name\n\n        val (resultText, resultColor) = if (result.success) {\n            if (result.log.any { it.level == TestingUtils.Logger.LogLevel.Warning }) {\n                R.string.test_warning to R.color.colorTestWarning\n            } else {\n                R.string.test_passed to R.color.colorTestPass\n            }\n        } else {\n            R.string.test_failed to R.color.colorTestFail\n        }\n\n        statusText.setText(resultText)\n        statusText.setTextColor(ContextCompat.getColor(itemView.context, resultColor))\n\n        val stackTrace = result.exception?.getStackTracePretty(false)?.ifBlank { null }\n        val messages = result.exception?.getAllMessages()?.ifBlank { null }\n        val resultLog = result.log.joinToString(\"\\n\")\n        val fullLog =\n            resultLog +\n                    (messages?.let { \"\\n\\nError: $it\" } ?: \"\") +\n                    (stackTrace?.let { \"\\n\\n$it\" } ?: \"\")\n\n        failDescription.text = messages?.lastLine() ?: resultLog.lastLine()\n\n        logButton.setOnClickListener {\n            val builder: AlertDialog.Builder =\n                AlertDialog.Builder(it.context, R.style.AlertDialogCustom)\n            builder.setMessage(fullLog)\n                .setTitle(R.string.test_log)\n                // Ok button just closes the dialog\n                .setPositiveButton(R.string.ok) { _, _ -> }\n\n            api.sourcePlugin?.let { path ->\n                val pluginFile = File(path)\n                // Cannot delete a deleted plugin\n                if (!pluginFile.exists()) return@let\n\n                builder.setNegativeButton(R.string.delete_plugin) { _, _ ->\n                    ioSafe {\n                        val success = PluginManager.deletePlugin(pluginFile)\n\n                        runOnMainThread {\n                            if (success) {\n                                showToast(R.string.plugin_deleted, Toast.LENGTH_SHORT)\n                            } else {\n                                showToast(R.string.error, Toast.LENGTH_SHORT)\n                            }\n                        }\n                    }\n                }\n            }\n\n            builder.show()\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestView.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.testing\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.widget.TextView\nimport androidx.annotation.DrawableRes\nimport androidx.annotation.StringRes\nimport androidx.cardview.widget.CardView\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.withStyledAttributes\nimport androidx.core.view.isVisible\nimport androidx.core.widget.ContentLoadingProgressBar\nimport com.google.android.material.button.MaterialButton\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.utils.AppContextUtils.animateProgressTo\n\nclass TestView @JvmOverloads constructor(\n    context: Context,\n    attrs: AttributeSet? = null,\n    defStyleAttr: Int = 0\n) : CardView(context, attrs) {\n    enum class TestState(@StringRes val stringRes: Int, @DrawableRes val icon: Int) {\n        None(R.string.start, R.drawable.ic_baseline_play_arrow_24),\n\n        //        Paused(R.string.resume, R.drawable.ic_baseline_play_arrow_24),\n        Stopped(R.string.restart, R.drawable.ic_baseline_play_arrow_24),\n        Running(R.string.stop, R.drawable.pause_to_play),\n    }\n\n    var mainSection: View? = null\n    var testsPassedSection: View? = null\n    var testsFailedSection: View? = null\n\n    var mainSectionText: TextView? = null\n    var mainSectionHeader: TextView? = null\n    var testsPassedSectionText: TextView? = null\n    var testsFailedSectionText: TextView? = null\n    var totalProgressBar: ContentLoadingProgressBar? = null\n\n    var playPauseButton: MaterialButton? = null\n    var stateListener: (TestState) -> Unit = {}\n\n    private var state = TestState.None\n\n    init {\n        LayoutInflater.from(context).inflate(R.layout.view_test, this, true)\n\n        mainSection = findViewById(R.id.main_test_section)\n        testsPassedSection = findViewById(R.id.passed_test_section)\n        testsFailedSection = findViewById(R.id.failed_test_section)\n\n        mainSectionHeader = findViewById(R.id.main_test_header)\n        mainSectionText = findViewById(R.id.main_test_section_progress)\n        testsPassedSectionText = findViewById(R.id.passed_test_section_progress)\n        testsFailedSectionText = findViewById(R.id.failed_test_section_progress)\n\n        totalProgressBar = findViewById(R.id.test_total_progress)\n        playPauseButton = findViewById(R.id.tests_play_pause)\n\n        attrs?.let {\n            context.withStyledAttributes(it, R.styleable.TestView) {\n                mainSectionHeader?.text = getString(R.styleable.TestView_header_text)\n            }\n        }\n\n        playPauseButton?.setOnClickListener {\n            val newState = when (state) {\n                TestState.None -> TestState.Running\n                TestState.Running -> TestState.Stopped\n                TestState.Stopped -> TestState.Running\n            }\n            setState(newState)\n        }\n    }\n\n    fun setOnPlayButtonListener(listener: (TestState) -> Unit) {\n        stateListener = listener\n    }\n\n    fun setState(newState: TestState) {\n        state = newState\n        stateListener.invoke(newState)\n        playPauseButton?.setText(newState.stringRes)\n        playPauseButton?.icon = ContextCompat.getDrawable(context, newState.icon)\n    }\n\n    fun setProgress(passed: Int, failed: Int, total: Int?) {\n        val totalProgress = passed + failed\n        mainSectionText?.text = \"$totalProgress / ${total?.toString() ?: \"?\"}\"\n        testsPassedSectionText?.text = passed.toString()\n        testsFailedSectionText?.text = failed.toString()\n\n        totalProgressBar?.max = (total ?: 0) * 1000\n        totalProgressBar?.animateProgressTo(totalProgress * 1000)\n\n        totalProgressBar?.isVisible = !(totalProgress == 0 || (total ?: 0) == 0)\n        if (totalProgress == total) {\n            setState(TestState.Stopped)\n        }\n    }\n\n    fun setMainHeader(@StringRes header: Int) {\n        mainSectionHeader?.setText(header)\n    }\n\n    fun setOnMainClick(listener: OnClickListener) {\n        mainSection?.setOnClickListener(listener)\n    }\n\n    fun setOnPassedClick(listener: OnClickListener) {\n        testsPassedSection?.setOnClickListener(listener)\n    }\n\n    fun setOnFailedClick(listener: OnClickListener) {\n        testsFailedSection?.setOnClickListener(listener)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/testing/TestViewModel.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.testing\n\nimport androidx.lifecycle.LiveData\nimport androidx.lifecycle.MutableLiveData\nimport androidx.lifecycle.ViewModel\nimport com.lagradost.cloudstream3.APIHolder\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf\nimport com.lagradost.cloudstream3.utils.TestingUtils\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.cancel\n\nclass TestViewModel : ViewModel() {\n    data class TestProgress(\n        val passed: Int,\n        val failed: Int,\n        val total: Int\n    )\n\n    enum class ProviderFilter {\n        All,\n        Passed,\n        Failed\n    }\n\n    private val _providerProgress = MutableLiveData<TestProgress>(null)\n    val providerProgress: LiveData<TestProgress> = _providerProgress\n\n    private val _providerResults =\n        MutableLiveData<List<Pair<MainAPI, TestingUtils.TestResultProvider>>>(\n            emptyList()\n        )\n\n    val providerResults: LiveData<List<Pair<MainAPI, TestingUtils.TestResultProvider>>> =\n        _providerResults\n\n    private var scope: CoroutineScope? = null\n    val isRunningTest\n        get() = scope != null\n\n    private var filter = ProviderFilter.All\n    private val providers = threadSafeListOf<Pair<MainAPI, TestingUtils.TestResultProvider>>()\n    private var passed = 0\n    private var failed = 0\n    private var total = 0\n\n    private fun updateProgress() {\n        _providerProgress.postValue(TestProgress(passed, failed, total))\n        postProviders()\n    }\n\n    private fun postProviders() {\n        synchronized(providers) {\n            val filtered = when (filter) {\n                ProviderFilter.All -> providers\n                ProviderFilter.Passed -> providers.filter { it.second.success }\n                ProviderFilter.Failed -> providers.filter { !it.second.success }\n            }\n            _providerResults.postValue(filtered)\n        }\n    }\n\n    fun setFilterMethod(filter: ProviderFilter) {\n        if (this.filter == filter) return\n        this.filter = filter\n        postProviders()\n    }\n\n    private fun addProvider(api: MainAPI, results: TestingUtils.TestResultProvider) {\n        synchronized(providers) {\n            val index = providers.indexOfFirst { it.first == api }\n            if (index == -1) {\n                providers.add(api to results)\n                if (results.success) passed++ else failed++\n            } else {\n                providers[index] = api to results\n            }\n            updateProgress()\n        }\n    }\n\n    fun init() {\n        total = synchronized(APIHolder.allProviders) { APIHolder.allProviders.size }\n        updateProgress()\n    }\n\n    fun startTest() {\n        scope = CoroutineScope(Dispatchers.Default)\n\n        val apis = synchronized(APIHolder.allProviders) { APIHolder.allProviders.toTypedArray() }\n        total = apis.size\n        failed = 0\n        passed = 0\n        providers.clear()\n        updateProgress()\n\n        TestingUtils.getDeferredProviderTests(scope ?: return, apis) { api, result ->\n            addProvider(api, result)\n        }\n    }\n\n    fun stopTest() {\n        scope?.cancel()\n        scope = null\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/settings/utils/DirectoryPicker.kt",
    "content": "package com.lagradost.cloudstream3.ui.settings.utils\n\nimport android.content.Intent\nimport android.net.Uri\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.fragment.app.Fragment\nimport com.lagradost.cloudstream3.CloudStreamApp\nimport com.lagradost.safefile.SafeFile\n\nfun Fragment.getChooseFolderLauncher(dirSelected: (uri: Uri?, path: String?) -> Unit) =\n    registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->\n        // It lies, it can be null if file manager quits.\n        if (uri == null) return@registerForActivityResult\n        val context = context ?: CloudStreamApp.context ?: return@registerForActivityResult\n        // RW perms for the path\n        val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or\n                Intent.FLAG_GRANT_WRITE_URI_PERMISSION\n\n        context.contentResolver.takePersistableUriPermission(uri, flags)\n\n        val filePath = SafeFile.fromUri(context, uri)?.filePath()\n        println(\"Selected URI path: $uri - Full path: $filePath\")\n\n        // store the actual URI instead of the path due to permissions.\n        // filePath should only be used for cosmetic purposes.\n        dirSelected(uri, filePath)\n    }"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentExtensions.kt",
    "content": "package com.lagradost.cloudstream3.ui.setup\n\nimport android.os.Bundle\nimport android.view.View\nimport androidx.core.view.isVisible\nimport androidx.navigation.fragment.findNavController\nimport com.lagradost.cloudstream3.APIHolder.apis\nimport com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.FragmentSetupExtensionsBinding\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.plugins.RepositoryManager\nimport com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.settings.extensions.PluginsViewModel\nimport com.lagradost.cloudstream3.ui.settings.extensions.RepoAdapter\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\n\nclass SetupFragmentExtensions : BaseFragment<FragmentSetupExtensionsBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentSetupExtensionsBinding::inflate)\n) {\n    companion object {\n        const val SETUP_EXTENSION_BUNDLE_IS_SETUP = \"isSetup\"\n\n        /**\n         * If false then this is treated a singular screen with a done button\n         * */\n        fun newInstance(isSetup: Boolean): Bundle {\n            return Bundle().apply {\n                putBoolean(SETUP_EXTENSION_BUNDLE_IS_SETUP, isSetup)\n            }\n        }\n    }\n\n    override fun onResume() {\n        super.onResume()\n        afterRepositoryLoadedEvent += ::setRepositories\n    }\n\n    override fun onStop() {\n        super.onStop()\n        afterRepositoryLoadedEvent -= ::setRepositories\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(view)\n    }\n\n    private fun setRepositories(success: Boolean = true) {\n        main {\n            val repositories = RepositoryManager.getRepositories() + PREBUILT_REPOSITORIES\n            val hasRepos = repositories.isNotEmpty()\n            binding?.repoRecyclerView?.isVisible = hasRepos\n            binding?.blankRepoScreen?.isVisible = !hasRepos\n\n            if (hasRepos) {\n                binding?.repoRecyclerView?.adapter = RepoAdapter(true, {}, {\n                    PluginsViewModel.downloadAll(activity, it.url, null)\n                }).apply { submitList(repositories.toList()) }\n            }\n//            else {\n//                list_repositories?.setOnClickListener {\n//                    // Open webview on tv if browser fails\n//                    openBrowser(PUBLIC_REPOSITORIES_LIST, isTvSettings(), this)\n//                }\n//            }\n        }\n    }\n\n    override fun onBindingCreated(binding: FragmentSetupExtensionsBinding) {\n        val isSetup = arguments?.getBoolean(SETUP_EXTENSION_BUNDLE_IS_SETUP) ?: false\n\n        safe {\n            setRepositories()\n            binding.apply {\n                if (!isSetup) {\n                    nextBtt.setText(R.string.setup_done)\n                }\n                prevBtt.isVisible = isSetup\n\n                nextBtt.setOnClickListener {\n                    // Continue setup\n                    if (isSetup)\n                        if (\n                        // If any available languages\n                            synchronized(apis) { apis.distinctBy { it.lang }.size > 1 }\n                        ) {\n                            findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_provider_languages)\n                        } else {\n                            findNavController().navigate(R.id.action_navigation_setup_extensions_to_navigation_setup_media)\n                        }\n                    else\n                        findNavController().navigate(R.id.navigation_home)\n                }\n\n                prevBtt.setOnClickListener {\n                    findNavController().navigate(R.id.navigation_setup_language)\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLanguage.kt",
    "content": "package com.lagradost.cloudstream3.ui.setup\n\nimport android.view.View\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.edit\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity\nimport com.lagradost.cloudstream3.databinding.FragmentSetupLanguageBinding\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.settings.appLanguages\nimport com.lagradost.cloudstream3.ui.settings.getCurrentLocale\nimport com.lagradost.cloudstream3.ui.settings.nameNextToFlagEmoji\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\n\nconst val HAS_DONE_SETUP_KEY = \"HAS_DONE_SETUP\"\n\nclass SetupFragmentLanguage : BaseFragment<FragmentSetupLanguageBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentSetupLanguageBinding::inflate)\n) {\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(view)\n    }\n\n    override fun onBindingCreated(binding: FragmentSetupLanguageBinding) {\n        // We don't want a crash for all users\n        safe {\n            val ctx = context ?: return@safe\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n\n            val arrayAdapter =\n                ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)\n\n            binding.apply {\n                // Icons may crash on some weird android versions?\n                safe {\n                    val drawable = when {\n                        BuildConfig.DEBUG -> R.drawable.cloud_2_gradient_debug\n                        BuildConfig.FLAVOR == \"prerelease\" -> R.drawable.cloud_2_gradient_beta\n                        else -> R.drawable.cloud_2_gradient\n                    }\n                    appIconImage.setImageDrawable(ContextCompat.getDrawable(ctx, drawable))\n                }\n\n                val current = getCurrentLocale(ctx)\n                val languageTagsIETF = appLanguages.map { it.second }\n                val languageNames = appLanguages.map { it.nameNextToFlagEmoji() }\n                val currentIndex = languageTagsIETF.indexOf(current)\n\n                arrayAdapter.addAll(languageNames)\n                listview1.adapter = arrayAdapter\n                listview1.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n                listview1.setItemChecked(currentIndex, true)\n\n                listview1.setOnItemClickListener { _, _, selectedLangIndex, _ ->\n                    val langTagIETF = languageTagsIETF[selectedLangIndex]\n                    CommonActivity.setLocale(activity, langTagIETF)\n                    settingsManager.edit {\n                        putString(getString(R.string.locale_key), langTagIETF)\n                    }\n                }\n\n                nextBtt.setOnClickListener {\n                    // If no plugins go to plugins page\n                    val nextDestination = if (\n                        PluginManager.getPluginsOnline().isEmpty()\n                        && PluginManager.getPluginsLocal().isEmpty()\n                    //&& PREBUILT_REPOSITORIES.isNotEmpty()\n                    ) R.id.action_navigation_global_to_navigation_setup_extensions\n                    else R.id.action_navigation_setup_language_to_navigation_setup_provider_languages\n\n                    findNavController().navigate(\n                        nextDestination,\n                        SetupFragmentExtensions.newInstance(true)\n                    )\n                }\n\n                skipBtt.setOnClickListener {\n                    setKey(HAS_DONE_SETUP_KEY, true)\n                    findNavController().navigate(R.id.navigation_home)\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLayout.kt",
    "content": "package com.lagradost.cloudstream3.ui.setup\n\nimport android.view.View\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport androidx.core.content.edit\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.FragmentSetupLayoutBinding\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\n\nclass SetupFragmentLayout : BaseFragment<FragmentSetupLayoutBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentSetupLayoutBinding::inflate)\n) {\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(view)\n    }\n\n    override fun onBindingCreated(binding: FragmentSetupLayoutBinding) {\n        safe {\n            val ctx = context ?: return@safe\n\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n\n            val prefNames = resources.getStringArray(R.array.app_layout)\n            val prefValues = resources.getIntArray(R.array.app_layout_values)\n\n            val currentLayout =\n                settingsManager.getInt(getString(R.string.app_layout_key), -1)\n\n            val arrayAdapter =\n                ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)\n\n            arrayAdapter.addAll(prefNames.toList())\n            binding.apply {\n                listview1.adapter = arrayAdapter\n                listview1.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n                listview1.setItemChecked(\n                    prefValues.indexOf(currentLayout), true\n                )\n\n                listview1.setOnItemClickListener { _, _, position, _ ->\n                    settingsManager.edit {\n                        putInt(getString(R.string.app_layout_key), prefValues[position])\n                    }\n                    activity?.recreate()\n                }\n\n                nextBtt.setOnClickListener {\n                    setKey(HAS_DONE_SETUP_KEY, true)\n                    findNavController().navigate(R.id.navigation_home)\n                }\n\n                prevBtt.setOnClickListener {\n                    findNavController().popBackStack()\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentMedia.kt",
    "content": "package com.lagradost.cloudstream3.ui.setup\n\nimport android.view.View\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport androidx.core.content.edit\nimport androidx.core.util.forEach\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.databinding.FragmentSetupMediaBinding\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.utils.DataStoreHelper\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\n\nclass SetupFragmentMedia : BaseFragment<FragmentSetupMediaBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentSetupMediaBinding::inflate)\n) {\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(view)\n    }\n\n    override fun onBindingCreated(binding: FragmentSetupMediaBinding) {\n        safe {\n            val ctx = context ?: return@safe\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n\n            val arrayAdapter =\n                ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)\n\n            val names = enumValues<TvType>().sorted().map { it.name }\n            val selected = mutableListOf<Int>()\n\n            arrayAdapter.addAll(names)\n            binding.apply {\n                listview1.let {\n                    it.adapter = arrayAdapter\n                    it.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE\n\n                    it.setOnItemClickListener { _, _, _, _ ->\n                        it.checkedItemPositions?.forEach { key, value ->\n                            if (value) {\n                                selected.add(key)\n                            } else {\n                                selected.remove(key)\n                            }\n                        }\n                        val prefValues = selected.mapNotNull { pos ->\n                            val item =\n                                it.getItemAtPosition(pos)?.toString() ?: return@mapNotNull null\n                            val itemVal = TvType.valueOf(item)\n                            itemVal.ordinal.toString()\n                        }.toSet()\n                        settingsManager.edit {\n                            putStringSet(getString(R.string.prefer_media_type_key), prefValues)\n                        }\n\n                        // Regenerate set homepage\n                        DataStoreHelper.currentHomePage = null\n                    }\n                }\n\n                nextBtt.setOnClickListener {\n                    findNavController().navigate(R.id.navigation_setup_media_to_navigation_setup_layout)\n                }\n\n                prevBtt.setOnClickListener {\n                    findNavController().popBackStack()\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentProviderLanguage.kt",
    "content": "package com.lagradost.cloudstream3.ui.setup\n\nimport android.view.View\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport androidx.core.content.edit\nimport androidx.core.util.forEach\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.AllLanguagesName\nimport com.lagradost.cloudstream3.APIHolder\nimport com.lagradost.cloudstream3.databinding.FragmentSetupProviderLanguagesBinding\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.utils.AppContextUtils.getApiProviderLangSettings\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.getNameNextToFlagEmoji\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\n\nclass SetupFragmentProviderLanguage : BaseFragment<FragmentSetupProviderLanguagesBinding>(\n    BaseFragment.BindingCreator.Inflate(FragmentSetupProviderLanguagesBinding::inflate)\n) {\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(view)\n    }\n\n    override fun onBindingCreated(binding: FragmentSetupProviderLanguagesBinding) {\n        safe {\n            val ctx = context ?: return@safe\n\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)\n\n            val arrayAdapter =\n                ArrayAdapter<String>(ctx, R.layout.sort_bottom_single_choice)\n\n            val currentLangTags = ctx.getApiProviderLangSettings()\n\n            val languagesTagName = synchronized(APIHolder.apis) {\n                listOf( Pair(AllLanguagesName, getString(R.string.all_languages_preference)) ) +\n                APIHolder.apis.map { Pair(it.lang, getNameNextToFlagEmoji(it.lang) ?: it.lang) }\n                    .toSet().sortedBy { it.second.substringAfter(\"\\u00a0\").lowercase() } // name ignoring flag emoji\n            }\n\n            val currentIndexList = currentLangTags.map { langTag ->\n                languagesTagName.indexOfFirst { lang -> lang.first == langTag }\n            }.filter { it > -1 }\n\n            arrayAdapter.addAll(languagesTagName.map { it.second })\n            binding.apply {\n                listview1.adapter = arrayAdapter\n                listview1.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE\n                currentIndexList.forEach {\n                    listview1.setItemChecked(it, true)\n                }\n\n                listview1.setOnItemClickListener { _, _, _, _ ->\n                    val selectedLanguages = mutableSetOf<String>()\n                    listview1.checkedItemPositions?.forEach { key, value ->\n                        if (value) selectedLanguages.add(languagesTagName[key].first)\n                    }\n                    settingsManager.edit {\n                        putStringSet(\n                            ctx.getString(R.string.provider_lang_key),\n                            selectedLanguages.toSet()\n                        )\n                    }\n                }\n\n                nextBtt.setOnClickListener {\n                    findNavController().navigate(R.id.navigation_setup_provider_languages_to_navigation_setup_media)\n                }\n\n                prevBtt.setOnClickListener {\n                    findNavController().popBackStack()\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.subtitles\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.res.Resources\nimport android.graphics.Color\nimport android.os.Bundle\nimport android.util.DisplayMetrics\nimport android.util.TypedValue\nimport android.view.View\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.annotation.OptIn\nimport androidx.media3.common.text.Cue\nimport androidx.media3.common.util.UnstableApi\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_DEPRESSED\nimport com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_DROP_SHADOW\nimport com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_NONE\nimport com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_OUTLINE\nimport com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_RAISED\nimport com.jaredrummler.android.colorpicker.ColorPickerDialog\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent\nimport com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.ChromecastSubtitleSettingsBinding\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.DataStore.setKey\nimport com.lagradost.cloudstream3.utils.Event\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage\n\nconst val CHROME_SUBTITLE_KEY = \"chome_subtitle_settings\"\n\ndata class SaveChromeCaptionStyle(\n    @JsonProperty(\"fontFamily\") var fontFamily: String? = null,\n    @JsonProperty(\"fontGenericFamily\") var fontGenericFamily: Int? = null,\n    @JsonProperty(\"backgroundColor\") var backgroundColor: Int = 0x00FFFFFF, // transparent\n    @JsonProperty(\"edgeColor\") var edgeColor: Int = Color.BLACK, // BLACK\n    @JsonProperty(\"edgeType\") var edgeType: Int = EDGE_TYPE_OUTLINE,\n    @JsonProperty(\"foregroundColor\") var foregroundColor: Int = Color.WHITE,\n    @JsonProperty(\"fontScale\") var fontScale: Float = 1.05f,\n    @JsonProperty(\"windowColor\") var windowColor: Int = Color.TRANSPARENT,\n)\n\nclass ChromecastSubtitlesFragment : BaseFragment<ChromecastSubtitleSettingsBinding>(\n    BaseFragment.BindingCreator.Inflate(ChromecastSubtitleSettingsBinding::inflate)\n) {\n    companion object {\n        val applyStyleEvent = Event<SaveChromeCaptionStyle>()\n\n        //fun Context.fromSaveToStyle(data: SaveChromeCaptionStyle): CaptionStyleCompat {\n        //    return CaptionStyleCompat(\n        //        data.foregroundColor,\n        //        data.backgroundColor,\n        //        data.windowColor,\n        //        data.edgeType,\n        //        data.edgeColor,\n        //        if (typeface == null) Typeface.SANS_SERIF else ResourcesCompat.getFont(\n        //            this,\n        //            typeface\n        //        )\n        //    )\n        //}\n\n        fun push(activity: Activity?, hide: Boolean = true) {\n            activity.navigate(R.id.global_to_navigation_chrome_subtitles, Bundle().apply {\n                putBoolean(\"hide\", hide)\n            })\n        }\n\n        private fun getDefColor(id: Int): Int {\n            return when (id) {\n                0 -> Color.WHITE\n                1 -> Color.BLACK\n                2 -> Color.TRANSPARENT\n                3 -> Color.TRANSPARENT\n                else -> Color.TRANSPARENT\n            }\n        }\n\n        fun Context.saveStyle(style: SaveChromeCaptionStyle) {\n            this.setKey(CHROME_SUBTITLE_KEY, style)\n        }\n\n        private fun getPixels(unit: Int, size: Float): Int {\n            val metrics: DisplayMetrics = Resources.getSystem().displayMetrics\n            return TypedValue.applyDimension(unit, size, metrics).toInt()\n        }\n\n        fun getCurrentSavedStyle(): SaveChromeCaptionStyle {\n            return getKey(CHROME_SUBTITLE_KEY) ?: defaultState\n        }\n\n        private val defaultState = SaveChromeCaptionStyle()\n    }\n\n    private fun onColorSelected(stuff: Pair<Int, Int>) {\n        setColor(stuff.first, stuff.second)\n        if (hide)\n            activity?.hideSystemUI()\n    }\n\n    private fun onDialogDismissed(id: Int) {\n        if (hide)\n            activity?.hideSystemUI()\n    }\n\n    private fun getColor(id: Int): Int {\n        val color = when (id) {\n            0 -> state.foregroundColor\n            1 -> state.edgeColor\n            2 -> state.backgroundColor\n            3 -> state.windowColor\n\n            else -> Color.TRANSPARENT\n        }\n\n        return if (color == Color.TRANSPARENT) Color.BLACK else color\n    }\n\n    private fun setColor(id: Int, color: Int?) {\n        val realColor = color ?: getDefColor(id)\n        when (id) {\n            0 -> state.foregroundColor = realColor\n            1 -> state.edgeColor = realColor\n            2 -> state.backgroundColor = realColor\n            3 -> state.windowColor = realColor\n\n            else -> Unit\n        }\n        updateState()\n    }\n\n    private fun updateState() {\n        //subtitle_text?.setStyle(fromSaveToStyle(state))\n    }\n\n    private lateinit var state: SaveChromeCaptionStyle\n    private var hide: Boolean = true\n\n    override fun onDestroy() {\n        super.onDestroy()\n        onColorSelectedEvent -= ::onColorSelected\n    }\n\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padBottom = isLandscape(),\n            padLeft = isLayout(TV or EMULATOR)\n        )\n    }\n\n    override fun onBindingCreated(binding: ChromecastSubtitleSettingsBinding) {\n        hide = arguments?.getBoolean(\"hide\") ?: true\n        onColorSelectedEvent += ::onColorSelected\n        onDialogDismissedEvent += ::onDialogDismissed\n\n        state = getCurrentSavedStyle()\n        updateState()\n\n        val isTvSettings = isLayout(TV or EMULATOR)\n        fun View.setFocusableInTv() {\n            this.isFocusableInTouchMode = isTvSettings\n        }\n\n        fun View.setup(id: Int) {\n            setFocusableInTv()\n            this.setOnClickListener {\n                activity?.let {\n                    ColorPickerDialog.newBuilder()\n                        .setDialogId(id)\n                        .setShowAlphaSlider(true)\n                        .setColor(getColor(id))\n                        .show(it)\n                }\n            }\n\n            this.setOnLongClickListener {\n                setColor(id, null)\n                showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n        }\n\n        binding.apply {\n            subsTextColor.setup(0)\n            subsOutlineColor.setup(1)\n            subsBackgroundColor.setup(2)\n        }\n\n        val dismissCallback = {\n            if (hide)\n                activity?.hideSystemUI()\n        }\n\n        binding.subsEdgeType.setFocusableInTv()\n        binding.subsEdgeType.setOnClickListener { textView ->\n            val edgeTypes = listOf(\n                Pair(\n                    EDGE_TYPE_NONE,\n                    textView.context.getString(R.string.subtitles_none)\n                ),\n                Pair(\n                    EDGE_TYPE_OUTLINE,\n                    textView.context.getString(R.string.subtitles_outline)\n                ),\n                Pair(\n                    EDGE_TYPE_DEPRESSED,\n                    textView.context.getString(R.string.subtitles_depressed)\n                ),\n                Pair(\n                    EDGE_TYPE_DROP_SHADOW,\n                    textView.context.getString(R.string.subtitles_shadow)\n                ),\n                Pair(\n                    EDGE_TYPE_RAISED,\n                    textView.context.getString(R.string.subtitles_raised)\n                ),\n            )\n\n            //showBottomDialog\n            activity?.showDialog(\n                edgeTypes.map { it.second },\n                edgeTypes.map { it.first }.indexOf(state.edgeType),\n                (textView as TextView).text.toString(),\n                false,\n                dismissCallback\n            ) { index ->\n                state.edgeType = edgeTypes.map { it.first }[index]\n                updateState()\n            }\n        }\n\n        binding.subsEdgeType.setOnLongClickListener {\n            state.edgeType = defaultState.edgeType\n            updateState()\n            showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n            return@setOnLongClickListener true\n        }\n\n        binding.subsFontSize.setFocusableInTv()\n        binding.subsFontSize.setOnClickListener { textView ->\n            val fontSizes = listOf(\n                Pair(0.75f, \"75%\"),\n                Pair(0.80f, \"80%\"),\n                Pair(0.85f, \"85%\"),\n                Pair(0.90f, \"90%\"),\n                Pair(0.95f, \"95%\"),\n                Pair(1.00f, \"100%\"),\n                Pair(1.05f, textView.context.getString(R.string.normal)),\n                Pair(1.10f, \"110%\"),\n                Pair(1.15f, \"115%\"),\n                Pair(1.20f, \"120%\"),\n                Pair(1.25f, \"125%\"),\n                Pair(1.30f, \"130%\"),\n                Pair(1.35f, \"135%\"),\n                Pair(1.40f, \"140%\"),\n                Pair(1.45f, \"145%\"),\n                Pair(1.50f, \"150%\"),\n            )\n\n            //showBottomDialog\n            activity?.showDialog(\n                fontSizes.map { it.second },\n                fontSizes.map { it.first }.indexOf(state.fontScale),\n                (textView as TextView).text.toString(),\n                false,\n                dismissCallback\n            ) { index ->\n                state.fontScale = fontSizes.map { it.first }[index]\n                //textView.context.updateState() // font size not changed\n            }\n        }\n\n        binding.subsFontSize.setOnLongClickListener { _ ->\n            state.fontScale = defaultState.fontScale\n            //textView.context.updateState() // font size not changed\n            showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n            return@setOnLongClickListener true\n        }\n\n        binding.subsFont.setFocusableInTv()\n        binding.subsFont.setOnClickListener { textView ->\n            val fontTypes = listOf(\n                null to textView.context.getString(R.string.normal),\n                \"Droid Sans\" to \"Droid Sans\",\n                \"Droid Sans Mono\" to \"Droid Sans Mono\",\n                \"Droid Serif Regular\" to \"Droid Serif Regular\",\n                \"Cutive Mono\" to \"Cutive Mono\",\n                \"Short Stack\" to \"Short Stack\",\n                \"Quintessential\" to \"Quintessential\",\n                \"Alegreya Sans SC\" to \"Alegreya Sans SC\",\n            )\n\n            //showBottomDialog\n            activity?.showDialog(\n                fontTypes.map { it.second },\n                fontTypes.map { it.first }.indexOf(state.fontFamily),\n                (textView as TextView).text.toString(),\n                false,\n                dismissCallback\n            ) { index ->\n                state.fontFamily = fontTypes.map { it.first }[index]\n                updateState()\n            }\n        }\n        binding.subsFont.setOnLongClickListener { _ ->\n            state.fontFamily = defaultState.fontFamily\n            updateState()\n            showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n            return@setOnLongClickListener true\n        }\n\n        binding.cancelBtt.setOnClickListener {\n            activity?.popCurrentPage()\n        }\n\n        binding.applyBtt.setOnClickListener {\n            it.context.saveStyle(state)\n            applyStyleEvent.invoke(state)\n            //it.context.fromSaveToStyle(state)\n            activity?.popCurrentPage()\n        }\n\n        setSubtitleCues(binding)\n    }\n\n    @OptIn(UnstableApi::class)\n    private fun setSubtitleCues(binding: ChromecastSubtitleSettingsBinding) {\n        binding.subtitleText.apply {\n            setCues(\n                listOf(\n                    Cue.Builder()\n                        .setTextSize(\n                            getPixels(TypedValue.COMPLEX_UNIT_SP, 25.0f).toFloat(),\n                            Cue.TEXT_SIZE_TYPE_ABSOLUTE\n                        )\n                        .setText(context.getString(R.string.subtitles_example_text))\n                        .build()\n                )\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt",
    "content": "package com.lagradost.cloudstream3.ui.subtitles\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.res.Resources\nimport android.graphics.Color\nimport android.graphics.Typeface\nimport android.os.Bundle\nimport android.text.Layout\nimport android.text.Spannable\nimport android.text.SpannableString\nimport android.text.style.StyleSpan\nimport android.util.DisplayMetrics\nimport android.util.TypedValue\nimport android.view.View\nimport android.widget.TextView\nimport android.widget.Toast\nimport androidx.annotation.FontRes\nimport androidx.annotation.OptIn\nimport androidx.annotation.Px\nimport androidx.core.content.edit\nimport androidx.core.content.res.ResourcesCompat\nimport androidx.media3.common.text.Cue\nimport androidx.media3.common.util.UnstableApi\nimport androidx.media3.ui.CaptionStyleCompat\nimport androidx.media3.ui.SubtitleView\nimport androidx.preference.PreferenceManager\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.jaredrummler.android.colorpicker.ColorPickerDialog\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent\nimport com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.SubtitleSettingsBinding\nimport com.lagradost.cloudstream3.ui.BaseDialogFragment\nimport com.lagradost.cloudstream3.ui.BaseFragment\nimport com.lagradost.cloudstream3.ui.player.CustomDecoder\nimport com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.setSubtitleAlignment\nimport com.lagradost.cloudstream3.ui.player.OutlineSpan\nimport com.lagradost.cloudstream3.ui.player.RoundedBackgroundColorSpan\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLandscape\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.DataStore.setKey\nimport com.lagradost.cloudstream3.utils.Event\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog\nimport com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.languages\nimport com.lagradost.cloudstream3.utils.UIHelper.fixSystemBarsPadding\nimport com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage\nimport com.lagradost.cloudstream3.utils.UIHelper.toPx\nimport java.io.File\n\nconst val SUBTITLE_KEY = \"subtitle_settings\"\nconst val SUBTITLE_AUTO_SELECT_KEY = \"subs_auto_select\"\nconst val SUBTITLE_DOWNLOAD_KEY = \"subs_auto_download\"\n\ndata class SaveCaptionStyle(\n    @JsonProperty(\"foregroundColor\") var foregroundColor: Int,\n    @JsonProperty(\"backgroundColor\") var backgroundColor: Int,\n    @JsonProperty(\"windowColor\") var windowColor: Int,\n    @OptIn(UnstableApi::class)\n    @JsonProperty(\"edgeType\") var edgeType: @CaptionStyleCompat.EdgeType Int,\n    @JsonProperty(\"edgeColor\") var edgeColor: Int,\n    @FontRes\n    @JsonProperty(\"typeface\") var typeface: Int?,\n    @JsonProperty(\"typefaceFilePath\") var typefaceFilePath: String?,\n    /**in dp**/\n    @JsonProperty(\"elevation\") var elevation: Int,\n    /**in sp**/\n    @JsonProperty(\"fixedTextSize\") var fixedTextSize: Float?,\n    @Px\n    @JsonProperty(\"edgeSize\") var edgeSize: Float? = null,\n    @JsonProperty(\"removeCaptions\") var removeCaptions: Boolean = false,\n    @JsonProperty(\"removeBloat\") var removeBloat: Boolean = true,\n    /** Apply caps lock to the text **/\n    @JsonProperty(\"upperCase\") var upperCase: Boolean = false,\n    /** Apply bold to the text **/\n    @JsonProperty(\"bold\") var bold: Boolean = false,\n    /** Apply italic to the text **/\n    @JsonProperty(\"italic\") var italic: Boolean = false,\n    /** in px, background radius, aka how round the background (backgroundColor) on each row is **/\n    @JsonProperty(\"backgroundRadius\") var backgroundRadius: Float? = null,\n    /** The SSA_ALIGNMENT */\n    @JsonProperty(\"alignment\") var alignment: Int? = null,\n)\n\nconst val DEF_SUBS_ELEVATION = 20\n\n@OptIn(UnstableApi::class)\nclass SubtitlesFragment : BaseDialogFragment<SubtitleSettingsBinding>(\n    BaseFragment.BindingCreator.Inflate(SubtitleSettingsBinding::inflate)\n) {\n    companion object {\n        val applyStyleEvent = Event<SaveCaptionStyle>()\n        private val captionRegex = Regex(\"\"\"(-\\s?|)[\\[({][\\S\\s]*?[])}]\\s*\"\"\")\n\n        fun setSubtitleViewStyle(\n            view: SubtitleView?,\n            data: SaveCaptionStyle,\n            applyElevation: Boolean\n        ) {\n            if (view == null) return\n            val ctx = view.context ?: return\n            val style = ctx.fromSaveToStyle(data)\n            view.setStyle(style)\n\n            if (applyElevation) {\n                view.setPadding(\n                    view.paddingLeft, data.elevation.toPx, view.paddingRight, view.paddingBottom\n                )\n            }\n\n            // we default to 25sp, this is needed as RoundedBackgroundColorSpan breaks on override sizes\n            val size = data.fixedTextSize ?: 25.0f\n            view.setFixedTextSize(TypedValue.COMPLEX_UNIT_SP, size)\n            view.setBottomPaddingFraction(0.0f)\n            /*if (size != null) {\n                view.setFixedTextSize(TypedValue.COMPLEX_UNIT_SP, size)\n            } else {\n                view.setUserDefaultTextSize()\n            }*/\n        }\n\n        fun Cue.Builder.applyStyle(style: SaveCaptionStyle): Cue.Builder {\n            val edgeSize = style.edgeSize\n\n            /*\n            This is old code for only applying on non null\n\n            val fixedFontSize = style.fixedTextSize\n            val absoluteFontSize =\n                fixedFontSize?.let { getPixels(TypedValue.COMPLEX_UNIT_SP, it).toFloat() }\n\n            // 1. apply override size\n            if (absoluteFontSize != null) {\n                setTextSize(absoluteFontSize, Cue.TEXT_SIZE_TYPE_ABSOLUTE)\n            }*/\n\n            // 1. remove any subtitle size set by the subtitle file (like ass)\n            // instead we use the inherit size of the subtitle view\n            setTextSize(Cue.DIMEN_UNSET, Cue.TYPE_UNSET)\n\n            // 2. apply edge\n            text?.let { text ->\n                val customSpan = SpannableString.valueOf(text)\n                if (edgeSize != null) {\n                    customSpan.setSpan(\n                        OutlineSpan(edgeSize), 0, customSpan.length,\n                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE\n                    )\n                }\n                setText(customSpan)\n            }\n\n            // 3. apply bold + italic\n            text?.let { text ->\n                val customSpan = SpannableString.valueOf(text)\n\n                val typeface = when (style.bold to style.italic) {\n                    (true to true) -> Typeface.BOLD_ITALIC\n                    (true to false) -> Typeface.BOLD\n                    (false to true) -> Typeface.ITALIC\n                    (false to false) -> Typeface.NORMAL\n                    else -> {\n                        Typeface.NORMAL\n                    }\n                }\n                if (typeface != Typeface.NORMAL) {\n                    val styleSpan = StyleSpan(typeface)\n                    customSpan.setSpan(\n                        styleSpan, 0, customSpan.length,\n                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE\n                    )\n                }\n                setText(customSpan)\n            }\n\n            // 4. apply radius\n            text?.let { text ->\n                val customSpan = SpannableString.valueOf(text)\n                val radius = style.backgroundRadius\n\n                if (radius != null && style.backgroundColor != Color.TRANSPARENT) {\n                    val styleSpan = RoundedBackgroundColorSpan(\n                        style.backgroundColor,\n                        this.textAlignment ?: Layout.Alignment.ALIGN_CENTER,\n                        2.0F + radius * 0.5f,\n                        radius\n                    )\n                    customSpan.setSpan(\n                        styleSpan, 0, customSpan.length,\n                        Spannable.SPAN_EXCLUSIVE_EXCLUSIVE\n                    )\n                }\n                setText(customSpan)\n            }\n\n            // 5. remove captions\n            text?.let { text ->\n                if (style.removeCaptions) {\n                    setText(text.replace(captionRegex, \"\"))\n                }\n            }\n\n            // 6. set alignment\n            return this.setSubtitleAlignment(style.alignment)\n        }\n\n        private fun Context.fromSaveToStyle(data: SaveCaptionStyle): CaptionStyleCompat {\n            return CaptionStyleCompat(\n                data.foregroundColor,\n                // we actually override with a custom span when backgroundRadius != null\n                if (data.backgroundRadius == null) data.backgroundColor else Color.TRANSPARENT,\n                data.windowColor,\n                data.edgeType,\n                data.edgeColor,\n                data.typefaceFilePath?.let {\n                    try {\n                        // RuntimeException: Font asset not found\n                        Typeface.createFromFile(File(it))\n                    } catch (e: Exception) {\n                        null\n                    }\n                } ?: data.typeface?.let {\n                    ResourcesCompat.getFont(\n                        this,\n                        it\n                    )\n                }\n                ?: Typeface.SANS_SERIF\n            )\n        }\n\n        fun push(activity: Activity?, hide: Boolean = true) {\n            activity.navigate(R.id.global_to_navigation_subtitles, Bundle().apply {\n                putBoolean(\"hide\", hide)\n                putBoolean(\"popFragment\", true)\n            })\n        }\n\n        private fun getDefColor(id: Int): Int {\n            return when (id) {\n                0 -> Color.WHITE\n                1 -> Color.BLACK\n                2 -> Color.TRANSPARENT\n                3 -> Color.TRANSPARENT\n                else -> Color.TRANSPARENT\n            }\n        }\n\n        private var cachedSubtitleStyle: SaveCaptionStyle? = null\n\n        fun Context.saveStyle(style: SaveCaptionStyle) {\n            cachedSubtitleStyle = style\n            this.setKey(SUBTITLE_KEY, style)\n        }\n\n        fun getCurrentSavedStyle(): SaveCaptionStyle {\n            return cachedSubtitleStyle ?: (getKey(SUBTITLE_KEY) ?: SaveCaptionStyle(\n                foregroundColor = getDefColor(0),\n                backgroundColor = getDefColor(2),\n                windowColor = getDefColor(3),\n                edgeType = CaptionStyleCompat.EDGE_TYPE_OUTLINE,\n                edgeColor = getDefColor(1),\n                typeface = null,\n                typefaceFilePath = null,\n                elevation = DEF_SUBS_ELEVATION,\n                fixedTextSize = null,\n            )).also { cachedSubtitleStyle = it }\n        }\n\n        private fun Context.getSavedFonts(): List<File> {\n            val externalFiles = getExternalFilesDir(null) ?: return emptyList()\n            val fontDir = File(externalFiles.absolutePath + \"/Fonts\").also {\n                it.mkdir()\n            }\n            return fontDir.list()?.mapNotNull {\n                // No idea which formats are supported, but these should be.\n                if (it.endsWith(\".ttf\") || it.endsWith(\".otf\")) {\n                    File(fontDir.absolutePath + \"/\" + it)\n                } else null\n            } ?: listOf()\n        }\n\n        private fun getPixels(unit: Int, size: Float): Int {\n            val metrics: DisplayMetrics = Resources.getSystem().displayMetrics\n            return TypedValue.applyDimension(unit, size, metrics).toInt()\n        }\n\n        fun getDownloadSubsLanguageTagIETF(): List<String> {\n            return getKey(SUBTITLE_DOWNLOAD_KEY) ?: listOf(\"en\")\n        }\n\n        fun getAutoSelectLanguageTagIETF(): String {\n            return getKey(SUBTITLE_AUTO_SELECT_KEY) ?: \"en\"\n        }\n    }\n\n    private fun onColorSelected(stuff: Pair<Int, Int>) {\n        context?.setColor(stuff.first, stuff.second)\n        if (hide)\n            activity?.hideSystemUI()\n    }\n\n    private fun onDialogDismissed(@Suppress(\"UNUSED_PARAMETER\") id: Int) {\n        if (hide)\n            activity?.hideSystemUI()\n    }\n\n    private fun Context.setColor(id: Int, color: Int?) {\n        val realColor = color ?: getDefColor(id)\n        when (id) {\n            0 -> state.foregroundColor = realColor\n            1 -> state.edgeColor = realColor\n            2 -> state.backgroundColor = realColor\n            3 -> state.windowColor = realColor\n\n            else -> Unit\n        }\n        updateState()\n    }\n\n    private fun Context.updateState() {\n        val text = getString(R.string.subtitles_example_text)\n        val fixedText = SpannableString.valueOf(if (state.upperCase) text.uppercase() else text)\n        setSubtitleViewStyle(binding?.subtitleText, state, false)\n\n        binding?.subtitleText?.setCues(\n            listOf(\n                Cue.Builder()\n                    .setText(fixedText)\n                    .applyStyle(state)\n                    .build()\n            )\n        )\n    }\n\n    private fun getColor(id: Int): Int {\n        val color = when (id) {\n            0 -> state.foregroundColor\n            1 -> state.edgeColor\n            2 -> state.backgroundColor\n            3 -> state.windowColor\n\n            else -> Color.TRANSPARENT\n        }\n\n        return if (color == Color.TRANSPARENT) Color.BLACK else color\n    }\n\n    private lateinit var state: SaveCaptionStyle\n    private var hide: Boolean = true\n\n    override fun onDestroy() {\n        super.onDestroy()\n        onColorSelectedEvent -= ::onColorSelected\n    }\n\n    override fun onStart() {\n        super.onStart()\n        dialog?.window?.setWindowAnimations(R.style.DialogFullscreenPlayer)\n    }\n\n    override fun getTheme(): Int {\n        return R.style.DialogFullscreenPlayer\n    }\n\n    var systemBarsAddPadding = isLayout(TV or EMULATOR)\n    override fun fixLayout(view: View) {\n        fixSystemBarsPadding(\n            view,\n            padBottom = systemBarsAddPadding || isLandscape(),\n            padLeft = systemBarsAddPadding\n        )\n    }\n\n    override fun onBindingCreated(binding: SubtitleSettingsBinding) {\n        hide = arguments?.getBoolean(\"hide\") ?: true\n        val popFragment = arguments?.getBoolean(\"popFragment\") ?: false\n        onColorSelectedEvent += ::onColorSelected\n        onDialogDismissedEvent += ::onDialogDismissed\n        binding.subsImportText.text = getString(R.string.subs_import_text).format(\n            context?.getExternalFilesDir(null)?.absolutePath.toString() + \"/Fonts\"\n        )\n\n        state = getCurrentSavedStyle()\n        context?.updateState()\n\n        val isTvTrueSettings = isLayout(TV)\n        fun View.setFocusableInTv() {\n            this.isFocusableInTouchMode = isTvTrueSettings\n        }\n\n        fun View.setup(id: Int) {\n            setFocusableInTv()\n\n            this.setOnClickListener {\n                activity?.let {\n                    ColorPickerDialog.newBuilder()\n                        .setDialogId(id)\n                        .setShowAlphaSlider(true)\n                        .setColor(getColor(id))\n                        .show(it)\n                }\n            }\n\n            this.setOnLongClickListener {\n                it.context.setColor(id, null)\n                showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n        }\n        binding.apply {\n            subsTextColor.setup(0)\n            subsOutlineColor.setup(1)\n            subsBackgroundColor.setup(2)\n            subsWindowColor.setup(3)\n\n            val dismissCallback = {\n                if (hide)\n                    activity?.hideSystemUI()\n            }\n\n            subsSubtitleElevation.setFocusableInTv()\n            subsSubtitleElevation.setOnClickListener { textView ->\n                // tbh this should not be a dialog if it has so many values\n                val elevationTypes = listOf(\n                    0 to textView.context.getString(R.string.none)\n                ) + (1..40).map { x ->\n                    val i = x * 10\n                    i to \"${i}dp\"\n                }\n\n                //showBottomDialog\n                activity?.showDialog(\n                    elevationTypes.map { it.second },\n                    elevationTypes.map { it.first }.indexOf(state.elevation),\n                    (textView as TextView).text.toString(),\n                    false,\n                    dismissCallback\n                ) { index ->\n                    state.elevation = elevationTypes.map { it.first }[index]\n                    textView.context.updateState()\n                    if (hide)\n                        activity?.hideSystemUI()\n                }\n            }\n\n            subsSubtitleElevation.setOnLongClickListener {\n                state.elevation = DEF_SUBS_ELEVATION\n                it.context.updateState()\n                showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n\n            subsBackgroundRadius.setFocusableInTv()\n            subsBackgroundRadius.setOnClickListener { textView ->\n                // tbh this should not be a dialog if it has so many values\n                val radiusTypes = listOf(\n                    null to textView.context.getString(R.string.none)\n                ) + (1..10).map { x ->\n                    val i = x * 5\n                    i to \"${i}px\"\n                }\n\n                activity?.showDialog(\n                    radiusTypes.map { it.second },\n                    radiusTypes.map { it.first }.indexOf(state.backgroundRadius?.toInt()),\n                    (textView as TextView).text.toString(),\n                    false,\n                    dismissCallback\n                ) { index ->\n                    state.backgroundRadius = radiusTypes.map { it.first }[index]?.toFloat()\n                    textView.context.updateState()\n                }\n            }\n\n            subsBackgroundRadius.setOnLongClickListener {\n                state.backgroundRadius = null\n                it.context.updateState()\n                showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n\n            subsSubtitleAlignment.setFocusableInTv()\n            subsSubtitleAlignment.setOnClickListener { textView ->\n                val alignmentTypes = listOf(\n                    null to R.string.automatic,\n                    CustomDecoder.SSA_ALIGNMENT_BOTTOM_LEFT to R.string.bottom_left,\n                    CustomDecoder.SSA_ALIGNMENT_BOTTOM_CENTER to R.string.bottom_center,\n                    CustomDecoder.SSA_ALIGNMENT_BOTTOM_RIGHT to R.string.bottom_right,\n                    CustomDecoder.SSA_ALIGNMENT_MIDDLE_LEFT to R.string.middle_left,\n                    CustomDecoder.SSA_ALIGNMENT_MIDDLE_CENTER to R.string.middle_center,\n                    CustomDecoder.SSA_ALIGNMENT_MIDDLE_RIGHT to R.string.middle_right,\n                    CustomDecoder.SSA_ALIGNMENT_TOP_LEFT to R.string.top_left,\n                    CustomDecoder.SSA_ALIGNMENT_TOP_CENTER to R.string.top_center,\n                    CustomDecoder.SSA_ALIGNMENT_TOP_RIGHT to R.string.top_right,\n                )\n\n                activity?.showDialog(\n                    alignmentTypes.map { textView.context.getString(it.second) },\n                    alignmentTypes.map { it.first }.indexOf(state.alignment),\n                    (textView as TextView).text.toString(),\n                    false,\n                    dismissCallback\n                ) { index ->\n                    state.alignment = alignmentTypes.map { it.first }[index]\n                    textView.context.updateState()\n                }\n            }\n\n            subsEdgeType.setFocusableInTv()\n            subsEdgeType.setOnClickListener { textView ->\n                val edgeTypes = listOf(\n                    CaptionStyleCompat.EDGE_TYPE_NONE to\n                            textView.context.getString(R.string.subtitles_none),\n                    CaptionStyleCompat.EDGE_TYPE_OUTLINE to\n                            textView.context.getString(R.string.subtitles_outline),\n                    CaptionStyleCompat.EDGE_TYPE_DEPRESSED to\n                            textView.context.getString(R.string.subtitles_depressed),\n                    CaptionStyleCompat.EDGE_TYPE_DROP_SHADOW to\n                            textView.context.getString(R.string.subtitles_shadow),\n                    CaptionStyleCompat.EDGE_TYPE_RAISED to\n                            textView.context.getString(R.string.subtitles_raised),\n                )\n\n                //showBottomDialog\n                activity?.showDialog(\n                    edgeTypes.map { it.second },\n                    edgeTypes.map { it.first }.indexOf(state.edgeType),\n                    (textView as TextView).text.toString(),\n                    false,\n                    dismissCallback\n                ) { index ->\n                    state.edgeType = edgeTypes.map { it.first }[index]\n                    textView.context.updateState()\n                }\n            }\n\n            subsEdgeType.setOnLongClickListener {\n                state.edgeType = CaptionStyleCompat.EDGE_TYPE_OUTLINE\n                it.context.updateState()\n                showToast(R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n\n            subsFontSize.setFocusableInTv()\n            subsFontSize.setOnClickListener { textView ->\n                val fontSizes = listOf(\n                    null to textView.context.getString(R.string.normal),\n                ) + (6..60).map { i -> i.toFloat() to \"${i}sp\" }\n\n                //showBottomDialog\n                activity?.showDialog(\n                    fontSizes.map { it.second },\n                    fontSizes.map { it.first }.indexOf(state.fixedTextSize),\n                    (textView as TextView).text.toString(),\n                    false,\n                    dismissCallback\n                ) { index ->\n                    state.fixedTextSize = fontSizes.map { it.first }[index]\n                    textView.context.updateState()\n                }\n            }\n\n            subsEdgeSize.setFocusableInTv()\n            subsEdgeSize.setOnClickListener { textView ->\n                val fontSizes = listOf(\n                    null to textView.context.getString(R.string.normal),\n                ) + (1..60).map { i -> i.toFloat() to \"${i}px\" }\n\n                //showBottomDialog\n                activity?.showDialog(\n                    fontSizes.map { it.second },\n                    fontSizes.map { it.first }.indexOf(state.edgeSize),\n                    (textView as TextView).text.toString(),\n                    false,\n                    dismissCallback\n                ) { index ->\n                    state.edgeSize = fontSizes.map { it.first }[index]\n                    textView.context.updateState()\n                }\n            }\n\n            subtitlesRemoveBloat.isChecked = state.removeBloat\n            subtitlesRemoveBloat.setOnCheckedChangeListener { _, b ->\n                state.removeBloat = b\n            }\n            subtitlesUppercase.isChecked = state.upperCase\n            subtitlesUppercase.setOnCheckedChangeListener { _, b ->\n                state.upperCase = b\n                context?.updateState()\n            }\n\n            subtitlesRemoveCaptions.isChecked = state.removeCaptions\n            subtitlesRemoveCaptions.setOnCheckedChangeListener { _, b ->\n                state.removeCaptions = b\n            }\n\n            subtitlesBold.isChecked = state.bold\n            subtitlesBold.setOnCheckedChangeListener { _, b ->\n                state.bold = b\n                context?.updateState()\n            }\n\n            subtitlesItalic.isChecked = state.italic\n            subtitlesItalic.setOnCheckedChangeListener { _, b ->\n                state.italic = b\n                context?.updateState()\n            }\n\n            subsFontSize.setOnLongClickListener { _ ->\n                state.fixedTextSize = null\n                context?.updateState()\n                showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n\n            subsEdgeSize.setOnLongClickListener { _ ->\n                state.edgeSize = null\n                context?.updateState()\n                showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n\n            //Fetch current value from preference\n            context?.let { ctx ->\n                subtitlesFilterSubLang.isChecked =\n                    PreferenceManager.getDefaultSharedPreferences(ctx)\n                        .getBoolean(getString(R.string.filter_sub_lang_key), false)\n            }\n\n            subtitlesFilterSubLang.setOnCheckedChangeListener { _, b ->\n                context?.let { ctx ->\n                    PreferenceManager.getDefaultSharedPreferences(ctx).edit {\n                        putBoolean(getString(R.string.filter_sub_lang_key), b)\n                    }\n                }\n            }\n\n            subsFont.setFocusableInTv()\n            subsFont.setOnClickListener { textView ->\n                val fontTypes = listOf(\n                    null to textView.context.getString(R.string.normal),\n                    R.font.trebuchet_ms to \"Trebuchet MS\",\n                    R.font.netflix_sans to \"Netflix Sans\",\n                    R.font.google_sans to \"Google Sans\",\n                    R.font.open_sans to \"Open Sans\",\n                    R.font.futura to \"Futura\",\n                    R.font.consola to \"Consola\",\n                    R.font.gotham to \"Gotham\",\n                    R.font.lucida_grande to \"Lucida Grande\",\n                    R.font.stix_general to \"STIX General\",\n                    R.font.times_new_roman to \"Times New Roman\",\n                    R.font.verdana to \"Verdana\",\n                    R.font.ubuntu_regular to \"Ubuntu\",\n                    R.font.comic_sans to \"Comic Sans\",\n                    R.font.poppins_regular to \"Poppins\",\n                )\n                val savedFontTypes = textView.context.getSavedFonts()\n\n                val currentIndex =\n                    savedFontTypes.indexOfFirst { it.absolutePath == state.typefaceFilePath }\n                        .let { index ->\n                            if (index == -1)\n                                fontTypes.indexOfFirst { it.first == state.typeface }\n                            else index + fontTypes.size\n                        }\n\n                //showBottomDialog\n                activity?.showDialog(\n                    fontTypes.map { it.second } + savedFontTypes.map { it.name },\n                    currentIndex,\n                    (textView as TextView).text.toString(),\n                    false,\n                    dismissCallback\n                ) { index ->\n                    if (index < fontTypes.size) {\n                        state.typeface = fontTypes[index].first\n                        state.typefaceFilePath = null\n                    } else {\n                        state.typefaceFilePath = savedFontTypes[index - fontTypes.size].absolutePath\n                        state.typeface = null\n                    }\n                    textView.context.updateState()\n                }\n            }\n\n            subsFont.setOnLongClickListener { textView ->\n                state.typeface = null\n                state.typefaceFilePath = null\n                textView.context.updateState()\n                showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n\n            subsAutoSelectLanguage.setFocusableInTv()\n            subsAutoSelectLanguage.setOnClickListener { textView ->\n                val languagesTagName =\n                    listOf(\n                        Pair(\n                            textView.context.getString(R.string.none),\n                            textView.context.getString(R.string.none)\n                        )\n                    ) +\n                            languages\n                                .map { Pair(it.IETF_tag, it.nameNextToFlagEmoji()) }\n                                .sortedBy {\n                                    it.second.substringAfter(\"\\u00a0\").lowercase()\n                                } // name ignoring flag emoji\n\n                val (langTagsIETF, langNames) = languagesTagName.unzip()\n\n                activity?.showDialog(\n                    langNames,\n                    langTagsIETF.indexOf(getAutoSelectLanguageTagIETF()),\n                    (textView as TextView).text.toString(),\n                    true,\n                    dismissCallback\n                ) { index ->\n                    setKey(SUBTITLE_AUTO_SELECT_KEY, langTagsIETF[index])\n                }\n            }\n\n            subsAutoSelectLanguage.setOnLongClickListener {\n                setKey(SUBTITLE_AUTO_SELECT_KEY, \"en\")\n                showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n\n            subsDownloadLanguages.setFocusableInTv()\n            subsDownloadLanguages.setOnClickListener { textView ->\n                val languagesTagName =\n                    languages\n                        .map { Pair(it.IETF_tag, it.nameNextToFlagEmoji()) }\n                        .sortedBy {\n                            it.second.substringAfter(\"\\u00a0\").lowercase()\n                        } // name ignoring flag emoji\n\n                val (langTagsIETF, langNames) = languagesTagName.unzip()\n\n                val selectedLanguages = getDownloadSubsLanguageTagIETF()\n                    .map { langTagsIETF.indexOf(it) }\n                    .filter { it >= 0 }\n\n                activity?.showMultiDialog(\n                    langNames,\n                    selectedLanguages,\n                    (textView as TextView).text.toString(),\n                    dismissCallback\n                ) { indexList ->\n                    setKey(SUBTITLE_DOWNLOAD_KEY, indexList.map { langTagsIETF[it] }.toList())\n                }\n            }\n\n            subsDownloadLanguages.setOnLongClickListener {\n                setKey(SUBTITLE_DOWNLOAD_KEY, listOf(\"en\"))\n\n                showToast(activity, R.string.subs_default_reset_toast, Toast.LENGTH_SHORT)\n                return@setOnLongClickListener true\n            }\n\n            cancelBtt.setOnClickListener {\n                if (popFragment) {\n                    activity?.popCurrentPage()\n                } else {\n                    dismiss()\n                }\n            }\n\n            applyBtt.setOnClickListener {\n                it.context.saveStyle(state)\n                applyStyleEvent.invoke(state)\n                if (popFragment) {\n                    activity?.popCurrentPage()\n                } else {\n                    dismiss()\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/AniSkip.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.util.Log\nimport androidx.annotation.StringRes\nimport com.fasterxml.jackson.databind.annotation.JsonSerialize\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.LoadResponse.Companion.getMalId\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport java.lang.Long.min\n\nobject EpisodeSkip {\n    private const val TAG = \"EpisodeSkip\"\n\n    enum class SkipType(@StringRes name: Int) {\n        Opening(R.string.skip_type_op),\n        Ending(R.string.skip_type_ed),\n        Recap(R.string.skip_type_recap),\n        MixedOpening(R.string.skip_type_mixed_op),\n        MixedEnding(R.string.skip_type_mixed_ed),\n        Credits(R.string.skip_type_creddits),\n        Intro(R.string.skip_type_creddits),\n    }\n\n    data class SkipStamp(\n        val type: SkipType,\n        val skipToNextEpisode: Boolean,\n        val startMs: Long,\n        val endMs: Long,\n    ) {\n        val uiText = if (skipToNextEpisode) txt(R.string.next_episode) else txt(\n            R.string.skip_type_format,\n            txt(type.name)\n        )\n    }\n\n    private val cachedStamps = HashMap<Int, List<SkipStamp>>()\n\n    private fun shouldSkipToNextEpisode(endMs: Long, episodeDurationMs: Long): Boolean {\n        return episodeDurationMs - endMs < 20_000L // some might have outro that we don't care about tbh\n    }\n\n    suspend fun getStamps(\n        data: LoadResponse,\n        episode: ResultEpisode,\n        episodeDurationMs: Long,\n        hasNextEpisode: Boolean,\n    ): List<SkipStamp> {\n        cachedStamps[episode.id]?.let { list ->\n            return list\n        }\n\n        val out = mutableListOf<SkipStamp>()\n        Log.i(TAG, \"Requesting SkipStamp from ${data.syncData}\")\n\n        if (data is AnimeLoadResponse && (data.type == TvType.Anime || data.type == TvType.OVA)) {\n            data.getMalId()?.toIntOrNull()?.let { malId ->\n                val (resultLength, stamps) = AniSkip.getResult(\n                    malId,\n                    episode.episode,\n                    episodeDurationMs\n                ) ?: return@let null\n                // because it also returns an expected episode length we use that just in case it is mismatched with like 2s next episode will still work\n                val dur = min(episodeDurationMs, resultLength)\n                stamps.mapNotNull { stamp ->\n                    val skipType = when (stamp.skipType) {\n                        \"op\" -> SkipType.Opening\n                        \"ed\" -> SkipType.Ending\n                        \"recap\" -> SkipType.Recap\n                        \"mixed-ed\" -> SkipType.MixedEnding\n                        \"mixed-op\" -> SkipType.MixedOpening\n                        else -> null\n                    } ?: return@mapNotNull null\n                    val end = (stamp.interval.endTime * 1000.0).toLong()\n                    val start = (stamp.interval.startTime * 1000.0).toLong()\n                    SkipStamp(\n                        type = skipType,\n                        skipToNextEpisode = hasNextEpisode && shouldSkipToNextEpisode(\n                            end,\n                            dur\n                        ),\n                        startMs = start,\n                        endMs = end\n                    )\n                }.let { list ->\n                    out.addAll(list)\n                }\n            }\n        }\n        if (out.isNotEmpty())\n            cachedStamps[episode.id] = out\n        return out\n    }\n}\n\n// taken from https://github.com/saikou-app/saikou/blob/3803f8a7a59b826ca193664d46af3a22bbc989f7/app/src/main/java/ani/saikou/others/AniSkip.kt\n// the following is GPLv3 code https://github.com/saikou-app/saikou/blob/main/LICENSE.md\nobject AniSkip {\n    private const val TAG = \"AniSkip\"\n    suspend fun getResult(\n        malId: Int,\n        episodeNumber: Int,\n        episodeLength: Long\n    ): Pair<Long, List<Stamp>>? {\n        return try {\n            val url =\n                \"https://api.aniskip.com/v2/skip-times/$malId/$episodeNumber?types[]=ed&types[]=mixed-ed&types[]=mixed-op&types[]=op&types[]=recap&episodeLength=${episodeLength / 1000L}\"\n            Log.i(TAG, \"Requesting $url\")\n\n            val a = app.get(url)\n            val res = a.parsed<AniSkipResponse>()\n            Log.i(TAG, \"Found ${res.found} with ${res.results?.size} results\")\n            if (res.found && !res.results.isNullOrEmpty()) (res.results[0].episodeLength * 1000).toLong() to res.results else null\n        } catch (t: Throwable) {\n            Log.i(TAG, \"error = ${t.message}\")\n            logError(t)\n            null\n        }\n    }\n\n    data class AniSkipResponse(\n        @JsonSerialize val found: Boolean,\n        @JsonSerialize val results: List<Stamp>?,\n        @JsonSerialize val message: String?,\n        @JsonSerialize val statusCode: Int\n    )\n\n    data class Stamp(\n        @JsonSerialize val interval: AniSkipInterval,\n        @JsonSerialize val skipType: String,\n        @JsonSerialize val skipId: String,\n        @JsonSerialize val episodeLength: Double\n    )\n\n    data class AniSkipInterval(\n        @JsonSerialize val startTime: Double,\n        @JsonSerialize val endTime: Double\n    )\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/AppContextUtils.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.animation.ObjectAnimator\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.app.Activity.RESULT_CANCELED\nimport android.app.NotificationChannel\nimport android.app.NotificationManager\nimport android.content.Context\nimport android.content.DialogInterface\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.database.Cursor\nimport android.media.AudioAttributes\nimport android.media.AudioFocusRequest\nimport android.media.AudioManager\nimport android.media.tv.TvContract.Channels.COLUMN_INTERNAL_PROVIDER_ID\nimport android.net.ConnectivityManager\nimport android.net.Network\nimport android.net.NetworkCapabilities\nimport android.os.Build\nimport android.os.Handler\nimport android.os.Looper\nimport android.text.Spanned\nimport android.util.Log\nimport android.view.View\nimport android.view.View.LAYOUT_DIRECTION_LTR\nimport android.view.View.LAYOUT_DIRECTION_RTL\nimport android.view.animation.DecelerateInterpolator\nimport android.widget.Toast\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.annotation.RequiresApi\nimport androidx.annotation.WorkerThread\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.net.toUri\nimport androidx.core.text.HtmlCompat\nimport androidx.core.text.toSpanned\nimport androidx.core.widget.ContentLoadingProgressBar\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.FragmentActivity\nimport androidx.navigation.fragment.findNavController\nimport androidx.preference.PreferenceManager\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.RecyclerView\nimport androidx.tvprovider.media.tv.PreviewChannelHelper\nimport androidx.tvprovider.media.tv.TvContractCompat\nimport androidx.tvprovider.media.tv.WatchNextProgram\nimport androidx.tvprovider.media.tv.WatchNextProgram.fromCursor\nimport androidx.viewpager2.widget.ViewPager2\nimport com.google.android.gms.cast.framework.CastContext\nimport com.google.android.gms.cast.framework.CastState\nimport com.google.android.gms.common.ConnectionResult\nimport com.google.android.gms.common.GoogleApiAvailability\nimport com.google.android.gms.common.wrappers.Wrappers\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.lagradost.cloudstream3.APIHolder.apis\nimport com.lagradost.cloudstream3.AllLanguagesName\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.DubStatus\nimport com.lagradost.cloudstream3.HomePageList\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.MainActivity.Companion.afterRepositoryLoadedEvent\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.isMovieType\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.plugins.RepositoryManager\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING_RESUME_WATCHING\nimport com.lagradost.cloudstream3.syncproviders.providers.Kitsu\nimport com.lagradost.cloudstream3.ui.WebviewFragment\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.ui.result.ResultFragment\nimport com.lagradost.cloudstream3.ui.settings.Globals\nimport com.lagradost.cloudstream3.ui.settings.extensions.PluginsFragment\nimport com.lagradost.cloudstream3.ui.settings.extensions.RepositoryData\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getAllResumeStateIds\nimport com.lagradost.cloudstream3.utils.DataStoreHelper.getLastWatched\nimport com.lagradost.cloudstream3.utils.FillerEpisodeCheck.toClassDir\nimport com.lagradost.cloudstream3.utils.JsUnpacker.Companion.load\nimport com.lagradost.cloudstream3.utils.UIHelper.navigate\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport okhttp3.Cache\nimport java.io.File\nimport java.net.URL\nimport java.net.URLDecoder\nimport java.util.concurrent.Executor\nimport java.util.concurrent.Executors\n\n\nobject AppContextUtils {\n    fun RecyclerView.isRecyclerScrollable(): Boolean {\n        val layoutManager =\n            this.layoutManager as? LinearLayoutManager?\n        val adapter = adapter\n        return if (layoutManager == null || adapter == null) false else layoutManager.findLastCompletelyVisibleItemPosition() < adapter.itemCount - 7 // bit more than 1 to make it more seamless\n    }\n\n    fun View.isLtr() = this.layoutDirection == LAYOUT_DIRECTION_LTR\n    fun View.isRtl() = this.layoutDirection == LAYOUT_DIRECTION_RTL\n\n    fun BottomSheetDialog?.ownHide() {\n        this?.hide()\n    }\n\n    fun BottomSheetDialog?.ownShow() {\n        // the reason for this is because show has a shitty animation we don't want\n        this?.window?.setWindowAnimations(-1)\n        this?.show()\n        Handler(Looper.getMainLooper()).postDelayed({\n            this?.window?.setWindowAnimations(com.google.android.material.R.style.Animation_Design_BottomSheetDialog)\n        }, 200)\n    }\n\n    //fun Context.deleteFavorite(data: SearchResponse) {\n    //    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return\n    //    safe {\n    //        val existingId =\n    //            getWatchNextProgramByVideoId(data.url, this).second ?: return@safe\n    //        contentResolver.delete(\n//\n    //            TvContractCompat.buildWatchNextProgramUri(existingId),\n    //            null, null\n    //        )\n    //    }\n    //}\n    fun String?.html(): Spanned {\n        return getHtmlText(this ?: return \"\".toSpanned())\n    }\n\n    private fun getHtmlText(text: String): Spanned {\n        return try {\n            // I have no idea if this can throw any error, but I dont want to try\n            HtmlCompat.fromHtml(\n                text, HtmlCompat.FROM_HTML_MODE_LEGACY\n            )\n        } catch (e: Exception) {\n            logError(e)\n            text.toSpanned()\n        }\n    }\n    /** Get channel ID by name */\n    @SuppressLint(\"RestrictedApi\")\n    private fun buildWatchNextProgramUri(\n        context: Context,\n        card: DataStoreHelper.ResumeWatchingResult,\n        resumeWatching: DownloadObjects.ResumeWatching?\n    ): WatchNextProgram {\n        val isSeries = card.type?.isMovieType() == false\n        val title = if (isSeries) {\n            context.getNameFull(card.name, card.episode, card.season)\n        } else {\n            card.name\n        }\n\n        val builder = WatchNextProgram.Builder()\n            .setEpisodeTitle(title)\n            .setType(\n                if (isSeries) {\n                    TvContractCompat.WatchNextPrograms.TYPE_TV_EPISODE\n                } else TvContractCompat.WatchNextPrograms.TYPE_MOVIE\n            )\n            .setWatchNextType(TvContractCompat.WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE)\n            .setTitle(title)\n            .setPosterArtUri(card.posterUrl?.toUri())\n            .setIntentUri((card.id?.let {\n                \"$APP_STRING_RESUME_WATCHING://$it\"\n            } ?: card.url).toUri())\n            .setInternalProviderId(card.url)\n            .setLastEngagementTimeUtcMillis(\n                resumeWatching?.updateTime ?: System.currentTimeMillis()\n            )\n\n        card.watchPos?.let {\n            builder.setDurationMillis(it.duration.toInt())\n            builder.setLastPlaybackPositionMillis(it.position.toInt())\n        }\n\n        if (isSeries)\n            card.episode?.let {\n                builder.setEpisodeNumber(it)\n            }\n\n        return builder.build()\n    }\n\n    // https://stackoverflow.com/a/67441735/13746422\n    fun ViewPager2.reduceDragSensitivity(f: Int = 4) {\n        val recyclerViewField = ViewPager2::class.java.getDeclaredField(\"mRecyclerView\")\n        recyclerViewField.isAccessible = true\n        val recyclerView = recyclerViewField.get(this) as RecyclerView\n\n        val touchSlopField = RecyclerView::class.java.getDeclaredField(\"mTouchSlop\")\n        touchSlopField.isAccessible = true\n        val touchSlop = touchSlopField.get(recyclerView) as Int\n        touchSlopField.set(recyclerView, touchSlop * f)       // \"8\" was obtained experimentally\n    }\n\n    fun ContentLoadingProgressBar?.animateProgressTo(to: Int) {\n        if (this == null) return\n        val animation: ObjectAnimator = ObjectAnimator.ofInt(\n            this,\n            \"progress\",\n            this.progress,\n            to\n        )\n        animation.duration = 500\n        animation.setAutoCancel(true)\n        animation.interpolator = DecelerateInterpolator()\n        animation.start()\n    }\n\n    fun Context.createNotificationChannel(\n        channelId: String,\n        channelName: String,\n        description: String\n    ) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            val importance = NotificationManager.IMPORTANCE_DEFAULT\n            val channel =\n                NotificationChannel(channelId, channelName, importance).apply {\n                    this.description = description\n                }\n\n            // Register the channel with the system.\n            val notificationManager: NotificationManager =\n                this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager\n\n            notificationManager.createNotificationChannel(channel)\n        }\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    fun getAllWatchNextPrograms(context: Context): Set<Long> {\n        val COLUMN_WATCH_NEXT_ID_INDEX = 0\n        val cursor = context.contentResolver.query(\n            TvContractCompat.WatchNextPrograms.CONTENT_URI,\n            WatchNextProgram.PROJECTION,\n            /* selection = */ null,\n            /* selectionArgs = */ null,\n            /* sortOrder = */ null\n        )\n        val set = mutableSetOf<Long>()\n        cursor?.use {\n            if (it.moveToFirst()) {\n                do {\n                    set.add(cursor.getLong(COLUMN_WATCH_NEXT_ID_INDEX))\n                } while (it.moveToNext())\n            }\n        }\n        return set\n    }\n\n    /**\n     * Find the Watch Next program for given id.\n     * Returns the first instance available.\n     */\n    @SuppressLint(\"RestrictedApi\")\n    // Suppress RestrictedApi due to https://issuetracker.google.com/138150076\n    fun findFirstWatchNextProgram(context: Context, predicate: (Cursor) -> Boolean):\n            Pair<WatchNextProgram?, Long?> {\n        val COLUMN_WATCH_NEXT_ID_INDEX = 0\n//        val COLUMN_WATCH_NEXT_INTERNAL_PROVIDER_ID_INDEX = 1\n//        val COLUMN_WATCH_NEXT_COLUMN_BROWSABLE_INDEX = 2\n\n        val cursor = context.contentResolver.query(\n            TvContractCompat.WatchNextPrograms.CONTENT_URI,\n            WatchNextProgram.PROJECTION,\n            /* selection = */ null,\n            /* selectionArgs = */ null,\n            /* sortOrder = */ null\n        )\n        cursor?.use {\n            if (it.moveToFirst()) {\n                do {\n                    if (predicate(cursor)) {\n                        return fromCursor(cursor) to cursor.getLong(COLUMN_WATCH_NEXT_ID_INDEX)\n                    }\n                } while (it.moveToNext())\n            }\n        }\n        return null to null\n    }\n\n    /**\n     * Query the Watch Next list and find the program with given videoId.\n     * Return null if not found.\n     */\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    @SuppressLint(\"Range\")\n    @Synchronized\n    private fun getWatchNextProgramByVideoId(\n        id: String,\n        context: Context\n    ): Pair<WatchNextProgram?, Long?> {\n        return findFirstWatchNextProgram(context) { cursor ->\n            (cursor.getString(cursor.getColumnIndex(COLUMN_INTERNAL_PROVIDER_ID)) == id)\n        }\n    }\n\n    /** Prevents losing data when removing and adding simultaneously */\n    private val continueWatchingLock = Mutex()\n\n    // https://github.com/googlearchive/leanback-homescreen-channels/blob/master/app/src/main/java/com/google/android/tvhomescreenchannels/SampleTvProvider.java\n    @SuppressLint(\"RestrictedApi\")\n    @Throws\n    @WorkerThread\n    suspend fun Context.addProgramsToContinueWatching(data: List<DataStoreHelper.ResumeWatchingResult>) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return\n        val context = this\n        continueWatchingLock.withLock {\n            // A way to get all last watched timestamps\n            val timeStampHashMap = HashMap<Int, DownloadObjects.ResumeWatching>()\n            getAllResumeStateIds()?.forEach { id ->\n                val lastWatched = getLastWatched(id) ?: return@forEach\n                timeStampHashMap[lastWatched.parentId] = lastWatched\n            }\n\n            val currentProgramIds = data.mapNotNull { episodeInfo ->\n                try {\n                    val customId = \"${episodeInfo.id}|${episodeInfo.apiName}|${episodeInfo.url}\"\n                    val (program, id) = getWatchNextProgramByVideoId(customId, context)\n                    val nextProgram = buildWatchNextProgramUri(\n                        context,\n                        episodeInfo,\n                        timeStampHashMap[episodeInfo.id]\n                    )\n\n                    // If the program is already in the Watch Next row, update it\n                    if (program != null && id != null) {\n                        PreviewChannelHelper(context).updateWatchNextProgram(\n                            nextProgram,\n                            id,\n                        )\n                        id\n                    } else {\n                        PreviewChannelHelper(context)\n                            .publishWatchNextProgram(nextProgram)\n                    }\n                } catch (e: Exception) {\n                    logError(e)\n                    null\n                }\n            }.toSet()\n\n            val allOldPrograms = getAllWatchNextPrograms(context) - currentProgramIds\n\n            // Ensures synced watch next progress by deleting all old programs.\n            allOldPrograms.forEach {\n                context.contentResolver.delete(\n                    TvContractCompat.buildWatchNextProgramUri(it),\n                    null, null\n                )\n            }\n        }\n    }\n\n    fun sortSubs(subs: Set<SubtitleData>): List<SubtitleData> {\n        return subs.sortedBy { it.name }\n    }\n\n    fun Context.getApiSettings(): HashSet<String> {\n        //val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n\n        val hashSet = HashSet<String>()\n        val activeLangs = getApiProviderLangSettings()\n        val hasUniversal = activeLangs.contains(AllLanguagesName)\n        hashSet.addAll(synchronized(apis) { apis.filter { hasUniversal || activeLangs.contains(it.lang) } }\n            .map { it.name })\n\n        /*val set = settingsManager.getStringSet(\n            this.getString(R.string.search_providers_list_key),\n            hashSet\n        )?.toHashSet() ?: hashSet\n\n        val list = HashSet<String>()\n        for (name in set) {\n            val api = getApiFromNameNull(name) ?: continue\n            if (activeLangs.contains(api.lang)) {\n                list.add(name)\n            }\n        }*/\n        //if (list.isEmpty()) return hashSet\n        //return list\n        return hashSet\n    }\n\n    fun Context.getApiDubstatusSettings(): HashSet<DubStatus> {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        val hashSet = HashSet<DubStatus>()\n        hashSet.addAll(DubStatus.values())\n        val list = settingsManager.getStringSet(\n            this.getString(R.string.display_sub_key),\n            hashSet.map { it.name }.toMutableSet()\n        ) ?: return hashSet\n\n        val names = DubStatus.values().map { it.name }.toHashSet()\n        //if(realSet.isEmpty()) return hashSet\n\n        return list.filter { names.contains(it) }.map { DubStatus.valueOf(it) }.toHashSet()\n    }\n\n    fun Context.getApiProviderLangSettings(): HashSet<String> {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        val hashSet = hashSetOf(AllLanguagesName) // def is all languages\n//        hashSet.add(\"en\") // def is only en\n        val list = settingsManager.getStringSet(\n            this.getString(R.string.provider_lang_key),\n            hashSet\n        )\n\n        if (list.isNullOrEmpty()) return hashSet\n        return list.toHashSet()\n    }\n\n    fun Context.getApiTypeSettings(): HashSet<TvType> {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        val hashSet = HashSet<TvType>()\n        hashSet.addAll(TvType.values())\n        val list = settingsManager.getStringSet(\n            this.getString(R.string.search_types_list_key),\n            hashSet.map { it.name }.toMutableSet()\n        )\n\n        if (list.isNullOrEmpty()) return hashSet\n\n        val names = TvType.values().map { it.name }.toHashSet()\n        val realSet = list.filter { names.contains(it) }.map { TvType.valueOf(it) }.toHashSet()\n        if (realSet.isEmpty()) return hashSet\n\n        return realSet\n    }\n\n    fun Context.updateHasTrailers() {\n        LoadResponse.isTrailersEnabled = getHasTrailers()\n    }\n\n    private fun Context.getHasTrailers(): Boolean {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        return settingsManager.getBoolean(this.getString(R.string.show_trailers_key), true)\n    }\n\n    fun Context.filterProviderByPreferredMedia(hasHomePageIsRequired: Boolean = true): List<MainAPI> {\n        // We are getting the weirdest crash ever done:\n        // java.lang.ClassCastException: com.lagradost.cloudstream3.TvType cannot be cast to com.lagradost.cloudstream3.TvType\n        // Trying fixing using classloader fuckery\n        val oldLoader = Thread.currentThread().contextClassLoader\n        Thread.currentThread().contextClassLoader = TvType::class.java.classLoader\n\n        val default = TvType.values()\n            .sorted()\n            .filter { it != TvType.NSFW }\n            .map { it.ordinal }\n\n        Thread.currentThread().contextClassLoader = oldLoader\n\n        val defaultSet = default.map { it.toString() }.toSet()\n        val currentPrefMedia = try {\n            PreferenceManager.getDefaultSharedPreferences(this)\n                .getStringSet(this.getString(R.string.prefer_media_type_key), defaultSet)\n                ?.mapNotNull { it.toIntOrNull() ?: return@mapNotNull null }\n        } catch (e: Throwable) {\n            null\n        } ?: default\n        val langs = this.getApiProviderLangSettings()\n        val hasUniversal = langs.contains(AllLanguagesName)\n        val allApis = synchronized(apis) {\n            apis.filter { api -> (hasUniversal || langs.contains(api.lang)) && (api.hasMainPage || !hasHomePageIsRequired) }\n        }\n        return if (currentPrefMedia.isEmpty()) {\n            allApis\n        } else {\n            // Filter API depending on preferred media type\n            allApis.filter { api -> api.supportedTypes.any { currentPrefMedia.contains(it.ordinal) } }\n        }\n    }\n\n    fun Context.filterSearchResultByFilmQuality(data: List<SearchResponse>): List<SearchResponse> {\n        // Filter results omitting entries with certain quality\n        if (data.isNotEmpty()) {\n            val filteredSearchQuality = PreferenceManager.getDefaultSharedPreferences(this)\n                ?.getStringSet(getString(R.string.pref_filter_search_quality_key), setOf())\n                ?.mapNotNull { entry ->\n                    entry.toIntOrNull() ?: return@mapNotNull null\n                } ?: listOf()\n            if (filteredSearchQuality.isNotEmpty()) {\n                return data.filter { item ->\n                    val searchQualVal = item.quality?.ordinal ?: -1\n                    //Log.i(\"filterSearch\", \"QuickSearch item => ${item.toJson()}\")\n                    !filteredSearchQuality.contains(searchQualVal)\n                }\n            }\n        }\n        return data\n    }\n\n    fun Context.filterHomePageListByFilmQuality(data: HomePageList): HomePageList {\n        // Filter results omitting entries with certain quality\n        if (data.list.isNotEmpty()) {\n            val filteredSearchQuality = PreferenceManager.getDefaultSharedPreferences(this)\n                ?.getStringSet(getString(R.string.pref_filter_search_quality_key), setOf())\n                ?.mapNotNull { entry ->\n                    entry.toIntOrNull() ?: return@mapNotNull null\n                } ?: listOf()\n            if (filteredSearchQuality.isNotEmpty()) {\n                return HomePageList(\n                    name = data.name,\n                    isHorizontalImages = data.isHorizontalImages,\n                    list = data.list.filter { item ->\n                        val searchQualVal = item.quality?.ordinal ?: -1\n                        //Log.i(\"filterSearch\", \"QuickSearch item => ${item.toJson()}\")\n                        !filteredSearchQuality.contains(searchQualVal)\n                    }\n                )\n            }\n        }\n        return data\n    }\n\n    fun Activity.loadRepository(url: String) {\n        ioSafe {\n            val repo = RepositoryManager.parseRepository(url) ?: return@ioSafe\n            RepositoryManager.addRepository(\n                RepositoryData(\n                    repo.iconUrl ?: \"\",\n                    repo.name,\n                    url\n                )\n            )\n            main {\n                showToast(\n                    getString(R.string.player_loaded_subtitles, repo.name),\n                    Toast.LENGTH_LONG\n                )\n            }\n            afterRepositoryLoadedEvent.invoke(true)\n            addRepositoryDialog(repo.name, url)\n        }\n    }\n\n    fun Activity.addRepositoryDialog(\n        repositoryName: String,\n        repositoryURL: String,\n    ) {\n        val repos = RepositoryManager.getRepositories()\n\n        // navigate to newly added repository on pressing Open Repository\n        fun openAddedRepo() {\n            if (repos.isNotEmpty()) {\n                navigate(\n                    R.id.global_to_navigation_settings_plugins,\n                    PluginsFragment.newInstance(\n                        repositoryName,\n                        repositoryURL,\n                        false,\n                    )\n                )\n            }\n        }\n\n        runOnUiThread {\n            AlertDialog.Builder(this).apply {\n                setTitle(repositoryName)\n                setMessage(R.string.download_all_plugins_from_repo)\n                setPositiveButton(R.string.open_downloaded_repo) { _, _ ->\n                    openAddedRepo()\n                }\n                setNegativeButton(R.string.dismiss, null)\n                show().setDefaultFocus()\n            }\n        }\n    }\n\n    private fun Context.hasWebView(): Boolean {\n        return this.packageManager.hasSystemFeature(\"android.software.webview\")\n    }\n\n    fun openWebView(fragment: Fragment?, url: String) {\n        if (fragment?.context?.hasWebView() == true)\n            safe {\n                fragment\n                    .findNavController()\n                    .navigate(R.id.navigation_webview, WebviewFragment.newInstance(url))\n            }\n    }\n\n    /**\n     * If fallbackWebview is true and a fragment is supplied then it will open a webview with the url if the browser fails.\n     * */\n    fun Context.openBrowser(\n        url: String,\n        fallbackWebview: Boolean = false,\n        fragment: Fragment? = null,\n    ) = (this.getActivity() ?: activity)?.runOnUiThread {\n        try {\n            val intent = Intent(Intent.ACTION_VIEW)\n            intent.data = url.toUri()\n            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)\n\n            // activityResultRegistry is used to fall back to webview if a browser is missing\n            // On older versions the startActivity just crashes, but on newer android versions\n            // You need to check the result to make sure it failed\n            val activityResultRegistry = fragment?.activity?.activityResultRegistry\n            if (activityResultRegistry != null) {\n                activityResultRegistry.register(\n                    url,\n                    ActivityResultContracts.StartActivityForResult()\n                ) { result ->\n                    if (result.resultCode == RESULT_CANCELED && fallbackWebview) {\n                        openWebView(fragment, url)\n                    }\n                }.launch(intent)\n            } else this.startActivity(intent)\n        } catch (e: Exception) {\n            logError(e)\n            if (fallbackWebview) {\n                openWebView(fragment, url)\n            }\n        }\n    }\n\n    fun Context.isNetworkAvailable(): Boolean {\n        val connectivityManager =\n            getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager\n        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            val network = connectivityManager.activeNetwork ?: return false\n            val networkCapabilities =\n                connectivityManager.getNetworkCapabilities(network) ?: return false\n            networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)\n        } else {\n            @Suppress(\"DEPRECATION\")\n            connectivityManager.activeNetworkInfo?.isConnected == true\n        }\n    }\n\n    fun splitQuery(url: URL): Map<String, String> {\n        val queryPairs: MutableMap<String, String> = LinkedHashMap()\n        val query: String = url.query\n        val pairs = query.split(\"&\").toTypedArray()\n        for (pair in pairs) {\n            val idx = pair.indexOf(\"=\")\n            queryPairs[URLDecoder.decode(pair.substring(0, idx), \"UTF-8\")] =\n                URLDecoder.decode(pair.substring(idx + 1), \"UTF-8\")\n        }\n        return queryPairs\n    }\n\n    /**| S1:E2 Hello World\n     * | Episode 2. Hello world\n     * | Hello World\n     * | Season 1 - Episode 2\n     * | Episode 2\n     * **/\n    fun Context.getNameFull(name: String?, episode: Int?, season: Int?): String {\n        val rEpisode = if (episode == 0) null else episode\n        val rSeason = if (season == 0) null else season\n\n        val seasonName = getString(R.string.season)\n        val episodeName = getString(R.string.episode)\n        val seasonNameShort = getString(R.string.season_short)\n        val episodeNameShort = getString(R.string.episode_short)\n\n        if (name != null) {\n            return if (rEpisode != null && rSeason != null) {\n                \"$seasonNameShort${rSeason}:$episodeNameShort${rEpisode} $name\"\n            } else if (rEpisode != null) {\n                \"$episodeName $rEpisode. $name\"\n            } else {\n                name\n            }\n        } else {\n            if (rEpisode != null && rSeason != null) {\n                return \"$seasonName $rSeason - $episodeName $rEpisode\"\n            } else if (rSeason == null) {\n                return \"$episodeName $rEpisode\"\n            }\n        }\n        return \"\"\n    }\n\n    fun Context.getShortSeasonText(episode: Int?, season: Int?): String? {\n        val rEpisode = if (episode == 0) null else episode\n        val rSeason = if (season == 0) null else season\n        val seasonNameShort = getString(R.string.season_short)\n        val episodeNameShort = getString(R.string.episode_short)\n        return if (rEpisode != null && rSeason != null) {\n            \"$seasonNameShort${rSeason}:$episodeNameShort${rEpisode}\"\n        } else if (rEpisode != null) {\n            \"$episodeNameShort$rEpisode\"\n        }else null\n    }\n\n    fun Activity?.loadCache() {\n        try {\n            cacheClass(\"android.net.NetworkCapabilities\".load())\n        } catch (_: Exception) {\n        }\n    }\n\n    //private val viewModel: ResultViewModel by activityViewModels()\n\n    private fun getResultsId(): Int {\n        return if (Globals.isLayout(Globals.TV or Globals.EMULATOR)) {\n            R.id.global_to_navigation_results_tv\n        } else {\n            R.id.global_to_navigation_results_phone\n        }\n    }\n\n    fun loadResult(\n        url: String,\n        apiName: String,\n        name : String,\n        startAction: Int = 0,\n        startValue: Int = 0\n    ) {\n        (activity as FragmentActivity?)?.loadResult(url, apiName, name, startAction, startValue)\n    }\n\n    fun FragmentActivity.loadResult(\n        url: String,\n        apiName: String,\n        name : String,\n        startAction: Int = 0,\n        startValue: Int = 0\n    ) {\n        try {\n            val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n            Kitsu.isEnabled =\n                settingsManager.getBoolean(this.getString(R.string.show_kitsu_posters_key), true)\n        } catch (t: Throwable) {\n            logError(t)\n        }\n\n        this.runOnUiThread {\n            // viewModelStore.clear()\n            this.navigate(\n                getResultsId(),\n                ResultFragment.newInstance(url, apiName, name, startAction, startValue)\n            )\n        }\n    }\n\n    fun loadSearchResult(\n        card: SearchResponse,\n        startAction: Int = 0,\n        startValue: Int? = null,\n    ) {\n        activity?.loadSearchResult(card, startAction, startValue)\n    }\n\n    fun Activity?.loadSearchResult(\n        card: SearchResponse,\n        startAction: Int = 0,\n        startValue: Int? = null,\n    ) {\n        this?.runOnUiThread {\n            // viewModelStore.clear()\n            this.navigate(\n                getResultsId(),\n                ResultFragment.newInstance(card, startAction, startValue)\n            )\n        }\n        //(this as? AppCompatActivity?)?.loadResult(card.url, card.apiName, startAction, startValue)\n    }\n\n    fun Activity.requestLocalAudioFocus(focusRequest: AudioFocusRequest?) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            if (focusRequest == null) {\n                Log.e(\"TAG\", \"focusRequest was null\")\n                return\n            }\n\n            val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager\n            audioManager.requestAudioFocus(focusRequest)\n        } else {\n            val audioManager: AudioManager =\n                getSystemService(Context.AUDIO_SERVICE) as AudioManager\n            @Suppress(\"DEPRECATION\")\n            audioManager.requestAudioFocus(\n                null,\n                AudioManager.STREAM_MUSIC,\n                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK\n            )\n        }\n    }\n\n    private var currentAudioFocusRequest: AudioFocusRequest? = null\n    private var currentAudioFocusChangeListener: AudioManager.OnAudioFocusChangeListener? = null\n    var onAudioFocusEvent = Event<Boolean>()\n\n    private fun getAudioListener(): AudioManager.OnAudioFocusChangeListener? {\n        if (currentAudioFocusChangeListener != null) return currentAudioFocusChangeListener\n        currentAudioFocusChangeListener = AudioManager.OnAudioFocusChangeListener {\n            onAudioFocusEvent.invoke(\n                when (it) {\n                    AudioManager.AUDIOFOCUS_GAIN -> false\n                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE -> false\n                    AudioManager.AUDIOFOCUS_GAIN_TRANSIENT -> false\n                    else -> true\n                }\n            )\n        }\n        return currentAudioFocusChangeListener\n    }\n\n    fun Context.isCastApiAvailable(): Boolean {\n        val isCastApiAvailable =\n            GoogleApiAvailability.getInstance()\n                .isGooglePlayServicesAvailable(applicationContext) == ConnectionResult.SUCCESS\n\n        try {\n            applicationContext?.let {\n                val task = CastContext.getSharedInstance(it) { it.run() }\n                task.result\n            }\n        } catch (e: Exception) {\n            println(e)\n            // Track non-fatal\n            return false\n        }\n\n        return isCastApiAvailable\n    }\n\n    fun Context.isConnectedToChromecast(): Boolean {\n        if (isCastApiAvailable()) {\n            val executor: Executor = Executors.newSingleThreadExecutor()\n            val castContext = CastContext.getSharedInstance(this, executor)\n            if (castContext.result.castState == CastState.CONNECTED) {\n                return true\n            }\n        }\n        return false\n    }\n\n    /**\n     * Sets the focus to the negative button when in TV and Emulator layout.\n     **/\n    fun AlertDialog.setDefaultFocus(buttonFocus: Int = DialogInterface.BUTTON_NEGATIVE) {\n        if (!Globals.isLayout(Globals.TV or Globals.EMULATOR)) return\n        this.getButton(buttonFocus).run {\n            isFocusableInTouchMode = true\n            requestFocus()\n        }\n    }\n\n    fun Context.isUsingMobileData(): Boolean {\n        val connectionManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager\n        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            val activeNetwork: Network? = connectionManager.activeNetwork\n            val networkCapabilities = connectionManager.getNetworkCapabilities(activeNetwork)\n            networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true &&\n                    !networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)\n        } else {\n            @Suppress(\"DEPRECATION\")\n            connectionManager.activeNetworkInfo?.type == ConnectivityManager.TYPE_MOBILE\n        }\n    }\n\n\n    private fun Activity?.cacheClass(clazz: String?) {\n        clazz?.let { c ->\n            this?.cacheDir?.let {\n                Cache(\n                    directory = File(it, c.toClassDir()),\n                    maxSize = 20L * 1024L * 1024L // 20 MiB\n                )\n            }\n        }\n    }\n\n    fun Context.isAppInstalled(uri: String): Boolean {\n        val pm = Wrappers.packageManager(this)\n\n        return try {\n            pm.getPackageInfo(uri, 0) // PackageManager.GET_ACTIVITIES\n            true\n        } catch (e: PackageManager.NameNotFoundException) {\n            false\n        }\n    }\n\n    fun getFocusRequest(): AudioFocusRequest? {\n        if (currentAudioFocusRequest != null) return currentAudioFocusRequest\n        currentAudioFocusRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {\n                setAudioAttributes(AudioAttributes.Builder().run {\n                    setUsage(AudioAttributes.USAGE_MEDIA)\n                    setContentType(AudioAttributes.CONTENT_TYPE_MOVIE)\n                    build()\n                })\n                setAcceptsDelayedFocusGain(true)\n                getAudioListener()?.let {\n                    setOnAudioFocusChangeListener(it)\n                }\n                build()\n            }\n        } else null\n        return currentAudioFocusRequest\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/BackPressedCallbackHelper.kt",
    "content": "package com.lagradost.cloudstream3.utils\r\n\r\nimport androidx.activity.ComponentActivity\r\nimport androidx.activity.OnBackPressedCallback\r\nimport java.lang.ref.WeakReference\r\nimport java.util.WeakHashMap\r\n\r\nobject BackPressedCallbackHelper {\r\n\r\n    private val backPressedCallbacks =\r\n        WeakHashMap<ComponentActivity, MutableMap<String, OnBackPressedCallback>>()\r\n\r\n    class CallbackHelper(\r\n        private val activityRef: WeakReference<ComponentActivity>,\r\n        private val callback: OnBackPressedCallback\r\n    ) {\r\n        fun runDefault() {\r\n            val activity = activityRef.get() ?: return\r\n            val wasEnabled = callback.isEnabled\r\n            callback.isEnabled = false\r\n            try {\r\n                activity.onBackPressedDispatcher.onBackPressed()\r\n            } finally {\r\n                callback.isEnabled = wasEnabled\r\n            }\r\n        }\r\n    }\r\n\r\n    fun ComponentActivity.attachBackPressedCallback(\r\n        id: String,\r\n        callback: CallbackHelper.() -> Unit\r\n    ) {\r\n        val callbackMap = backPressedCallbacks.getOrPut(this) { mutableMapOf() }\r\n        if (callbackMap.containsKey(id)) return\r\n\r\n        // We use WeakReference to protect against potential leaks.\r\n        val activityRef = WeakReference(this)\r\n        val newCallback = object : OnBackPressedCallback(true) {\r\n            override fun handleOnBackPressed() {\r\n                CallbackHelper(activityRef, this).callback()\r\n            }\r\n        }\r\n\r\n        callbackMap[id] = newCallback\r\n        onBackPressedDispatcher.addCallback(this, newCallback)\r\n    }\r\n\r\n    fun ComponentActivity.disableBackPressedCallback(id : String) {\r\n        backPressedCallbacks[this]?.get(id)?.isEnabled = false\r\n    }\r\n\r\n    fun ComponentActivity.enableBackPressedCallback(id : String) {\r\n        backPressedCallbacks[this]?.get(id)?.isEnabled = true\r\n    }\r\n\r\n    fun ComponentActivity.detachBackPressedCallback(id: String) {\r\n        val callbackMap = backPressedCallbacks[this] ?: return\r\n        callbackMap[id]?.let { callback ->\r\n            callback.isEnabled = false\r\n            callbackMap.remove(id)\r\n        }\r\n\r\n        if (callbackMap.isEmpty()) {\r\n            backPressedCallbacks.remove(this)\r\n        }\r\n    }\r\n}\r\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.content.Context\nimport android.net.Uri\nimport android.widget.Toast\nimport androidx.activity.result.ActivityResultLauncher\nimport androidx.activity.result.contract.ActivityResultContracts\nimport androidx.annotation.WorkerThread\nimport androidx.core.net.toUri\nimport androidx.fragment.app.FragmentActivity\nimport androidx.preference.PreferenceManager\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.fasterxml.jackson.module.kotlin.readValue\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.plugins.PLUGINS_KEY\nimport com.lagradost.cloudstream3.plugins.PLUGINS_KEY_LOCAL\nimport com.lagradost.cloudstream3.syncproviders.AccountManager\nimport com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_CACHED_LIST\nimport com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_CACHED_LIST\nimport com.lagradost.cloudstream3.syncproviders.providers.KitsuApi.Companion.KITSU_CACHED_LIST\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.DataStore.getDefaultSharedPrefs\nimport com.lagradost.cloudstream3.utils.DataStore.getSharedPrefs\nimport com.lagradost.cloudstream3.utils.DataStore.mapper\nimport com.lagradost.cloudstream3.utils.UIHelper.checkWrite\nimport com.lagradost.cloudstream3.utils.UIHelper.requestRW\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.setupStream\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport com.lagradost.cloudstream3.utils.downloader.DownloadQueueManager.QUEUE_KEY\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_DOWNLOAD_INFO\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_RESUME_IN_QUEUE\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_RESUME_PACKAGES\nimport com.lagradost.safefile.MediaFileContentType\nimport com.lagradost.safefile.SafeFile\nimport okhttp3.internal.closeQuietly\nimport java.io.IOException\nimport java.io.OutputStream\nimport java.io.PrintWriter\nimport java.lang.System.currentTimeMillis\nimport java.text.SimpleDateFormat\nimport java.util.Date\nimport java.util.Locale\n\nobject BackupUtils {\n\n    /**\n     * No sensitive or breaking data in the backup\n     * */\n    private val nonTransferableKeys = listOf(\n        ANILIST_CACHED_LIST,\n        MAL_CACHED_LIST,\n        KITSU_CACHED_LIST,\n\n        // The plugins themselves are not backed up\n        PLUGINS_KEY,\n        PLUGINS_KEY_LOCAL,\n\n        AccountManager.ACCOUNT_TOKEN,\n        AccountManager.ACCOUNT_IDS,\n\n        \"biometric_key\", // can lock down users if backup is shared on a incompatible device\n        \"nginx_user\", // Nginx user key\n\n        // No access rights after restore data from backup\n        \"download_path_key\",\n        \"download_path_key_visual\",\n        \"backup_path_key\",\n        \"backup_dir_path_key\",\n\n        // When sharing backup we do not want to transfer what is essentially the password\n        // Note that this is deprecated, and can be removed after all tokens have expired\n        \"anilist_token\",\n        \"anilist_user\",\n        \"mal_user\",\n        \"mal_token\",\n        \"mal_refresh_token\",\n        \"mal_unixtime\",\n        \"open_subtitles_user\",\n        \"subdl_user\",\n        \"simkl_token\",\n\n\n        // Downloads can not be restored from backups.\n        // The download path URI can not be transferred.\n        // In the future we may potentially write metadata to files in the download directory\n        // and make it possible to restore download folders using that metadata.\n        DOWNLOAD_EPISODE_CACHE_BACKUP,\n        DOWNLOAD_EPISODE_CACHE,\n        \n        // Download headers are unintuitively used in the resume watching system.\n        // We can therefore not prune download headers in backups.\n        //DOWNLOAD_HEADER_CACHE_BACKUP,\n        //DOWNLOAD_HEADER_CACHE,\n        \n\n        // This may overwrite valid local data with invalid data\n        KEY_DOWNLOAD_INFO,\n\n        // Prevent backups from automatically starting downloads\n        KEY_RESUME_IN_QUEUE,\n        KEY_RESUME_PACKAGES,\n        QUEUE_KEY\n    )\n\n    /** false if key should not be contained in backup */\n    private fun String.isTransferable(): Boolean {\n        return !nonTransferableKeys.any { this.contains(it) }\n    }\n\n    private var restoreFileSelector: ActivityResultLauncher<Array<String>>? = null\n\n    // Kinda hack, but I couldn't think of a better way\n    data class BackupVars(\n        @JsonProperty(\"_Bool\") val bool: Map<String, Boolean>?,\n        @JsonProperty(\"_Int\") val int: Map<String, Int>?,\n        @JsonProperty(\"_String\") val string: Map<String, String>?,\n        @JsonProperty(\"_Float\") val float: Map<String, Float>?,\n        @JsonProperty(\"_Long\") val long: Map<String, Long>?,\n        @JsonProperty(\"_StringSet\") val stringSet: Map<String, Set<String>?>?,\n    )\n\n    data class BackupFile(\n        @JsonProperty(\"datastore\") val datastore: BackupVars,\n        @JsonProperty(\"settings\") val settings: BackupVars\n    )\n\n    @Suppress(\"UNCHECKED_CAST\")\n    private fun getBackup(context: Context?): BackupFile? {\n        if (context == null) return null\n\n        val allData = context.getSharedPrefs().all.filter { it.key.isTransferable() }\n        val allSettings = context.getDefaultSharedPrefs().all.filter { it.key.isTransferable() }\n\n        val allDataSorted = BackupVars(\n            allData.filter { it.value is Boolean } as? Map<String, Boolean>,\n            allData.filter { it.value is Int } as? Map<String, Int>,\n            allData.filter { it.value is String } as? Map<String, String>,\n            allData.filter { it.value is Float } as? Map<String, Float>,\n            allData.filter { it.value is Long } as? Map<String, Long>,\n            allData.filter { it.value as? Set<String> != null } as? Map<String, Set<String>>\n        )\n\n        val allSettingsSorted = BackupVars(\n            allSettings.filter { it.value is Boolean } as? Map<String, Boolean>,\n            allSettings.filter { it.value is Int } as? Map<String, Int>,\n            allSettings.filter { it.value is String } as? Map<String, String>,\n            allSettings.filter { it.value is Float } as? Map<String, Float>,\n            allSettings.filter { it.value is Long } as? Map<String, Long>,\n            allSettings.filter { it.value as? Set<String> != null } as? Map<String, Set<String>>\n        )\n\n        return BackupFile(\n            allDataSorted,\n            allSettingsSorted\n        )\n    }\n\n    @WorkerThread\n    fun restore(\n        context: Context?,\n        backupFile: BackupFile,\n        restoreSettings: Boolean,\n        restoreDataStore: Boolean\n    ) {\n        if (context == null) return\n        if (restoreSettings) {\n            context.restoreMap(backupFile.settings.bool, true)\n            context.restoreMap(backupFile.settings.int, true)\n            context.restoreMap(backupFile.settings.string, true)\n            context.restoreMap(backupFile.settings.float, true)\n            context.restoreMap(backupFile.settings.long, true)\n            context.restoreMap(backupFile.settings.stringSet, true)\n        }\n\n        if (restoreDataStore) {\n            context.restoreMap(backupFile.datastore.bool)\n            context.restoreMap(backupFile.datastore.int)\n            context.restoreMap(backupFile.datastore.string)\n            context.restoreMap(backupFile.datastore.float)\n            context.restoreMap(backupFile.datastore.long)\n            context.restoreMap(backupFile.datastore.stringSet)\n        }\n\n        // Make sure the library is fresh\n        for(api in AccountManager.syncApis) {\n            api.requireLibraryRefresh = true\n        }\n    }\n\n    fun backup(context: Context?) = ioSafe {\n        if (context == null) return@ioSafe\n\n        var fileStream: OutputStream? = null\n        var printStream: PrintWriter? = null\n        try {\n            if (!context.checkWrite()) {\n                showToast(R.string.backup_failed, Toast.LENGTH_LONG)\n                context.getActivity()?.requestRW()\n                return@ioSafe\n            }\n\n            val date = SimpleDateFormat(\"yyyy_MM_dd_HH_mm\", Locale.getDefault()).format(Date(currentTimeMillis()))\n            val displayName = \"CS3_Backup_${date}\"\n            val backupFile = getBackup(context)\n            val stream = setupBackupStream(context, displayName)\n\n            fileStream = stream.openNew()\n            printStream = PrintWriter(fileStream)\n            printStream.print(mapper.writeValueAsString(backupFile))\n\n            showToast(\n                R.string.backup_success,\n                Toast.LENGTH_LONG\n            )\n        } catch (e: Exception) {\n            logError(e)\n            try {\n                showToast(\n                    txt(R.string.backup_failed_error_format, e.toString()),\n                    Toast.LENGTH_LONG\n                )\n            } catch (e: Exception) {\n                logError(e)\n            }\n        } finally {\n            printStream?.closeQuietly()\n            fileStream?.closeQuietly()\n        }\n    }\n\n    @Throws(IOException::class)\n    private fun setupBackupStream(context: Context, name: String, ext: String = \"txt\"): DownloadObjects.StreamData {\n        return setupStream(\n            baseFile = getCurrentBackupDir(context).first ?: getDefaultBackupDir(context)\n            ?: throw IOException(\"Bad config\"),\n            name,\n            folder = null,\n            extension = ext,\n            tryResume = false\n        )\n    }\n\n    fun FragmentActivity.setUpBackup() {\n        try {\n            restoreFileSelector =\n                registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri: Uri? ->\n                    if (uri == null) return@registerForActivityResult\n                    val activity = this\n                    ioSafe {\n                        try {\n                            val input = activity.contentResolver.openInputStream(uri)\n                                ?: return@ioSafe\n\n                            val restoredValue =\n                                mapper.readValue<BackupFile>(input)\n\n                            restore(\n                                activity,\n                                restoredValue,\n                                restoreSettings = true,\n                                restoreDataStore = true\n                            )\n                            activity.runOnUiThread { activity.recreate() }\n                        } catch (e: Exception) {\n                            logError(e)\n                            main { // smth can fail in .format\n                                showToast(\n                                    getString(R.string.restore_failed_format).format(e.toString())\n                                )\n                            }\n                        }\n                    }\n                }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    fun FragmentActivity.restorePrompt() {\n        runOnUiThread {\n            try {\n                restoreFileSelector?.launch(\n                    arrayOf(\n                        \"text/plain\",\n                        \"text/str\",\n                        \"text/x-unknown\",\n                        \"application/json\",\n                        \"unknown/unknown\",\n                        \"content/unknown\",\n                        \"application/octet-stream\",\n                    )\n                )\n            } catch (e: Exception) {\n                showToast(e.message)\n                logError(e)\n            }\n        }\n    }\n\n    private fun <T> Context.restoreMap(\n        map: Map<String, T>?,\n        isEditingAppSettings: Boolean = false\n    ) {\n        val editor = DataStore.editor(this, isEditingAppSettings)\n        map?.forEach {\n            if (it.key.isTransferable()) {\n                editor.setKeyRaw(it.key, it.value)\n            }\n        }\n        editor.apply()\n    }\n\n    /**\n     * Copy of [com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.basePathToFile], [com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getDefaultDir] and [com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getBasePath]\n     * modded for backup specific paths\n     * */\n\n    fun getDefaultBackupDir(context: Context): SafeFile? {\n        return SafeFile.fromMedia(context, MediaFileContentType.Downloads)\n    }\n\n    fun getCurrentBackupDir(context: Context): Pair<SafeFile?, String?> {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)\n        val basePathSetting =\n            settingsManager.getString(context.getString(R.string.backup_path_key), null)\n        return baseBackupPathToFile(context, basePathSetting) to basePathSetting\n    }\n\n    private fun baseBackupPathToFile(context: Context, path: String?): SafeFile? {\n        return when {\n            path.isNullOrBlank() -> getDefaultBackupDir(context)\n            path.startsWith(\"content://\") -> SafeFile.fromUri(context, path.toUri())\n            else -> SafeFile.fromFilePath(context, path)\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.app.KeyguardManager\nimport android.content.Context\nimport android.os.Build\nimport android.util.Log\nimport androidx.appcompat.app.AppCompatActivity\nimport androidx.biometric.BiometricManager\nimport androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG\nimport androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK\nimport androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL\nimport androidx.biometric.BiometricPrompt\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.ContextCompat.getString\nimport androidx.fragment.app.FragmentActivity\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.R\n\nobject BiometricAuthenticator {\n\n    const val TAG = \"cs3Auth\"\n    private const val MAX_FAILED_ATTEMPTS = 3\n    private var failedAttempts = 0\n    private var biometricManager: BiometricManager? = null\n    var biometricPrompt: BiometricPrompt? = null\n    var promptInfo: BiometricPrompt.PromptInfo? = null\n    var authCallback: BiometricCallback? = null // listen to authentication success\n\n    private fun initializeBiometrics(activity: FragmentActivity) {\n        val executor = ContextCompat.getMainExecutor(activity)\n\n        biometricManager = BiometricManager.from(activity)\n\n        biometricPrompt = BiometricPrompt(\n            activity,\n            executor,\n            object : BiometricPrompt.AuthenticationCallback() {\n                override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {\n                    super.onAuthenticationError(errorCode, errString)\n                    showToast(\"$errString\")\n                    Log.e(TAG, \"$errorCode\")\n                    authCallback?.onAuthenticationError()\n                        //activity.finish()\n                }\n\n                override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {\n                    super.onAuthenticationSucceeded(result)\n                    failedAttempts = 0\n                    authCallback?.onAuthenticationSuccess()\n                }\n\n                override fun onAuthenticationFailed() {\n                    super.onAuthenticationFailed()\n                    failedAttempts++\n                    if (failedAttempts >= MAX_FAILED_ATTEMPTS) {\n                        failedAttempts = 0\n                        activity.finish()\n                    }\n                }\n            })\n    }\n\n    @Suppress(\"DEPRECATION\")\n    // authentication dialog prompt builder\n    private fun authenticationDialog(\n        activity: Activity,\n        title: Int,\n        setDeviceCred: Boolean,\n    ) {\n        val description = activity.getString(R.string.biometric_prompt_description)\n\n        if (setDeviceCred) {\n            // For API level > 30, Newer API setAllowedAuthenticators is used\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n\n                val authFlag = DEVICE_CREDENTIAL or BIOMETRIC_WEAK or BIOMETRIC_STRONG\n                promptInfo = BiometricPrompt.PromptInfo.Builder()\n                    .setTitle(activity.getString(title))\n                    .setDescription(description)\n                    .setAllowedAuthenticators(authFlag)\n                    .build()\n            } else {\n                // for apis < 30\n                promptInfo = BiometricPrompt.PromptInfo.Builder()\n                    .setTitle(activity.getString(title))\n                    .setDescription(description)\n                    .setDeviceCredentialAllowed(true)\n                    .build()\n            }\n        } else {\n            // fallback for A12+ when both fingerprint & Face unlock is absent but PIN is set\n            promptInfo = BiometricPrompt.PromptInfo.Builder()\n                .setTitle(activity.getString(title))\n                .setDescription(description)\n                .setDeviceCredentialAllowed(true)\n                .build()\n        }\n    }\n\n    private fun isBiometricHardWareAvailable(): Boolean {\n        // Authentication occurs only when this is true and device is truly capable.\n        var result = false\n        when {\n            Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA -> {\n                @SuppressLint(\"RestrictedApi\")\n                when (biometricManager?.canAuthenticate(\n                    DEVICE_CREDENTIAL or BIOMETRIC_STRONG or BIOMETRIC_WEAK\n                )) {\n                    BiometricManager.BIOMETRIC_SUCCESS -> result = true\n                    BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true\n                    BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true\n                    BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false\n                }\n            }\n\n            Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> {\n                @Suppress(\"SwitchIntDef\")\n                when (biometricManager?.canAuthenticate(\n                    DEVICE_CREDENTIAL or BIOMETRIC_STRONG or BIOMETRIC_WEAK\n                )) {\n                    BiometricManager.BIOMETRIC_SUCCESS -> result = true\n                    BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true\n                    BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true\n                    BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false\n                }\n            }\n\n            else -> {\n                @Suppress(\"DEPRECATION\", \"SwitchIntDef\")\n                when (biometricManager?.canAuthenticate()) {\n                    BiometricManager.BIOMETRIC_SUCCESS -> result = true\n                    BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false\n                    BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true\n                    BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true\n                    BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false\n                }\n            }\n        }\n\n        return result\n    }\n\n    // checks if device is secured i.e has at least some type of lock\n    fun deviceHasPasswordPinLock(context: Context?): Boolean {\n        val keyMgr =\n            context?.getSystemService(AppCompatActivity.KEYGUARD_SERVICE) as? KeyguardManager\n        return keyMgr?.isKeyguardSecure ?: false\n    }\n\n    // function to start authentication in any fragment or activity\n    fun startBiometricAuthentication(activity: FragmentActivity, title: Int, setDeviceCred: Boolean) {\n        initializeBiometrics(activity)\n        authCallback = activity as? BiometricCallback\n        if (isBiometricHardWareAvailable()) {\n            authCallback = activity as? BiometricCallback\n            authenticationDialog(activity, title, setDeviceCred)\n            promptInfo?.let { biometricPrompt?.authenticate(it) }\n        } else {\n            if (deviceHasPasswordPinLock(activity)) {\n                authCallback = activity as? BiometricCallback\n                authenticationDialog(activity, R.string.password_pin_authentication_title, true)\n                promptInfo?.let { biometricPrompt?.authenticate(it) }\n\n            } else {\n                showToast(R.string.biometric_unsupported)\n            }\n        }\n    }\n\n    fun isAuthEnabled(ctx: Context):Boolean {\n        return ctx.let {\n            PreferenceManager.getDefaultSharedPreferences(ctx)\n                .getBoolean(getString(ctx, R.string.biometric_key), false)\n        }\n    }\n\n    interface BiometricCallback {\n        fun onAuthenticationSuccess()\n        fun onAuthenticationError()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/CastHelper.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport androidx.core.net.toUri\nimport androidx.media3.common.MimeTypes\nimport com.google.android.gms.cast.*\nimport com.google.android.gms.cast.framework.CastSession\nimport com.google.android.gms.cast.framework.media.RemoteMediaClient\nimport com.google.android.gms.common.api.PendingResult\nimport com.google.android.gms.common.images.WebImage\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.MetadataHolder\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.withContext\nimport org.json.JSONObject\n\nobject CastHelper {\n    fun getMediaInfo(\n        epData: ResultEpisode,\n        holder: MetadataHolder,\n        index: Int,\n        data: JSONObject?,\n        subtitles: List<SubtitleData>\n    ): MediaInfo {\n        val link = holder.currentLinks[index]\n        val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)\n        movieMetadata.putString(\n            MediaMetadata.KEY_SUBTITLE,\n            if (holder.isMovie)\n                \"${link.name} ${Qualities.getStringByInt(link.quality)}\"\n            else\n                (epData.name ?: \"Episode ${epData.episode}\") + \" - ${link.name} ${Qualities.getStringByInt(link.quality)}\"\n        )\n\n        holder.title?.let {\n            movieMetadata.putString(MediaMetadata.KEY_TITLE, it)\n        }\n\n        val srcPoster = epData.poster ?: holder.poster\n        if (srcPoster != null) {\n            movieMetadata.addImage(WebImage(srcPoster.toUri()))\n        }\n\n        var subIndex = 0\n        val tracks = subtitles.map {\n            MediaTrack.Builder(subIndex++.toLong(), MediaTrack.TYPE_TEXT)\n                .setName(it.name)\n                .setSubtype(MediaTrack.SUBTYPE_SUBTITLES)\n                .setContentId(it.url)\n                .build()\n        }\n\n        val builder = MediaInfo.Builder(link.url)\n            .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)\n            .setContentType(when(link.type) {\n                ExtractorLinkType.M3U8 -> MimeTypes.APPLICATION_M3U8\n                ExtractorLinkType.DASH -> MimeTypes.APPLICATION_MPD\n                else -> MimeTypes.VIDEO_MP4\n            })\n            .setMetadata(movieMetadata)\n            .setMediaTracks(tracks)\n        data?.let {\n            builder.setCustomData(data)\n        }\n\n        return builder.build()\n    }\n\n    fun awaitLinks(\n        pending: PendingResult<RemoteMediaClient.MediaChannelResult>?,\n        callback: (Boolean) -> Unit\n    ) {\n        if (pending == null) return\n        main {\n            val res = withContext(Dispatchers.IO) { pending.await() }\n            when (res.status.statusCode) {\n                CastStatusCodes.FAILED -> {\n                    callback.invoke(true)\n                    println(\"FAILED AND LOAD NEXT\")\n                }\n                else -> Unit //IDK DO SMTH HERE\n            }\n        }\n    }\n\n    fun CastSession?.startCast(\n        apiName: String,\n        isMovie: Boolean,\n        title: String?,\n        poster: String?,\n        currentEpisodeIndex: Int,\n        episodes: List<ResultEpisode>,\n        currentLinks: List<ExtractorLink>,\n        subtitles: List<SubtitleData>,\n        startIndex: Int? = null,\n        startTime: Long? = null,\n    ): Boolean {\n        try {\n            if (this == null) return false\n            if (episodes.isEmpty()) return false\n            if (currentEpisodeIndex >= episodes.size) return false\n\n            val epData = episodes[currentEpisodeIndex]\n\n            val holder =\n                MetadataHolder(\n                    apiName,\n                    isMovie,\n                    title,\n                    poster,\n                    currentEpisodeIndex,\n                    episodes,\n                    currentLinks,\n                    subtitles\n                )\n\n            val index = if (startIndex == null || startIndex < 0) 0 else startIndex\n\n            val mediaItem =\n                getMediaInfo(epData, holder, index, JSONObject(holder.toJson()), subtitles)\n\n            awaitLinks(\n                this.remoteMediaClient?.load(\n                    MediaLoadRequestData.Builder().setMediaInfo(mediaItem)\n                        .setCurrentTime(startTime ?: 0L).build()\n                )\n            ) {\n                if (currentLinks.size > index + 1)\n                    startCast(\n                        apiName,\n                        isMovie,\n                        title,\n                        poster,\n                        currentEpisodeIndex,\n                        episodes,\n                        currentLinks,\n                        subtitles,\n                        index + 1,\n                        startTime\n                    )\n            }\n            return true\n        } catch (e: Exception) {\n            logError(e)\n            return false\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/CastOptionsProvider.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.content.Context\nimport com.google.android.gms.cast.CastMediaControlIntent\nimport com.google.android.gms.cast.framework.CastOptions\nimport com.google.android.gms.cast.framework.OptionsProvider\nimport com.google.android.gms.cast.framework.SessionProvider\nimport com.google.android.gms.cast.framework.media.CastMediaOptions\nimport com.google.android.gms.cast.framework.media.MediaIntentReceiver\nimport com.google.android.gms.cast.framework.media.NotificationOptions\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.ControllerActivity\nimport java.util.*\n\nclass CastOptionsProvider : OptionsProvider {\n    override fun getCastOptions(context: Context): CastOptions {\n        val buttonActions = listOf(\n            MediaIntentReceiver.ACTION_REWIND,\n            MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK,\n            MediaIntentReceiver.ACTION_FORWARD,\n            MediaIntentReceiver.ACTION_STOP_CASTING\n        )\n\n        val name = ControllerActivity::class.qualifiedName!!\n\n        val compatButtonAction = intArrayOf(1, 3)\n        val notificationOptions =\n            NotificationOptions.Builder()\n                .setTargetActivityClassName(name)\n                .setActions(buttonActions, compatButtonAction)\n                .setForward30DrawableResId(R.drawable.go_forward_30)\n                .setRewind30DrawableResId(R.drawable.go_back_30)\n                .setSkipStepMs(30000)\n                .build()\n\n        val mediaOptions = CastMediaOptions.Builder()\n            .setNotificationOptions(notificationOptions)\n            .setExpandedControllerActivityClassName(name)\n            .build()\n\n        return CastOptions.Builder()\n            .setReceiverApplicationId(CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID)\n            //.setReceiverApplicationId(\"\")\n            //  C0868879 = SAMPLE, CHANGE TO A NICE ID at https://developers.google.com/cast/docs/registration\n            .setStopReceiverApplicationWhenEndingSession(true)\n            .setCastMediaOptions(mediaOptions)\n            .build()\n    }\n\n    override fun getAdditionalSessionProviders(p0: Context): MutableList<SessionProvider> {\n        return Collections.emptyList()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/ConsistentLiveData.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport androidx.annotation.MainThread\nimport androidx.lifecycle.LiveData\nimport com.lagradost.cloudstream3.mvvm.Resource\n\n/**\n * This is an atomic LiveData where you can do .value instantly after doing .postValue.\n *\n * The default behavior is a footgun that will cause race conditions, \n * as we do not really care if it is posted as we only want the latest data (even in the binding).\n *\n * Fuck all that is LiveData, because we want this value to be accessible everywhere instantly.\n * */\nopen class ConsistentLiveData<T>(initValue : T? = null) : LiveData<T>(initValue) {\n    @Volatile private var internalValue : T? = initValue\n\n    override fun getValue(): T? {\n        return internalValue\n    }\n\n    /** If someone want the old behavior then good for them */\n    val postedValue : T? get() = super.getValue()\n\n    public override fun postValue(value : T?) {\n        super.postValue(value)\n        internalValue = value\n    }\n\n    @MainThread\n    public override fun setValue(value: T?) {\n        super.setValue(value)\n        internalValue = value\n    }\n}\n\n/** Atomic resource livedata, to make it easier to work with resources without local copies */\nclass ResourceLiveData<T>(initValue : Resource<T>? = null) : ConsistentLiveData<Resource<T>>(initValue) {\n    var success\n        get() = when(val output = this.value) {\n            is Resource.Success<T> -> {\n                output.value\n            }\n            else -> null\n        }\n        set(value) = this.postValue(value?.let { Resource.Success<T>(it) } )\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.content.Context\nimport android.content.SharedPreferences\nimport androidx.preference.PreferenceManager\nimport com.fasterxml.jackson.databind.DeserializationFeature\nimport com.fasterxml.jackson.databind.json.JsonMapper\nimport com.fasterxml.jackson.module.kotlin.kotlinModule\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeyClass\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKeyClass\nimport com.lagradost.cloudstream3.mvvm.logError\nimport kotlin.reflect.KClass\nimport kotlin.reflect.KProperty\nimport androidx.core.content.edit\n\n/** Used to display metadata about downloads and resume watching */\nconst val DOWNLOAD_HEADER_CACHE = \"download_header_cache\"\nconst val DOWNLOAD_HEADER_CACHE_BACKUP = \"BACKUP_download_header_cache\"\n\n//const val WATCH_HEADER_CACHE = \"watch_header_cache\"\nconst val DOWNLOAD_EPISODE_CACHE = \"download_episode_cache\"\nconst val DOWNLOAD_EPISODE_CACHE_BACKUP = \"BACKUP_download_episode_cache\"\nconst val VIDEO_PLAYER_BRIGHTNESS = \"video_player_alpha_key\"\nconst val USER_SELECTED_HOMEPAGE_API = \"home_api_used\"\nconst val USER_PROVIDER_API = \"user_custom_sites\"\nconst val PREFERENCES_NAME = \"rebuild_preference\"\n\n// TODO degelgate by value for get & set\n\nclass PreferenceDelegate<T : Any>(\n    val key: String, val default: T //, private val klass: KClass<T>\n) {\n    private val klass: KClass<out T> = default::class\n\n    // simple cache to make it not get the key every time it is accessed, however this requires\n    // that ONLY this changes the key\n    private var cache: T? = null\n\n    operator fun getValue(self: Any?, property: KProperty<*>) =\n        cache ?: getKeyClass(key, klass.java).also { newCache -> cache = newCache } ?: default\n\n    operator fun setValue(\n        self: Any?,\n        property: KProperty<*>,\n        t: T?\n    ) {\n        cache = t\n        if (t == null) {\n            removeKey(key)\n        } else {\n            setKeyClass(key, t)\n        }\n    }\n}\n\n/** When inserting many keys use this function, this is because apply for every key is very expensive on memory */\ndata class Editor(\n    val editor: SharedPreferences.Editor\n) {\n    /** Always remember to call apply after */\n    fun <T> setKeyRaw(path: String, value: T) {\n        @Suppress(\"UNCHECKED_CAST\")\n        if (isStringSet(value)) {\n            editor.putStringSet(path, value as Set<String>)\n        } else {\n            when (value) {\n                is Boolean -> editor.putBoolean(path, value)\n                is Int -> editor.putInt(path, value)\n                is String -> editor.putString(path, value)\n                is Float -> editor.putFloat(path, value)\n                is Long -> editor.putLong(path, value)\n            }\n        }\n    }\n\n    private fun isStringSet(value: Any?): Boolean {\n        if (value is Set<*>) {\n            return value.filterIsInstance<String>().size == value.size\n        }\n        return false\n    }\n\n    fun apply() {\n        editor.apply()\n        System.gc()\n    }\n}\n\nobject DataStore {\n    val mapper: JsonMapper = JsonMapper.builder().addModule(kotlinModule())\n        .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()\n\n    private fun getPreferences(context: Context): SharedPreferences {\n        return context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE)\n    }\n\n    fun Context.getSharedPrefs(): SharedPreferences {\n        return getPreferences(this)\n    }\n\n\n    fun getFolderName(folder: String, path: String): String {\n        return \"${folder}/${path}\"\n    }\n\n    fun editor(context: Context, isEditingAppSettings: Boolean = false): Editor {\n        val editor: SharedPreferences.Editor =\n            if (isEditingAppSettings) context.getDefaultSharedPrefs()\n                .edit() else context.getSharedPrefs().edit()\n        return Editor(editor)\n    }\n\n    fun Context.getDefaultSharedPrefs(): SharedPreferences {\n        return PreferenceManager.getDefaultSharedPreferences(this)\n    }\n\n    fun Context.getKeys(folder: String): List<String> {\n        // Ensure that the folder ends with \"/\" to prevent matching with other folders\n        val fixedFolder = folder.trimEnd('/') + \"/\"\n        return this.getSharedPrefs().all.keys.filter { it.startsWith(fixedFolder) }\n    }\n\n    fun Context.removeKey(folder: String, path: String) {\n        removeKey(getFolderName(folder, path))\n    }\n\n    fun Context.containsKey(folder: String, path: String): Boolean {\n        return containsKey(getFolderName(folder, path))\n    }\n\n    fun Context.containsKey(path: String): Boolean {\n        val prefs = getSharedPrefs()\n        return prefs.contains(path)\n    }\n\n    fun Context.removeKey(path: String) {\n        try {\n            val prefs = getSharedPrefs()\n            if (prefs.contains(path)) {\n                prefs.edit {\n                    remove(path)\n                }\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    fun Context.removeKeys(folder: String): Int {\n        val keys = getKeys(\"$folder/\")\n        try {\n            getSharedPrefs().edit {\n                keys.forEach { value ->\n                    remove(value)\n                }\n            }\n            return keys.size\n        } catch (e: Exception) {\n            logError(e)\n            return 0\n        }\n    }\n\n    fun <T> Context.setKey(path: String, value: T) {\n        try {\n            getSharedPrefs().edit {\n                putString(path, mapper.writeValueAsString(value))\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    fun <T> Context.getKey(path: String, valueType: Class<T>): T? {\n        try {\n            val json: String = getSharedPrefs().getString(path, null) ?: return null\n            return json.toKotlinObject(valueType)\n        } catch (e: Exception) {\n            return null\n        }\n    }\n\n    fun <T> Context.setKey(folder: String, path: String, value: T) {\n        setKey(getFolderName(folder, path), value)\n    }\n\n    inline fun <reified T : Any> String.toKotlinObject(): T {\n        return mapper.readValue(this, T::class.java)\n    }\n\n    fun <T> String.toKotlinObject(valueType: Class<T>): T {\n        return mapper.readValue(this, valueType)\n    }\n\n    // GET KEY GIVEN PATH AND DEFAULT VALUE, NULL IF ERROR\n    inline fun <reified T : Any> Context.getKey(path: String, defVal: T?): T? {\n        try {\n            val json: String = getSharedPrefs().getString(path, null) ?: return defVal\n            return json.toKotlinObject()\n        } catch (e: Exception) {\n            return null\n        }\n    }\n\n    inline fun <reified T : Any> Context.getKey(path: String): T? {\n        return getKey(path, null)\n    }\n\n    inline fun <reified T : Any> Context.getKey(folder: String, path: String): T? {\n        return getKey(getFolderName(folder, path), null)\n    }\n\n    inline fun <reified T : Any> Context.getKey(folder: String, path: String, defVal: T?): T? {\n        return getKey(getFolderName(folder, path), defVal) ?: defVal\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.content.Context\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder.unixTimeMS\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.context\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeyClass\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKeys\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKeyClass\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.DubStatus\nimport com.lagradost.cloudstream3.EpisodeResponse\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.SearchQuality\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.syncproviders.AccountManager\nimport com.lagradost.cloudstream3.syncproviders.SyncAPI\nimport com.lagradost.cloudstream3.ui.WatchType\nimport com.lagradost.cloudstream3.ui.library.ListSorting\nimport com.lagradost.cloudstream3.ui.player.ExtractorUri\nimport com.lagradost.cloudstream3.ui.player.NEXT_WATCH_EPISODE_PERCENTAGE\nimport com.lagradost.cloudstream3.ui.result.EpisodeSortType\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.ui.result.VideoWatchState\nimport com.lagradost.cloudstream3.utils.AppContextUtils.filterProviderByPreferredMedia\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\nimport java.util.Calendar\nimport java.util.Date\nimport java.util.GregorianCalendar\nimport kotlin.reflect.KClass\nimport kotlin.reflect.KProperty\n\nconst val VIDEO_POS_DUR = \"video_pos_dur\"\nconst val VIDEO_WATCH_STATE = \"video_watch_state\"\nconst val RESULT_WATCH_STATE = \"result_watch_state\"\nconst val RESULT_WATCH_STATE_DATA = \"result_watch_state_data\"\nconst val RESULT_SUBSCRIBED_STATE_DATA = \"result_subscribed_state_data\"\nconst val RESULT_FAVORITES_STATE_DATA = \"result_favorites_state_data\"\nconst val RESULT_RESUME_WATCHING = \"result_resume_watching_2\" // changed due to id changes\nconst val RESULT_RESUME_WATCHING_OLD = \"result_resume_watching\"\nconst val RESULT_RESUME_WATCHING_HAS_MIGRATED = \"result_resume_watching_migrated\"\nconst val RESULT_EPISODE = \"result_episode\"\nconst val RESULT_SEASON = \"result_season\"\nconst val RESULT_DUB = \"result_dub\"\nconst val KEY_RESULT_SORT = \"result_sort\"\nconst val USER_PINNED_PROVIDERS = \"user_pinned_providers\" //key for pinned user set\n\nclass UserPreferenceDelegate<T : Any>(\n    private val key: String, private val default: T //, private val klass: KClass<T>\n) {\n    private val klass: KClass<out T> = default::class\n    private val realKey get() = \"${DataStoreHelper.currentAccount}/$key\"\n    operator fun getValue(self: Any?, property: KProperty<*>) =\n        getKeyClass(realKey, klass.java) ?: default\n\n    operator fun setValue(\n        self: Any?,\n        property: KProperty<*>,\n        t: T?\n    ) {\n        if (t == null) {\n            removeKey(realKey)\n        } else {\n            setKeyClass(realKey, t)\n        }\n    }\n}\n\nobject DataStoreHelper {\n    // be aware, don't change the index of these as Account uses the index for the art\n    val profileImages = arrayOf(\n        R.drawable.profile_bg_dark_blue,\n        R.drawable.profile_bg_blue,\n        R.drawable.profile_bg_orange,\n        R.drawable.profile_bg_pink,\n        R.drawable.profile_bg_purple,\n        R.drawable.profile_bg_red,\n        R.drawable.profile_bg_teal\n    )\n\n    private var searchPreferenceProvidersStrings: List<String> by UserPreferenceDelegate(\n        /** java moment right here, as listOf()::class.java != List(0) { \"\" }::class.java */\n        \"search_pref_providers\", List(0) { \"\" }\n    )\n\n    private fun serializeTv(data: List<TvType>): List<String> = data.map { it.name }\n\n    private fun deserializeTv(data: List<String>): List<TvType> {\n        return data.mapNotNull { listName ->\n            TvType.values().firstOrNull { it.name == listName }\n        }\n    }\n\n    var searchPreferenceProviders: List<String>\n        get() {\n            val ret = searchPreferenceProvidersStrings\n            return ret.ifEmpty {\n                context?.filterProviderByPreferredMedia()?.map { it.name } ?: emptyList()\n            }\n        }\n        set(value) {\n            searchPreferenceProvidersStrings = value\n        }\n\n    private var searchPreferenceTagsStrings: List<String> by UserPreferenceDelegate(\n        \"search_pref_tags\",\n        listOf(TvType.Movie, TvType.TvSeries).map { it.name })\n    var searchPreferenceTags: List<TvType>\n        get() = deserializeTv(searchPreferenceTagsStrings)\n        set(value) {\n            searchPreferenceTagsStrings = serializeTv(value)\n        }\n\n\n    private var homePreferenceStrings: List<String> by UserPreferenceDelegate(\n        \"home_pref_homepage\",\n        listOf(TvType.Movie, TvType.TvSeries).map { it.name })\n    var homePreference: List<TvType>\n        get() = deserializeTv(homePreferenceStrings)\n        set(value) {\n            homePreferenceStrings = serializeTv(value)\n        }\n\n    var homeBookmarkedList: IntArray by UserPreferenceDelegate(\n        \"home_bookmarked_last_list\",\n        IntArray(0)\n    )\n    var playBackSpeed: Float by UserPreferenceDelegate(\"playback_speed\", 1.0f)\n    var resizeMode: Int by UserPreferenceDelegate(\"resize_mode\", 0)\n    var librarySortingMode: Int by UserPreferenceDelegate(\n        \"library_sorting_mode\",\n        ListSorting.AlphabeticalA.ordinal\n    )\n    private var _resultsSortingMode: Int by UserPreferenceDelegate(\n        \"results_sorting_mode\",\n        EpisodeSortType.NUMBER_ASC.ordinal\n    )\n    var resultsSortingMode: EpisodeSortType\n        get() = EpisodeSortType.entries.getOrNull(_resultsSortingMode) ?: EpisodeSortType.NUMBER_ASC\n        set(value) {\n            _resultsSortingMode = value.ordinal\n        }\n\n    data class Account(\n        @JsonProperty(\"keyIndex\")\n        val keyIndex: Int,\n        @JsonProperty(\"name\")\n        val name: String,\n        @JsonProperty(\"customImage\")\n        val customImage: String? = null,\n        @JsonProperty(\"defaultImageIndex\")\n        val defaultImageIndex: Int,\n        @JsonProperty(\"lockPin\")\n        val lockPin: String? = null,\n    ) {\n        val image\n            get() = customImage?.let { UiImage.Image(it) } ?: profileImages.getOrNull(\n                defaultImageIndex\n            )?.let { UiImage.Drawable(it) } ?: UiImage.Drawable(profileImages.first())\n    }\n\n    const val TAG = \"data_store_helper\"\n    var accounts by PreferenceDelegate(\"$TAG/account\", arrayOf<Account>())\n    var selectedKeyIndex by PreferenceDelegate(\"$TAG/account_key_index\", 0)\n    val currentAccount: String get() = selectedKeyIndex.toString()\n\n    /**\n     * Get or set the current account homepage.\n     * Setting this does not automatically reload the homepage.\n     */\n    var currentHomePage: String?\n        get() = getKey(\"$currentAccount/$USER_SELECTED_HOMEPAGE_API\")\n        set(value) {\n            val key = \"$currentAccount/$USER_SELECTED_HOMEPAGE_API\"\n            if (value == null) {\n                removeKey(key)\n            } else {\n                setKey(key, value)\n            }\n        }\n\n    fun setAccount(account: Account) {\n        val homepage = currentHomePage\n\n        selectedKeyIndex = account.keyIndex\n        AccountManager.updateAccountIds()\n        showToast(context?.getString(R.string.logged_account, account.name) ?: account.name)\n        MainActivity.bookmarksUpdatedEvent(true)\n        MainActivity.reloadLibraryEvent(true)\n        val oldAccount = accounts.find { it.keyIndex == account.keyIndex }\n        if (oldAccount != null && currentHomePage != homepage) {\n            // This is not a new account, and the homepage has changed, reload it\n            MainActivity.reloadHomeEvent(true)\n        }\n    }\n\n    fun getDefaultAccount(context: Context): Account {\n        return accounts.let { currentAccounts ->\n            currentAccounts.getOrNull(currentAccounts.indexOfFirst { it.keyIndex == 0 }) ?: Account(\n                keyIndex = 0,\n                name = context.getString(R.string.default_account),\n                defaultImageIndex = 0\n            )\n        }\n    }\n\n    fun getAccounts(context: Context): List<Account> {\n        return accounts.toMutableList().apply {\n            val item = getDefaultAccount(context)\n            remove(item)\n            add(0, item)\n        }\n    }\n\n    /** Gets the current selected account (or default), may return null if context is null and the user is using the default account */\n    fun getCurrentAccount(): Account? {\n        return (context?.let {\n            getAccounts(it)\n        } ?: accounts.toList()).firstNotNullOfOrNull { account ->\n            if (account.keyIndex == selectedKeyIndex) {\n                account\n            } else {\n                null\n            }\n        }\n    }\n\n    data class PosDur(\n        @JsonProperty(\"position\") val position: Long,\n        @JsonProperty(\"duration\") val duration: Long\n    )\n\n    fun PosDur.fixVisual(): PosDur {\n        if (duration <= 0) return PosDur(0, duration)\n        val percentage = position * 100 / duration\n        if (percentage <= 1) return PosDur(0, duration)\n        if (percentage <= 5) return PosDur(5 * duration / 100, duration)\n        if (percentage >= 95) return PosDur(duration, duration)\n        return this\n    }\n\n    fun Int.toYear(): Date =\n        GregorianCalendar.getInstance().also { it.set(Calendar.YEAR, this) }.time\n\n    /**\n     * Used to display notifications on new episodes and posters in library.\n     **/\n    abstract class LibrarySearchResponse(\n        @JsonProperty(\"id\") override var id: Int?,\n        @JsonProperty(\"latestUpdatedTime\") open val latestUpdatedTime: Long,\n        @JsonProperty(\"name\") override val name: String,\n        @JsonProperty(\"url\") override val url: String,\n        @JsonProperty(\"apiName\") override val apiName: String,\n        @JsonProperty(\"type\") override var type: TvType?,\n        @JsonProperty(\"posterUrl\") override var posterUrl: String?,\n        @JsonProperty(\"year\") open val year: Int?,\n        @JsonProperty(\"syncData\") open val syncData: Map<String, String>?,\n        @JsonProperty(\"quality\") override var quality: SearchQuality?,\n        @JsonProperty(\"posterHeaders\") override var posterHeaders: Map<String, String>?,\n        @JsonProperty(\"plot\") open val plot: String? = null,\n        @JsonProperty(\"score\") override var score: Score? = null,\n        @JsonProperty(\"tags\") open val tags: List<String>? = null,\n    ) : SearchResponse {\n        @JsonProperty(\"rating\", access = JsonProperty.Access.WRITE_ONLY)\n        @Deprecated(\n            \"`rating` is the old scoring system, use score instead\",\n            replaceWith = ReplaceWith(\"score\"),\n            level = DeprecationLevel.ERROR\n        )\n        var rating: Int? = null\n            set(value) {\n                if (value != null) {\n                    @Suppress(\"DEPRECATION_ERROR\")\n                    score = Score.fromOld(value)\n                }\n            }\n    }\n\n    data class SubscribedData(\n        @JsonProperty(\"subscribedTime\") val subscribedTime: Long,\n        @JsonProperty(\"lastSeenEpisodeCount\") val lastSeenEpisodeCount: Map<DubStatus, Int?>,\n        override var id: Int?,\n        override val latestUpdatedTime: Long,\n        override val name: String,\n        override val url: String,\n        override val apiName: String,\n        override var type: TvType?,\n        override var posterUrl: String?,\n        override val year: Int?,\n        override val syncData: Map<String, String>? = null,\n        override var quality: SearchQuality? = null,\n        override var posterHeaders: Map<String, String>? = null,\n        override val plot: String? = null,\n        override var score: Score? = null,\n        override val tags: List<String>? = null,\n    ) : LibrarySearchResponse(\n        id,\n        latestUpdatedTime,\n        name,\n        url,\n        apiName,\n        type,\n        posterUrl,\n        year,\n        syncData,\n        quality,\n        posterHeaders,\n        plot,\n        score,\n        tags\n    ) {\n        fun toLibraryItem(): SyncAPI.LibraryItem? {\n            return SyncAPI.LibraryItem(\n                name,\n                url,\n                id?.toString() ?: return null,\n                null,\n                null,\n                null,\n                latestUpdatedTime,\n                apiName,\n                type,\n                posterUrl,\n                posterHeaders,\n                quality,\n                year?.toYear(),\n                this.id,\n                plot = this.plot,\n                score = this.score,\n                tags = this.tags\n            )\n        }\n    }\n\n    data class BookmarkedData(\n        @JsonProperty(\"bookmarkedTime\") val bookmarkedTime: Long,\n        override var id: Int?,\n        override val latestUpdatedTime: Long,\n        override val name: String,\n        override val url: String,\n        override val apiName: String,\n        override var type: TvType?,\n        override var posterUrl: String?,\n        override val year: Int?,\n        override val syncData: Map<String, String>? = null,\n        override var quality: SearchQuality? = null,\n        override var posterHeaders: Map<String, String>? = null,\n        override val plot: String? = null,\n        override var score: Score? = null,\n        override val tags: List<String>? = null,\n    ) : LibrarySearchResponse(\n        id,\n        latestUpdatedTime,\n        name,\n        url,\n        apiName,\n        type,\n        posterUrl,\n        year,\n        syncData,\n        quality,\n        posterHeaders,\n        plot\n    ) {\n        fun toLibraryItem(id: String): SyncAPI.LibraryItem {\n            return SyncAPI.LibraryItem(\n                name,\n                url,\n                id,\n                null,\n                null,\n                null,\n                latestUpdatedTime,\n                apiName,\n                type,\n                posterUrl,\n                posterHeaders,\n                quality,\n                year?.toYear(),\n                this.id,\n                plot = this.plot,\n                score = this.score,\n                tags = this.tags\n            )\n        }\n    }\n\n    data class FavoritesData(\n        @JsonProperty(\"favoritesTime\") val favoritesTime: Long,\n        override var id: Int?,\n        override val latestUpdatedTime: Long,\n        override val name: String,\n        override val url: String,\n        override val apiName: String,\n        override var type: TvType?,\n        override var posterUrl: String?,\n        override val year: Int?,\n        override val syncData: Map<String, String>? = null,\n        override var quality: SearchQuality? = null,\n        override var posterHeaders: Map<String, String>? = null,\n        override val plot: String? = null,\n        override var score: Score? = null,\n        override val tags: List<String>? = null,\n    ) : LibrarySearchResponse(\n        id,\n        latestUpdatedTime,\n        name,\n        url,\n        apiName,\n        type,\n        posterUrl,\n        year,\n        syncData,\n        quality,\n        posterHeaders,\n        plot\n    ) {\n        fun toLibraryItem(): SyncAPI.LibraryItem? {\n            return SyncAPI.LibraryItem(\n                name,\n                url,\n                id?.toString() ?: return null,\n                null,\n                null,\n                null,\n                latestUpdatedTime,\n                apiName,\n                type,\n                posterUrl,\n                posterHeaders,\n                quality,\n                year?.toYear(),\n                this.id,\n                plot = this.plot,\n                score = this.score,\n                tags = this.tags\n            )\n        }\n    }\n\n    data class ResumeWatchingResult(\n        @JsonProperty(\"name\") override val name: String,\n        @JsonProperty(\"url\") override val url: String,\n        @JsonProperty(\"apiName\") override val apiName: String,\n        @JsonProperty(\"type\") override var type: TvType? = null,\n        @JsonProperty(\"posterUrl\") override var posterUrl: String?,\n        @JsonProperty(\"watchPos\") val watchPos: PosDur?,\n        @JsonProperty(\"id\") override var id: Int?,\n        @JsonProperty(\"parentId\") val parentId: Int?,\n        @JsonProperty(\"episode\") val episode: Int?,\n        @JsonProperty(\"season\") val season: Int?,\n        @JsonProperty(\"isFromDownload\") val isFromDownload: Boolean,\n        @JsonProperty(\"quality\") override var quality: SearchQuality? = null,\n        @JsonProperty(\"posterHeaders\") override var posterHeaders: Map<String, String>? = null,\n        @JsonProperty(\"score\") override var score: Score? = null,\n    ) : SearchResponse\n\n    /**\n     * A datastore wide account for future implementations of a multiple account system\n     **/\n\n    fun getAllWatchStateIds(): List<Int>? {\n        val folder = \"$currentAccount/$RESULT_WATCH_STATE\"\n        return getKeys(folder)?.mapNotNull {\n            it.removePrefix(\"$folder/\").toIntOrNull()\n        }\n    }\n\n    fun deleteAllResumeStateIds() {\n        val folder = \"$currentAccount/$RESULT_RESUME_WATCHING\"\n        removeKeys(folder)\n    }\n\n    fun deleteBookmarkedData(id: Int?) {\n        if (id == null) return\n        AccountManager.localListApi.requireLibraryRefresh = true\n        removeKey(\"$currentAccount/$RESULT_WATCH_STATE\", id.toString())\n        removeKey(\"$currentAccount/$RESULT_WATCH_STATE_DATA\", id.toString())\n    }\n\n    fun getAllResumeStateIds(): List<Int>? {\n        val folder = \"$currentAccount/$RESULT_RESUME_WATCHING\"\n        return getKeys(folder)?.mapNotNull {\n            it.removePrefix(\"$folder/\").toIntOrNull()\n        }\n    }\n\n    private fun getAllResumeStateIdsOld(): List<Int>? {\n        val folder = \"$currentAccount/$RESULT_RESUME_WATCHING_OLD\"\n        return getKeys(folder)?.mapNotNull {\n            it.removePrefix(\"$folder/\").toIntOrNull()\n        }\n    }\n\n    fun migrateResumeWatching() {\n        // if (getKey(RESULT_RESUME_WATCHING_HAS_MIGRATED, false) != true) {\n        setKey(RESULT_RESUME_WATCHING_HAS_MIGRATED, true)\n        getAllResumeStateIdsOld()?.forEach { id ->\n            getLastWatchedOld(id)?.let {\n                setLastWatched(\n                    it.parentId,\n                    null,\n                    it.episode,\n                    it.season,\n                    it.isFromDownload,\n                    it.updateTime\n                )\n                removeLastWatchedOld(it.parentId)\n            }\n        }\n        //}\n    }\n\n    fun setLastWatched(\n        parentId: Int?,\n        episodeId: Int?,\n        episode: Int?,\n        season: Int?,\n        isFromDownload: Boolean = false,\n        updateTime: Long? = null,\n    ) {\n        if (parentId == null) return\n        setKey(\n            \"$currentAccount/$RESULT_RESUME_WATCHING\",\n            parentId.toString(),\n            DownloadObjects.ResumeWatching(\n                parentId,\n                episodeId,\n                episode,\n                season,\n                updateTime ?: System.currentTimeMillis(),\n                isFromDownload\n            )\n        )\n    }\n\n    private fun removeLastWatchedOld(parentId: Int?) {\n        if (parentId == null) return\n        removeKey(\"$currentAccount/$RESULT_RESUME_WATCHING_OLD\", parentId.toString())\n    }\n\n    fun removeLastWatched(parentId: Int?) {\n        if (parentId == null) return\n        removeKey(\"$currentAccount/$RESULT_RESUME_WATCHING\", parentId.toString())\n    }\n\n    fun getLastWatched(id: Int?): DownloadObjects.ResumeWatching? {\n        if (id == null) return null\n        return getKey(\n            \"$currentAccount/$RESULT_RESUME_WATCHING\",\n            id.toString(),\n        )\n    }\n\n    private fun getLastWatchedOld(id: Int?): DownloadObjects.ResumeWatching? {\n        if (id == null) return null\n        return getKey(\n            \"$currentAccount/$RESULT_RESUME_WATCHING_OLD\",\n            id.toString(),\n        )\n    }\n\n    fun setBookmarkedData(id: Int?, data: BookmarkedData) {\n        if (id == null) return\n        setKey(\"$currentAccount/$RESULT_WATCH_STATE_DATA\", id.toString(), data)\n        AccountManager.localListApi.requireLibraryRefresh = true\n    }\n\n    fun getBookmarkedData(id: Int?): BookmarkedData? {\n        if (id == null) return null\n        return getKey(\"$currentAccount/$RESULT_WATCH_STATE_DATA\", id.toString())\n    }\n\n    fun getAllBookmarkedData(): List<BookmarkedData> {\n        return getKeys(\"$currentAccount/$RESULT_WATCH_STATE_DATA\")?.mapNotNull {\n            getKey(it)\n        } ?: emptyList()\n    }\n\n    fun getAllSubscriptions(): List<SubscribedData> {\n        return getKeys(\"$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA\")?.mapNotNull {\n            getKey(it)\n        } ?: emptyList()\n    }\n\n    fun removeSubscribedData(id: Int?) {\n        if (id == null) return\n        AccountManager.localListApi.requireLibraryRefresh = true\n        removeKey(\"$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA\", id.toString())\n    }\n\n    /**\n     * Set new seen episodes and update time\n     **/\n    fun updateSubscribedData(id: Int?, data: SubscribedData?, episodeResponse: EpisodeResponse?) {\n        if (id == null || data == null || episodeResponse == null) return\n        val newData = data.copy(\n            latestUpdatedTime = unixTimeMS,\n            lastSeenEpisodeCount = episodeResponse.getLatestEpisodes()\n        )\n        setKey(\"$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA\", id.toString(), newData)\n    }\n\n    fun setSubscribedData(id: Int?, data: SubscribedData) {\n        if (id == null) return\n        setKey(\"$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA\", id.toString(), data)\n        AccountManager.localListApi.requireLibraryRefresh = true\n    }\n\n    fun getSubscribedData(id: Int?): SubscribedData? {\n        if (id == null) return null\n        return getKey(\"$currentAccount/$RESULT_SUBSCRIBED_STATE_DATA\", id.toString())\n    }\n\n    fun getAllFavorites(): List<FavoritesData> {\n        return getKeys(\"$currentAccount/$RESULT_FAVORITES_STATE_DATA\")?.mapNotNull {\n            getKey(it)\n        } ?: emptyList()\n    }\n\n    fun removeFavoritesData(id: Int?) {\n        if (id == null) return\n        AccountManager.localListApi.requireLibraryRefresh = true\n        removeKey(\"$currentAccount/$RESULT_FAVORITES_STATE_DATA\", id.toString())\n    }\n\n    fun setFavoritesData(id: Int?, data: FavoritesData) {\n        if (id == null) return\n        setKey(\"$currentAccount/$RESULT_FAVORITES_STATE_DATA\", id.toString(), data)\n        AccountManager.localListApi.requireLibraryRefresh = true\n    }\n\n    fun getFavoritesData(id: Int?): FavoritesData? {\n        if (id == null) return null\n        return getKey(\"$currentAccount/$RESULT_FAVORITES_STATE_DATA\", id.toString())\n    }\n\n    fun setViewPos(id: Int?, pos: Long, dur: Long) {\n        if (id == null) return\n        if (dur < 30_000) return // too short\n        setKey(\"$currentAccount/$VIDEO_POS_DUR\", id.toString(), PosDur(pos, dur))\n    }\n\n    /** Sets the position, duration, and resume data of an episode/movie,\n     *\n     * if nextEpisode is not specified it will not be able to set the next episode as resumable if progress > NEXT_WATCH_EPISODE_PERCENTAGE\n     * */\n    fun setViewPosAndResume(id: Int?, position: Long, duration: Long, currentEpisode: Any?, nextEpisode: Any?) {\n        setViewPos(id, position, duration)\n        if (id != null) {\n            when (val meta = currentEpisode) {\n                is ResultEpisode -> {\n                    if (meta.videoWatchState == VideoWatchState.Watched) {\n                        setVideoWatchState(id, VideoWatchState.None)\n                    }\n                }\n            }\n        }\n\n        val percentage = position * 100L / duration\n        val nextEp = percentage >= NEXT_WATCH_EPISODE_PERCENTAGE\n        val resumeMeta = if (nextEp) nextEpisode else currentEpisode\n        if (resumeMeta == null && nextEp) {\n            // remove last watched as it is the last episode and you have watched too much\n            when (val newMeta = currentEpisode) {\n                is ResultEpisode -> {\n                    removeLastWatched(newMeta.parentId)\n                }\n\n                is ExtractorUri -> {\n                    removeLastWatched(newMeta.parentId)\n                }\n            }\n        } else {\n            // save resume\n            when (resumeMeta) {\n                is ResultEpisode -> {\n                    setLastWatched(\n                        resumeMeta.parentId,\n                        resumeMeta.id,\n                        resumeMeta.episode,\n                        resumeMeta.season,\n                        isFromDownload = false\n                    )\n                }\n\n                is ExtractorUri -> {\n                    setLastWatched(\n                        resumeMeta.parentId,\n                        resumeMeta.id,\n                        resumeMeta.episode,\n                        resumeMeta.season,\n                        isFromDownload = true\n                    )\n                }\n            }\n        }\n    }\n\n    fun getViewPos(id: Int?): PosDur? {\n        if (id == null) return null\n        return getKey(\"$currentAccount/$VIDEO_POS_DUR\", id.toString(), null)\n    }\n\n    fun getVideoWatchState(id: Int?): VideoWatchState? {\n        if (id == null) return null\n        return getKey(\"$currentAccount/$VIDEO_WATCH_STATE\", id.toString(), null)\n    }\n\n    fun setVideoWatchState(id: Int?, watchState: VideoWatchState) {\n        if (id == null) return\n\n        // None == No key\n        if (watchState == VideoWatchState.None) {\n            removeKey(\"$currentAccount/$VIDEO_WATCH_STATE\", id.toString())\n        } else {\n            setKey(\"$currentAccount/$VIDEO_WATCH_STATE\", id.toString(), watchState)\n        }\n    }\n\n    fun getDub(id: Int): DubStatus? {\n        return DubStatus.entries\n            .getOrNull(getKey(\"$currentAccount/$RESULT_DUB\", id.toString(), -1) ?: -1)\n    }\n\n    fun setDub(id: Int, status: DubStatus) {\n        setKey(\"$currentAccount/$RESULT_DUB\", id.toString(), status.ordinal)\n    }\n\n    fun setResultWatchState(id: Int?, status: Int) {\n        if (id == null) return\n        if (status == WatchType.NONE.internalId) {\n            deleteBookmarkedData(id)\n        } else {\n            setKey(\"$currentAccount/$RESULT_WATCH_STATE\", id.toString(), status)\n        }\n    }\n\n    fun getResultWatchState(id: Int): WatchType {\n        return WatchType.fromInternalId(\n            getKey<Int>(\n                \"$currentAccount/$RESULT_WATCH_STATE\",\n                id.toString(),\n                null\n            )\n        )\n    }\n\n    fun getResultSeason(id: Int): Int? {\n        return getKey(\"$currentAccount/$RESULT_SEASON\", id.toString(), null)\n    }\n\n    fun setResultSeason(id: Int, value: Int?) {\n        setKey(\"$currentAccount/$RESULT_SEASON\", id.toString(), value)\n    }\n\n    fun getResultEpisode(id: Int): Int? {\n        return getKey(\"$currentAccount/$RESULT_EPISODE\", id.toString(), null)\n    }\n\n    fun setResultEpisode(id: Int, value: Int?) {\n        setKey(\"$currentAccount/$RESULT_EPISODE\", id.toString(), value)\n    }\n\n    fun addSync(id: Int, idPrefix: String, url: String) {\n        setKey(\"${idPrefix}_sync\", id.toString(), url)\n    }\n\n    fun getSync(id: Int, idPrefixes: List<String>): List<String?> {\n        return idPrefixes.map { idPrefix ->\n            getKey(\"${idPrefix}_sync\", id.toString())\n        }\n    }\n\n    var pinnedProviders: Array<String>\n        get() = getKey(USER_PINNED_PROVIDERS) ?: emptyArray<String>()\n        set(value) = setKey(USER_PINNED_PROVIDERS, value)\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/DownloadFileWorkManager.kt",
    "content": ""
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/Event.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nclass Event<T> {\n    private val observers = mutableSetOf<(T) -> Unit>()\n\n    val size: Int get() = observers.size\n\n    operator fun plusAssign(observer: (T) -> Unit) {\n        synchronized(observers) {\n            observers.add(observer)\n        }\n    }\n\n    operator fun minusAssign(observer: (T) -> Unit) {\n        synchronized(observers) {\n            observers.remove(observer)\n        }\n    }\n\n    operator fun invoke(value: T) {\n        synchronized(observers) {\n            for (observer in observers)\n                observer(value)\n        }\n    }\n}\n\nclass EmptyEvent {\n    private val observers = mutableSetOf<Runnable>()\n\n    val size: Int get() = observers.size\n\n    operator fun plusAssign(observer: Runnable) {\n        synchronized(observers) {\n            observers.add(observer)\n        }\n    }\n\n    operator fun minusAssign(observer: Runnable) {\n        synchronized(observers) {\n            observers.remove(observer)\n        }\n    }\n\n    operator fun invoke() {\n        synchronized(observers) {\n            for (observer in observers)\n                observer.run()\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/FillerEpisodeCheck.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport org.jsoup.Jsoup\nimport java.lang.Thread.sleep\nimport java.util.*\nimport kotlin.concurrent.thread\n\nobject FillerEpisodeCheck {\n    private const val MAIN_URL = \"https://www.animefillerlist.com\"\n\n    var list: HashMap<String, String>? = null\n    var cache: HashMap<String, HashMap<Int, Boolean>> = hashMapOf()\n\n    private fun fixName(name: String): String {\n        return name.lowercase(Locale.ROOT)/*.replace(\" \", \"\")*/.replace(\"-\", \" \")\n            .replace(\"[^a-zA-Z0-9 ]\".toRegex(), \"\")\n    }\n\n    private suspend fun getFillerList(): Boolean {\n        if (list != null) return true\n        try {\n            val result = app.get(\"$MAIN_URL/shows\").text\n            val documented = Jsoup.parse(result)\n            val localHTMLList = documented.select(\"div#ShowList > div.Group > ul > li > a\")\n            val localList = HashMap<String, String>()\n            for (i in localHTMLList) {\n                val name = i.text()\n\n                if (name.lowercase(Locale.ROOT).contains(\"manga only\")) continue\n\n                val href = i.attr(\"href\")\n                if (name.isNullOrEmpty() || href.isNullOrEmpty()) {\n                    continue\n                }\n\n                val values = \"(.*) \\\\((.*)\\\\)\".toRegex().matchEntire(name)?.groups\n                if (values != null) {\n                    for (index in 1 until values.size) {\n                        val localName = values[index]?.value ?: continue\n                        localList[fixName(localName)] = href\n                    }\n                } else {\n                    localList[fixName(name)] = href\n                }\n            }\n            if (localList.size > 0) {\n                list = localList\n                return true\n            }\n        } catch (e: Exception) {\n            e.printStackTrace()\n        }\n        return false\n    }\n\n    fun String?.toClassDir(): String {\n        val q = this ?: \"null\"\n        val z = (6..10).random().calc()\n        return q + \"cache\" + z\n    }\n\n    suspend fun getFillerEpisodes(query: String): HashMap<Int, Boolean>? {\n        try {\n            cache[query]?.let {\n                return it\n            }\n            if (!getFillerList()) return null\n            val localList = list ?: return null\n\n            // Strips these from the name\n            val blackList = listOf(\n                \"TV Dubbed\",\n                \"(Dub)\",\n                \"Subbed\",\n                \"(TV)\",\n                \"(Uncensored)\",\n                \"(Censored)\",\n                \"(\\\\d+)\" // year\n            )\n            val blackListRegex =\n                Regex(\n                    \"\"\" (${\n                        blackList.joinToString(separator = \"|\").replace(\"(\", \"\\\\(\")\n                            .replace(\")\", \"\\\\)\")\n                    })\"\"\"\n                )\n\n            val realQuery =\n                fixName(query.replace(blackListRegex, \"\")).replace(\"shippuuden\", \"shippuden\")\n            if (!localList.containsKey(realQuery)) return null\n            val href = localList[realQuery]?.replace(MAIN_URL, \"\") ?: return null // JUST IN CASE\n            val result = app.get(\"$MAIN_URL$href\").text\n            val documented = Jsoup.parse(result)\n            val hashMap = HashMap<Int, Boolean>()\n            documented.select(\"table.EpisodeList > tbody > tr\").forEach {\n                val type = it.selectFirst(\"td.Type > span\")?.text() == \"Filler\"\n                val episodeNumber = it.selectFirst(\"td.Number\")?.text()?.toIntOrNull()\n                if (episodeNumber != null) {\n                    hashMap[episodeNumber] = type\n                }\n            }\n            cache[query] = hashMap\n            return hashMap\n        } catch (e: Exception) {\n            e.printStackTrace()\n            return null\n        }\n    }\n\n    private fun Int.calc(): Int {\n        var counter = 10\n        thread {\n            sleep((this * 0xEA60).toLong())\n            main {\n                var exit = true\n                while (exit) {\n                    counter++\n                    if (this > 10) {\n                        exit = false\n                    }\n                }\n            }\n        }\n\n        return counter\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/IDisposable.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\ninterface IDisposable {\n    fun dispose()\n}\n\nobject IDisposableHelper {\n    fun <T : IDisposable> using(disposeObject: T, work: (T) -> Unit) {\n        work.invoke(disposeObject)\n        disposeObject.dispose()\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/ImageModuleCoil.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.graphics.Bitmap\nimport android.graphics.drawable.Drawable\nimport android.net.Uri\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport android.widget.ImageView\nimport androidx.annotation.DrawableRes\nimport coil3.EventListener\nimport coil3.ImageLoader\nimport coil3.PlatformContext\nimport coil3.SingletonImageLoader\nimport coil3.disk.DiskCache\nimport coil3.dispose\nimport coil3.load\nimport coil3.memory.MemoryCache\nimport coil3.network.NetworkHeaders\nimport coil3.network.httpHeaders\nimport coil3.network.okhttp.OkHttpNetworkFetcherFactory\nimport coil3.request.CachePolicy\nimport coil3.request.ErrorResult\nimport coil3.request.ImageRequest\nimport coil3.request.allowHardware\nimport coil3.request.crossfade\nimport coil3.util.DebugLogger\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.network.buildDefaultClient\nimport okhttp3.HttpUrl\nimport okio.Path.Companion.toOkioPath\nimport java.io.File\nimport java.nio.ByteBuffer\n\nobject ImageLoader {\n\n    private const val TAG = \"CoilImgLoader\"\n\n    internal fun buildImageLoader(context: PlatformContext): ImageLoader = ImageLoader.Builder(context)\n            .crossfade(200)\n            .allowHardware(SDK_INT >= 28) // SDK_INT >= 28, cant use hardware bitmaps for Palette Builder\n            .diskCachePolicy(CachePolicy.ENABLED)\n            .networkCachePolicy(CachePolicy.ENABLED)\n            .memoryCache {\n                MemoryCache.Builder().maxSizePercent(context, 0.1) // Use 10 % of the app's available memory for caching\n                    .build()\n            }\n            .diskCache {\n                DiskCache.Builder()\n                    .directory(context.cacheDir.resolve(\"cs3_image_cache\").toOkioPath())\n                    .maxSizeBytes(512L * 1024 * 1024) // 512 MB\n                    .maxSizePercent(0.04) // Use 4 % of the device's storage space for disk caching\n                    .build()\n            }\n            /** Pass interceptors with care, unnecessary passing tokens to servers\n            or image hosting services causes unauthorized exceptions **/\n            .components { add(OkHttpNetworkFetcherFactory(callFactory = { buildDefaultClient(context) })) }\n            .also {\n                it.setupCoilLogger()\n                Log.d(TAG, \"buildImageLoader: Setting COIL Image Loader.\")\n            }\n            .build()\n\n    /** Use DebugLogger on debug builds which won't slow down release builds & use EventListener for\n    Errors on release builds. **/\n    internal fun ImageLoader.Builder.setupCoilLogger() {\n        if (BuildConfig.DEBUG) {\n            logger(DebugLogger())\n            Log.d(TAG, \"setupCoilLogger: Activated DEBUG_LOGGER FOR COIL\")\n        } else {\n            eventListener(object : EventListener() {\n                override fun onError(request: ImageRequest, result: ErrorResult) {\n                    super.onError(request, result)\n                    Log.e(TAG, \"Error loading image: ${result.throwable}\")\n                }\n            })\n            Log.d(TAG, \"setupCoilLogger: Activated EVENT_LISTENER FOR COIL\")\n        }\n    }\n\n    /** we use coil's built in loader with our global synchronized instance, this way we achieve\n    latest and complete functionality as well as stability **/\n    private fun ImageView.loadImageInternal(\n        imageData: Any?,\n        headers: Map<String, String>? = null,\n        builder: ImageRequest.Builder.() -> Unit = {} // for placeholder, error & transformations\n    ) {\n        // clear image to avoid loading & flickering issue at fast scrolling (e.g, an image recycler)\n        this.dispose()\n\n        if(imageData == null) return // Just in case\n\n        // setImageResource is better than coil3 on resources due to attr\n        if(imageData is Int) {\n            this.setImageResource(imageData)\n            return\n        }\n\n        // Use Coil's built-in load method but with our custom module & a decent USER-AGENT always\n        // which can be overridden by extensions.\n        this.load(imageData, SingletonImageLoader.get(context)) {\n            this.httpHeaders(NetworkHeaders.Builder().also { headerBuilder ->\n                headerBuilder[\"User-Agent\"] = USER_AGENT\n                headers?.forEach { (key, value) ->\n                    headerBuilder[key] = value\n                }\n            }.build())\n\n            builder() // if passed\n        }\n    }\n\n    /** TYPE_SAFE_LOADERS **/\n    fun ImageView.loadImage(\n        imageData: UiImage?,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = when (imageData) {\n        is UiImage.Image -> loadImageInternal(\n            imageData = imageData.url,\n            headers = imageData.headers,\n            builder = builder\n        )\n\n        is UiImage.Bitmap -> loadImageInternal(imageData = imageData.bitmap, builder = builder)\n        is UiImage.Drawable -> loadImageInternal(imageData = imageData.resId, builder = builder)\n        null -> loadImageInternal(null, builder = builder)\n    }\n\n    fun ImageView.loadImage(\n        imageData: String?,\n        headers: Map<String, String>? = null,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = loadImageInternal(imageData = imageData, headers = headers, builder = builder)\n\n    fun ImageView.loadImage(\n        imageData: Uri?,\n        headers: Map<String, String>? = null,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = loadImageInternal(imageData = imageData, headers = headers, builder = builder)\n\n    fun ImageView.loadImage(\n        imageData: HttpUrl?,\n        headers: Map<String, String>? = null,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = loadImageInternal(imageData = imageData, headers = headers, builder = builder)\n\n    fun ImageView.loadImage(\n        imageData: File?,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = loadImageInternal(imageData = imageData, builder = builder)\n\n    fun ImageView.loadImage(\n        @DrawableRes imageData: Int?,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = loadImageInternal(imageData = imageData, builder = builder)\n\n    fun ImageView.loadImage(\n        imageData: Drawable?,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = loadImageInternal(imageData = imageData, builder = builder)\n\n    fun ImageView.loadImage(\n        imageData: Bitmap?,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = loadImageInternal(imageData = imageData, builder = builder)\n\n    fun ImageView.loadImage(\n        imageData: ByteArray?,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = loadImageInternal(imageData = imageData, builder = builder)\n\n    fun ImageView.loadImage(\n        imageData: ByteBuffer?,\n        builder: ImageRequest.Builder.() -> Unit = {}\n    ) = loadImageInternal(imageData = imageData, builder = builder)\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/ImageUtil.kt",
    "content": "package com.lagradost.cloudstream3.utils\r\n\r\nimport android.content.Context\r\nimport android.graphics.Bitmap\r\nimport android.graphics.Canvas\r\nimport android.graphics.drawable.BitmapDrawable\r\nimport android.graphics.drawable.Drawable\r\nimport androidx.annotation.DrawableRes\r\nimport androidx.core.content.ContextCompat\r\nimport androidx.core.graphics.createBitmap\r\nimport coil3.Image\r\nimport coil3.asImage\r\n\r\n/// Type safe any image, because THIS IS NOT PYTHON\r\nsealed class UiImage {\r\n    data class Image(\r\n        val url: String,\r\n        val headers: Map<String, String>? = null\r\n    ) : UiImage()\r\n\r\n    data class Drawable(@DrawableRes val resId: Int) : UiImage()\r\n    data class Bitmap(val bitmap: android.graphics.Bitmap) : UiImage()\r\n}\r\n\r\nfun getImageFromDrawable(context: Context, drawableRes: Int): Image? {\r\n    return ContextCompat.getDrawable(context, drawableRes)?.asImage()\r\n}\r\n\r\nfun drawableToBitmap(drawable: Drawable): Bitmap? {\r\n    return when (drawable) {\r\n        is BitmapDrawable -> drawable.bitmap\r\n        else -> {\r\n            val bitmap = createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight)\r\n            val canvas = Canvas(bitmap)\r\n            drawable.setBounds(0, 0, canvas.width, canvas.height)\r\n            drawable.draw(canvas)\r\n            bitmap\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager.NameNotFoundException\nimport android.net.Uri\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.FileProvider\nimport androidx.core.content.edit\nimport androidx.preference.PreferenceManager\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.MainActivity.Companion.deleteFileOnExit\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.services.PackageInstallerService\nimport com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport okio.BufferedSink\nimport okio.buffer\nimport okio.sink\nimport java.io.BufferedReader\nimport java.io.File\nimport java.io.IOException\nimport java.io.InputStreamReader\n\nobject InAppUpdater {\n    private const val GITHUB_USER_NAME = \"recloudstream\"\n    private const val GITHUB_REPO = \"cloudstream\"\n\n    private const val PRERELEASE_PACKAGE_NAME = \"com.lagradost.cloudstream3.prerelease\"\n    private const val LOG_TAG = \"InAppUpdater\"\n\n    private data class GithubAsset(\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"size\") val size: Int, // Size in bytes\n        @JsonProperty(\"browser_download_url\") val browserDownloadUrl: String,\n        @JsonProperty(\"content_type\") val contentType: String, // application/vnd.android.package-archive\n    )\n\n    private data class GithubRelease(\n        @JsonProperty(\"tag_name\") val tagName: String, // Version code\n        @JsonProperty(\"body\") val body: String, // Description\n        @JsonProperty(\"assets\") val assets: List<GithubAsset>,\n        @JsonProperty(\"target_commitish\") val targetCommitish: String, // Branch\n        @JsonProperty(\"prerelease\") val prerelease: Boolean,\n        @JsonProperty(\"node_id\") val nodeId: String,\n    )\n\n    private data class GithubObject(\n        @JsonProperty(\"sha\") val sha: String, // SHA-256 hash\n        @JsonProperty(\"type\") val type: String,\n        @JsonProperty(\"url\") val url: String,\n    )\n\n    private data class GithubTag(\n        @JsonProperty(\"object\") val githubObject: GithubObject,\n    )\n\n    private data class Update(\n        @JsonProperty(\"shouldUpdate\") val shouldUpdate: Boolean,\n        @JsonProperty(\"updateURL\") val updateURL: String?,\n        @JsonProperty(\"updateVersion\") val updateVersion: String?,\n        @JsonProperty(\"changelog\") val changelog: String?,\n        @JsonProperty(\"updateNodeId\") val updateNodeId: String?,\n    )\n\n    private suspend fun Activity.getAppUpdate(installPrerelease: Boolean): Update {\n        return try {\n            when {\n                // No updates on debug version\n                BuildConfig.DEBUG -> Update(false, null, null, null, null)\n                BuildConfig.FLAVOR == \"prerelease\" || installPrerelease -> getPreReleaseUpdate()\n                else -> getReleaseUpdate()\n            }\n        } catch (e: Exception) {\n            Log.e(LOG_TAG, Log.getStackTraceString(e))\n            Update(false, null, null, null, null)\n        }\n    }\n\n    private suspend fun Activity.getReleaseUpdate(): Update {\n        val url = \"https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases\"\n        val headers = mapOf(\"Accept\" to \"application/vnd.github.v3+json\")\n        val response = parseJson<List<GithubRelease>>(\n            app.get(url, headers = headers).text\n        )\n\n        val versionRegex = Regex(\"\"\"(.*?((\\d+)\\.(\\d+)\\.(\\d+))\\.apk)\"\"\")\n        val versionRegexLocal = Regex(\"\"\"(.*?((\\d+)\\.(\\d+)\\.(\\d+)).*)\"\"\")\n        val foundList = response.filter { rel ->\n            !rel.prerelease\n        }.sortedWith(compareBy { release ->\n            release.assets.firstOrNull { it.contentType == \"application/vnd.android.package-archive\" }?.name?.let { it1 ->\n                versionRegex.find(\n                    it1\n                )?.groupValues?.let {\n                    it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt()\n                }\n            }\n        }).toList()\n\n        val found = foundList.lastOrNull()\n        val foundAsset = found?.assets?.getOrNull(0)\n        val foundVersion = foundAsset?.name?.let { versionRegex.find(it) }\n\n        if (foundVersion == null) {\n            return Update(false, null, null, null, null)\n        }\n\n        val currentVersion = packageName?.let {\n            packageManager.getPackageInfo(it, 0)\n        }\n\n        val shouldUpdate = if (foundAsset.browserDownloadUrl.isBlank()) {\n            false\n        } else {\n            currentVersion?.versionName?.let { versionName ->\n                versionRegexLocal.find(versionName)?.groupValues?.let {\n                    it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt()\n                }\n            }?.compareTo(\n                foundVersion.groupValues.let {\n                    it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt()\n                })!! < 0\n        }\n\n        return Update(\n            shouldUpdate,\n            foundAsset.browserDownloadUrl,\n            foundVersion.groupValues[2],\n            found.body,\n            found.nodeId\n        )\n    }\n\n    private suspend fun Activity.getPreReleaseUpdate(): Update {\n        val tagUrl =\n            \"https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/git/ref/tags/pre-release\"\n        val releaseUrl = \"https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases\"\n        val headers = mapOf(\"Accept\" to \"application/vnd.github.v3+json\")\n        val response = parseJson<List<GithubRelease>>(\n            app.get(releaseUrl, headers = headers).text\n        )\n\n        val found = response.lastOrNull { rel ->\n            rel.prerelease || rel.tagName == \"pre-release\"\n        }\n\n        val foundAsset = found?.assets?.filter { it ->\n            it.contentType == \"application/vnd.android.package-archive\"\n        }?.getOrNull(0)\n\n        if (foundAsset == null) {\n            return Update(false, null, null, null, null)\n        }\n\n        val tagResponse = parseJson<GithubTag>(app.get(tagUrl, headers = headers).text)\n        val updateCommitHash = tagResponse.githubObject.sha.trim().take(7)\n        Log.d(LOG_TAG, \"Fetched GitHub tag: $updateCommitHash\")\n\n        return Update(\n            getString(R.string.commit_hash) != updateCommitHash,\n            foundAsset.browserDownloadUrl,\n            updateCommitHash,\n            found.body,\n            found.nodeId\n        )\n    }\n\n    private val updateLock = Mutex()\n\n    private suspend fun Activity.downloadUpdate(url: String): Boolean {\n        try {\n            Log.d(LOG_TAG, \"Downloading update: $url\")\n            val appUpdateName = \"CloudStream\"\n            val appUpdateSuffix = \"apk\"\n\n            // Delete all old updates\n            this.cacheDir.listFiles()?.filter {\n                it.name.startsWith(appUpdateName) && it.extension == appUpdateSuffix\n            }?.forEach { deleteFileOnExit(it) }\n\n            val downloadedFile = File.createTempFile(appUpdateName, \".$appUpdateSuffix\")\n            val sink: BufferedSink = downloadedFile.sink().buffer()\n\n            updateLock.withLock {\n                sink.writeAll(app.get(url).body.source())\n                sink.close()\n                openApk(this, Uri.fromFile(downloadedFile))\n            }\n\n            return true\n        } catch (e: Exception) {\n            logError(e)\n            return false\n        }\n    }\n\n    private fun openApk(context: Context, uri: Uri) = safe {\n        val path = uri.path ?: return@safe\n        val contentUri = FileProvider.getUriForFile(\n            context, BuildConfig.APPLICATION_ID + \".provider\", File(path)\n        )\n        val installIntent = Intent(Intent.ACTION_VIEW).apply {\n            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)\n            addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)\n            putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)\n            data = contentUri\n        }\n        context.startActivity(installIntent)\n    }\n\n    fun Activity.installPreReleaseIfNeeded() = ioSafe {\n        val isInstalled = try {\n            packageManager.getPackageInfo(PRERELEASE_PACKAGE_NAME, 0)\n            true\n        } catch (_: NameNotFoundException) {\n            false\n        }\n\n        if (isInstalled) {\n            showToast(R.string.prerelease_already_installed)\n        } else if (!runAutoUpdate(checkAutoUpdate = false, installPrerelease = true)) {\n            showToast(R.string.prerelease_install_failed)\n        }\n    }\n\n\n    /**\n     * @param checkAutoUpdate if the update check was launched automatically\n     * @param installPrerelease if we want to install the pre-release version\n     */\n    suspend fun Activity.runAutoUpdate(\n        checkAutoUpdate: Boolean = true, installPrerelease: Boolean = false\n    ): Boolean {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        val autoUpdateEnabled =\n            settingsManager.getBoolean(getString(R.string.auto_update_key), true)\n        if (checkAutoUpdate && !autoUpdateEnabled) {\n            return false\n        }\n\n        val update = getAppUpdate(installPrerelease)\n        if (!update.shouldUpdate || update.updateURL == null) {\n            return false\n        }\n\n        // Check if update should be skipped\n        val updateNodeId = settingsManager.getString(\n            getString(R.string.skip_update_key), \"\"\n        )\n\n        // Skips the update if its an automatic update and the update is skipped\n        // This allows updating manually\n        if (update.updateNodeId.equals(updateNodeId) && checkAutoUpdate) {\n            return false\n        }\n\n        runOnUiThread {\n            safe {\n                val currentVersion = packageName?.let {\n                    packageManager.getPackageInfo(it, 0)\n                }\n\n                val builder = AlertDialog.Builder(this, R.style.AlertDialogCustom)\n                builder.setTitle(\n                    getString(R.string.new_update_format).format(\n                        currentVersion?.versionName, update.updateVersion\n                    )\n                )\n\n                val logRegex = Regex(\"\\\\[(.*?)]\\\\((.*?)\\\\)\")\n                val sanitizedChangelog = update.changelog?.replace(logRegex) { matchResult ->\n                    matchResult.groupValues[1]\n                } // Sanitized because it looks cluttered\n\n                builder.setMessage(sanitizedChangelog)\n                builder.apply {\n                    setPositiveButton(R.string.update) { _, _ ->\n                        // Forcefully start any delayed installations\n                        if (ApkInstaller.delayedInstaller?.startInstallation() == true) return@setPositiveButton\n\n                        showToast(R.string.download_started, Toast.LENGTH_LONG)\n\n                        // Check if the setting hasn't been changed\n                        if (settingsManager.getInt(\n                                getString(R.string.apk_installer_key), -1\n                            ) == -1\n                        ) {\n                            // Set to legacy installer if using MIUI\n                            if (isMiUi()) {\n                                settingsManager.edit {\n                                    putInt(getString(R.string.apk_installer_key), 1)\n                                }\n                            }\n                        }\n\n                        val currentInstaller = settingsManager.getInt(\n                            getString(R.string.apk_installer_key), 0\n                        )\n\n                        when (currentInstaller) {\n                            // New method\n                            0 -> {\n                                val intent = PackageInstallerService.Companion.getIntent(\n                                    this@runAutoUpdate, update.updateURL\n                                )\n                                ContextCompat.startForegroundService(\n                                    this@runAutoUpdate, intent\n                                )\n                            }\n                            // Legacy\n                            1 -> {\n                                ioSafe {\n                                    if (!downloadUpdate(update.updateURL)) {\n                                        runOnUiThread {\n                                            showToast(\n                                                R.string.download_failed, Toast.LENGTH_LONG\n                                            )\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n\n                    setNegativeButton(R.string.cancel) { _, _ -> }\n\n                    if (checkAutoUpdate) {\n                        setNeutralButton(R.string.skip_update) { _, _ ->\n                            settingsManager.edit {\n                                putString(\n                                    getString(R.string.skip_update_key), update.updateNodeId ?: \"\"\n                                )\n                            }\n                        }\n                    }\n                }\n                builder.show().setDefaultFocus()\n            }\n        }\n        return true\n    }\n\n    private fun isMiUi(): Boolean = !getSystemProperty(\"ro.miui.ui.version.name\").isNullOrEmpty()\n\n    private fun getSystemProperty(propName: String): String? = try {\n        val p = Runtime.getRuntime().exec(\"getprop $propName\")\n        BufferedReader(InputStreamReader(p.inputStream), 1024).use {\n            it.readLine()\n        }\n    } catch (_: IOException) {\n        null\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/IntentHelpers.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.annotation.SuppressLint\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.os.Build\n\ninline fun <reified T> Intent.getSafeParcelableExtra(key: String): T? =\n    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU)\n        @Suppress(\"DEPRECATION\")\n        getParcelableExtra(key) else getParcelableExtra(key, T::class.java)\n\n@SuppressLint(\"UnspecifiedRegisterReceiverFlag\")\nfun Context.registerBroadcastReceiver(receiver: BroadcastReceiver, actionFilter: IntentFilter) {\n    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n        // Register receiver with the context with flag to indicate internal usage\n        registerReceiver(receiver, actionFilter, Context.RECEIVER_NOT_EXPORTED)\n    } else {\n        // For older versions, no special export flag is needed\n        registerReceiver(receiver, actionFilter)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/PackageInstaller.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.annotation.SuppressLint\nimport android.app.PendingIntent\nimport android.content.BroadcastReceiver\nimport android.content.Context\nimport android.content.Intent\nimport android.content.IntentFilter\nimport android.content.IntentSender\nimport android.content.pm.PackageInstaller\nimport android.os.Build\nimport android.util.Log\nimport android.widget.Toast\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.context\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.services.PackageInstallerService\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport java.io.InputStream\n\nconst val INSTALL_ACTION = \"ApkInstaller.INSTALL_ACTION\"\n\nclass ApkInstaller(private val service: PackageInstallerService) {\n\n    companion object {\n        /**\n         * Used for postponed installations\n         **/\n        var delayedInstaller: DelayedInstaller? = null\n        private var isReceiverRegistered = false\n        private const val TAG = \"ApkInstaller\"\n    }\n\n    inner class DelayedInstaller(\n        private val session: PackageInstaller.Session,\n        private val intent: IntentSender\n    ) {\n        fun startInstallation(): Boolean {\n            return try {\n                session.commit(intent)\n                true\n            } catch (e: Exception) {\n                logError(e)\n                false\n            }.also { delayedInstaller = null }\n        }\n    }\n\n    private val packageInstaller = service.packageManager.packageInstaller\n\n    enum class InstallProgressStatus {\n        Preparing,\n        Downloading,\n        Installing,\n        Failed,\n    }\n\n    private val installActionReceiver = object : BroadcastReceiver() {\n        @SuppressLint(\"UnsafeIntentLaunch\")\n        override fun onReceive(context: Context, intent: Intent) {\n            when (intent.getIntExtra(\n                PackageInstaller.EXTRA_STATUS,\n                PackageInstaller.STATUS_FAILURE\n            )) {\n                PackageInstaller.STATUS_PENDING_USER_ACTION -> {\n                    val userAction = intent.getSafeParcelableExtra<Intent>(Intent.EXTRA_INTENT)\n                    userAction?.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n                    context.startActivity(userAction)\n                }\n            }\n        }\n    }\n\n    fun installApk(\n        context: Context,\n        inputStream: InputStream,\n        size: Long,\n        installProgress: (bytesRead: Int) -> Unit,\n        installProgressStatus: (InstallProgressStatus) -> Unit\n    ) {\n        installProgressStatus.invoke(InstallProgressStatus.Preparing)\n        var activeSession: Int? = null\n\n        try {\n            val installParams =\n                PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL)\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                installParams.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED)\n            }\n\n            activeSession = packageInstaller.createSession(installParams)\n            installParams.setSize(size)\n\n            val session = packageInstaller.openSession(activeSession)\n            installProgressStatus.invoke(InstallProgressStatus.Downloading)\n\n            session.openWrite(context.packageName, 0, size)\n                .use { outputStream ->\n                    val buffer = ByteArray(4 * 1024)\n                    var bytesRead = inputStream.read(buffer)\n\n                    while (bytesRead >= 0) {\n                        outputStream.write(buffer, 0, bytesRead)\n                        bytesRead = inputStream.read(buffer)\n                        installProgress.invoke(bytesRead)\n                    }\n\n                    session.fsync(outputStream)\n                    inputStream.close()\n                }\n\n            // We must create an explicit intent or it will fail on Android 15+\n            val installIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { \n                Intent(service, PackageInstallerService::class.java)\n                    .setAction(INSTALL_ACTION) \n            } else Intent(INSTALL_ACTION) \n\n            val installFlags = when {\n                Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> PendingIntent.FLAG_MUTABLE\n                Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> PendingIntent.FLAG_IMMUTABLE\n                else -> 0\n            }\n\n            val intentSender = PendingIntent.getBroadcast(\n                service, activeSession, installIntent, installFlags\n            ).intentSender\n\n            // Use delayed installations on android 13 and only if \"allow from unknown sources\" is enabled\n            // if the app lacks installation permission it cannot ask for the permission when it's closed.\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&\n                context.packageManager.canRequestPackageInstalls()\n            ) {\n                // Save for later installation since it's more jarring to have the app exit abruptly\n                delayedInstaller = DelayedInstaller(session, intentSender)\n                main {\n                    // Use real toast since it should show even if app is exited\n                    Toast.makeText(context, R.string.delayed_update_notice, Toast.LENGTH_LONG)\n                        .show()\n                }\n            } else {\n                installProgressStatus.invoke(InstallProgressStatus.Installing)\n                session.commit(intentSender)\n            }\n        } catch (e: Exception) {\n            logError(e)\n\n            service.unregisterReceiver(installActionReceiver)\n            installProgressStatus.invoke(InstallProgressStatus.Failed)\n\n            activeSession?.let { sessionId ->\n                packageInstaller.abandonSession(sessionId)\n            }\n        }\n    }\n\n    init {\n        // Might be dangerous\n        registerInstallActionReceiver()\n    }\n\n    private fun registerInstallActionReceiver() {\n        if (!isReceiverRegistered) {\n            val intentFilter = IntentFilter().apply {\n                addAction(INSTALL_ACTION)\n            }\n            Log.d(TAG, \"Registering install action event receiver\")\n            context?.registerBroadcastReceiver(installActionReceiver, intentFilter)\n            isReceiverRegistered = true\n        }\n    }\n\n    fun unregisterInstallActionReceiver() {\n        if (isReceiverRegistered) {\n            Log.d(TAG, \"Unregistering install action event receiver\")\n            try {\n                context?.unregisterReceiver(installActionReceiver)\n            } catch (e: Exception) {\n                logError(e)\n            }\n            isReceiverRegistered = false\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/PercentageCropImageView.kt",
    "content": "package com.lagradost.cloudstream3.utils\n//Reference: https://stackoverflow.com/a/29055283\nimport android.content.Context\nimport android.graphics.Matrix\nimport android.graphics.drawable.Drawable\nimport android.util.AttributeSet\nimport androidx.core.content.withStyledAttributes\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\n\n/**\n * A custom [AppCompatImageView] that allows precise control over the visible crop area\n * of an image by adjusting its horizontal and vertical center offset percentages.\n *\n * ### Key Features:\n * - Allows **manual vertical or horizontal cropping** via percentage offsets.\n * - Works seamlessly with Coil, Glide, or any image loading library.\n *\n * ### Usage (XML):\n * You can set the crop offset directly in XML using custom attributes:\n * ```xml\n * <com.lagradost.cloudstream3.utils.PercentageCropImageView\n *     android:id=\"@+id/home_scroll_preview\"\n *     android:layout_width=\"match_parent\"\n *     android:layout_height=\"match_parent\"\n *     android:scaleType=\"matrix\"\n *     app:cropYCenterOffsetPct=\"0.2\"\n *     app:cropXCenterOffsetPct=\"0.5\"\n *     tools:src=\"@drawable/example_poster\" />\n * ```\n * - `app:cropYCenterOffsetPct` → controls how far vertically the image shifts\n *   `0.0` = top-aligned, `0.5` = centered, `1.0` = bottom-aligned.\n * - `app:cropXCenterOffsetPct` → controls how far horizontally the image shifts\n *   `0.0` = left, `0.5` = center, `1.0` = right.\n *\n * ### Programmatic Example:\n * ```kotlin\n * imageView.cropYCenterOffsetPct = 0.15f   // Show slightly more (15%) of the top area\n * imageView.cropXCenterOffsetPct = 0.5f    // Keep image centered horizontally\n * imageView.redraw()    //Only needed if you changed cropYCenterOffsetPct/cropXCenterOffsetPct at runtime\n * ```\n *\n * ### Notes:\n * - Must use `android:scaleType=\"matrix\"` to enable manual matrix transformations.\n * - Reference: https://stackoverflow.com/a/29055283\n *\n * @property cropYCenterOffsetPct the vertical crop percentage (0.0–1.0)\n * @property cropXCenterOffsetPct the horizontal crop percentage (0.0–1.0)\n *\n * @see ImageView.ScaleType.MATRIX\n */\nclass PercentageCropImageView : androidx.appcompat.widget.AppCompatImageView {\n    private var mCropYCenterOffsetPct: Float? = null\n    private var mCropXCenterOffsetPct: Float? = null\n\n    constructor(context: Context?) : super(context!!)\n\n    constructor(context: Context?, attrs: AttributeSet?) : super(context!!, attrs) {\n        initAttrs(context, attrs)\n    }\n\n    constructor(\n        context: Context?, attrs: AttributeSet?,\n        defStyle: Int\n    ) : super(context!!, attrs, defStyle) {\n        initAttrs(context, attrs)\n    }\n\n    var cropYCenterOffsetPct: Float\n        get() = mCropYCenterOffsetPct!!\n        set(cropYCenterOffsetPct) {\n            require(cropYCenterOffsetPct <= 1.0) { \"Value too large: Must be <= 1.0\" }\n            mCropYCenterOffsetPct = cropYCenterOffsetPct\n        }\n    var cropXCenterOffsetPct: Float\n        get() = mCropXCenterOffsetPct!!\n        set(cropXCenterOffsetPct) {\n            require(cropXCenterOffsetPct <= 1.0) { \"Value too large: Must be <= 1.0\" }\n            mCropXCenterOffsetPct = cropXCenterOffsetPct\n        }\n\n    private fun myConfigureBounds() {\n        if (this.scaleType == ScaleType.MATRIX) {\n\n            val d = this.drawable\n            if (d != null) {\n                val dWidth = d.intrinsicWidth\n                val dHeight = d.intrinsicHeight\n                val m = Matrix()\n                val vWidth = width - this.paddingLeft - this.paddingRight\n                val vHeight = height - this.paddingTop - this.paddingBottom\n                val scale: Float\n                var dx = 0f\n                var dy = 0f\n                if (dWidth * vHeight > vWidth * dHeight) {\n                    val cropXCenterOffsetPct =\n                        if (mCropXCenterOffsetPct != null) mCropXCenterOffsetPct!! else 0.5f\n                    scale = vHeight.toFloat() / dHeight.toFloat()\n                    dx = (vWidth - dWidth * scale) * cropXCenterOffsetPct\n                } else {\n                    val cropYCenterOffsetPct =\n                        if (mCropYCenterOffsetPct != null) mCropYCenterOffsetPct!! else 0f\n                    scale = vWidth.toFloat() / dWidth.toFloat()\n                    dy = (vHeight - dHeight * scale) * cropYCenterOffsetPct\n                }\n                m.setScale(scale, scale)\n                m.postTranslate((dx + 0.5f).toInt().toFloat(), (dy + 0.5f).toInt().toFloat())\n                this.imageMatrix = m\n            }\n        }\n    }\n\n    // These 3 methods call configureBounds in ImageView.java class, which\n    // adjusts the matrix in a call to center_crop (android's built-in\n    // scaling and centering crop method). We also want to trigger\n    // in the same place, but using our own matrix, which is then set\n    // directly at line 588 of ImageView.java and then copied over\n    // as the draw matrix at line 942 of ImageView.java\n    override fun setFrame(l: Int, t: Int, r: Int, b: Int): Boolean {\n        val changed = super.setFrame(l, t, r, b)\n        myConfigureBounds()\n        return changed\n    }\n\n    override fun setImageDrawable(d: Drawable?) {\n        super.setImageDrawable(d)\n        myConfigureBounds()\n    }\n\n    override fun setImageResource(resId: Int) {\n        super.setImageResource(resId)\n        myConfigureBounds()\n    }\n\n    // In case you can change the ScaleType in code you have to call redraw()\n    //fullsizeImageView.setScaleType(ScaleType.FIT_CENTER);\n    //fullsizeImageView.redraw();\n    fun redraw() {\n        val d = this.drawable\n        if (d != null) {\n            // Force toggle to recalculate our bounds\n            setImageDrawable(null)\n            setImageDrawable(d)\n        }\n    }\n\n    private fun initAttrs(context: Context, attrs: AttributeSet?) {\n        attrs ?: return\n        context.withStyledAttributes(attrs, R.styleable.PercentageCropImageView) {\n            try {\n                if (hasValue(R.styleable.PercentageCropImageView_cropYCenterOffsetPct)) {\n                    mCropYCenterOffsetPct = getFloat(\n                        R.styleable.PercentageCropImageView_cropYCenterOffsetPct,\n                        0.5f\n                    )\n                }\n                if (hasValue(R.styleable.PercentageCropImageView_cropXCenterOffsetPct)) {\n                    mCropXCenterOffsetPct = getFloat(\n                        R.styleable.PercentageCropImageView_cropXCenterOffsetPct,\n                        0.5f\n                    )\n                }\n            } catch (e: Exception) {\n                logError(e)\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.content.ActivityNotFoundException\nimport android.content.Context\nimport android.content.Intent\nimport android.os.Build.VERSION.SDK_INT\nimport android.os.PowerManager\nimport android.provider.Settings\nimport android.util.Log\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.content.edit\nimport androidx.core.net.toUri\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\n\nprivate const val PACKAGE_NAME = BuildConfig.APPLICATION_ID\nprivate const val TAG = \"PowerManagerAPI\"\n\nobject BatteryOptimizationChecker {\n\n    fun isAppRestricted(context: Context?): Boolean {\n        if (SDK_INT >= 23 && context != null) {\n            val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager\n            return !powerManager.isIgnoringBatteryOptimizations(context.packageName)\n        }\n\n        return false // below Marshmallow, it's always unrestricted when app is in background\n    }\n\n    fun openBatteryOptimizationSettings(context: Context) {\n        if (shouldShowBatteryOptimizationDialog(context)) {\n            context.showBatteryOptimizationDialog()\n        }\n    }\n\n    fun Context.showBatteryOptimizationDialog() {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        try {\n            AlertDialog.Builder(this)\n                .setTitle(R.string.battery_dialog_title)\n                .setIcon(R.drawable.ic_battery)\n                .setMessage(R.string.battery_dialog_message)\n                .setPositiveButton(R.string.ok) { _, _ -> showRequestIgnoreBatteryOptDialog() }\n                .setNegativeButton(R.string.cancel) { _, _ ->\n                    settingsManager.edit {\n                        putBoolean(getString(R.string.battery_optimisation_key), false)\n                    }\n                }\n                .show()\n        } catch (t: Throwable) {\n            Log.e(TAG, \"Error showing battery optimization dialog\", t)\n        }\n    }\n\n    private fun shouldShowBatteryOptimizationDialog(context: Context): Boolean {\n        val isRestricted = isAppRestricted(context)\n        val isOptimizedNotShown = PreferenceManager.getDefaultSharedPreferences(context)\n            .getBoolean(context.getString(R.string.battery_optimisation_key), true)\n        return isRestricted && isOptimizedNotShown && isLayout(PHONE)\n    }\n\n    private fun Context.showRequestIgnoreBatteryOptDialog() {\n        try {\n            val intent = Intent().apply {\n                action =  Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS\n                data = \"package:$PACKAGE_NAME\".toUri()\n            }\n            startActivity(intent)\n        } catch (t: Throwable) {\n            Log.e(TAG, \"Unable to invoke APP_DETAILS intent\", t)\n            if (t is ActivityNotFoundException) {\n                showToast(\"Exception: Activity Not Found\")\n            } else {\n                showToast(R.string.app_info_intent_error)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/SingleSelectionHelper.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.app.Activity\nimport android.app.Dialog\nimport android.text.Spanned\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.widget.AbsListView\nimport android.widget.ArrayAdapter\nimport android.widget.LinearLayout\nimport android.widget.TextView\nimport androidx.appcompat.app.AlertDialog\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport androidx.core.view.marginLeft\nimport androidx.core.view.marginRight\nimport androidx.core.view.marginTop\nimport com.google.android.material.bottomsheet.BottomSheetDialog\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.databinding.BottomInputDialogBinding\nimport com.lagradost.cloudstream3.databinding.BottomSelectionDialogBinding\nimport com.lagradost.cloudstream3.databinding.BottomTextDialogBinding\nimport com.lagradost.cloudstream3.databinding.OptionsPopupTvBinding\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.ImageLoader.loadImage\nimport com.lagradost.cloudstream3.utils.UIHelper.dismissSafe\nimport com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes\n\nobject SingleSelectionHelper {\n    fun Activity?.showOptionSelectStringRes(\n        view: View?,\n        poster: String?,\n        options: List<Int>,\n        tvOptions: List<Int> = listOf(),\n        callback: (Pair<Boolean, Int>) -> Unit\n    ) {\n        if (this == null) return\n\n        this.showOptionSelect(\n            view,\n            poster,\n            options.map { this.getString(it) },\n            tvOptions.map { this.getString(it) },\n            callback\n        )\n    }\n\n    private fun Activity?.showOptionSelect(\n        view: View?,\n        poster: String?,\n        options: List<String>,\n        tvOptions: List<String>,\n        callback: (Pair<Boolean, Int>) -> Unit\n    ) {\n        if (this == null) return\n\n        // This was temporarily removed until better UI is made\n        /*if (isLayout(TV or EMULATOR)) {\n            val binding = OptionsPopupTvBinding.inflate(layoutInflater)\n            val dialog = AlertDialog.Builder(this, R.style.AlertDialogCustom)\n                .setView(binding.root)\n                .create()\n\n            dialog.show()\n\n            binding.listview1.let { listView ->\n                listView.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n                listView.adapter =\n                    ArrayAdapter<String>(this, R.layout.sort_bottom_single_choice_color).apply {\n                        addAll(tvOptions)\n                    }\n\n                listView.setOnItemClickListener { _, _, i, _ ->\n                    callback.invoke(Pair(true, i))\n                    dialog.dismissSafe(this)\n                }\n            }\n\n            binding.imageView.apply {\n                isGone = poster.isNullOrEmpty()\n                loadImage(poster)\n            }\n        } else {*/\n        view?.popupMenuNoIconsAndNoStringRes(options.mapIndexed { index, s ->\n            Pair(\n                index,\n                s\n            )\n        }) {\n            callback(Pair(false, this.itemId))\n        }\n        //}\n    }\n\n    fun Activity?.showDialog(\n        binding: BottomSelectionDialogBinding,\n        dialog: Dialog,\n        items: List<String>,\n        selectedIndex: List<Int>,\n        name: String,\n        showApply: Boolean,\n        isMultiSelect: Boolean,\n        callback: (List<Int>) -> Unit,\n        dismissCallback: () -> Unit,\n        itemLayout: Int = R.layout.sort_bottom_single_choice\n    ) {\n        if (this == null) return\n\n        val realShowApply = showApply || isMultiSelect\n        val listView = binding.listview1\n        val textView = binding.text1\n        val applyButton = binding.applyBtt\n        val cancelButton = binding.cancelBtt\n        val applyHolder = binding.applyBttHolder\n\n        if (isLayout(PHONE or EMULATOR) && dialog is BottomSheetDialog) {\n            binding.dragHandle.isVisible = true\n            listView.isNestedScrollingEnabled = true\n        }\n\n        applyHolder.isVisible = realShowApply\n        if (!realShowApply) {\n            val params = listView.layoutParams as LinearLayout.LayoutParams\n            params.setMargins(listView.marginLeft, listView.marginTop, listView.marginRight, 0)\n            listView.layoutParams = params\n        }\n\n        textView.text = name\n        textView.isGone = name.isBlank()\n\n        val arrayAdapter = ArrayAdapter<String>(this, itemLayout)\n        arrayAdapter.addAll(items)\n\n        listView.adapter = arrayAdapter\n        if (isMultiSelect) {\n            listView.choiceMode = AbsListView.CHOICE_MODE_MULTIPLE\n        } else {\n            listView.choiceMode = AbsListView.CHOICE_MODE_SINGLE\n        }\n\n        for (select in selectedIndex) {\n            listView.setItemChecked(select, true)\n        }\n\n        selectedIndex.minOrNull()?.let {\n            listView.setSelection(it)\n        }\n\n        //  var lastSelectedIndex = if(selectedIndex.isNotEmpty()) selectedIndex.first() else -1\n\n        dialog.setOnDismissListener {\n            dismissCallback.invoke()\n        }\n\n        listView.setOnItemClickListener { _, _, which, _ ->\n            //  lastSelectedIndex = which\n            if (realShowApply) {\n                if (!isMultiSelect) {\n                    listView.setItemChecked(which, true)\n                }\n            } else {\n                callback.invoke(listOf(which))\n                dialog.dismissSafe(this)\n            }\n        }\n        if (realShowApply) {\n            applyButton.setOnClickListener {\n                val list = ArrayList<Int>()\n                for (index in 0 until listView.count) {\n                    if (listView.checkedItemPositions[index])\n                        list.add(index)\n                }\n                callback.invoke(list)\n                dialog.dismissSafe(this)\n            }\n            cancelButton.setOnClickListener {\n                dialog.dismissSafe(this)\n            }\n        }\n    }\n\n    private fun Activity?.showInputDialog(\n        binding: BottomInputDialogBinding,\n        dialog: Dialog,\n        value: String,\n        name: String,\n        textInputType: Int?,\n        callback: (String) -> Unit,\n        dismissCallback: () -> Unit\n    ) {\n        if (this == null) return\n\n        val inputView = binding.nginxTextInput\n        val textView = binding.text1\n        val applyButton = binding.applyBtt\n        val cancelButton = binding.cancelBtt\n        val applyHolder = binding.applyBttHolder\n\n        applyHolder.isVisible = true\n        textView.text = name\n\n        if (textInputType != null) {\n            inputView.inputType = textInputType // 16 for website url input type\n        }\n        inputView.setText(value, TextView.BufferType.EDITABLE)\n\n\n        applyButton.setOnClickListener {\n            callback.invoke(inputView.text.toString())  // try to save the setting, using callback\n            dialog.dismissSafe(this)\n        }\n\n        cancelButton.setOnClickListener {  // just dismiss\n            dialog.dismissSafe(this)\n        }\n\n        dialog.setOnDismissListener {\n            dismissCallback.invoke()\n        }\n\n    }\n\n    fun Activity?.showMultiDialog(\n        items: List<String>,\n        selectedIndex: List<Int>,\n        name: String,\n        dismissCallback: () -> Unit,\n        callback: (List<Int>) -> Unit,\n    ) {\n        if (this == null) return\n\n        val binding: BottomSelectionDialogBinding = BottomSelectionDialogBinding.inflate(\n            LayoutInflater.from(this)\n        )\n        val builder =\n            AlertDialog.Builder(this, R.style.AlertDialogCustom)\n                .setView(binding.root)\n\n        val dialog = builder.create()\n        dialog.show()\n        showDialog(\n            binding,\n            dialog,\n            items,\n            selectedIndex,\n            name,\n            showApply = true,\n            isMultiSelect = true,\n            callback,\n            dismissCallback\n        )\n    }\n\n    fun Activity?.showDialog(\n        items: List<String>,\n        selectedIndex: Int,\n        name: String,\n        showApply: Boolean,\n        dismissCallback: () -> Unit,\n        callback: (Int) -> Unit,\n    ) {\n        if (this == null) return\n\n        val binding: BottomSelectionDialogBinding = BottomSelectionDialogBinding.inflate(\n            LayoutInflater.from(this)\n        )\n        val builder =\n            AlertDialog.Builder(this, R.style.AlertDialogCustom)\n                .setView(binding.root)\n\n        val dialog = builder.create()\n        dialog.show()\n\n\n        showDialog(\n            binding,\n            dialog,\n            items,\n            listOf(selectedIndex),\n            name,\n            showApply,\n            false,\n            { if (it.isNotEmpty()) callback.invoke(it.first()) },\n            dismissCallback\n        )\n    }\n\n    /** Only for a low amount of items */\n    fun Activity?.showBottomDialog(\n        items: List<String>,\n        selectedIndex: Int,\n        name: String,\n        showApply: Boolean,\n        dismissCallback: () -> Unit,\n        callback: (Int) -> Unit,\n    ) {\n        if (this == null) return\n\n        val binding: BottomSelectionDialogBinding = BottomSelectionDialogBinding.inflate(\n            LayoutInflater.from(this)\n        )\n\n        val builder =\n            BottomSheetDialog(this)\n        builder.setContentView(binding.root)\n\n        builder.show()\n        showDialog(\n            binding,\n            builder,\n            items,\n            listOf(selectedIndex),\n            name,\n            showApply,\n            false,\n            { if (it.isNotEmpty()) callback.invoke(it.first()) },\n            dismissCallback\n        )\n    }\n\n    fun Activity.showBottomDialogInstant(\n        items: List<String>,\n        name: String,\n        dismissCallback: () -> Unit,\n        callback: (Int) -> Unit,\n    ): BottomSheetDialog {\n        val builder =\n            BottomSheetDialog(this)\n\n        val binding: BottomSelectionDialogBinding = BottomSelectionDialogBinding.inflate(\n            LayoutInflater.from(this)\n        )\n\n        //builder.setContentView(R.layout.bottom_selection_dialog_direct)\n        builder.setContentView(binding.root)\n        builder.show()\n        showDialog(\n            binding,\n            builder,\n            items,\n            emptyList(),\n            name,\n            showApply = false,\n            isMultiSelect = false,\n            callback = { if (it.isNotEmpty()) callback.invoke(it.first()) },\n            dismissCallback = dismissCallback,\n            itemLayout = R.layout.sort_bottom_single_choice_no_checkmark\n        )\n        return builder\n    }\n\n    fun Activity.showNginxTextInputDialog(\n        name: String,\n        value: String,\n        textInputType: Int?,\n        dismissCallback: () -> Unit,\n        callback: (String) -> Unit,\n    ) {\n        val builder = BottomSheetDialog(this)\n\n        val binding: BottomInputDialogBinding = BottomInputDialogBinding.inflate(\n            LayoutInflater.from(this)\n        )\n\n        builder.setContentView(binding.root)\n\n        builder.show()\n        showInputDialog(\n            binding,\n            builder,\n            value,\n            name,\n            textInputType,  // type is a uri\n            callback,\n            dismissCallback\n        )\n    }\n\n    fun Activity.showBottomDialogText(\n        title: String,\n        text: Spanned,\n        dismissCallback: () -> Unit\n    ) {\n        val binding = BottomTextDialogBinding.inflate(layoutInflater)\n        val dialog = BottomSheetDialog(this)\n\n        dialog.setContentView(binding.root)\n\n        binding.dialogTitle.text = title\n        binding.dialogText.text = text\n\n        dialog.setOnDismissListener {\n            dismissCallback.invoke()\n        }\n\n        dialog.show()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/SnackbarHelper.kt",
    "content": "package com.lagradost.cloudstream3.utils\r\n\r\nimport android.app.Activity\r\nimport android.view.View\r\nimport androidx.annotation.MainThread\r\nimport androidx.annotation.StringRes\r\nimport com.google.android.material.snackbar.Snackbar\r\nimport com.lagradost.api.Log\r\nimport com.lagradost.cloudstream3.R\r\nimport com.lagradost.cloudstream3.mvvm.logError\r\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\r\n\r\nobject SnackbarHelper {\r\n\r\n    private const val TAG = \"COMPACT\"\r\n    private var currentSnackbar: Snackbar? = null\r\n\r\n    @MainThread\r\n    fun showSnackbar(\r\n        act: Activity?,\r\n        message: UiText,\r\n        duration: Int = Snackbar.LENGTH_SHORT,\r\n        actionText: UiText? = null,\r\n        actionCallback: (() -> Unit)? = null\r\n    ) {\r\n        if (act == null) return\r\n        showSnackbar(act, message.asString(act), duration,\r\n            actionText?.asString(act), actionCallback)\r\n    }\r\n\r\n    @MainThread\r\n    fun showSnackbar(\r\n        act: Activity?,\r\n        @StringRes message: Int,\r\n        duration: Int = Snackbar.LENGTH_SHORT,\r\n        @StringRes actionText: Int? = null,\r\n        actionCallback: (() -> Unit)? = null\r\n    ) {\r\n        if (act == null) return\r\n        showSnackbar(act, act.getString(message), duration,\r\n            actionText?.let { act.getString(it) }, actionCallback)\r\n    }\r\n\r\n    @MainThread\r\n    fun showSnackbar(\r\n        act: Activity?,\r\n        message: String?,\r\n        duration: Int = Snackbar.LENGTH_SHORT,\r\n        actionText: String? = null,\r\n        actionCallback: (() -> Unit)? = null\r\n    ) {\r\n        if (act == null || message == null) {\r\n            Log.w(TAG, \"Invalid showSnackbar: act = $act, message = $message\")\r\n            return\r\n        }\r\n        Log.i(TAG, \"showSnackbar: $message\")\r\n\r\n        try {\r\n            currentSnackbar?.dismiss()\r\n        } catch (e: Exception) {\r\n            logError(e)\r\n        }\r\n\r\n        try {\r\n            val parentView = act.findViewById<View>(android.R.id.content)\r\n            val snackbar = Snackbar.make(parentView, message, duration)\r\n\r\n            actionCallback?.let {\r\n                snackbar.setAction(actionText) { actionCallback.invoke() }\r\n            }\r\n\r\n            snackbar.show()\r\n            currentSnackbar = snackbar\r\n\r\n            snackbar.setBackgroundTint(act.colorFromAttribute(R.attr.primaryBlackBackground))\r\n            snackbar.setTextColor(act.colorFromAttribute(R.attr.textColor))\r\n            snackbar.setActionTextColor(act.colorFromAttribute(R.attr.colorPrimary))\r\n\r\n        } catch (e: Exception) {\r\n            logError(e)\r\n        }\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/SubtitleUtils.kt",
    "content": "package com.lagradost.cloudstream3.utils\r\n\r\nimport android.content.Context\r\nimport com.lagradost.api.Log\r\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.basePathToFile\r\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects\r\n\r\nobject SubtitleUtils {\r\n\r\n    // Only these files are allowed, so no videos as subtitles\r\n    private val allowedExtensions = listOf(\r\n        \".vtt\", \".srt\", \".txt\", \".ass\",\r\n        \".ttml\", \".sbv\", \".dfxp\"\r\n    )\r\n\r\n    fun deleteMatchingSubtitles(context: Context, info: DownloadObjects.DownloadedFileInfo) {\r\n        val cleanDisplay = cleanDisplayName(info.displayName)\r\n\r\n        val base = basePathToFile(context, info.basePath)\r\n        val folder =\r\n            base?.gotoDirectory(info.relativePath, createMissingDirectories = false) ?: return\r\n        val folderFiles = folder.listFiles() ?: return\r\n\r\n        for (file in folderFiles) {\r\n            val name = file.name() ?: continue\r\n            if (!isMatchingSubtitle(name, info.displayName, cleanDisplay)) {\r\n                continue\r\n            }\r\n            if (file.delete() != true) {\r\n                Log.e(\"SubtitleDeletion\", \"Failed to delete subtitle file: $name\")\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * @param name the file name of the subtitle\r\n     * @param display the file name of the video\r\n     * @param cleanDisplay the cleanDisplayName of the video file name\r\n     */\r\n    fun isMatchingSubtitle(\r\n        name: String,\r\n        display: String,\r\n        cleanDisplay: String\r\n    ): Boolean {\r\n        // Check if the file has a valid subtitle extension\r\n        val hasValidExtension = allowedExtensions.any { name.contains(it, ignoreCase = true) }\r\n\r\n        // We can't have the exact same file as a subtitle\r\n        val isNotDisplayName = !name.equals(display, ignoreCase = true)\r\n\r\n        // Check if the file name starts with a cleaned version of the display name\r\n        val startsWithCleanDisplay = cleanDisplayName(name).startsWith(cleanDisplay, ignoreCase = true)\r\n\r\n        return hasValidExtension && isNotDisplayName && startsWithCleanDisplay\r\n    }\r\n\r\n    fun cleanDisplayName(name: String): String {\r\n        return name.substringBeforeLast('.').trim()\r\n    }\r\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\n// TODO: FIX\n\nimport android.util.Log\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder.apis\n//import com.lagradost.cloudstream3.animeproviders.AniflixProvider\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport java.util.concurrent.TimeUnit\n\nobject SyncUtil {\n    private val regexs = listOf(\n        Regex(\"\"\"(9anime)\\.(?:to|center|id)/watch/.*?\\.([^/?]*)\"\"\"),\n        Regex(\"\"\"(gogoanime|gogoanimes)\\..*?/category/([^/?]*)\"\"\"),\n        Regex(\"\"\"(twist\\.moe)/a/([^/?]*)\"\"\"),\n    )\n\n    private const val TAG = \"SYNCUTIL\"\n\n    private const val GOGOANIME = \"Gogoanime\"\n    private const val NINE_ANIME = \"9anime\"\n    private const val TWIST_MOE = \"Twistmoe\"\n\n    private val matchList =\n        mapOf(\n            \"9anime\" to NINE_ANIME,\n            \"gogoanime\" to GOGOANIME,\n            \"gogoanimes\" to GOGOANIME,\n            \"twist.moe\" to TWIST_MOE\n        )\n\n    suspend fun getIdsFromUrl(url: String?): Pair<String?, String?>? {\n        if (url == null) return null\n        Log.i(TAG, \"getIdsFromUrl $url\")\n\n        for (regex in regexs) {\n            regex.find(url)?.let { match ->\n                if (match.groupValues.size == 3) {\n                    val site = match.groupValues[1]\n                    val slug = match.groupValues[2]\n                    matchList[site]?.let { realSite ->\n                        getIdsFromSlug(slug, realSite)?.let {\n                            return it\n                        } ?: kotlin.run {\n                            if (slug.endsWith(\"-dub\")) {\n                                println(\"testing non -dub slug $slug\")\n                                getIdsFromSlug(slug.removeSuffix(\"-dub\"), realSite)?.let {\n                                    return it\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        return null\n    }\n\n    /** first. Mal, second. Anilist,\n     * valid sites are: Gogoanime, Twistmoe and 9anime*/\n    private suspend fun getIdsFromSlug(\n        slug: String,\n        site: String = \"Gogoanime\"\n    ): Pair<String?, String?>? {\n        Log.i(TAG, \"getIdsFromSlug $slug $site\")\n        try {\n            //Gogoanime, Twistmoe and 9anime\n            val url =\n                \"https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/pages/$site/$slug.json\"\n            val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).text\n            val mapped = parseJson<MalSyncPage?>(response)\n\n            val overrideMal = mapped?.malId ?: mapped?.mal?.id ?: mapped?.anilist?.malId\n            val overrideAnilist = mapped?.aniId ?: mapped?.anilist?.id\n\n            if (overrideMal != null) {\n                return overrideMal.toString() to overrideAnilist?.toString()\n            }\n            return null\n        } catch (e: Exception) {\n            logError(e)\n        }\n        return null\n    }\n\n    suspend fun getUrlsFromId(id: String, type: String = \"anilist\"): List<String> {\n        val url =\n            \"https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/$type/anime/$id.json\"\n        val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).parsed<SyncPage>()\n        val pages = response.pages ?: return emptyList()\n        val current =\n            pages.gogoanime.values.union(pages.nineanime.values).union(pages.twistmoe.values)\n                .mapNotNull { it.url }.toMutableList()\n\n        if (type == \"anilist\") { // TODO MAKE BETTER\n            synchronized(apis) {\n                apis.filter { it.name.contains(\"Aniflix\", ignoreCase = true) }.forEach {\n                    current.add(\"${it.mainUrl}/anime/$id\")\n                }\n            }\n        }\n        return current\n    }\n\n    data class SyncPage(\n        @JsonProperty(\"Pages\") val pages: SyncPages?,\n    )\n\n    data class SyncPages(\n        @JsonProperty(\"9anime\") val nineanime: Map<String, ProviderPage> = emptyMap(),\n        @JsonProperty(\"Gogoanime\") val gogoanime: Map<String, ProviderPage> = emptyMap(),\n        @JsonProperty(\"Twistmoe\") val twistmoe: Map<String, ProviderPage> = emptyMap(),\n    )\n\n    data class ProviderPage(\n        @JsonProperty(\"url\") val url: String?,\n    )\n\n    data class MalSyncPage(\n        @JsonProperty(\"identifier\") val identifier: String?,\n        @JsonProperty(\"type\") val type: String?,\n        @JsonProperty(\"page\") val page: String?,\n        @JsonProperty(\"title\") val title: String?,\n        @JsonProperty(\"url\") val url: String?,\n        @JsonProperty(\"image\") val image: String?,\n        @JsonProperty(\"hentai\") val hentai: Boolean?,\n        @JsonProperty(\"sticky\") val sticky: Boolean?,\n        @JsonProperty(\"active\") val active: Boolean?,\n        @JsonProperty(\"actor\") val actor: String?,\n        @JsonProperty(\"malId\") val malId: Int?,\n        @JsonProperty(\"aniId\") val aniId: Int?,\n        @JsonProperty(\"createdAt\") val createdAt: String?,\n        @JsonProperty(\"updatedAt\") val updatedAt: String?,\n        @JsonProperty(\"deletedAt\") val deletedAt: String?,\n        @JsonProperty(\"Mal\") val mal: Mal?,\n        @JsonProperty(\"Anilist\") val anilist: Anilist?,\n        @JsonProperty(\"malUrl\") val malUrl: String?\n    )\n\n    data class Anilist(\n//            @JsonProperty(\"altTitle\") val altTitle: List<String>?,\n//            @JsonProperty(\"externalLinks\") val externalLinks: List<String>?,\n        @JsonProperty(\"id\") val id: Int?,\n        @JsonProperty(\"malId\") val malId: Int?,\n        @JsonProperty(\"type\") val type: String?,\n        @JsonProperty(\"title\") val title: String?,\n        @JsonProperty(\"url\") val url: String?,\n        @JsonProperty(\"image\") val image: String?,\n        @JsonProperty(\"category\") val category: String?,\n        @JsonProperty(\"hentai\") val hentai: Boolean?,\n        @JsonProperty(\"createdAt\") val createdAt: String?,\n        @JsonProperty(\"updatedAt\") val updatedAt: String?,\n        @JsonProperty(\"deletedAt\") val deletedAt: String?\n    )\n\n    data class Mal(\n//            @JsonProperty(\"altTitle\") val altTitle: List<String>?,\n        @JsonProperty(\"id\") val id: Int?,\n        @JsonProperty(\"type\") val type: String?,\n        @JsonProperty(\"title\") val title: String?,\n        @JsonProperty(\"url\") val url: String?,\n        @JsonProperty(\"image\") val image: String?,\n        @JsonProperty(\"category\") val category: String?,\n        @JsonProperty(\"hentai\") val hentai: Boolean?,\n        @JsonProperty(\"createdAt\") val createdAt: String?,\n        @JsonProperty(\"updatedAt\") val updatedAt: String?,\n        @JsonProperty(\"deletedAt\") val deletedAt: String?\n    )\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/TestingUtils.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.mvvm.logError\nimport kotlinx.coroutines.*\nimport org.junit.Assert\nimport kotlin.random.Random\n\nobject TestingUtils {\n    open class TestResult(val success: Boolean) {\n        companion object {\n            val Pass = TestResult(true)\n            val Fail = TestResult(false)\n        }\n    }\n\n    class Logger {\n        enum class LogLevel {\n            Normal,\n            Warning,\n            Error;\n        }\n\n        data class Message(val level: LogLevel, val message: String) {\n            override fun toString(): String {\n                val level = when (this.level) {\n                    LogLevel.Normal -> \"\"\n                    LogLevel.Warning -> \"Warning: \"\n                    LogLevel.Error -> \"Error: \"\n                }\n                return \"$level$message\"\n            }\n        }\n\n        private val messageLog = mutableListOf<Message>()\n\n        fun getRawLog(): List<Message> = messageLog\n\n        fun log(message: String) {\n            messageLog.add(Message(LogLevel.Normal, message))\n        }\n\n        fun warn(message: String) {\n            messageLog.add(Message(LogLevel.Warning, message))\n        }\n\n        fun error(message: String) {\n            messageLog.add(Message(LogLevel.Error, message))\n        }\n    }\n\n    class TestResultList(val results: List<SearchResponse>) : TestResult(true)\n    class TestResultLoad(val extractorData: String, val shouldLoadLinks: Boolean) : TestResult(true)\n\n    class TestResultProvider(\n        success: Boolean,\n        val log: List<Logger.Message>,\n        val exception: Throwable?\n    ) :\n        TestResult(success)\n\n    @Throws(AssertionError::class, CancellationException::class)\n    suspend fun testHomepage(\n        api: MainAPI,\n        logger: Logger\n    ): TestResult {\n        if (api.hasMainPage) {\n            try {\n                val f = api.mainPage.first()\n                val homepage =\n                    api.getMainPage(1, MainPageRequest(f.name, f.data, f.horizontalImages))\n                when {\n                    homepage == null -> {\n                        logger.error(\"Provider ${api.name} did not correctly load homepage!\")\n                    }\n\n                    homepage.items.isEmpty() -> {\n                        logger.warn(\"Provider ${api.name} does not contain any homepage rows!\")\n                    }\n\n                    homepage.items.any { it.list.isEmpty() } -> {\n                        logger.warn(\"Provider ${api.name} does not have any items in a homepage row!\")\n                    }\n                }\n                val homePageList = homepage?.items?.flatMap { it.list } ?: emptyList()\n                return TestResultList(homePageList)\n            } catch (e: Throwable) {\n                when (e) {\n                    is NotImplementedError -> {\n                        Assert.fail(\"Provider marked as hasMainPage, while in reality is has not been implemented\")\n                    }\n\n                    is CancellationException -> {\n                        throw e\n                    }\n\n                    else -> {\n                        e.message?.let { logger.warn(\"Exception thrown when loading homepage: \\\"$it\\\"\") }\n                    }\n                }\n            }\n        }\n        return TestResult.Pass\n    }\n\n    @Throws(AssertionError::class, CancellationException::class)\n    private suspend fun testSearch(\n        api: MainAPI,\n        testQueries: List<String>,\n        logger: Logger,\n    ): TestResult {\n        val searchResults = testQueries.firstNotNullOfOrNull { query ->\n            try {\n                logger.log(\"Searching for: $query\")\n                api.search(query, 1)?.items?.takeIf { it.isNotEmpty() }\n            } catch (e: Throwable) {\n                if (e is NotImplementedError) {\n                    Assert.fail(\"Provider has not implemented search()\")\n                } else if (e is CancellationException) {\n                    throw e\n                }\n                logError(e)\n                null\n            }\n        }\n\n        return if (searchResults.isNullOrEmpty()) {\n            Assert.fail(\"Api ${api.name} did not return any search responses\")\n            TestResult.Fail // Should not be reached\n        } else {\n            TestResultList(searchResults)\n        }\n    }\n\n\n    @Throws(AssertionError::class, CancellationException::class)\n    private suspend fun testLoad(\n        api: MainAPI,\n        result: SearchResponse,\n        logger: Logger\n    ): TestResult {\n        try {\n            if (result.apiName != api.name) {\n                logger.warn(\"Wrong apiName on SearchResponse: ${api.name} != ${result.apiName}\")\n            }\n\n            val loadResponse = api.load(result.url)\n\n            if (loadResponse == null) {\n                logger.error(\"Returned null loadResponse on ${result.url} on ${api.name}\")\n                return TestResult.Fail\n            }\n\n            if (loadResponse.apiName != api.name) {\n                logger.warn(\"Wrong apiName on LoadResponse: ${api.name} != ${loadResponse.apiName}\")\n            }\n\n            if (!api.supportedTypes.contains(loadResponse.type)) {\n                logger.warn(\"Api ${api.name} on load does not contain any of the supportedTypes: ${loadResponse.type}\")\n            }\n\n            val url = when (loadResponse) {\n                is AnimeLoadResponse -> {\n                    val gotNoEpisodes =\n                        loadResponse.episodes.keys.isEmpty() || loadResponse.episodes.keys.any { loadResponse.episodes[it].isNullOrEmpty() }\n\n                    if (gotNoEpisodes) {\n                        logger.error(\"Api ${api.name} got no episodes on ${loadResponse.url}\")\n                        return TestResult.Fail\n                    }\n\n                    (loadResponse.episodes[loadResponse.episodes.keys.firstOrNull()])?.firstOrNull()?.data\n                }\n\n                is MovieLoadResponse -> {\n                    val gotNoEpisodes = loadResponse.dataUrl.isBlank()\n                    if (gotNoEpisodes) {\n                        logger.error(\"Api ${api.name} got no movie on ${loadResponse.url}\")\n                        return TestResult.Fail\n                    }\n\n                    loadResponse.dataUrl\n                }\n\n                is TvSeriesLoadResponse -> {\n                    val gotNoEpisodes = loadResponse.episodes.isEmpty()\n                    if (gotNoEpisodes) {\n                        logger.error(\"Api ${api.name} got no episodes on ${loadResponse.url}\")\n                        return TestResult.Fail\n                    }\n                    loadResponse.episodes.firstOrNull()?.data\n                }\n\n                is LiveStreamLoadResponse -> {\n                    loadResponse.dataUrl\n                }\n\n                else -> {\n                    logger.error(\"Unknown load response: ${loadResponse.javaClass.name}\")\n                    return TestResult.Fail\n                }\n            } ?: return TestResult.Fail\n\n            return TestResultLoad(url, loadResponse.type != TvType.CustomMedia)\n\n//            val loadTest = testLoadResponse(api, load, logger)\n//            if (loadTest is TestResultLoad) {\n//                testLinkLoading(api, loadTest.extractorData, logger).success\n//            } else {\n//                false\n//            }\n//            if (!validResults) {\n//                logger(\"Api ${api.name} did not load on the first search results: ${smallSearchResults.map { it.name }}\")\n//            }\n\n//            return TestResult(validResults)\n        } catch (e: Throwable) {\n            if (e is NotImplementedError) {\n                Assert.fail(\"Provider has not implemented load()\")\n            }\n            throw e\n        }\n    }\n\n    @Throws(AssertionError::class, CancellationException::class)\n    private suspend fun testLinkLoading(\n        api: MainAPI,\n        url: String?,\n        logger: Logger\n    ): TestResult {\n        Assert.assertNotNull(\"Api ${api.name} has invalid url on episode\", url)\n        if (url == null) return TestResult.Fail // Should never trigger\n\n        var linksLoaded = 0\n        try {\n            val success = api.loadLinks(url, false, {}) { link ->\n                logger.log(\"Video loaded: ${link.name}\")\n                Assert.assertTrue(\n                    \"Api ${api.name} returns link with invalid url ${link.url}\",\n                    link.url.length > 4\n                )\n                linksLoaded++\n            }\n            if (success) {\n                logger.log(\"Links loaded: $linksLoaded\")\n                return TestResult(linksLoaded > 0)\n            } else {\n                Assert.fail(\"Api ${api.name} returns false on loadLinks() with $linksLoaded links loaded\")\n            }\n        } catch (e: Throwable) {\n            when (e) {\n                is NotImplementedError -> {\n                    Assert.fail(\"Provider has not implemented loadLinks()\")\n                }\n\n                else -> {\n                    logger.error(\"Failed link loading on ${api.name} using data: $url\")\n                    throw e\n                }\n            }\n        }\n        return TestResult.Pass\n    }\n\n    fun getDeferredProviderTests(\n        scope: CoroutineScope,\n        providers: Array<MainAPI>,\n        callback: (MainAPI, TestResultProvider) -> Unit\n    ) {\n        providers.forEach { api ->\n            scope.launch {\n                val logger = Logger()\n\n                val result = try {\n                    logger.log(\"Trying ${api.name}\")\n\n                    // Test Homepage\n                    val homepage = testHomepage(api, logger)\n                    Assert.assertTrue(\"Homepage failed to load\", homepage.success)\n                    val homePageList = (homepage as? TestResultList)?.results ?: emptyList()\n\n                    // Test Search Results\n                    val searchQueries =\n                        // Use the random 3 home page results as queries since they are guaranteed to exist\n                        (homePageList.shuffled(Random).take(3).map { it.name.split(\" \").first() } +\n                                // If home page is sparse then use generic search queries\n                                listOf(\"over\", \"iron\", \"guy\")).take(3)\n\n                    val searchResults = testSearch(api, searchQueries, logger)\n                    Assert.assertTrue(\"Failed to get search results\", searchResults.success)\n                    searchResults as TestResultList\n\n                    // Test Load and LoadLinks\n                    // Only try the first 3 search results to prevent spamming\n                    val success = searchResults.results.take(3).any { searchResponse ->\n                        logger.log(\"Testing search result: ${searchResponse.url}\")\n                        val loadResponse = testLoad(api, searchResponse, logger)\n                        if (loadResponse !is TestResultLoad) {\n                            false\n                        } else {\n                            if (loadResponse.shouldLoadLinks) {\n                                testLinkLoading(api, loadResponse.extractorData, logger).success\n                            } else {\n                                logger.log(\"Skipping link loading test\")\n                                true\n                            }\n                        }\n                    }\n\n                    if (success) {\n                        logger.log(\"Success ${api.name}\")\n                        TestResultProvider(true, logger.getRawLog(), null)\n                    } else {\n                        logger.error(\"Link loading failed\")\n                        TestResultProvider(false, logger.getRawLog(), null)\n                    }\n                } catch (e: Throwable) {\n                    TestResultProvider(false, logger.getRawLog(), e)\n                }\n                callback.invoke(api, result)\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/TextUtil.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.content.Context\nimport android.util.Log\nimport android.widget.TextView\nimport androidx.annotation.StringRes\nimport androidx.core.view.isGone\nimport androidx.core.view.isVisible\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.utils.AppContextUtils.html\n\nsealed class UiText {\n    companion object {\n        const val TAG = \"UiText\"\n    }\n\n    data class DynamicString(val value: String) : UiText() {\n        override fun toString(): String = value\n\n        override fun equals(other: Any?): Boolean {\n            if (other !is DynamicString) return false\n            return this.value == other.value\n        }\n\n        override fun hashCode(): Int = value.hashCode()\n    }\n\n    class StringResource(\n        @StringRes val resId: Int,\n        val args: List<Any>\n    ) : UiText() {\n        override fun toString(): String =\n            \"resId = $resId\\nargs = ${args.toList().map { \"(${it::class} = $it)\" }}\"\n        override fun equals(other: Any?): Boolean {\n            if (other !is StringResource) return false\n            return this.resId == other.resId && this.args == other.args\n        }\n\n        override fun hashCode(): Int {\n            var result = resId\n            result = 31 * result + args.hashCode()\n            return result\n        }\n    }\n\n    fun asStringNull(context: Context?): String? {\n        try {\n            return asString(context ?: return null)\n        } catch (e: Exception) {\n            Log.e(TAG, \"Got invalid data from $this\")\n            logError(e)\n            return null\n        }\n    }\n\n    fun asString(context: Context): String {\n        return when (this) {\n            is DynamicString -> value\n            is StringResource -> {\n                val str = context.getString(resId)\n                if (args.isEmpty()) {\n                    str\n                } else {\n                    str.format(*args.map {\n                        when (it) {\n                            is UiText -> it.asString(context)\n                            else -> it\n                        }\n                    }.toTypedArray())\n                }\n            }\n        }\n    }\n}\n\nfun txt(value: String): UiText {\n    return UiText.DynamicString(value)\n}\n\n@JvmName(\"txtNull\")\nfun txt(value: String?): UiText? {\n    return UiText.DynamicString(value ?: return null)\n}\n\nfun txt(@StringRes resId: Int, vararg args: Any): UiText {\n    return UiText.StringResource(resId, args.toList())\n}\n\n@JvmName(\"txtNull\")\nfun txt(@StringRes resId: Int?, vararg args: Any?): UiText? {\n    if (resId == null || args.any { it == null }) {\n        return null\n    }\n    return UiText.StringResource(resId, args.filterNotNull().toList())\n}\n\nfun TextView?.setText(text: UiText?) {\n    if (this == null) return\n    if (text == null) {\n        this.isVisible = false\n    } else {\n        val str = text.asStringNull(context)?.let {\n            if (this.maxLines == 1) {\n                it.replace(\"\\n\", \" \")\n            } else {\n                it\n            }\n        }\n\n        this.isGone = str.isNullOrBlank()\n        this.text = str\n    }\n}\n\nfun TextView?.setTextHtml(text: UiText?) {\n    if (this == null) return\n    if (text == null) {\n        this.isVisible = false\n    } else {\n        val str = text.asStringNull(context)\n        this.isGone = str.isNullOrBlank()\n        this.text = str.html()\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.annotation.SuppressLint\nimport android.content.ComponentName\nimport android.content.ContentUris\nimport android.content.Context\nimport android.content.Intent\nimport android.util.Log\nimport androidx.core.net.toUri\nimport androidx.tvprovider.media.tv.Channel\nimport androidx.tvprovider.media.tv.PreviewProgram\nimport androidx.tvprovider.media.tv.TvContractCompat\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.base64Encode\nimport com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING_SHARE\nimport com.lagradost.cloudstream3.utils.DataStore.getKey\nimport com.lagradost.cloudstream3.utils.DataStore.setKey\nimport java.net.URLEncoder\n\nconst val PROGRAM_ID_LIST_KEY = \"persistent_program_ids\"\n\nobject TvChannelUtils {\n    fun Context.saveProgramId(programId: Long) {\n        val existing: List<Long> = getKey(PROGRAM_ID_LIST_KEY) ?: emptyList()\n        val updated = (existing + programId).distinct()\n        setKey(PROGRAM_ID_LIST_KEY, updated)\n    }\n    fun Context.getStoredProgramIds(): List<Long> {\n        return getKey(PROGRAM_ID_LIST_KEY) ?: emptyList()\n    }\n    fun Context.removeProgramId(programId: Long) {\n        val existing: List<Long> = getKey(PROGRAM_ID_LIST_KEY) ?: emptyList()\n        val updated = existing.filter { it != programId }\n        setKey(PROGRAM_ID_LIST_KEY, updated)\n    }\n\n\n    fun getChannelId(context: Context, channelName: String): Long? {\n        return try {\n            context.contentResolver.query(\n                TvContractCompat.Channels.CONTENT_URI,\n                arrayOf(\n                    TvContractCompat.Channels._ID,\n                    TvContractCompat.Channels.COLUMN_DISPLAY_NAME\n                ),\n                null,\n                null,\n                null\n            )?.use { cursor ->\n                while (cursor.moveToNext()) {\n                    val id = cursor.getLong(\n                        cursor.getColumnIndexOrThrow(TvContractCompat.Channels._ID)\n                    )\n                    val name = cursor.getString(\n                        cursor.getColumnIndexOrThrow(TvContractCompat.Channels.COLUMN_DISPLAY_NAME)\n                    )\n                    if (name == channelName) return id\n                }\n                null\n            }\n        } catch (e: Exception) {\n            Log.e(\"TvChannelUtils\", \"Query failed: ${e.message}\", e)\n            null\n        }\n    }\n\n    /** Insert programs into a channel */\n    @SuppressLint(\"RestrictedApi\")\n    fun addPrograms(context: Context, channelId: Long, items: List<SearchResponse>) {\n        for (item in items) {\n            try {\n                val nameBase64 = base64Encode(item.apiName.toByteArray(Charsets.UTF_8))\n                val urlBase64 = base64Encode(item.url.toByteArray(Charsets.UTF_8))\n                val csshareUri = \"$APP_STRING_SHARE:$nameBase64?$urlBase64\"\n                val poster=item.posterUrl\n                val builder = PreviewProgram.Builder()\n                    .setChannelId(channelId)\n                    .setTitle(item.name)\n                    .apply {\n                        val scoreText = item.score?.toStringNull(0.1, 10, 1)?.let {\n                            \" - \" + txt(R.string.rating_format, it).asString(context)\n                        } ?: \"\"\n                        setDescription(\"${item.apiName}$scoreText\")\n                    }\n                    .setContentId(item.url)\n                    .setType(TvContractCompat.PreviewPrograms.TYPE_MOVIE)\n                    .setIntentUri(csshareUri.toUri())\n                    .setPosterArtAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_2_3)\n\n                // Validate poster URL before setting\n                if (!poster.isNullOrBlank() && poster.startsWith(\"http\")) {\n                    builder.setPosterArtUri(poster.toUri())\n\n                }\n                val program = builder.build()\n\n                val uri = context.contentResolver.insert(\n                    TvContractCompat.PreviewPrograms.CONTENT_URI,\n                    program.toContentValues()\n                )\n\n                if (uri != null) {\n                    val programId = ContentUris.parseId(uri)\n                    context.saveProgramId(programId)\n                    Log.d(\"TvChannelUtils\", \"Inserted program ${item.name}, ID=$programId\")\n                } else {\n                    Log.e(\"TvChannelUtils\", \"Insert failed for ${item.name}\")\n                }\n\n            } catch (error: Exception) {\n                Log.e(\"TvChannelUtils\", \"Error inserting ${item.name}: $error\")\n            }\n        }\n    }\n\n    fun deleteStoredPrograms(context: Context) {\n        val programIds = context.getStoredProgramIds()\n\n        for (id in programIds) {\n            val uri = ContentUris.withAppendedId(TvContractCompat.PreviewPrograms.CONTENT_URI, id)\n            try {\n                val rowsDeleted = context.contentResolver.delete(uri, null, null)\n                if (rowsDeleted > 0) {\n                    context.removeProgramId(id) // Remove from persistent list\n                } else {\n                    Log.w(\"ProgramDelete\", \"No program found for ID: $id\")\n                }\n            } catch (e: Exception) {\n                Log.e(\"ProgramDelete\", \"Failed to delete program ID: $id\", e)\n            }\n        }\n\n        Log.d(\"ProgramDelete\", \"Finished deleting stored programs\")\n    }\n\n    fun createTvChannel(context: Context) {\n        val componentName = ComponentName(context, MainActivity::class.java)\n        val iconUri = \"android.resource://${context.packageName}/mipmap/ic_launcher\".toUri()\n        val inputId = TvContractCompat.buildInputId(componentName)\n        val channel = Channel.Builder()\n            .setType(TvContractCompat.Channels.TYPE_PREVIEW)\n            .setAppLinkIconUri(iconUri)\n            .setDisplayName(context.getString(R.string.app_name))\n            .setAppLinkIntent(Intent(Intent.ACTION_VIEW).apply {\n                data = \"cloudstreamapp://open\".toUri()\n            })\n            .setInputId(inputId)\n            .build()\n\n        val channelUri = context.contentResolver.insert(\n            TvContractCompat.Channels.CONTENT_URI,\n            channel.toContentValues()\n        )\n\n        channelUri?.let {\n            val channelId = ContentUris.parseId(it)\n            TvContractCompat.requestChannelBrowsable(context, channelId)\n            Log.d(\"TvChannelUtils\", \"Channel Created: $channelId\")\n        }\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.app.AppOpsManager\nimport android.app.Dialog\nimport android.content.ClipData\nimport android.content.ClipboardManager\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.content.res.Configuration\nimport android.content.res.Resources\nimport android.graphics.Bitmap\nimport android.graphics.Canvas\nimport android.graphics.Color\nimport android.graphics.ColorFilter\nimport android.graphics.Paint\nimport android.graphics.PixelFormat\nimport android.graphics.drawable.Drawable\nimport android.os.Build\nimport android.os.Bundle\nimport android.os.TransactionTooLargeException\nimport android.util.Log\nimport android.view.Gravity\nimport android.view.MenuItem\nimport android.view.View\nimport android.view.ViewGroup\nimport android.view.ViewGroup.MarginLayoutParams\nimport android.view.WindowManager\nimport android.view.inputmethod.InputMethodManager\nimport android.widget.ListAdapter\nimport android.widget.ListView\nimport android.widget.Toast.LENGTH_LONG\nimport androidx.annotation.AttrRes\nimport androidx.annotation.ColorInt\nimport androidx.annotation.DimenRes\nimport androidx.annotation.StyleRes\nimport androidx.appcompat.view.ContextThemeWrapper\nimport androidx.appcompat.view.menu.MenuBuilder\nimport androidx.appcompat.widget.PopupMenu\nimport androidx.core.app.ActivityCompat\nimport androidx.core.content.ContextCompat\nimport androidx.core.content.getSystemService\nimport androidx.core.content.withStyledAttributes\nimport androidx.core.graphics.alpha\nimport androidx.core.graphics.blue\nimport androidx.core.graphics.green\nimport androidx.core.graphics.red\nimport androidx.core.view.marginBottom\nimport androidx.core.view.marginLeft\nimport androidx.core.view.marginRight\nimport androidx.core.view.marginTop\nimport androidx.core.view.updateLayoutParams\nimport androidx.core.view.updatePadding\nimport androidx.core.view.ViewCompat\nimport androidx.core.view.WindowCompat\nimport androidx.core.view.WindowInsetsCompat\nimport androidx.core.view.WindowInsetsControllerCompat\nimport androidx.fragment.app.Fragment\nimport androidx.fragment.app.FragmentActivity\nimport androidx.navigation.NavOptions\nimport androidx.navigation.fragment.NavHostFragment\nimport androidx.palette.graphics.Palette\nimport androidx.preference.PreferenceManager\nimport com.google.android.material.appbar.AppBarLayout\nimport com.google.android.material.chip.Chip\nimport com.google.android.material.chip.ChipDrawable\nimport com.google.android.material.chip.ChipGroup\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.context\nimport com.lagradost.cloudstream3.CommonActivity.activity\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR\nimport com.lagradost.cloudstream3.ui.settings.Globals.PHONE\nimport com.lagradost.cloudstream3.ui.settings.Globals.TV\nimport com.lagradost.cloudstream3.ui.settings.Globals.isLayout\nimport com.lagradost.cloudstream3.utils.AppContextUtils.isRtl\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport kotlinx.coroutines.delay\nimport kotlin.math.roundToInt\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.disableBackPressedCallback\nimport com.lagradost.cloudstream3.utils.BackPressedCallbackHelper.enableBackPressedCallback\n\nobject UIHelper {\n    val Int.toPx: Int get() = (this * Resources.getSystem().displayMetrics.density).toInt()\n    val Float.toPx: Float get() = (this * Resources.getSystem().displayMetrics.density)\n    val Int.toDp: Int get() = (this / Resources.getSystem().displayMetrics.density).toInt()\n    val Float.toDp: Float get() = (this / Resources.getSystem().displayMetrics.density)\n\n    fun Context.checkWrite(): Boolean {\n        return (ContextCompat.checkSelfPermission(\n            this,\n            Manifest.permission.WRITE_EXTERNAL_STORAGE\n        )\n                == PackageManager.PERMISSION_GRANTED\n                // Since Android 13, we can't request external storage permission,\n                // so don't check it.\n                || Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU)\n    }\n\n    fun populateChips(\n        view: ChipGroup?,\n        tags: List<String>,\n        @StyleRes style: Int = R.style.ChipFilled,\n        @AttrRes textColor: Int? = R.attr.white,\n    ) {\n        if (view == null) return\n        view.removeAllViews()\n        val context = view.context ?: return\n        val maxTags = tags.take(10) // Limited because they are too much\n\n        maxTags.forEach { tag ->\n            val chip = Chip(context)\n            val chipDrawable = ChipDrawable.createFromAttributes(\n                context,\n                null,\n                0,\n                style\n            )\n            chip.setChipDrawable(chipDrawable)\n            chip.text = tag\n            chip.isChecked = false\n            chip.isCheckable = false\n            chip.isFocusable = false\n            chip.isClickable = false\n            textColor?.let {\n                chip.setTextColor(context.colorFromAttribute(it))\n            }\n            view.addView(chip)\n        }\n    }\n\n    fun Activity.requestRW() {\n        ActivityCompat.requestPermissions(\n            this,\n            arrayOf(\n                Manifest.permission.WRITE_EXTERNAL_STORAGE,\n                Manifest.permission.READ_EXTERNAL_STORAGE,\n                Manifest.permission.MANAGE_EXTERNAL_STORAGE\n            ),\n            1337\n        )\n    }\n\n    fun clipboardHelper(label: UiText, text: CharSequence) {\n        val ctx = context ?: return\n        try {\n            ctx.let {\n                val clip = ClipData.newPlainText(label.asString(ctx), text)\n                val labelSuffix = txt(R.string.toast_copied).asString(ctx)\n                ctx.getSystemService<ClipboardManager>()?.setPrimaryClip(clip)\n\n                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {\n                    showToast(\"${label.asString(ctx)} $labelSuffix\")\n                }\n            }\n        } catch (t: Throwable) {\n            Log.e(\"ClipboardService\", \"$t\")\n            when (t) {\n                is SecurityException -> {\n                    showToast(R.string.clipboard_permission_error)\n                }\n\n                is TransactionTooLargeException -> {\n                    showToast(R.string.clipboard_too_large)\n                }\n\n                else -> {\n                    showToast(R.string.clipboard_unknown_error, LENGTH_LONG)\n                }\n            }\n        }\n    }\n\n    /**\n     * Sets ListView height dynamically based on the height of the items.\n     *\n     * @param listView to be resized\n     * @return true if the listView is successfully resized, false otherwise\n     */\n    fun setListViewHeightBasedOnItems(listView: ListView?) {\n        val listAdapter: ListAdapter = listView?.adapter ?: return\n        val numberOfItems: Int = listAdapter.count\n\n        // Get total height of all items.\n        var totalItemsHeight = 0\n        for (itemPos in 0 until numberOfItems) {\n            val item: View = listAdapter.getView(itemPos, null, listView)\n            item.measure(0, 0)\n            totalItemsHeight += item.measuredHeight\n        }\n\n        // Get total height of all item dividers.\n        val totalDividersHeight: Int = listView.dividerHeight *\n                (numberOfItems - 1)\n\n        // Set list height.\n        val params: ViewGroup.LayoutParams = listView.layoutParams\n        params.height = totalItemsHeight + totalDividersHeight\n        listView.layoutParams = params\n        listView.requestLayout()\n    }\n\n    fun Context.getSpanCount(isHorizontal:Boolean=false): Int {\n//        val compactView = false\n        val spanCountLandscape = if (isHorizontal) 3 else 6\n        val spanCountPortrait = if (isHorizontal) 2 else 3\n        val orientation = resources.configuration.orientation\n\n        return if (orientation == Configuration.ORIENTATION_LANDSCAPE) {\n            spanCountLandscape\n        } else spanCountPortrait\n    }\n\n    fun Fragment.hideKeyboard() {\n        activity?.window?.decorView?.clearFocus()\n        view?.let {\n            hideKeyboard(it)\n        }\n    }\n\n    fun View?.setAppBarNoScrollFlagsOnTV() {\n        if (isLayout(TV or EMULATOR)) {\n            this?.updateLayoutParams<AppBarLayout.LayoutParams> {\n                scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_NO_SCROLL\n            }\n        }\n    }\n\n    fun Activity.hideKeyboard() {\n        window?.decorView?.clearFocus()\n        this.findViewById<View>(android.R.id.content)?.rootView?.let {\n            hideKeyboard(it)\n        }\n    }\n\n    fun Activity?.navigate(\n        navigationId: Int,\n        args: Bundle? = null,\n        navOptions: NavOptions? = null // To control nav graph & manage back stack\n    ) {\n        val tag = \"NavComponent\"\n        if (this is FragmentActivity) {\n            try {\n                runOnUiThread {\n                    // Navigate using navigation ID\n                    val navHostFragment =\n                        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment\n                    Log.i(tag, \"Navigating to fragment: $navigationId\")\n                    navHostFragment?.navController?.navigate(navigationId, args, navOptions)\n                }\n            } catch (t: Throwable) {\n                logError(t)\n            }\n        }\n    }\n\n    // Open activities from an activity outside the nav graph\n    fun Context.openActivity(activity: Class<*>, args: Bundle? = null) {\n        val tag = \"NavComponent\"\n        try {\n            val intent = Intent(this, activity)\n            if (args != null) {\n                intent.putExtras(args)\n            }\n            Log.i(tag, \"Navigating to Activity: ${activity.simpleName}\")\n            startActivity(intent)\n        } catch (t: Throwable) {\n            logError(t)\n        }\n    }\n\n    /** If you want to call this from a BackPressedCallback, pass the name of the callback to temporarily disable it */\n    fun FragmentActivity.popCurrentPage(fromBackPressedCallback: String? = null) {\n        // Use the main looper handler to post actions on the main thread\n        main {\n            // Post the back press action to the main thread handler to ensure it executes\n            // after any currently pending UI updates or fragment transactions.\n            if (fromBackPressedCallback != null) {\n                disableBackPressedCallback(fromBackPressedCallback)\n            }\n            if (!supportFragmentManager.isStateSaved) {\n                // Get the top fragment from the back stack\n                Log.d(\"popFragment\", \"Destroying Fragment\")\n                // If the state is not saved, it's safe to perform the back press action.\n                onBackPressedDispatcher.onBackPressed()\n            } else {\n                // If the state is saved, retry the back press action after a slight delay.\n                // This gives the FragmentManager time to complete any ongoing state-saving\n                // operations or transactions, ensuring that we do not encounter an IllegalStateException.\n                delay(100)\n                if (!supportFragmentManager.isStateSaved) {\n                    Log.d(\"popFragment\", \"Destroying after delay\")\n                    onBackPressedDispatcher.onBackPressed()\n                }\n            }\n            if (fromBackPressedCallback != null) {\n                enableBackPressedCallback(fromBackPressedCallback)\n            }\n        }\n    }\n\n    @ColorInt\n    fun Context.getResourceColor(@AttrRes resource: Int, alphaFactor: Float = 1f): Int {\n        val color = colorFromAttribute(resource)\n        return if (alphaFactor < 1f) adjustAlpha(color, alphaFactor) else color\n    }\n\n    @ColorInt\n    fun Context.colorFromAttribute(@AttrRes attribute: Int): Int {\n        var color = 0\n        withStyledAttributes(attrs = intArrayOf(attribute)) {\n            color = getColor(0, 0)\n        }\n        return color\n    }\n\n    @ColorInt\n    fun adjustAlpha(@ColorInt color: Int, factor: Float): Int {\n        val alpha = (color.alpha * factor).roundToInt()\n        return Color.argb(alpha, color.red, color.green, color.blue)\n    }\n\n    var createPaletteAsyncCache: HashMap<String, Palette> = hashMapOf()\n    fun createPaletteAsync(url: String, bitmap: Bitmap, callback: (Palette) -> Unit) {\n        createPaletteAsyncCache[url]?.let { palette ->\n            callback.invoke(palette)\n            return\n        }\n        Palette.from(bitmap).generate { paletteNull ->\n            paletteNull?.let { palette ->\n                createPaletteAsyncCache[url] = palette\n                callback(palette)\n            }\n        }\n    }\n\n    fun Activity.hideSystemUI() {\n        // Enables regular immersive mode.\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            val controller = WindowCompat.getInsetsController(window, window.decorView)\n            controller.systemBarsBehavior =\n                WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE\n            controller.hide(WindowInsetsCompat.Type.systemBars())\n            return\n        }\n\n        // For \"lean back\" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.\n        // Or for \"sticky immersive,\" replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY\n        @Suppress(\"DEPRECATION\")\n        window.decorView.systemUiVisibility = (\n                View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY\n                        // Set the content to appear under the system bars so that the\n                        // content doesn't resize when the system bars hide and show.\n                        or View.SYSTEM_UI_FLAG_LAYOUT_STABLE\n                        or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION\n                        or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN\n                        // Hide the nav bar and status bar\n                        or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION\n                        or View.SYSTEM_UI_FLAG_FULLSCREEN\n                )\n    }\n\n    fun Activity.enableEdgeToEdgeCompat() {\n        // edge-to-edge is very buggy on earlier versions\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) return\n        WindowCompat.enableEdgeToEdge(window)\n    }\n\n    fun Activity.setNavigationBarColorCompat(@AttrRes resourceId: Int) {\n        // edge-to-edge handles this\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) return\n\n        @Suppress(\"DEPRECATION\")\n        window?.navigationBarColor = colorFromAttribute(resourceId)\n    }\n\n    fun Context.getStatusBarHeight(): Int {\n        if (isLayout(TV or EMULATOR)) {\n            return 0\n        }\n\n        var result = 0\n        val resourceId = resources.getIdentifier(\"status_bar_height\", \"dimen\", \"android\")\n        if (resourceId > 0) {\n            result = resources.getDimensionPixelSize(resourceId)\n        }\n        return result\n    }\n\n    fun fixPaddingStatusbarMargin(v: View?) {\n        if (v == null) return\n        val ctx = v.context ?: return\n\n        v.layoutParams = v.layoutParams.apply {\n            if (this is MarginLayoutParams) {\n                setMargins(\n                    v.marginLeft,\n                    v.marginTop + ctx.getStatusBarHeight(),\n                    v.marginRight,\n                    v.marginBottom\n                )\n            }\n        }\n    }\n\n    fun fixPaddingStatusbarView(v: View?) {\n        if (v == null) return\n        val ctx = v.context ?: return\n        val params = v.layoutParams\n        params.height = ctx.getStatusBarHeight()\n        v.layoutParams = params\n    }\n\n    fun fixSystemBarsPadding(\n        v: View,\n        @DimenRes heightResId: Int? = null,\n        @DimenRes widthResId: Int? = null,\n        padTop: Boolean = true,\n        padBottom: Boolean = true,\n        padLeft: Boolean = true,\n        padRight: Boolean = true,\n        overlayCutout: Boolean = true,\n        fixIme: Boolean = false\n    ) {\n        // edge-to-edge is very buggy on earlier versions so we just\n        // handle the status bar here instead.\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {\n            if (padTop) {\n                val ctx = v.context ?: return\n                v.updatePadding(top = ctx.getStatusBarHeight())\n            }\n            return\n        }\n\n        ViewCompat.setOnApplyWindowInsetsListener(v) { view, windowInsets ->\n            val leftCheck = if (view.isRtl()) padRight else padLeft\n            val rightCheck = if (view.isRtl()) padLeft else padRight\n\n            val insetTypes = WindowInsetsCompat.Type.systemBars() or\n                WindowInsetsCompat.Type.displayCutout() or\n                if (fixIme) WindowInsetsCompat.Type.ime() else 0\n\n            val insets = windowInsets.getInsets(insetTypes)\n\n            view.updatePadding(\n                left = if (leftCheck) insets.left else view.paddingLeft,\n                right = if (rightCheck) insets.right else view.paddingRight,\n                bottom = if (padBottom) insets.bottom else view.paddingBottom,\n                top = if (padTop) insets.top else view.paddingTop\n            )\n\n            heightResId?.let {\n                val heightPx = view.resources.getDimensionPixelSize(it)\n                view.updateLayoutParams {\n                    height = heightPx + insets.bottom\n                }\n            }\n\n            widthResId?.let {\n                val widthPx = view.resources.getDimensionPixelSize(it)\n                view.updateLayoutParams {\n                    val startInset = if (view.isRtl()) insets.right else insets.left\n                    width = if (startInset > 0) widthPx + startInset else widthPx\n                }\n            }\n\n            if (overlayCutout && isLayout(PHONE)) {\n                // Draw a black overlay over the cutout. We do this so that\n                // it doesn't use the fragment background. We want it to\n                // appear as if the screen actually ends at cutout.\n                val cutout = windowInsets.displayCutout\n                if (cutout != null) {\n                    val left = if (!leftCheck) 0 else cutout.safeInsetLeft\n                    val right = if (!rightCheck) 0 else cutout.safeInsetRight\n                    view.overlay.clear()\n                    if (left > 0 || right > 0) {\n                        view.overlay.add(\n                            CutoutOverlayDrawable(\n                                view,\n                                leftCutout = left,\n                                rightCutout = right\n                            )\n                        )\n                    }\n                }\n            }\n\n            WindowInsetsCompat.CONSUMED\n        }\n    }\n\n    fun Context.getNavigationBarHeight(): Int {\n        var result = 0\n        val resourceId = resources.getIdentifier(\"navigation_bar_height\", \"dimen\", \"android\")\n        if (resourceId > 0) {\n            result = resources.getDimensionPixelSize(resourceId)\n        }\n        return result\n    }\n\n    fun Context?.isBottomLayout(): Boolean {\n        if (this == null) return true\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        return settingsManager.getBoolean(getString(R.string.bottom_title_key), true)\n    }\n\n    fun Activity.changeStatusBarState(hide: Boolean) {\n        try {\n            if (hide) {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                    val controller = WindowCompat.getInsetsController(window, window.decorView)\n                    controller.hide(WindowInsetsCompat.Type.statusBars())\n                } else {\n                    @Suppress(\"DEPRECATION\")\n                    window.setFlags(\n                        WindowManager.LayoutParams.FLAG_FULLSCREEN,\n                        WindowManager.LayoutParams.FLAG_FULLSCREEN\n                    )\n                }\n            } else {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                    val controller = WindowCompat.getInsetsController(window, window.decorView)\n                    controller.show(WindowInsetsCompat.Type.statusBars())\n                } else {\n                    @Suppress(\"DEPRECATION\")\n                    window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)\n                }\n            }\n        } catch (t: Throwable) {\n            logError(t)\n        }\n    }\n\n    // Shows the system bars by removing all the flags\n    // except for the ones that make the content appear under the system bars.\n    fun Activity.showSystemUI() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            val controller = WindowCompat.getInsetsController(window, window.decorView)\n            if (isLayout(EMULATOR)) {\n                controller.show(WindowInsetsCompat.Type.navigationBars())\n                controller.hide(WindowInsetsCompat.Type.statusBars())\n            } else controller.show(WindowInsetsCompat.Type.systemBars())\n            return\n        }\n\n        @Suppress(\"DEPRECATION\")\n        window.decorView.systemUiVisibility =\n            (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)\n\n        changeStatusBarState(isLayout(EMULATOR))\n    }\n\n    fun hideKeyboard(view: View?) {\n        if (view == null) return\n\n        val inputMethodManager =\n            view.context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager?\n        inputMethodManager?.hideSoftInputFromWindow(view.windowToken, 0)\n    }\n\n    fun showInputMethod(view: View?) {\n        if (view == null) return\n        val inputMethodManager =\n            view.context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager?\n        inputMethodManager?.showSoftInput(view, 0)\n    }\n\n    fun Dialog?.dismissSafe(activity: Activity?) {\n        if (this?.isShowing == true && activity?.isFinishing == false) {\n            this.dismiss()\n        }\n    }\n\n    fun Dialog?.dismissSafe() {\n        if (this?.isShowing == true && activity?.isFinishing != true) {\n            this.dismiss()\n        }\n    }\n\n    /**id, stringRes */\n    @SuppressLint(\"RestrictedApi\")\n    fun View.popupMenuNoIcons(\n        items: List<Pair<Int, Int>>,\n        onMenuItemClick: MenuItem.() -> Unit,\n    ): PopupMenu {\n        val ctw = ContextThemeWrapper(context, R.style.PopupMenu)\n        val popup = PopupMenu(\n            ctw,\n            this,\n            Gravity.NO_GRAVITY,\n            androidx.appcompat.R.attr.actionOverflowMenuStyle,\n            0\n        )\n\n        items.forEach { (id, stringRes) ->\n            popup.menu.add(0, id, 0, stringRes)\n        }\n\n        (popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true)\n\n        popup.setOnMenuItemClickListener {\n            it.onMenuItemClick()\n            true\n        }\n\n        popup.show()\n        return popup\n    }\n\n    /**id, string */\n    @SuppressLint(\"RestrictedApi\")\n    fun View.popupMenuNoIconsAndNoStringRes(\n        items: List<Pair<Int, String>>,\n        onMenuItemClick: MenuItem.() -> Unit,\n    ): PopupMenu {\n        val ctw = ContextThemeWrapper(context, R.style.PopupMenu)\n        val popup = PopupMenu(\n            ctw,\n            this,\n            Gravity.NO_GRAVITY,\n            androidx.appcompat.R.attr.actionOverflowMenuStyle,\n            0\n        )\n\n        items.forEach { (id, string) ->\n            popup.menu.add(0, id, 0, string)\n        }\n\n        (popup.menu as? MenuBuilder)?.setOptionalIconsVisible(true)\n\n        popup.setOnMenuItemClickListener {\n            it.onMenuItemClick()\n            true\n        }\n\n        popup.show()\n        return popup\n    }\n}\n\nprivate class CutoutOverlayDrawable(\n    private val view: View,\n    private val leftCutout: Int,\n    private val rightCutout: Int,\n) : Drawable() {\n    private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {\n        color = Color.BLACK\n        style = Paint.Style.FILL\n    }\n\n    override fun draw(canvas: Canvas) {\n        if (leftCutout > 0) canvas.drawRect(\n            0f,\n            0f,\n            leftCutout.toFloat(),\n            view.height.toFloat(),\n            paint\n        )\n        if (rightCutout > 0) {\n            canvas.drawRect(\n                view.width - rightCutout.toFloat(),\n                0f, view.width.toFloat(),\n                view.height.toFloat(),\n                paint\n            )\n        }\n    }\n\n    override fun setAlpha(alpha: Int) {}\n    override fun setColorFilter(colorFilter: ColorFilter?) {}\n\n    @Suppress(\"OVERRIDE_DEPRECATION\")\n    override fun getOpacity() = PixelFormat.OPAQUE\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/Vector2.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport kotlin.math.sqrt\n\ndata class Vector2(val x : Float, val y : Float) {\n    operator fun minus(other: Vector2) = Vector2(x - other.x, y - other.y)\n    operator fun plus(other: Vector2) = Vector2(x + other.x, y + other.y)\n    operator fun times(other: Int) = Vector2(x * other, y * other)\n    override fun toString(): String = \"($x, $y)\"\n    fun distanceTo(other: Vector2) = (this - other).length\n    private val lengthSquared by lazy { x*x + y*y }\n    val length by lazy { sqrt(lengthSquared) }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadHelper.kt",
    "content": ""
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadFileManagement.kt",
    "content": "package com.lagradost.cloudstream3.utils.downloader\n\nimport android.content.Context\nimport android.net.Uri\nimport androidx.core.net.toUri\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.getFolderPrefix\nimport com.lagradost.cloudstream3.isEpisodeBased\nimport com.lagradost.safefile.MediaFileContentType\nimport com.lagradost.safefile.SafeFile\n\nobject DownloadFileManagement {\n    private const val RESERVED_CHARS = \"|\\\\?*<\\\":>+[]/\\'\"\n    internal fun sanitizeFilename(name: String, removeSpaces: Boolean = false): String {\n        var tempName = name\n        for (c in RESERVED_CHARS) {\n            tempName = tempName.replace(c, ' ')\n        }\n        if (removeSpaces) tempName = tempName.replace(\" \", \"\")\n        return tempName.replace(\"  \", \" \").trim(' ')\n    }\n\n    /**\n     * Used for getting video player subs.\n     * @return List of pairs for the files in this format: <Name, Uri>\n     * */\n    internal fun getFolder(\n        context: Context,\n        relativePath: String,\n        basePath: String?\n    ): List<Pair<String, Uri>>? {\n        val base = basePathToFile(context, basePath)\n        val folder =\n            base?.gotoDirectory(relativePath, createMissingDirectories = false) ?: return null\n\n        //if (folder.isDirectory() != false) return null\n\n        return folder.listFiles()\n            ?.mapNotNull { (it.name() ?: \"\") to (it.uri() ?: return@mapNotNull null) }\n    }\n\n    /**\n     * Turns a string to an UniFile. Used for stored string paths such as settings.\n     * Should only be used to get a download path.\n     * */\n    internal fun basePathToFile(context: Context, path: String?): SafeFile? {\n        return when {\n            path.isNullOrBlank() -> getDefaultDir(context)\n            path.startsWith(\"content://\") -> SafeFile.fromUri(context, path.toUri())\n            else -> SafeFile.fromFilePath(context, path)\n        }\n    }\n\n    /**\n     * Base path where downloaded things should be stored, changes depending on settings.\n     * Returns the file and a string to be stored for future file retrieval.\n     * UniFile.filePath is not sufficient for storage.\n     * */\n    internal fun Context.getBasePath(): Pair<SafeFile?, String?> {\n        val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)\n        val basePathSetting = settingsManager.getString(getString(R.string.download_path_key), null)\n        return basePathToFile(this, basePathSetting) to basePathSetting\n    }\n\n    internal fun getFileName(\n        context: Context,\n        metadata: DownloadObjects.DownloadEpisodeMetadata\n    ): String {\n        return getFileName(context, metadata.name, metadata.episode, metadata.season)\n    }\n\n    internal fun getFileName(\n        context: Context,\n        epName: String?,\n        episode: Int?,\n        season: Int?\n    ): String {\n        // kinda ugly ik\n        return sanitizeFilename(\n            if (epName == null) {\n                if (season != null) {\n                    \"${context.getString(R.string.season)} $season ${context.getString(R.string.episode)} $episode\"\n                } else {\n                    \"${context.getString(R.string.episode)} $episode\"\n                }\n            } else {\n                if (episode != null) {\n                    if (season != null) {\n                        \"${context.getString(R.string.season)} $season ${context.getString(R.string.episode)} $episode - $epName\"\n                    } else {\n                        \"${context.getString(R.string.episode)} $episode - $epName\"\n                    }\n                } else {\n                    epName\n                }\n            }\n        )\n    }\n\n\n    internal fun DownloadObjects.DownloadedFileInfo.toFile(context: Context): SafeFile? {\n        return basePathToFile(context, this.basePath)?.gotoDirectory(\n            relativePath,\n            createMissingDirectories = false\n        )\n            ?.findFile(displayName)\n    }\n\n    internal fun getFolder(currentType: TvType, titleName: String): String {\n        return if (currentType.isEpisodeBased()) {\n            val sanitizedFileName = sanitizeFilename(titleName)\n            \"${currentType.getFolderPrefix()}/$sanitizedFileName\"\n        } else currentType.getFolderPrefix()\n    }\n\n    /**\n     * Gets the default download path as an UniFile.\n     * Vital for legacy downloads, be careful about changing anything here.\n     *\n     * As of writing UniFile is used for everything but download directory on scoped storage.\n     * Special ContentResolver fuckery is needed for that as UniFile doesn't work.\n     * */\n    fun getDefaultDir(context: Context): SafeFile? {\n        // See https://www.py4u.net/discuss/614761\n        return SafeFile.fromMedia(\n            context, MediaFileContentType.Downloads\n        )\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadManager.kt",
    "content": "package com.lagradost.cloudstream3.utils.downloader\n\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.app.Notification\nimport android.app.PendingIntent\nimport android.content.Context\nimport android.content.Intent\nimport android.content.pm.PackageManager\nimport android.os.Build\nimport android.os.Build.VERSION.SDK_INT\nimport android.util.Log\nimport android.widget.Toast\nimport androidx.annotation.DrawableRes\nimport androidx.core.app.ActivityCompat\nimport androidx.core.app.NotificationCompat\nimport androidx.core.app.NotificationManagerCompat\nimport androidx.core.app.PendingIntentCompat\nimport androidx.core.net.toUri\nimport androidx.preference.PreferenceManager\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.BuildConfig\nimport com.lagradost.cloudstream3.CommonActivity.showToast\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.IDownloadableMinimum\nimport com.lagradost.cloudstream3.MainActivity\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.launchSafe\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.services.VideoDownloadService\nimport com.lagradost.cloudstream3.sortUrls\nimport com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO\nimport com.lagradost.cloudstream3.ui.player.LOADTYPE_INAPP_DOWNLOAD\nimport com.lagradost.cloudstream3.ui.player.RepoLinkGenerator\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper\nimport com.lagradost.cloudstream3.ui.player.source_priority.QualityDataHelper.getLinkPriority\nimport com.lagradost.cloudstream3.ui.result.ExtractorSubtitleLink\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment\nimport com.lagradost.cloudstream3.utils.AppContextUtils.createNotificationChannel\nimport com.lagradost.cloudstream3.utils.AppContextUtils.sortSubs\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE\nimport com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE\nimport com.lagradost.cloudstream3.utils.DataStore.getFolderName\nimport com.lagradost.cloudstream3.utils.DataStore.getKey\nimport com.lagradost.cloudstream3.utils.DataStore.removeKey\nimport com.lagradost.cloudstream3.utils.Event\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport com.lagradost.cloudstream3.utils.M3u8Helper2\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromTagToEnglishLanguageName\nimport com.lagradost.cloudstream3.utils.SubtitleUtils.deleteMatchingSubtitles\nimport com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getBasePath\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getDefaultDir\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getFileName\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getFolder\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.sanitizeFilename\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.toFile\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.CreateNotificationMetadata\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.DownloadEpisodeMetadata\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.DownloadItem\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.DownloadResumePackage\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.DownloadStatus\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.DownloadedFileInfo\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.DownloadedFileInfoResult\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.LazyStreamDownloadResponse\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.StreamData\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.DownloadQueueWrapper\nimport com.lagradost.cloudstream3.utils.downloader.DownloadUtils.appendAndDontOverride\nimport com.lagradost.cloudstream3.utils.downloader.DownloadUtils.cancel\nimport com.lagradost.cloudstream3.utils.downloader.DownloadUtils.downloadSubtitle\nimport com.lagradost.cloudstream3.utils.downloader.DownloadUtils.getEstimatedTimeLeft\nimport com.lagradost.cloudstream3.utils.downloader.DownloadUtils.getImageBitmapFromUrl\nimport com.lagradost.cloudstream3.utils.downloader.DownloadUtils.join\nimport com.lagradost.cloudstream3.utils.txt\nimport com.lagradost.safefile.SafeFile\nimport com.lagradost.safefile.closeQuietly\nimport kotlinx.coroutines.CancellationException\nimport kotlinx.coroutines.CoroutineScope\nimport kotlinx.coroutines.Dispatchers\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.async\nimport kotlinx.coroutines.awaitAll\nimport kotlinx.coroutines.cancel\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.flow.MutableStateFlow\nimport kotlinx.coroutines.flow.StateFlow\nimport kotlinx.coroutines.flow.update\nimport kotlinx.coroutines.isActive\nimport kotlinx.coroutines.launch\nimport kotlinx.coroutines.sync.Mutex\nimport kotlinx.coroutines.sync.withLock\nimport kotlinx.coroutines.withContext\nimport java.io.Closeable\nimport java.io.IOException\nimport java.io.OutputStream\n\nconst val DOWNLOAD_CHANNEL_ID = \"cloudstream3.general\"\nconst val DOWNLOAD_CHANNEL_NAME = \"Downloads\"\nconst val DOWNLOAD_CHANNEL_DESCRIPT = \"The download notification channel\"\n\nobject VideoDownloadManager {\n    fun maxConcurrentDownloads(context: Context): Int =\n        PreferenceManager.getDefaultSharedPreferences(context)\n            ?.getInt(context.getString(R.string.download_parallel_key), 3) ?: 3\n\n    private fun maxConcurrentConnections(context: Context): Int =\n        PreferenceManager.getDefaultSharedPreferences(context)\n            ?.getInt(context.getString(R.string.download_concurrent_key), 3) ?: 3\n\n    private val _currentDownloads: MutableStateFlow<Set<Int>> = MutableStateFlow(emptySet())\n    val currentDownloads: StateFlow<Set<Int>> = _currentDownloads\n\n    const val TAG = \"VDM\"\n    private const val DOWNLOAD_NOTIFICATION_TAG = \"FROM_DOWNLOADER\"\n\n    private const val USER_AGENT =\n        \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\"\n\n    @get:DrawableRes\n    val imgDone get() = R.drawable.rddone\n\n    @get:DrawableRes\n    val imgDownloading get() = R.drawable.rdload\n\n    @get:DrawableRes\n    val imgPaused get() = R.drawable.rdpause\n\n    @get:DrawableRes\n    val imgStopped get() = R.drawable.rderror\n\n    @get:DrawableRes\n    val imgError get() = R.drawable.rderror\n\n    @get:DrawableRes\n    val pressToPauseIcon get() = R.drawable.ic_baseline_pause_24\n\n    @get:DrawableRes\n    val pressToResumeIcon get() = R.drawable.ic_baseline_play_arrow_24\n\n    @get:DrawableRes\n    val pressToStopIcon get() = R.drawable.baseline_stop_24\n\n    enum class DownloadType {\n        IsPaused,\n        IsDownloading,\n        IsDone,\n        IsFailed,\n        IsStopped,\n        IsPending\n    }\n\n    enum class DownloadActionType {\n        Pause,\n        Resume,\n        Stop,\n    }\n\n\n    /** Invalid input, just skip to the next one as the same args will give the same error */\n    private val DOWNLOAD_INVALID_INPUT =\n        DownloadStatus(retrySame = false, tryNext = true, success = false)\n\n    /** no need to try any other mirror as we have downloaded the file */\n    private val DOWNLOAD_SUCCESS =\n        DownloadStatus(retrySame = false, tryNext = false, success = true)\n\n    /** the user pressed stop, so no need to download anything else */\n    private val DOWNLOAD_STOPPED =\n        DownloadStatus(retrySame = false, tryNext = false, success = true)\n\n    /** the process failed due to some reason, so we retry and also try the next mirror */\n    private val DOWNLOAD_FAILED = DownloadStatus(retrySame = true, tryNext = true, success = false)\n\n    /** bad config, skip all mirrors as every call to download will have the same bad config */\n    private val DOWNLOAD_BAD_CONFIG =\n        DownloadStatus(retrySame = false, tryNext = false, success = false)\n\n    const val KEY_RESUME_PACKAGES = \"download_resume_2\"\n    const val KEY_DOWNLOAD_INFO = \"download_info\"\n\n    /** A key to save all the downloads which have not yet started and those currently running, using [DownloadQueueWrapper]\n     * [KEY_RESUME_PACKAGES] can store keys which should not be automatically queued, unlike this key.\n     */\n    const val KEY_RESUME_IN_QUEUE = \"download_resume_queue_key\"\n//    private const val KEY_RESUME_QUEUE_PACKAGES = \"download_q_resume\"\n\n    val downloadStatus = HashMap<Int, DownloadType>()\n    val downloadStatusEvent = Event<Pair<Int, DownloadType>>()\n    val downloadDeleteEvent = Event<Int>()\n    val downloadEvent = Event<Pair<Int, DownloadActionType>>()\n    val downloadProgressEvent = Event<Triple<Int, Long, Long>>()\n//    val downloadQueue = LinkedList<DownloadResumePackage>()\n\n    private var hasCreatedNotChannel = false\n\n    private fun Context.createNotificationChannel() {\n        hasCreatedNotChannel = true\n\n        this.createNotificationChannel(\n            DOWNLOAD_CHANNEL_ID,\n            DOWNLOAD_CHANNEL_NAME,\n            DOWNLOAD_CHANNEL_DESCRIPT\n        )\n    }\n\n    fun cancelAllDownloadNotifications(context: Context) {\n        val manager = NotificationManagerCompat.from(context)\n        manager.activeNotifications.forEach { notification ->\n            if (notification.tag == DOWNLOAD_NOTIFICATION_TAG) {\n                manager.cancel(DOWNLOAD_NOTIFICATION_TAG, notification.id)\n            }\n        }\n    }\n\n\n    /**\n     * @param hlsProgress will together with hlsTotal display another notification if used, to lessen the confusion about estimated size.\n     * */\n    @SuppressLint(\"StringFormatInvalid\")\n    private suspend fun createDownloadNotification(\n        context: Context,\n        source: String?,\n        linkName: String?,\n        ep: DownloadEpisodeMetadata,\n        state: DownloadType,\n        progress: Long,\n        total: Long,\n        notificationCallback: (Int, Notification) -> Unit,\n        hlsProgress: Long? = null,\n        hlsTotal: Long? = null,\n        bytesPerSecond: Long\n    ): Notification? {\n        try {\n            if (total <= 0) return null// crash, invalid data\n\n            val builder = NotificationCompat.Builder(context, DOWNLOAD_CHANNEL_ID)\n                .setAutoCancel(true)\n                .setColorized(true)\n                .setOnlyAlertOnce(true)\n                .setShowWhen(false)\n                .setPriority(NotificationCompat.PRIORITY_DEFAULT)\n                .setColor(context.colorFromAttribute(R.attr.colorPrimary))\n                .setContentTitle(ep.mainName)\n                .setSmallIcon(\n                    when (state) {\n                        DownloadType.IsDone -> imgDone\n                        DownloadType.IsDownloading -> imgDownloading\n                        DownloadType.IsPaused -> imgPaused\n                        DownloadType.IsFailed -> imgError\n                        DownloadType.IsStopped -> imgStopped\n                        DownloadType.IsPending -> imgDownloading\n                    }\n                )\n\n            if (ep.sourceApiName != null) {\n                builder.setSubText(ep.sourceApiName)\n            }\n\n            if (source != null) {\n                val intent = Intent(context, MainActivity::class.java).apply {\n                    data = source.toUri()\n                    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK\n                }\n                val pendingIntent =\n                    PendingIntentCompat.getActivity(context, 0, intent, 0, false)\n                builder.setContentIntent(pendingIntent)\n            }\n\n            if (state == DownloadType.IsDownloading || state == DownloadType.IsPaused) {\n                builder.setProgress((total / 1000).toInt(), (progress / 1000).toInt(), false)\n            } else if (state == DownloadType.IsPending) {\n                builder.setProgress(0, 0, true)\n            }\n\n            val rowTwoExtra = if (ep.name != null) \" - ${ep.name}\\n\" else \"\"\n            val rowTwo = if (ep.season != null && ep.episode != null) {\n                \"${context.getString(R.string.season_short)}${ep.season}:${context.getString(R.string.episode_short)}${ep.episode}\" + rowTwoExtra\n            } else if (ep.episode != null) {\n                \"${context.getString(R.string.episode)} ${ep.episode}\" + rowTwoExtra\n            } else {\n                (ep.name ?: \"\") + \"\"\n            }\n            val downloadFormat = context.getString(R.string.download_format)\n\n            if (SDK_INT >= Build.VERSION_CODES.O) {\n                if (ep.poster != null) {\n                    val poster = withContext(Dispatchers.IO) {\n                        context.getImageBitmapFromUrl(ep.poster)\n                    }\n                    if (poster != null)\n                        builder.setLargeIcon(poster)\n                }\n\n                val progressPercentage: Long\n                val progressMbString: String\n                val totalMbString: String\n                val suffix: String\n\n                val mbFormat = \"%.1f MB\"\n\n                if (hlsProgress != null && hlsTotal != null) {\n                    progressPercentage = hlsProgress * 100 / hlsTotal\n                    progressMbString = hlsProgress.toString()\n                    totalMbString = hlsTotal.toString()\n                    suffix = \" - $mbFormat\".format(progress / 1000000f)\n                } else {\n                    progressPercentage = progress * 100 / total\n                    progressMbString = mbFormat.format(progress / 1000000f)\n                    totalMbString = mbFormat.format(total / 1000000f)\n                    suffix = \"\"\n                }\n\n                val mbPerSecondString =\n                    if (state == DownloadType.IsDownloading) {\n                        \" ($mbFormat/s)\".format(bytesPerSecond.toFloat() / 1000000f)\n                    } else \"\"\n\n                val remainingTime =\n                    if (state == DownloadType.IsDownloading) {\n                        getEstimatedTimeLeft(context, bytesPerSecond, progress, total)\n                    } else \"\"\n\n                val bigText =\n                    when (state) {\n                        DownloadType.IsDownloading, DownloadType.IsPaused -> {\n                            (if (linkName == null) \"\" else \"$linkName\\n\") + \"$rowTwo\\n$progressPercentage % ($progressMbString/$totalMbString)$suffix$mbPerSecondString $remainingTime\"\n                        }\n\n                        DownloadType.IsPending -> {\n                            (if (linkName == null) \"\" else \"$linkName\\n\") + rowTwo\n                        }\n\n                        DownloadType.IsFailed -> {\n                            downloadFormat.format(\n                                context.getString(R.string.download_failed),\n                                rowTwo\n                            )\n                        }\n\n                        DownloadType.IsDone -> {\n                            downloadFormat.format(context.getString(R.string.download_done), rowTwo)\n                        }\n\n                        DownloadType.IsStopped -> {\n                            downloadFormat.format(\n                                context.getString(R.string.download_canceled),\n                                rowTwo\n                            )\n                        }\n                    }\n\n                val bodyStyle = NotificationCompat.BigTextStyle()\n                bodyStyle.bigText(bigText)\n                builder.setStyle(bodyStyle)\n            } else {\n                val txt =\n                    when (state) {\n                        DownloadType.IsDownloading, DownloadType.IsPaused, DownloadType.IsPending -> {\n                            rowTwo\n                        }\n\n                        DownloadType.IsFailed -> {\n                            downloadFormat.format(\n                                context.getString(R.string.download_failed),\n                                rowTwo\n                            )\n                        }\n\n                        DownloadType.IsDone -> {\n                            downloadFormat.format(context.getString(R.string.download_done), rowTwo)\n                        }\n\n                        DownloadType.IsStopped -> {\n                            downloadFormat.format(\n                                context.getString(R.string.download_canceled),\n                                rowTwo\n                            )\n                        }\n                    }\n\n                builder.setContentText(txt)\n            }\n\n            if ((state == DownloadType.IsDownloading || state == DownloadType.IsPaused || state == DownloadType.IsPending) && SDK_INT >= Build.VERSION_CODES.O) {\n                val actionTypes: MutableList<DownloadActionType> = ArrayList()\n                // INIT\n                if (state == DownloadType.IsDownloading) {\n                    actionTypes.add(DownloadActionType.Pause)\n                    actionTypes.add(DownloadActionType.Stop)\n                }\n\n                if (state == DownloadType.IsPaused) {\n                    actionTypes.add(DownloadActionType.Resume)\n                    actionTypes.add(DownloadActionType.Stop)\n                }\n                if (state == DownloadType.IsPending) {\n                    actionTypes.add(DownloadActionType.Stop)\n                }\n\n                // ADD ACTIONS\n                for ((index, i) in actionTypes.withIndex()) {\n                    val actionResultIntent = Intent(context, VideoDownloadService::class.java)\n\n                    actionResultIntent.putExtra(\n                        \"type\", when (i) {\n                            DownloadActionType.Resume -> \"resume\"\n                            DownloadActionType.Pause -> \"pause\"\n                            DownloadActionType.Stop -> \"stop\"\n                        }\n                    )\n\n                    actionResultIntent.putExtra(\"id\", ep.id)\n\n                    val pending: PendingIntent = PendingIntent.getService(\n                        // BECAUSE episodes lying near will have the same id +1, index will give the same requested as the previous episode, *100000 fixes this\n                        context, (4337 + index * 1000000 + ep.id),\n                        actionResultIntent,\n                        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE\n                    )\n\n                    builder.addAction(\n                        NotificationCompat.Action(\n                            when (i) {\n                                DownloadActionType.Resume -> pressToResumeIcon\n                                DownloadActionType.Pause -> pressToPauseIcon\n                                DownloadActionType.Stop -> pressToStopIcon\n                            }, when (i) {\n                                DownloadActionType.Resume -> context.getString(R.string.resume)\n                                DownloadActionType.Pause -> context.getString(R.string.pause)\n                                DownloadActionType.Stop -> context.getString(R.string.cancel)\n                            }, pending\n                        )\n                    )\n                }\n            }\n\n            if (!hasCreatedNotChannel) {\n                context.createNotificationChannel()\n            }\n\n            val notification = builder.build()\n            notificationCallback(ep.id, notification)\n            with(NotificationManagerCompat.from(context)) {\n                // notificationId is a unique int for each notification that you must define\n                if (ActivityCompat.checkSelfPermission(\n                        context,\n                        Manifest.permission.POST_NOTIFICATIONS\n                    ) != PackageManager.PERMISSION_GRANTED\n                ) {\n                    return null\n                }\n                notify(DOWNLOAD_NOTIFICATION_TAG, ep.id, notification)\n            }\n            return notification\n        } catch (e: Exception) {\n            logError(e)\n            return null\n        }\n    }\n\n\n    @Throws(IOException::class)\n    fun setupStream(\n        context: Context,\n        name: String,\n        folder: String?,\n        extension: String,\n        tryResume: Boolean,\n    ): StreamData {\n        return setupStream(\n            context.getBasePath().first ?: getDefaultDir(context)\n            ?: throw IOException(\"Bad config\"),\n            name,\n            folder,\n            extension,\n            tryResume\n        )\n    }\n\n    /**\n     * Sets up the appropriate file and creates a data stream from the file.\n     * Used for initializing downloads and backups.\n     * */\n    @Throws(IOException::class)\n    fun setupStream(\n        baseFile: SafeFile,\n        name: String,\n        folder: String?,\n        extension: String,\n        tryResume: Boolean,\n    ): StreamData {\n        val displayName = getDisplayName(name, extension)\n\n        val subDir = baseFile.gotoDirectory(folder, createMissingDirectories = true)\n            ?: throw IOException(\"Cant create directory\")\n        val foundFile = subDir.findFile(displayName)\n\n        val (file, fileLength) = if (foundFile == null || foundFile.exists() != true) {\n            subDir.createFileOrThrow(displayName) to 0L\n        } else {\n            if (tryResume) {\n                foundFile to foundFile.lengthOrThrow()\n            } else {\n                foundFile.deleteOrThrow()\n                subDir.createFileOrThrow(displayName) to 0L\n            }\n        }\n\n        return StreamData(fileLength, file)\n    }\n\n    /** This class handles the notifications, as well as the relevant key */\n    data class DownloadMetaData(\n        private val id: Int?,\n        var bytesDownloaded: Long = 0,\n        var bytesWritten: Long = 0,\n\n        var totalBytes: Long? = null,\n\n        // notification metadata\n        private var lastUpdatedMs: Long = 0,\n        private var lastDownloadedBytes: Long = 0,\n        private val createNotificationCallback: (CreateNotificationMetadata) -> Unit,\n\n        private var internalType: DownloadType = DownloadType.IsPending,\n\n        // how many segments that we have downloaded\n        var hlsProgress: Int = 0,\n        // how many segments that exist\n        var hlsTotal: Int? = null,\n        // this is how many segments that has been written to the file\n        // will always be <= hlsProgress as we may keep some in a buffer\n        var hlsWrittenProgress: Int = 0,\n\n        // this is used for copy with metadata on how much we have downloaded for setKey\n        private var downloadFileInfoTemplate: DownloadedFileInfo? = null\n    ) : Closeable {\n        fun setResumeLength(length: Long) {\n            bytesDownloaded = length\n            bytesWritten = length\n            lastDownloadedBytes = length\n        }\n\n        val approxTotalBytes: Long\n            get() = totalBytes ?: hlsTotal?.let { total ->\n                (bytesDownloaded * (total / hlsProgress.toFloat())).toLong()\n            } ?: bytesDownloaded\n\n        private val isHLS get() = hlsTotal != null\n\n        private var stopListener: (() -> Unit)? = null\n\n        /** on cancel button pressed or failed invoke this once and only once */\n        fun setOnStop(callback: (() -> Unit)) {\n            stopListener = callback\n        }\n\n        fun removeStopListener() {\n            stopListener = null\n        }\n\n        private val downloadEventListener = { event: Pair<Int, DownloadActionType> ->\n            if (event.first == id) {\n                when (event.second) {\n                    DownloadActionType.Pause -> {\n                        type = DownloadType.IsPaused\n                    }\n\n                    DownloadActionType.Stop -> {\n                        type = DownloadType.IsStopped\n                        stopListener?.invoke()\n                        stopListener = null\n                    }\n\n                    DownloadActionType.Resume -> {\n                        type = DownloadType.IsDownloading\n                    }\n                }\n            }\n        }\n\n        private fun updateFileInfo() {\n            if (id == null) return\n            downloadFileInfoTemplate?.let { template ->\n                setKey(\n                    KEY_DOWNLOAD_INFO,\n                    id.toString(),\n                    template.copy(\n                        totalBytes = approxTotalBytes,\n                        extraInfo = if (isHLS) hlsWrittenProgress.toString() else null\n                    )\n                )\n            }\n        }\n\n        fun setDownloadFileInfoTemplate(template: DownloadedFileInfo) {\n            downloadFileInfoTemplate = template\n            updateFileInfo()\n        }\n\n        init {\n            if (id != null) {\n                downloadEvent += downloadEventListener\n            }\n        }\n\n        override fun close() {\n            // as we may need to resume hls downloads, we save the current written index\n            if (isHLS || totalBytes == null) {\n                updateFileInfo()\n            }\n            if (id != null) {\n                downloadEvent -= downloadEventListener\n                downloadStatus -= id\n            }\n            stopListener = null\n        }\n\n        var type\n            get() = internalType\n            set(value) {\n                internalType = value\n                notify()\n            }\n\n        fun onDelete() {\n            bytesDownloaded = 0\n            hlsWrittenProgress = 0\n            hlsProgress = 0\n            if (id != null)\n                downloadDeleteEvent(id)\n\n            //internalType = DownloadType.IsStopped\n            notify()\n        }\n\n        companion object {\n            const val UPDATE_RATE_MS: Long = 1000L\n        }\n\n        @JvmName(\"DownloadMetaDataNotify\")\n        private fun notify() {\n            // max 10 sec between notifications, min 0.1s, this is to stop div by zero\n            val dt = (System.currentTimeMillis() - lastUpdatedMs).coerceIn(100, 10000)\n\n            val bytesPerSecond =\n                ((bytesDownloaded - lastDownloadedBytes) * 1000L) / dt\n\n            lastDownloadedBytes = bytesDownloaded\n            lastUpdatedMs = System.currentTimeMillis()\n            try {\n                val bytes = approxTotalBytes\n\n                // notification creation\n                if (isHLS) {\n                    createNotificationCallback(\n                        CreateNotificationMetadata(\n                            internalType,\n                            bytesDownloaded,\n                            bytes,\n                            hlsTotal = hlsTotal?.toLong(),\n                            hlsProgress = hlsProgress.toLong(),\n                            bytesPerSecond = bytesPerSecond\n                        )\n                    )\n                } else {\n                    createNotificationCallback(\n                        CreateNotificationMetadata(\n                            internalType,\n                            bytesDownloaded,\n                            bytes,\n                            bytesPerSecond = bytesPerSecond\n                        )\n                    )\n                }\n\n                // as hls has an approx file size we want to update this metadata\n                if (isHLS) {\n                    updateFileInfo()\n                }\n\n                if (internalType == DownloadType.IsStopped || internalType == DownloadType.IsFailed) {\n                    stopListener?.invoke()\n                    stopListener = null\n                }\n\n                // push all events, this *should* not crash, TODO MUTEX?\n                if (id != null) {\n                    downloadStatus[id] = type\n                    downloadProgressEvent(Triple(id, bytesDownloaded, bytes))\n                    downloadStatusEvent(id to type)\n                }\n            } catch (t: Throwable) {\n                logError(t)\n                if (BuildConfig.DEBUG) {\n                    throw t\n                }\n            }\n        }\n\n        private fun checkNotification() {\n            if (lastUpdatedMs + UPDATE_RATE_MS > System.currentTimeMillis()) return\n            notify()\n        }\n\n\n        /** adds the length and pushes a notification if necessary */\n        fun addBytes(length: Long) {\n            bytesDownloaded += length\n            // we don't want to update the notification after it is paused,\n            // download progress may not stop directly when we \"pause\" it\n            if (type == DownloadType.IsDownloading) checkNotification()\n        }\n\n        fun addBytesWritten(length: Long) {\n            bytesWritten += length\n        }\n\n        /** adds the length + hsl progress and pushes a notification if necessary */\n        fun addSegment(length: Long) {\n            hlsProgress += 1\n            addBytes(length)\n        }\n\n        fun setWrittenSegment(segmentIndex: Int) {\n            hlsWrittenProgress = segmentIndex + 1\n            // in case of abort we need to save every written progress\n            updateFileInfo()\n        }\n    }\n\n\n    data class LazyStreamDownloadData(\n        private val url: String,\n        private val headers: Map<String, String>,\n        private val referer: String,\n        /** This specifies where chunk i starts and ends,\n         * bytes=${chuckStartByte[ i ]}-${chuckStartByte[ i+1 ] -1}\n         * where out of bounds => bytes=${chuckStartByte[ i ]}- */\n        private val chuckStartByte: LongArray,\n        val totalLength: Long?,\n        val downloadLength: Long?,\n        val chuckSize: Long,\n        val bufferSize: Int,\n        val isResumed: Boolean,\n    ) {\n        val size get() = chuckStartByte.size\n\n        /** returns what byte it has downloaded,\n         * so start at 10 and download 4 bytes = return 14\n         *\n         * the range is [startByte, endByte) to be able to do [a, b) [b, c) ect\n         *\n         * [a, null) will return inclusive to eof = [a, eof]\n         *\n         * throws an error if initial get request fails, can be specified as return startByte\n         * */\n        @Throws\n        private suspend fun resolve(\n            startByte: Long,\n            endByte: Long?,\n            callback: (suspend CoroutineScope.(LazyStreamDownloadResponse) -> Unit)\n        ): Long = withContext(Dispatchers.IO) {\n            var currentByte: Long = startByte\n            val stopAt = endByte ?: Long.MAX_VALUE\n            if (currentByte >= stopAt) return@withContext currentByte\n\n            val request = app.get(\n                url,\n                headers = headers + mapOf(\n                    // range header is inclusive so [startByte, endByte-1] = [startByte, endByte)\n                    // if nothing at end the server will continue until eof\n                    \"Range\" to \"bytes=$startByte-\" // ${endByte?.minus(1)?.toString() ?: \"\" }\n                ),\n                referer = referer,\n                verify = false\n            )\n            val requestStream = request.body.byteStream()\n\n            val buffer = ByteArray(bufferSize)\n            var read: Int\n\n            try {\n                while (requestStream.read(buffer, 0, bufferSize).also { read = it } >= 0) {\n                    val start = currentByte\n                    currentByte += read.toLong()\n\n                    // this stops overflow\n                    if (currentByte >= stopAt) {\n                        callback(LazyStreamDownloadResponse(buffer, start, stopAt))\n                        break\n                    } else {\n                        callback(LazyStreamDownloadResponse(buffer, start, currentByte))\n                    }\n                }\n            } catch (e: CancellationException) {\n                throw e\n            } catch (t: Throwable) {\n                logError(t)\n            } finally {\n                requestStream.closeQuietly()\n            }\n\n            return@withContext currentByte\n        }\n\n        /** retries the resolve n times and returns true if successful */\n        suspend fun resolveSafe(\n            index: Int,\n            retries: Int = 3,\n            callback: (suspend CoroutineScope.(LazyStreamDownloadResponse) -> Unit)\n        ): Boolean {\n            var start = chuckStartByte.getOrNull(index) ?: return false\n            val end = chuckStartByte.getOrNull(index + 1)\n\n            for (i in 0 until retries) {\n                try {\n                    // in case\n                    start = resolve(start, end, callback)\n                    // no end defined, so we don't care exactly where it ended\n                    if (end == null) return true\n                    // we have download more or exactly what we needed\n                    if (start >= end) return true\n                } catch (_: IllegalStateException) {\n                    return false\n                } catch (_: CancellationException) {\n                    return false\n                } catch (_: Throwable) {\n                    continue\n                }\n            }\n            return false\n        }\n    }\n\n    @Throws\n    suspend fun streamLazy(\n        url: String,\n        headers: Map<String, String>,\n        referer: String,\n        startByte: Long,\n        /** how many bytes every connection should be, by default it is 10 MiB */\n        chuckSize: Long = (1 shl 20) * 10,\n        /** maximum bytes in the buffer that responds */\n        bufferSize: Int = DEFAULT_BUFFER_SIZE,\n        /** how many bytes bytes it should require to use the parallel downloader instead,\n         * if we download a very small file we don't want it parallel */\n        maximumSmallSize: Long = chuckSize * 2\n    ): LazyStreamDownloadData {\n        // we don't want to make a separate connection for every 1kb\n        require(chuckSize > 1000)\n\n        val headRequest = app.head(url = url, headers = headers, referer = referer, verify = false)\n        var contentLength = headRequest.size\n        if (contentLength != null && contentLength <= 0) contentLength = null\n\n        val hasRangeSupport = when (headRequest.headers[\"Accept-Ranges\"]?.lowercase()?.trim()) {\n            // server has stated it has no support\n            \"none\" -> false\n            // server has stated it has support\n            \"bytes\" -> true\n            // if null or undefined (as bytes is the only range unit formally defined)\n            // If the get request returns partial content we support range\n            else -> {\n                headRequest.headers[\"Accept-Ranges\"]?.let { range ->\n                    Log.v(TAG, \"Unknown Accept-Ranges tag: $range\")\n                }\n                // as we don't poll the body this should be fine\n                val getRequest = app.get(\n                    url,\n                    headers = headers + mapOf(\n                        \"Range\" to \"bytes=0-${\n                            // we don't want to request more than the actual file\n                            // but also more than 0 bytes\n                            contentLength?.let { max ->\n                                minOf(maxOf(max - 1L, 3L), 1023L)\n                            } ?: 1023L\n                        }\"\n                    ),\n                    referer = referer,\n                    verify = false\n                )\n                // if head request did not work then we can just look for the size here too\n                // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range\n                if (contentLength == null) {\n                    contentLength =\n                        getRequest.headers[\"Content-Range\"]?.trim()?.lowercase()?.let { range ->\n                            // we only support \"bytes\" unit\n                            if (range.startsWith(\"bytes\")) {\n                                // may be '*' if unknown\n                                range.substringAfter(\"/\").toLongOrNull()\n                            } else {\n                                Log.v(TAG, \"Unknown Content-Range unit: $range\")\n                                null\n                            }\n                        }\n                }\n\n                // supports range if status is partial content https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206\n                getRequest.code == 206\n            }\n        }\n\n        Log.d(\n            TAG,\n            \"Starting stream with url=$url, startByte=$startByte, contentLength=$contentLength, hasRangeSupport=$hasRangeSupport\"\n        )\n\n        var downloadLength: Long? = null\n\n        val ranges = if (!hasRangeSupport) {\n            // is the equivalent of [0..EOF] as we cant resume, nor can parallelize it\n            downloadLength = contentLength\n            LongArray(1) { 0 }\n        } else if (contentLength == null || contentLength < maximumSmallSize) {\n            if (contentLength != null) {\n                downloadLength = contentLength - startByte\n            }\n            // is the equivalent of [startByte..EOF] as we don't know the size we can only do one\n            // connection\n            LongArray(1) { startByte }\n        } else {\n            downloadLength = contentLength - startByte\n            // div with ceiling as\n            // this makes the last part \"unknown ending\" and it will break at EOF\n            // so eg startByte = 0, downloadLength = 13, chuckSize = 10\n            // = LongArray(2) { 0, 10 } = [0,10) + [10..EOF]\n            LongArray(((downloadLength + chuckSize - 1) / chuckSize).toInt()) { idx ->\n                startByte + idx * chuckSize\n            }\n        }\n\n        return LazyStreamDownloadData(\n            url = url,\n            headers = headers,\n            referer = referer,\n            chuckStartByte = ranges,\n            downloadLength = downloadLength,\n            totalLength = contentLength,\n            chuckSize = chuckSize,\n            bufferSize = bufferSize,\n            // we have only resumed if we had a downloaded file and we can resume\n            isResumed = startByte > 0 && hasRangeSupport\n        )\n    }\n\n\n    /** download a file that consist of a single stream of data*/\n    suspend fun downloadThing(\n        context: Context,\n        link: IDownloadableMinimum,\n        name: String,\n        folder: String,\n        extension: String,\n        tryResume: Boolean,\n        parentId: Int?,\n        createNotificationCallback: (CreateNotificationMetadata) -> Unit,\n        parallelConnections: Int = 3,\n        /** how many bytes a valid file must be in bytes,\n         * this should be different for subtitles and video */\n        minimumSize: Long = 100\n    ): DownloadStatus = withContext(Dispatchers.IO) {\n        if (parallelConnections < 1) {\n            return@withContext DOWNLOAD_INVALID_INPUT\n        }\n\n        var fileStream: OutputStream? = null\n        //var requestStream: InputStream? = null\n        val metadata = DownloadMetaData(\n            totalBytes = 0,\n            bytesDownloaded = 0,\n            createNotificationCallback = createNotificationCallback,\n            id = parentId,\n        )\n        try {\n            // get the file path\n            val (baseFile, basePath) = context.getBasePath()\n            val displayName = getDisplayName(name, extension)\n            if (baseFile == null) return@withContext DOWNLOAD_BAD_CONFIG\n\n            // set up the download file\n            var stream = setupStream(baseFile, name, folder, extension, tryResume)\n\n            fileStream = stream.open()\n\n            metadata.setResumeLength(stream.startAt)\n            metadata.type = DownloadType.IsPending\n\n            val items = streamLazy(\n                url = link.url.replace(\" \", \"%20\"),\n                referer = link.referer,\n                startByte = stream.startAt,\n                headers = link.headers.appendAndDontOverride(\n                    mapOf(\n                        \"Accept-Encoding\" to \"identity\",\n                        \"accept\" to \"*/*\",\n                        \"user-agent\" to USER_AGENT,\n                        \"sec-ch-ua\" to \"\\\"Chromium\\\";v=\\\"91\\\", \\\" Not;A Brand\\\";v=\\\"99\\\"\",\n                        \"sec-fetch-mode\" to \"navigate\",\n                        \"sec-fetch-dest\" to \"video\",\n                        \"sec-fetch-user\" to \"?1\",\n                        \"sec-ch-ua-mobile\" to \"?0\",\n                    )\n                )\n            )\n\n            // too short file, treat it as a invalid link\n            if (items.totalLength != null && items.totalLength < minimumSize) {\n                fileStream.closeQuietly()\n                metadata.onDelete()\n                stream.delete()\n                return@withContext DOWNLOAD_INVALID_INPUT\n            }\n\n            // if we have an output stream that cant be resumed then we delete the entire file\n            // and set up the stream again\n            if (!items.isResumed && stream.startAt > 0) {\n                fileStream.closeQuietly()\n                stream.delete()\n                metadata.setResumeLength(0)\n                stream = setupStream(baseFile, name, folder, extension, false)\n                fileStream = stream.open()\n            }\n\n            metadata.totalBytes = items.totalLength\n            metadata.type = DownloadType.IsDownloading\n            metadata.setDownloadFileInfoTemplate(\n                DownloadedFileInfo(\n                    totalBytes = metadata.approxTotalBytes,\n                    relativePath = folder,\n                    displayName = displayName,\n                    basePath = basePath\n                )\n            )\n\n            val currentMutex = Mutex()\n            val current = (0 until items.size).iterator()\n\n            val fileMutex = Mutex()\n            // start to data\n            val pendingData: HashMap<Long, LazyStreamDownloadResponse> =\n                hashMapOf()\n\n            val fileChecker = launch(Dispatchers.IO) {\n                while (isActive) {\n                    if (stream.exists) {\n                        delay(5000)\n                        continue\n                    }\n                    fileMutex.withLock {\n                        metadata.type = DownloadType.IsStopped\n                    }\n                    break\n                }\n            }\n\n            val jobs = (0 until parallelConnections).map {\n                launch(Dispatchers.IO) {\n\n                    // @downloadexplanation\n                    // this may seem a bit complex but it more or less acts as a queue system\n                    // imagine we do the downloading [0,3] and it response in the order 0,2,3,1\n                    // file: [_,_,_,_] queue: [_,_,_,_] Initial condition\n                    // file: [X,_,_,_] queue: [_,_,_,_] + added 0 directly to file\n                    // file: [X,_,_,_] queue: [_,_,X,_] + added 2 to queue\n                    // file: [X,_,_,_] queue: [_,_,X,X] + added 3 to queue\n                    // file: [X,X,_,_] queue: [_,_,X,X] + added 1 directly to file\n                    // file: [X,X,X,X] queue: [_,_,_,_] write the queue and remove from it\n\n                    // note that this is a bit more complex compared to hsl as ever segment\n                    // will return several bytearrays, and is therefore chained by the byte\n                    // so every request has a front and back byte instead of an index\n                    // this *requires* that no gap exist due because of resolve\n                    val callback: (suspend CoroutineScope.(LazyStreamDownloadResponse) -> Unit) =\n                        callback@{ response ->\n                            if (!isActive) return@callback\n                            fileMutex.withLock {\n                                // wait until not paused\n                                while (metadata.type == DownloadType.IsPaused) delay(100)\n                                // if stopped then throw\n                                if (metadata.type == DownloadType.IsStopped || metadata.type == DownloadType.IsFailed) {\n                                    this.cancel()\n                                    return@callback\n                                }\n\n                                val responseSize = response.size\n                                metadata.addBytes(response.size)\n\n                                if (response.startByte == metadata.bytesWritten) {\n                                    // if we are first in the queue then write it directly\n                                    fileStream.write(\n                                        response.bytes,\n                                        0,\n                                        responseSize.toInt()\n                                    )\n                                    metadata.addBytesWritten(responseSize)\n                                } else {\n                                    // otherwise append to queue, we need to clone the bytes as they will be overridden otherwise\n                                    pendingData[response.startByte] =\n                                        response.copy(bytes = response.bytes.clone())\n                                }\n\n                                while (true) {\n                                    // remove the current queue start, so no possibility of\n                                    // while(true) { continue } in case size = 0, and removed extra\n                                    // garbage\n                                    val pending = pendingData.remove(metadata.bytesWritten) ?: break\n\n                                    val size = pending.size\n\n                                    fileStream.write(\n                                        pending.bytes,\n                                        0,\n                                        size.toInt()\n                                    )\n                                    metadata.addBytesWritten(size)\n                                }\n                            }\n                        }\n\n                    // this will take up the first available job and resolve\n                    while (true) {\n                        if (!isActive) return@launch\n                        fileMutex.withLock {\n                            if (metadata.type == DownloadType.IsStopped\n                                || metadata.type == DownloadType.IsFailed\n                            ) return@launch\n                        }\n\n                        // mutex just in case, we never want this to fail due to multithreading\n                        val index = currentMutex.withLock {\n                            if (!current.hasNext()) return@launch\n                            current.nextInt()\n                        }\n\n                        // in case something has gone wrong set to failed if the fail is not caused by\n                        // user cancellation\n                        if (!items.resolveSafe(index, callback = callback)) {\n                            fileMutex.withLock {\n                                if (metadata.type != DownloadType.IsStopped) {\n                                    metadata.type = DownloadType.IsFailed\n                                }\n                            }\n                            return@launch\n                        }\n                    }\n                }\n            }\n\n            // fast stop as the jobs may be in a slow request\n            metadata.setOnStop {\n                jobs.cancel()\n            }\n\n            jobs.join()\n            fileChecker.cancel()\n\n            // jobs are finished so we don't want to stop them anymore\n            metadata.removeStopListener()\n            if (!stream.exists) metadata.type = DownloadType.IsStopped\n\n            if (metadata.type == DownloadType.IsFailed) {\n                return@withContext DOWNLOAD_FAILED\n            }\n\n            if (metadata.type == DownloadType.IsStopped) {\n                // we need to close before delete\n                fileStream.closeQuietly()\n                metadata.onDelete()\n                stream.delete()\n                return@withContext DOWNLOAD_STOPPED\n            }\n\n            // in case the head request lies about content-size,\n            // then we don't want shit output\n            if (metadata.bytesDownloaded < minimumSize) {\n                // we need to close before delete\n                fileStream.closeQuietly()\n                metadata.onDelete()\n                stream.delete()\n                return@withContext DOWNLOAD_INVALID_INPUT\n            }\n\n            metadata.type = DownloadType.IsDone\n            return@withContext DOWNLOAD_SUCCESS\n        } catch (e: IOException) {\n            // some sort of IO error, this should not happened\n            // we just rethrow it\n            logError(e)\n            throw e\n        } catch (t: Throwable) {\n            // some sort of network error, will error\n\n            // note that when failing we don't want to delete the file,\n            // only user interaction has that power\n            metadata.type = DownloadType.IsFailed\n            return@withContext DOWNLOAD_FAILED\n        } finally {\n            fileStream?.closeQuietly()\n            //requestStream?.closeQuietly()\n            metadata.close()\n        }\n    }\n\n    private suspend fun downloadHLS(\n        context: Context,\n        link: ExtractorLink,\n        name: String,\n        folder: String,\n        parentId: Int?,\n        startIndex: Int?,\n        createNotificationCallback: (CreateNotificationMetadata) -> Unit,\n        parallelConnections: Int = 3\n    ): DownloadStatus = withContext(Dispatchers.IO) {\n        if (parallelConnections < 1) return@withContext DOWNLOAD_INVALID_INPUT\n\n        val metadata = DownloadMetaData(\n            createNotificationCallback = createNotificationCallback,\n            id = parentId\n        )\n        var fileStream: OutputStream? = null\n        try {\n            val extension = \"mp4\"\n\n            // the start .ts index\n            var startAt = startIndex ?: 0\n\n            // set up the file data\n            val (baseFile, basePath) = context.getBasePath()\n            if (baseFile == null) return@withContext DOWNLOAD_BAD_CONFIG\n\n            val displayName = getDisplayName(name, extension)\n            val stream =\n                setupStream(baseFile, name, folder, extension, startAt > 0)\n\n            if (!stream.resume) startAt = 0\n            fileStream = stream.open()\n\n            // push the metadata\n            metadata.setResumeLength(stream.startAt)\n            metadata.hlsProgress = startAt\n            metadata.hlsWrittenProgress = startAt\n            metadata.type = DownloadType.IsPending\n            metadata.setDownloadFileInfoTemplate(\n                DownloadedFileInfo(\n                    totalBytes = 0,\n                    relativePath = folder,\n                    displayName = displayName,\n                    basePath = basePath\n                )\n            )\n\n            // do the initial get request to fetch the segments\n            val m3u8 = M3u8Helper.M3u8Stream(\n                link.url, link.quality, link.headers.appendAndDontOverride(\n                    mapOf(\n                        \"Accept-Encoding\" to \"identity\",\n                        \"accept\" to \"*/*\",\n                        \"user-agent\" to USER_AGENT,\n                    ) + if (link.referer.isNotBlank()) mapOf(\"referer\" to link.referer) else emptyMap()\n                )\n            )\n\n            val items = M3u8Helper2.hslLazy(m3u8, selectBest = true, requireAudio = true)\n\n            metadata.hlsTotal = items.size\n            metadata.type = DownloadType.IsDownloading\n\n            val currentMutex = Mutex()\n            val current = (startAt until items.size).iterator()\n\n            val fileMutex = Mutex()\n            val pendingData: HashMap<Int, ByteArray> = hashMapOf()\n\n            val fileChecker = launch(Dispatchers.IO) {\n                while (isActive) {\n                    if (stream.exists) {\n                        delay(5000)\n                        continue\n                    }\n                    fileMutex.withLock {\n                        metadata.type = DownloadType.IsStopped\n                    }\n                    break\n                }\n            }\n\n            // see @downloadexplanation for explanation of this download strategy,\n            // this keeps all jobs working at all times,\n            // does several connections in parallel instead of a regular for loop to improve\n            // download speed\n            val jobs = (0 until parallelConnections).map {\n                launch(Dispatchers.IO) {\n                    while (true) {\n                        if (!isActive) return@launch\n                        fileMutex.withLock {\n                            if (metadata.type == DownloadType.IsStopped\n                                || metadata.type == DownloadType.IsFailed\n                            ) return@launch\n                        }\n\n                        // mutex just in case, we never want this to fail due to multithreading\n                        val index = currentMutex.withLock {\n                            if (!current.hasNext()) return@launch\n                            current.nextInt()\n                        }\n\n                        // in case something has gone wrong set to failed if the fail is not caused by\n                        // user cancellation\n                        val bytes = items.resolveLinkSafe(index) ?: run {\n                            fileMutex.withLock {\n                                if (metadata.type != DownloadType.IsStopped) {\n                                    metadata.type = DownloadType.IsFailed\n                                }\n                            }\n                            return@launch\n                        }\n\n                        fileMutex.withLock {\n                            try {\n                                // user pause\n                                while (metadata.type == DownloadType.IsPaused) delay(100)\n                                // if stopped then break to delete\n                                if (metadata.type == DownloadType.IsStopped || metadata.type == DownloadType.IsFailed || !isActive) return@launch\n\n                                val segmentLength = bytes.size.toLong()\n                                // send notification, no matter the actual write order\n                                metadata.addSegment(segmentLength)\n\n                                // directly write the bytes if you are first\n                                if (metadata.hlsWrittenProgress == index) {\n                                    fileStream.write(bytes)\n\n                                    metadata.addBytesWritten(segmentLength)\n                                    metadata.setWrittenSegment(index)\n                                } else {\n                                    // no need to clone as there will be no modification of this bytearray\n                                    pendingData[index] = bytes\n                                }\n\n                                // write the cached bytes submitted by other threads\n                                while (true) {\n                                    val cache =\n                                        pendingData.remove(metadata.hlsWrittenProgress) ?: break\n                                    val cacheLength = cache.size.toLong()\n\n                                    fileStream.write(cache)\n\n                                    metadata.addBytesWritten(cacheLength)\n                                    metadata.setWrittenSegment(metadata.hlsWrittenProgress)\n                                }\n                            } catch (t: Throwable) {\n                                // this is in case of write fail\n                                logError(t)\n                                if (metadata.type != DownloadType.IsStopped) {\n                                    metadata.type = DownloadType.IsFailed\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            // fast stop as the jobs may be in a slow request\n            metadata.setOnStop {\n                jobs.cancel()\n            }\n\n            jobs.join()\n            fileChecker.cancel()\n\n            metadata.removeStopListener()\n\n            if (!stream.exists) metadata.type = DownloadType.IsStopped\n\n            if (metadata.type == DownloadType.IsFailed) {\n                return@withContext DOWNLOAD_FAILED\n            }\n\n            if (metadata.type == DownloadType.IsStopped) {\n                // we need to close before delete\n                fileStream.closeQuietly()\n                metadata.onDelete()\n                stream.delete()\n                return@withContext DOWNLOAD_STOPPED\n            }\n\n            metadata.type = DownloadType.IsDone\n            return@withContext DOWNLOAD_SUCCESS\n        } catch (t: Throwable) {\n            logError(t)\n            metadata.type = DownloadType.IsFailed\n            return@withContext DOWNLOAD_FAILED\n        } finally {\n            fileStream?.closeQuietly()\n            metadata.close()\n        }\n    }\n\n    private fun getDisplayName(name: String, extension: String): String {\n        return \"$name.$extension\"\n    }\n\n    private suspend fun downloadSingleEpisode(\n        context: Context,\n        source: String?,\n        folder: String?,\n        ep: DownloadEpisodeMetadata,\n        link: ExtractorLink,\n        notificationCallback: (Int, Notification) -> Unit,\n        tryResume: Boolean = false,\n    ): DownloadStatus {\n        // no support for these file formats\n        if (link.type == ExtractorLinkType.MAGNET || link.type == ExtractorLinkType.TORRENT || link.type == ExtractorLinkType.DASH) {\n            return DOWNLOAD_INVALID_INPUT\n        }\n\n        val name = getFileName(context, ep)\n\n        // Make sure this is cancelled when download is done or cancelled.\n        val extractorJob = ioSafe {\n            if (link.extractorData != null) {\n                getApiFromNameNull(link.source)?.extractorVerifierJob(link.extractorData)\n            }\n        }\n\n        val callback: (CreateNotificationMetadata) -> Unit = { meta ->\n            main {\n                createDownloadNotification(\n                    context,\n                    source,\n                    link.name,\n                    ep,\n                    meta.type,\n                    meta.bytesDownloaded,\n                    meta.bytesTotal,\n                    notificationCallback,\n                    meta.hlsProgress,\n                    meta.hlsTotal,\n                    meta.bytesPerSecond\n                )\n            }\n        }\n\n        try {\n            when (link.type) {\n                ExtractorLinkType.M3U8 -> {\n                    val startIndex = if (tryResume) {\n                        context.getKey<DownloadedFileInfo>(\n                            KEY_DOWNLOAD_INFO,\n                            ep.id.toString(),\n                            null\n                        )?.extraInfo?.toIntOrNull()\n                    } else null\n\n                    return downloadHLS(\n                        context,\n                        link,\n                        name,\n                        folder ?: \"\",\n                        ep.id,\n                        startIndex,\n                        callback, parallelConnections = maxConcurrentConnections(context)\n                    )\n                }\n\n                ExtractorLinkType.VIDEO -> {\n                    return downloadThing(\n                        context,\n                        link,\n                        name,\n                        folder ?: \"\",\n                        \"mp4\",\n                        tryResume,\n                        ep.id,\n                        callback,\n                        parallelConnections = maxConcurrentConnections(context),\n                        /** We require at least 10 MB video files */\n                        minimumSize = (1 shl 20) * 10\n                    )\n                }\n\n                else -> throw IllegalArgumentException(\"Unsupported download type\")\n            }\n        } catch (_: Throwable) {\n            return DOWNLOAD_FAILED\n        } finally {\n            extractorJob.cancel()\n        }\n    }\n\n\n    fun getDownloadFileInfo(\n        context: Context,\n        id: Int,\n    ): DownloadedFileInfoResult? {\n        try {\n            val info =\n                context.getKey<DownloadedFileInfo>(KEY_DOWNLOAD_INFO, id.toString()) ?: return null\n            val file = info.toFile(context)\n\n            // only delete the key if the file is not found\n            if (file == null || file.exists() == false) {\n                return null\n            }\n\n            return DownloadedFileInfoResult(\n                file.lengthOrThrow(),\n                info.totalBytes,\n                file.uriOrThrow()\n            )\n        } catch (e: Exception) {\n            logError(e)\n            return null\n        }\n    }\n\n    fun deleteFilesAndUpdateSettings(\n        context: Context,\n        ids: Set<Int>,\n        scope: CoroutineScope,\n        onComplete: (Set<Int>) -> Unit = {}\n    ) {\n        scope.launchSafe(Dispatchers.IO) {\n            val deleteJobs = ids.map { id ->\n                async {\n                    id to deleteFileAndUpdateSettings(context, id)\n                }\n            }\n            val results = deleteJobs.awaitAll()\n\n            val (successfulResults, failedResults) = results.partition { it.second }\n            val successfulIds = successfulResults.map { it.first }.toSet()\n\n            if (failedResults.isNotEmpty()) {\n                failedResults.forEach { (id, _) ->\n                    // TODO show a toast if some failed?\n                    Log.e(\"FileDeletion\", \"Failed to delete file with ID: $id\")\n                }\n            } else {\n                Log.i(\"FileDeletion\", \"All files deleted successfully\")\n            }\n\n            onComplete.invoke(successfulIds)\n        }\n    }\n\n    private fun deleteFileAndUpdateSettings(context: Context, id: Int): Boolean {\n        val success = deleteFile(context, id)\n        if (success) context.removeKey(KEY_DOWNLOAD_INFO, id.toString())\n        return success\n    }\n\n    private fun deleteFile(context: Context, id: Int): Boolean {\n        val info =\n            context.getKey<DownloadedFileInfo>(KEY_DOWNLOAD_INFO, id.toString()) ?: return false\n        val file = info.toFile(context)\n\n        val isFileDeleted = file?.delete() == true || file?.exists() == false\n\n        if (isFileDeleted) {\n            deleteMatchingSubtitles(context, info)\n            downloadEvent.invoke(id to DownloadActionType.Stop)\n            downloadProgressEvent.invoke(Triple(id, 0, 0))\n            downloadStatusEvent.invoke(id to DownloadType.IsStopped)\n            downloadDeleteEvent.invoke(id)\n        }\n\n        return isFileDeleted\n    }\n\n    fun getDownloadResumePackage(context: Context, id: Int): DownloadResumePackage? {\n        return context.getKey(KEY_RESUME_PACKAGES, id.toString())\n    }\n\n    fun getDownloadQueuePackage(context: Context, id: Int): DownloadQueueWrapper? {\n        return context.getKey(KEY_RESUME_IN_QUEUE, id.toString())\n    }\n\n    fun getDownloadEpisodeMetadata(\n        episode: ResultEpisode,\n        titleName: String,\n        apiName: String,\n        currentPoster: String?,\n        currentIsMovie: Boolean,\n        tvType: TvType,\n    ): DownloadEpisodeMetadata {\n        return DownloadEpisodeMetadata(\n            episode.id,\n            episode.parentId,\n            sanitizeFilename(titleName),\n            apiName,\n            episode.poster ?: currentPoster,\n            episode.name,\n            if (currentIsMovie) null else episode.season,\n            if (currentIsMovie) null else episode.episode,\n            tvType,\n        )\n    }\n\n    class EpisodeDownloadInstance(\n        val context: Context,\n        val downloadQueueWrapper: DownloadQueueWrapper\n    ) {\n        private val TAG = \"EpisodeDownloadInstance\"\n        private var subtitleDownloadJob: Job? = null\n        private var downloadJob: Job? = null\n        private var linkLoadingJob: Job? = null\n\n        /** isCompleted just means the download should not be retried.\n         * It includes stopped by user AND completion of file download.\n         * */\n        var isCompleted = false\n            set(value) {\n                field = value\n                if (value) {\n                    removeKey(KEY_RESUME_IN_QUEUE, downloadQueueWrapper.id.toString())\n                    // Do not emit events when completed as it may also trigger on cancellation.\n\n\n                    // Force refresh the queue when completed.\n                    // May lead to some redundant calls, but ensures that the queue is always up to date.\n                    DownloadQueueManager.forceRefreshQueue()\n                }\n            }\n\n        /** Cancels all active jobs and sets instance to failed. */\n        fun cancelDownload() {\n            val cause = \"Cancel call from cancelDownload\"\n            this.subtitleDownloadJob?.cancel(cause)\n            this.linkLoadingJob?.cancel(cause)\n\n            // Should not cancel the download job, it may need to clean up itself.\n            // Better to send a status event using isStopped and let it cancel itself.\n            isCancelled = true\n        }\n\n        // Run to cancel ongoing work, delete partial work and refresh queue\n        private fun cleanup(status: DownloadType) {\n            removeKey(KEY_RESUME_IN_QUEUE, downloadQueueWrapper.id.toString())\n            val id = downloadQueueWrapper.id\n\n            // Delete subtitles on cancel\n            safe {\n                val info = context.getKey<DownloadedFileInfo>(KEY_DOWNLOAD_INFO, id.toString())\n                if (info != null) {\n                    deleteMatchingSubtitles(context, info)\n                }\n            }\n\n            downloadStatusEvent.invoke(Pair(id, status))\n            downloadStatus[id] = status\n            downloadEvent.invoke(Pair(id, DownloadActionType.Stop))\n\n            // Force refresh the queue when failed.\n            // May lead to some redundant calls, but ensures that the queue is always up to date.\n            DownloadQueueManager.forceRefreshQueue()\n        }\n\n        var isCancelled = false\n            set(value) {\n                val oldField = field\n                field = value\n\n                // Clean up cancelled work, but only once\n                if (value && !oldField) {\n                    cleanup(DownloadType.IsStopped)\n                }\n            }\n\n\n        /** This failure can be both downloader and user initiated.\n         * Do not automatically retry in case of failure. */\n        var isFailed = false\n            set(value) {\n                val oldField = field\n                field = value\n\n                // Clean up failed work, but only once\n                if (value && !oldField) {\n                    cleanup(DownloadType.IsFailed)\n                }\n            }\n\n        companion object {\n            private fun displayNotification(context: Context, id: Int, notification: Notification) {\n                safe {\n                    NotificationManagerCompat.from(context)\n                        .notify(DOWNLOAD_NOTIFICATION_TAG, id, notification)\n                }\n            }\n        }\n\n        private suspend fun downloadFromResume(\n            downloadResumePackage: DownloadResumePackage,\n            notificationCallback: (Int, Notification) -> Unit,\n        ) {\n            val item = downloadResumePackage.item\n            val id = item.ep.id\n            if (currentDownloads.value.contains(id)) { // IF IT IS ALREADY DOWNLOADING, RESUME IT\n                downloadEvent.invoke(id to DownloadActionType.Resume)\n                return\n            }\n\n            _currentDownloads.update { downloads ->\n                downloads + id\n            }\n\n            try {\n                for (index in (downloadResumePackage.linkIndex ?: 0) until item.links.size) {\n                    val link = item.links[index]\n                    val resume = downloadResumePackage.linkIndex == index\n\n                    setKey(\n                        KEY_RESUME_PACKAGES,\n                        id.toString(),\n                        DownloadResumePackage(item, index)\n                    )\n\n                    var connectionResult =\n                        downloadSingleEpisode(\n                            context,\n                            item.source,\n                            item.folder,\n                            item.ep,\n                            link,\n                            notificationCallback,\n                            resume\n                        )\n\n                    if (connectionResult.retrySame) {\n                        connectionResult = downloadSingleEpisode(\n                            context,\n                            item.source,\n                            item.folder,\n                            item.ep,\n                            link,\n                            notificationCallback,\n                            true\n                        )\n                    }\n\n                    if (connectionResult.success) { // SUCCESS\n                        isCompleted = true\n                        break\n                    } else if (!connectionResult.tryNext || index >= item.links.lastIndex) {\n                        isFailed = true\n                        break\n                    }\n                }\n            } catch (e: Exception) {\n                isFailed = true\n                logError(e)\n            } finally {\n                isFailed = !isCompleted\n                _currentDownloads.update { downloads ->\n                    downloads - id\n                }\n            }\n        }\n\n        private suspend fun startDownload(\n            info: DownloadItem?,\n            pkg: DownloadResumePackage?\n        ) {\n            try {\n                if (info != null) {\n                    getDownloadResumePackage(context, info.ep.id)?.let { dpkg ->\n                        downloadFromResume(dpkg) { id, notification ->\n                            displayNotification(context, id, notification)\n                        }\n                    } ?: run {\n                        if (info.links.isEmpty()) return\n                        downloadFromResume(\n                            DownloadResumePackage(info, null)\n                        ) { id, notification ->\n                            displayNotification(context, id, notification)\n                        }\n                    }\n                } else if (pkg != null) {\n                    downloadFromResume(pkg) { id, notification ->\n                        displayNotification(context, id, notification)\n                    }\n                }\n                return\n            } catch (e: Exception) {\n                isFailed = true\n                logError(e)\n                return\n            }\n        }\n\n        private suspend fun downloadFromResume() {\n            val resumePackage = downloadQueueWrapper.resumePackage ?: return\n            downloadFromResume(resumePackage) { id, notification ->\n                displayNotification(context, id, notification)\n            }\n        }\n\n        fun startDownload() {\n            Log.d(TAG, \"Starting download ${downloadQueueWrapper.id}\")\n            setKey(KEY_RESUME_IN_QUEUE, downloadQueueWrapper.id.toString(), downloadQueueWrapper)\n\n            ioSafe {\n                if (downloadQueueWrapper.resumePackage != null) {\n                    downloadFromResume()\n                    // Load links if they are not already loaded\n                } else if (downloadQueueWrapper.downloadItem != null && downloadQueueWrapper.downloadItem.links.isNullOrEmpty()) {\n                    downloadEpisodeWithoutLinks()\n                } else if (downloadQueueWrapper.downloadItem?.links != null) {\n                    downloadEpisodeWithLinks(\n                        sortUrls(downloadQueueWrapper.downloadItem.links.toSet()),\n                        downloadQueueWrapper.downloadItem.subs\n                    )\n                }\n            }\n        }\n\n        private fun downloadEpisodeWithLinks(\n            links: List<ExtractorLink>,\n            subs: List<SubtitleData>?\n        ) {\n            val downloadItem = downloadQueueWrapper.downloadItem ?: return\n            try {\n                // Prepare visual keys\n                setKey(\n                    DOWNLOAD_HEADER_CACHE,\n                    downloadItem.resultId.toString(),\n                    DownloadObjects.DownloadHeaderCached(\n                        apiName = downloadItem.apiName,\n                        url = downloadItem.resultUrl,\n                        type = downloadItem.resultType,\n                        name = downloadItem.resultName,\n                        poster = downloadItem.resultPoster,\n                        id = downloadItem.resultId,\n                        cacheTime = System.currentTimeMillis(),\n                    )\n                )\n                setKey(\n                    getFolderName(\n                        DOWNLOAD_EPISODE_CACHE,\n                        downloadItem.resultId.toString()\n                    ), // 3 deep folder for faster access\n                    downloadItem.episode.id.toString(),\n                    DownloadObjects.DownloadEpisodeCached(\n                        name = downloadItem.episode.name,\n                        poster = downloadItem.episode.poster,\n                        episode = downloadItem.episode.episode,\n                        season = downloadItem.episode.season,\n                        id = downloadItem.episode.id,\n                        parentId = downloadItem.resultId,\n                        score = downloadItem.episode.score,\n                        description = downloadItem.episode.description,\n                        cacheTime = System.currentTimeMillis(),\n                    )\n                )\n\n                val meta =\n                    getDownloadEpisodeMetadata(\n                        downloadItem.episode,\n                        downloadItem.resultName,\n                        downloadItem.apiName,\n                        downloadItem.resultPoster,\n                        downloadItem.isMovie,\n                        downloadItem.resultType\n                    )\n\n                val folder =\n                    getFolder(downloadItem.resultType, downloadItem.resultName)\n                val src = \"$DOWNLOAD_NAVIGATE_TO/${downloadItem.resultId}\"\n\n                // DOWNLOAD VIDEO\n                val info = DownloadItem(src, folder, meta, links)\n\n                this.downloadJob = ioSafe {\n                    startDownload(info, null)\n                }\n\n                // 1. Checks if the lang should be downloaded\n                // 2. Makes it into the download format\n                // 3. Downloads it as a .vtt file\n                this.subtitleDownloadJob = ioSafe {\n                    try {\n                        val downloadList = SubtitlesFragment.getDownloadSubsLanguageTagIETF()\n\n                        subs?.filter { subtitle ->\n                            downloadList.any { langTagIETF ->\n                                subtitle.languageCode == langTagIETF ||\n                                        subtitle.originalName.contains(\n                                            fromTagToEnglishLanguageName(\n                                                langTagIETF\n                                            ) ?: langTagIETF\n                                        )\n                            }\n                        }\n                            ?.map { ExtractorSubtitleLink(it.name, it.url, \"\", it.headers) }\n                            ?.take(3) // max subtitles download hardcoded (?_?)\n                            ?.forEach { link ->\n                                val fileName = getFileName(context, meta)\n                                downloadSubtitle(context, link, fileName, folder)\n                            }\n\n                    } catch (_: CancellationException) {\n                        val fileName = getFileName(context, meta)\n\n                        val info = DownloadedFileInfo(\n                            totalBytes = 0,\n                            relativePath = folder,\n                            displayName = fileName,\n                            basePath = context.getBasePath().second\n                        )\n\n                        deleteMatchingSubtitles(context, info)\n                    }\n                }\n            } catch (e: Exception) {\n                // The work is only failed if the job did not get started\n                if (this.downloadJob == null) {\n                    isFailed = true\n                }\n                logError(e)\n            }\n        }\n\n        private suspend fun downloadEpisodeWithoutLinks() {\n            val downloadItem = downloadQueueWrapper.downloadItem ?: return\n\n            val generator = RepoLinkGenerator(listOf(downloadItem.episode))\n            val currentLinks = mutableSetOf<ExtractorLink>()\n            val currentSubs = mutableSetOf<SubtitleData>()\n            val meta =\n                getDownloadEpisodeMetadata(\n                    downloadItem.episode,\n                    downloadItem.resultName,\n                    downloadItem.apiName,\n                    downloadItem.resultPoster,\n                    downloadItem.isMovie,\n                    downloadItem.resultType\n                )\n\n            createDownloadNotification(\n                context,\n                downloadItem.apiName,\n                txt(R.string.loading).asString(context),\n                meta,\n                DownloadType.IsPending,\n                0,\n                1,\n                { _, _ -> },\n                null,\n                null,\n                0\n            )?.let { linkLoadingNotification ->\n                displayNotification(context, downloadItem.episode.id, linkLoadingNotification)\n            }\n\n            linkLoadingJob = ioSafe {\n                generator.generateLinks(\n                    clearCache = false,\n                    sourceTypes = LOADTYPE_INAPP_DOWNLOAD,\n                    callback = {\n                        it.first?.let { link ->\n                            currentLinks.add(link)\n                        }\n                    },\n                    subtitleCallback = { sub ->\n                        currentSubs.add(sub)\n                    })\n            }\n\n            // Wait for link loading completion\n            linkLoadingJob?.join()\n\n            // Remove link loading notification\n            NotificationManagerCompat.from(context).cancel(DOWNLOAD_NOTIFICATION_TAG, downloadItem.episode.id)\n\n            if (linkLoadingJob?.isCancelled == true) {\n                // Same as if no links, but no toast.\n                // Cancelled link loading is presumed to be user initiated\n                isCancelled = true\n                return\n            } else if (currentLinks.isEmpty()) {\n                main {\n                    showToast(\n                        R.string.no_links_found_toast,\n                        Toast.LENGTH_SHORT\n                    )\n                }\n                isFailed = true\n                return\n            } else {\n                main {\n                    showToast(\n                        R.string.download_started,\n                        Toast.LENGTH_SHORT\n                    )\n                }\n            }\n\n            // Profiles should always contain a download type\n            val profile = QualityDataHelper.getProfiles().first { it.types.contains(\n                QualityDataHelper.QualityProfileType.Download)\n            }\n\n            val sortedLinks = currentLinks.sortedBy { link ->\n                // Negative, because the highest priority should be first\n                -getLinkPriority(profile.id, link)\n            }\n\n            downloadEpisodeWithLinks(\n                sortedLinks,\n                sortSubs(currentSubs),\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt",
    "content": "package com.lagradost.cloudstream3.utils.downloader\n\nimport android.net.Uri\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.services.DownloadQueueService\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.ui.result.ResultEpisode\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.safefile.SafeFile\nimport java.io.IOException\nimport java.io.OutputStream\nimport java.util.Objects\n\nobject DownloadObjects {\n    /** An item can either be something to resume or something new to start */\n    data class DownloadQueueWrapper(\n        @JsonProperty(\"resumePackage\") val resumePackage: DownloadResumePackage?,\n        @JsonProperty(\"downloadItem\") val downloadItem: DownloadQueueItem?,\n    ) {\n        init {\n            assert(resumePackage != null || downloadItem != null) {\n                \"ResumeID and downloadItem cannot both be null at the same time!\"\n            }\n        }\n\n        /** Loop through the current download instances to see if it is currently downloading. Also includes link loading. */\n        fun isCurrentlyDownloading(): Boolean {\n            return DownloadQueueService.downloadInstances.value.any { it.downloadQueueWrapper.id == this.id }\n        }\n\n        @JsonProperty(\"id\")\n        val id = resumePackage?.item?.ep?.id ?: downloadItem!!.episode.id\n\n        @JsonProperty(\"parentId\")\n        val parentId = resumePackage?.item?.ep?.parentId ?: downloadItem!!.episode.parentId\n    }\n\n    /** General data about the episode and show to start a download from. */\n    data class DownloadQueueItem(\n        @JsonProperty(\"episode\") val episode: ResultEpisode,\n        @JsonProperty(\"isMovie\") val isMovie: Boolean,\n        @JsonProperty(\"resultName\") val resultName: String,\n        @JsonProperty(\"resultType\") val resultType: TvType,\n        @JsonProperty(\"resultPoster\") val resultPoster: String?,\n        @JsonProperty(\"apiName\") val apiName: String,\n        @JsonProperty(\"resultId\") val resultId: Int,\n        @JsonProperty(\"resultUrl\") val resultUrl: String,\n        @JsonProperty(\"links\") val links: List<ExtractorLink>? = null,\n        @JsonProperty(\"subs\") val subs: List<SubtitleData>? = null,\n    ) {\n        fun toWrapper(): DownloadQueueWrapper {\n            return DownloadQueueWrapper(null, this)\n        }\n    }\n\n\n    abstract class DownloadCached(\n        @JsonProperty(\"id\") open val id: Int,\n    )\n\n    data class DownloadEpisodeCached(\n        @JsonProperty(\"name\") val name: String?,\n        @JsonProperty(\"poster\") val poster: String?,\n        @JsonProperty(\"episode\") val episode: Int,\n        @JsonProperty(\"season\") val season: Int?,\n        @JsonProperty(\"parentId\") val parentId: Int,\n        @JsonProperty(\"score\") var score: Score? = null,\n        @JsonProperty(\"description\") val description: String?,\n        @JsonProperty(\"cacheTime\") val cacheTime: Long,\n        override val id: Int,\n    ) : DownloadCached(id) {\n        @JsonProperty(\"rating\", access = JsonProperty.Access.WRITE_ONLY)\n        @Deprecated(\n            \"`rating` is the old scoring system, use score instead\",\n            replaceWith = ReplaceWith(\"score\"),\n            level = DeprecationLevel.ERROR\n        )\n        var rating: Int? = null\n            set(value) {\n                if (value != null) {\n                    @Suppress(\"DEPRECATION_ERROR\")\n                    score = Score.fromOld(value)\n                }\n            }\n    }\n\n    /** What to display to the user for a downloaded show/movie. Includes info such as name, poster and url */\n    data class DownloadHeaderCached(\n        @JsonProperty(\"apiName\") val apiName: String,\n        @JsonProperty(\"url\") val url: String,\n        @JsonProperty(\"type\") val type: TvType,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"poster\") val poster: String?,\n        @JsonProperty(\"cacheTime\") val cacheTime: Long,\n        override val id: Int,\n    ) : DownloadCached(id)\n\n    data class DownloadResumePackage(\n        @JsonProperty(\"item\") val item: DownloadItem,\n        /** Tills which link should get resumed */\n        @JsonProperty(\"linkIndex\") val linkIndex: Int?,\n    ) {\n        fun toWrapper(): DownloadQueueWrapper {\n            return DownloadQueueWrapper(this, null)\n        }\n    }\n\n    data class DownloadItem(\n        @JsonProperty(\"source\") val source: String?,\n        @JsonProperty(\"folder\") val folder: String?,\n        @JsonProperty(\"ep\") val ep: DownloadEpisodeMetadata,\n        @JsonProperty(\"links\") val links: List<ExtractorLink>,\n    )\n\n    /** Metadata for a specific episode and how to display it. */\n    data class DownloadEpisodeMetadata(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"parentId\") val parentId: Int,\n        @JsonProperty(\"mainName\") val mainName: String,\n        @JsonProperty(\"sourceApiName\") val sourceApiName: String?,\n        @JsonProperty(\"poster\") val poster: String?,\n        @JsonProperty(\"name\") val name: String?,\n        @JsonProperty(\"season\") val season: Int?,\n        @JsonProperty(\"episode\") val episode: Int?,\n        @JsonProperty(\"type\") val type: TvType?,\n    )\n\n\n    data class DownloadedFileInfo(\n        @JsonProperty(\"totalBytes\") val totalBytes: Long,\n        @JsonProperty(\"relativePath\") val relativePath: String,\n        @JsonProperty(\"displayName\") val displayName: String,\n        @JsonProperty(\"extraInfo\") val extraInfo: String? = null,\n        @JsonProperty(\"basePath\") val basePath: String? = null // null is for legacy downloads. See getBasePath()\n    )\n\n    data class DownloadedFileInfoResult(\n        @JsonProperty(\"fileLength\") val fileLength: Long,\n        @JsonProperty(\"totalBytes\") val totalBytes: Long,\n        @JsonProperty(\"path\") val path: Uri,\n    )\n\n\n    data class ResumeWatching(\n        @JsonProperty(\"parentId\") val parentId: Int,\n        @JsonProperty(\"episodeId\") val episodeId: Int?,\n        @JsonProperty(\"episode\") val episode: Int?,\n        @JsonProperty(\"season\") val season: Int?,\n        @JsonProperty(\"updateTime\") val updateTime: Long,\n        @JsonProperty(\"isFromDownload\") val isFromDownload: Boolean,\n    )\n\n\n    data class DownloadStatus(\n        /** if you should retry with the same args and hope for a better result */\n        val retrySame: Boolean,\n        /** if you should try the next mirror */\n        val tryNext: Boolean,\n        /** if the result is what the user intended */\n        val success: Boolean,\n    )\n\n\n    data class CreateNotificationMetadata(\n        val type: VideoDownloadManager.DownloadType,\n        val bytesDownloaded: Long,\n        val bytesTotal: Long,\n        val hlsProgress: Long? = null,\n        val hlsTotal: Long? = null,\n        val bytesPerSecond: Long\n    )\n\n    data class StreamData(\n        private val fileLength: Long,\n        val file: SafeFile,\n        //val fileStream: OutputStream,\n    ) {\n        @Throws(IOException::class)\n        fun open(): OutputStream {\n            return file.openOutputStreamOrThrow(resume)\n        }\n\n        @Throws(IOException::class)\n        fun openNew(): OutputStream {\n            return file.openOutputStreamOrThrow(false)\n        }\n\n        fun delete(): Boolean {\n            return file.delete() == true\n        }\n\n        val resume: Boolean get() = fileLength > 0L\n        val startAt: Long get() = if (resume) fileLength else 0L\n        val exists: Boolean get() = file.exists() == true\n    }\n\n\n    /** bytes have the size end-start where the byte range is [start,end)\n     * note that ByteArray is a pointer and therefore cant be stored without cloning it */\n    data class LazyStreamDownloadResponse(\n        val bytes: ByteArray,\n        val startByte: Long,\n        val endByte: Long,\n    ) {\n        val size get() = endByte - startByte\n\n        override fun toString(): String {\n            return \"$startByte->$endByte\"\n        }\n\n        override fun equals(other: Any?): Boolean {\n            if (other !is LazyStreamDownloadResponse) return false\n            return other.startByte == startByte && other.endByte == endByte\n        }\n\n        override fun hashCode(): Int {\n            return Objects.hash(startByte, endByte)\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadQueueManager.kt",
    "content": "package com.lagradost.cloudstream3.utils.downloader\n\nimport android.content.Context\nimport android.util.Log\nimport androidx.core.content.ContextCompat\nimport com.lagradost.cloudstream3.CloudStreamApp\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKeys\nimport com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey\nimport com.lagradost.cloudstream3.MainActivity.Companion.lastError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.plugins.PluginManager\nimport com.lagradost.cloudstream3.services.DownloadQueueService\nimport com.lagradost.cloudstream3.services.DownloadQueueService.Companion.downloadInstances\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.downloader.DownloadObjects.DownloadQueueWrapper\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_RESUME_IN_QUEUE\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.downloadStatus\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.downloadStatusEvent\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getDownloadFileInfo\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getDownloadQueuePackage\nimport com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getDownloadResumePackage\nimport kotlinx.coroutines.flow.MutableStateFlow\nimport kotlinx.coroutines.flow.StateFlow\nimport kotlinx.coroutines.flow.getAndUpdate\nimport kotlinx.coroutines.flow.update\nimport kotlinx.coroutines.flow.updateAndGet\n\n// 1. Put a download on the queue\n// 2. The queue manager starts a foreground service to handle the queue\n// 3. The service starts work manager jobs to handle the downloads?\nobject DownloadQueueManager {\n    private const val TAG = \"DownloadQueueManager\"\n    const val QUEUE_KEY = \"download_queue_key\"\n\n    /** Flow of all active queued download, no active downloads.\n     * This flow may see many changes, do not place expensive observers.\n     * downloadInstances is the flow keeping track of active downloads.\n     * @see com.lagradost.cloudstream3.services.DownloadQueueService.Companion.downloadInstances\n     */\n    private val _queue: MutableStateFlow<Array<DownloadQueueWrapper>> by lazy {\n        /** Persistent queue */\n        val currentValue = getKey<Array<DownloadQueueWrapper>>(QUEUE_KEY) ?: emptyArray()\n        MutableStateFlow(currentValue)\n    }\n\n    val queue: StateFlow<Array<DownloadQueueWrapper>> by lazy { _queue }\n\n    /** Start the queue, marks all queue objects as in progress.\n     * Note that this may run twice without the service restarting\n     * because MainActivity may be recreated. */\n    fun init(context: Context) {\n        ioSafe {\n            _queue.collect { queue ->\n                setKey(QUEUE_KEY, queue)\n            }\n        }\n\n        ioSafe startQueue@{\n            // Do not automatically start the queue if safe mode is activated.\n            if (PluginManager.isSafeMode()) {\n                // Prevent misleading UI\n                VideoDownloadManager.cancelAllDownloadNotifications(context)\n                return@startQueue\n            }\n\n            val resumeQueue =\n                getPreResumeIds().filterNot {\n                    VideoDownloadManager.currentDownloads.value.contains(it)\n                }\n                    .mapNotNull { id ->\n                        getDownloadResumePackage(context, id)?.toWrapper()\n                            ?: getDownloadQueuePackage(context, id)\n                    }\n\n            val newQueue = _queue.updateAndGet { localQueue ->\n                // Add resume packages to the first part of the queue, since they may have been removed from the queue when they started\n                (resumeQueue + localQueue).distinctBy { it.id }.toTypedArray()\n            }\n\n            // Once added to the queue they can be safely removed\n            removeKeys(KEY_RESUME_IN_QUEUE)\n\n            // Make sure the download buttons display a pending status\n            newQueue.forEach { obj ->\n                setQueueStatus(obj.id, VideoDownloadManager.DownloadType.IsPending)\n            }\n\n            if (newQueue.any()) {\n                startQueueService(context)\n            }\n        }\n    }\n\n    /** Downloads not yet started or in progress. */\n    private fun getPreResumeIds(): Set<Int> {\n        return getKeys(KEY_RESUME_IN_QUEUE)?.mapNotNull {\n            it.substringAfter(\"$KEY_RESUME_IN_QUEUE/\").toIntOrNull()\n        }?.toSet()\n            ?: emptySet()\n    }\n\n    /** Adds an object to the internal persistent queue. It does not re-add an existing item. @return true if successfully added  */\n    private fun add(downloadQueueWrapper: DownloadQueueWrapper): Boolean {\n        Log.d(TAG, \"Download added to queue: $downloadQueueWrapper\")\n        val newQueue = _queue.updateAndGet { localQueue ->\n            // Do not add the same episode twice\n            if (downloadQueueWrapper.isCurrentlyDownloading() || localQueue.any { it.id == downloadQueueWrapper.id }) {\n                return@updateAndGet localQueue\n            }\n            localQueue + downloadQueueWrapper\n        }\n        return newQueue.any { it.id == downloadQueueWrapper.id }\n    }\n\n    /** Removes all objects with the same id from the internal persistent queue */\n    private fun remove(id: Int) {\n        Log.d(TAG, \"Download removed from the queue: $id\")\n        _queue.update { localQueue ->\n            // The check is to prevent unnecessary updates\n            if (!localQueue.any { it.id == id }) {\n                return@update localQueue\n            }\n\n            localQueue.filter { it.id != id }.toTypedArray()\n        }\n    }\n\n    /** Removes all items and returns the previous queue */\n    private fun removeAll(): Array<DownloadQueueWrapper> {\n        Log.d(TAG, \"Removed everything from queue\")\n        return _queue.getAndUpdate {\n            emptyArray()\n        }\n    }\n\n    private fun reorder(downloadQueueWrapper: DownloadQueueWrapper, newPosition: Int) {\n        _queue.update { localQueue ->\n            val newIndex = newPosition.coerceIn(0, localQueue.size)\n            val id = downloadQueueWrapper.id\n\n            val newQueue = localQueue.filter { it.id != id }.toMutableList().apply {\n                this.add(newIndex, downloadQueueWrapper)\n            }.toTypedArray()\n\n            newQueue\n        }\n    }\n\n    /** Start a real download from the first item in the queue */\n    fun popQueue(context: Context): VideoDownloadManager.EpisodeDownloadInstance? {\n        val first = queue.value.firstOrNull() ?: return null\n\n        remove(first.id)\n\n        val downloadInstance = VideoDownloadManager.EpisodeDownloadInstance(context, first)\n\n        return downloadInstance\n    }\n\n    /** Marks the item as in queue for the download button */\n    private fun setQueueStatus(id: Int, status: VideoDownloadManager.DownloadType) {\n        downloadStatusEvent.invoke(\n            Pair(\n                id,\n                status\n            )\n        )\n        downloadStatus[id] = status\n    }\n\n    private fun startQueueService(context: Context?) {\n        if (context == null) {\n            Log.d(TAG, \"Cannot start download queue service, null context.\")\n            return\n        }\n        // Do not restart the download queue service\n        if (DownloadQueueService.isRunning) {\n            return\n        }\n        ioSafe {\n            val intent = DownloadQueueService.getIntent(context)\n            ContextCompat.startForegroundService(context, intent)\n        }\n    }\n\n    /** Cancels an active download or removes it from queue depending on where it is. */\n    fun cancelDownload(id: Int) {\n        Log.d(TAG, \"Cancelling download: $id\")\n\n        val currentInstance = downloadInstances.value.find { it.downloadQueueWrapper.id == id }\n\n        if (currentInstance != null) {\n            currentInstance.cancelDownload()\n        } else {\n            removeFromQueue(id)\n        }\n    }\n\n    /** Removes all queued items */\n    fun removeAllFromQueue() {\n        removeAll().forEach { wrapper ->\n            setQueueStatus(wrapper.id, VideoDownloadManager.DownloadType.IsStopped)\n        }\n    }\n\n    /** Removes all objects with the same id from the internal persistent queue  */\n    fun removeFromQueue(id: Int) {\n        ioSafe {\n            remove(id)\n            setQueueStatus(id, VideoDownloadManager.DownloadType.IsStopped)\n        }\n    }\n\n    /** Will move the download queue wrapper to a new position in the queue.\n     * If the item does not exist it will also insert it. */\n    fun reorderItem(downloadQueueWrapper: DownloadQueueWrapper, newPosition: Int) {\n        ioSafe {\n            reorder(downloadQueueWrapper, newPosition)\n        }\n    }\n\n    /** Add a new object to the queue. Will not queue completed downloads or current downloads. */\n    fun addToQueue(downloadQueueWrapper: DownloadQueueWrapper) = safe {\n        val context = CloudStreamApp.context ?: return@safe\n        val fileInfo = getDownloadFileInfo(context, downloadQueueWrapper.id)\n        val isComplete = fileInfo != null &&\n                // Assure no division by 0\n                fileInfo.totalBytes > 0 &&\n                // If more than 98% downloaded then do not add to queue\n                (fileInfo.fileLength.toFloat() / fileInfo.totalBytes.toFloat()) > 0.98f\n        // Do not queue completed files!\n        if (isComplete) return@safe\n\n        if (add(downloadQueueWrapper)) {\n            setQueueStatus(downloadQueueWrapper.id, VideoDownloadManager.DownloadType.IsPending)\n            startQueueService(context)\n        }\n    }\n\n\n    /** Refreshes the queue flow with the same value, but copied.\n     * Good to run if the downloads are affected by some outside value change. */\n    fun forceRefreshQueue() {\n        _queue.update { localQueue ->\n            localQueue.copyOf()\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadUtils.kt",
    "content": "package com.lagradost.cloudstream3.utils.downloader\n\nimport android.content.Context\nimport android.graphics.Bitmap\nimport androidx.core.graphics.drawable.toBitmap\nimport coil3.Extras\nimport coil3.SingletonImageLoader\nimport coil3.asDrawable\nimport coil3.request.ImageRequest\nimport coil3.request.SuccessResult\nimport com.lagradost.cloudstream3.R\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.ui.result.ExtractorSubtitleLink\nimport com.lagradost.cloudstream3.utils.Coroutines.ioSafe\nimport com.lagradost.cloudstream3.utils.UiText\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getFileName\nimport com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getFolder\nimport com.lagradost.cloudstream3.utils.txt\nimport kotlinx.coroutines.Job\nimport kotlinx.coroutines.runBlocking\n\n/** Separate object with helper functions for the downloader */\nobject DownloadUtils {\n    private val cachedBitmaps = hashMapOf<String, Bitmap>()\n    internal fun Context.getImageBitmapFromUrl(\n        url: String,\n        headers: Map<String, String>? = null\n    ): Bitmap? = safe {\n        if (cachedBitmaps.containsKey(url)) {\n            return@safe cachedBitmaps[url]\n        }\n\n        val imageLoader = SingletonImageLoader.get(this)\n\n        val request = ImageRequest.Builder(this)\n            .data(url)\n            .apply {\n                headers?.forEach { (key, value) ->\n                    extras[Extras.Key<String>(key)] = value\n                }\n            }\n            .build()\n\n        val bitmap = runBlocking {\n            val result = imageLoader.execute(request)\n            (result as? SuccessResult)?.image?.asDrawable(applicationContext.resources)\n                ?.toBitmap()\n        }\n\n        bitmap?.let {\n            cachedBitmaps[url] = it\n        }\n\n        return@safe bitmap\n    }\n\n    //calculate the time\n    internal fun getEstimatedTimeLeft(\n        context: Context,\n        bytesPerSecond: Long,\n        progress: Long,\n        total: Long\n    ): String {\n        if (bytesPerSecond <= 0) return \"\"\n        val timeInSec = (total - progress) / bytesPerSecond\n        val hrs = timeInSec / 3600\n        val mins = (timeInSec % 3600) / 60\n        val secs = timeInSec % 60\n        val timeFormated: UiText? = when {\n            hrs > 0 -> txt(\n                R.string.download_time_left_hour_min_sec_format,\n                hrs,\n                mins,\n                secs\n            )\n\n            mins > 0 -> txt(\n                R.string.download_time_left_min_sec_format,\n                mins,\n                secs\n            )\n\n            secs > 0 -> txt(\n                R.string.download_time_left_sec_format,\n                secs\n            )\n\n            else -> null\n        }\n        return timeFormated?.asString(context) ?: \"\"\n    }\n\n    internal fun downloadSubtitle(\n        context: Context?,\n        link: ExtractorSubtitleLink,\n        fileName: String,\n        folder: String\n    ) {\n        ioSafe {\n            VideoDownloadManager.downloadThing(\n                context ?: return@ioSafe,\n                link,\n                \"$fileName ${link.name}\",\n                folder,\n                if (link.url.contains(\".srt\")) \"srt\" else \"vtt\",\n                false,\n                null, createNotificationCallback = {}\n            )\n        }\n    }\n\n    fun downloadSubtitle(\n        context: Context?,\n        link: SubtitleData,\n        meta: DownloadObjects.DownloadEpisodeMetadata,\n    ) {\n        context?.let { ctx ->\n            val fileName = getFileName(ctx, meta)\n            val folder = getFolder(meta.type ?: return, meta.mainName)\n            downloadSubtitle(\n                ctx,\n                ExtractorSubtitleLink(link.name, link.url, \"\", link.headers),\n                fileName,\n                folder\n            )\n        }\n    }\n\n\n    /** Helper function to make sure duplicate attributes don't get overridden or inserted without lowercase cmp\n     * example: map(\"a\" to 1) appendAndDontOverride map(\"A\" to 2, \"a\" to 3, \"c\" to 4) = map(\"a\" to 1, \"c\" to 4)\n     * */\n    internal fun <V> Map<String, V>.appendAndDontOverride(rhs: Map<String, V>): Map<String, V> {\n        val out = this.toMutableMap()\n        val current = this.keys.map { it.lowercase() }\n        for ((key, value) in rhs) {\n            if (current.contains(key.lowercase())) continue\n            out[key] = value\n        }\n        return out\n    }\n\n    internal fun List<Job>.cancel() {\n        forEach { job ->\n            try {\n                job.cancel()\n            } catch (t: Throwable) {\n                logError(t)\n            }\n        }\n    }\n\n    internal suspend fun List<Job>.join() {\n        forEach { job ->\n            try {\n                job.join()\n            } catch (t: Throwable) {\n                logError(t)\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/widget/CenterZoomLayoutManager.kt",
    "content": "package com.lagradost.cloudstream3.widget\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport androidx.recyclerview.widget.LinearLayoutManager\nimport androidx.recyclerview.widget.LinearSnapHelper\nimport androidx.recyclerview.widget.RecyclerView\nimport com.lagradost.cloudstream3.mvvm.logError\nimport kotlin.math.abs\nimport kotlin.math.min\n\nclass CenterZoomLayoutManager : LinearLayoutManager {\n    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(\n        context, attrs, defStyleAttr, defStyleRes\n    )\n\n    constructor(context: Context?) : super(context)\n    constructor(context: Context?, orientation: Int, reverseLayout: Boolean) : super(\n        context,\n        orientation,\n        reverseLayout\n    )\n\n    private var itemListener: ((Int) -> Unit)? = null\n\n    // to not spam updates\n    private var lastViewIndex: Int? = null\n\n    private val mShrinkAmount = 0.15f\n    private val mShrinkDistance = 0.9f\n\n    fun updateSize(forceUpdate: Boolean = false) {\n        val midpoint = width / 2f\n        val d0 = 0f\n        val d1 = mShrinkDistance * midpoint\n        val s0 = 1f\n        val s1 = 1f - mShrinkAmount\n\n        var largestTag: Int? = null\n        var largestSize = 0f\n        for (i in 0 until childCount) {\n            getChildAt(i)?.let { child ->\n                try {\n                    val childMidpoint = (getDecoratedRight(child) + getDecoratedLeft(child)) / 2f\n                    val d = min(d1, abs(midpoint - childMidpoint))\n                    val scale = s0 + (s1 - s0) * (d - d0) / (d1 - d0)\n                    child.scaleX = scale\n                    child.scaleY = scale\n\n                    if (scale > largestSize) {\n                        (child.tag as Int?)?.let { tag ->\n                            largestSize = scale\n                            largestTag = tag\n                        }\n                    }\n                } catch (t : Throwable) {\n                    logError(t)\n                }\n            }\n        }\n\n        largestTag?.let { tag ->\n            if (lastViewIndex != tag || forceUpdate) {\n                lastViewIndex = tag\n                itemListener?.invoke(tag)\n            }\n        }\n    }\n\n    fun setOnSizeListener(listener: (Int) -> Unit) {\n        lastViewIndex = null\n        itemListener = listener\n    }\n\n    fun removeOnSizeListener() {\n        itemListener = null\n    }\n\n    override fun onLayoutCompleted(state: RecyclerView.State?) {\n        super.onLayoutCompleted(state)\n        if(waitForSnap != null) {\n            this.getChildAt(snapChild ?: 1)?.let { view ->\n                LinearSnapHelper().calculateDistanceToFinalSnap(this,view)?.get(0)?.let { dx ->\n                    waitForSnap?.invoke(dx)\n                    waitForSnap = null\n                }\n            }\n        }\n        updateSize()\n    }\n\n    private var waitForSnap : ((Int) -> Unit)? = null\n    private var snapChild : Int? = null\n\n    fun snap(snap : Int? = null, callback : (Int) -> Unit) {\n        waitForSnap = callback\n        snapChild = snap\n    }\n\n    override fun scrollHorizontallyBy(dx: Int, recycler: RecyclerView.Recycler, state: RecyclerView.State): Int {\n        val orientation = orientation\n        return if (orientation == HORIZONTAL) {\n            val scrolled = super.scrollHorizontallyBy(dx, recycler, state)\n            updateSize()\n            scrolled\n        } else {\n            0\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/widget/FlowLayout.kt",
    "content": "package com.lagradost.cloudstream3.widget\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.view.ViewGroup\nimport androidx.core.content.withStyledAttributes\nimport androidx.core.view.isVisible\nimport androidx.core.view.marginEnd\nimport com.lagradost.cloudstream3.R\nimport kotlin.math.max\n\nclass FlowLayout : ViewGroup {\n    var itemSpacing: Int = 0\n\n    constructor(context: Context?) : super(context)\n\n    //@JvmOverloads\n    //constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr)\n\n    @SuppressLint(\"CustomViewStyleable\")\n    internal constructor(c: Context, attrs: AttributeSet?) : super(c, attrs) {\n        c.withStyledAttributes(attrs, R.styleable.FlowLayout_Layout) {\n            itemSpacing = getDimensionPixelSize(R.styleable.FlowLayout_Layout_itemSpacing, 0)\n        }\n    }\n\n    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {\n        val realWidth = MeasureSpec.getSize(widthMeasureSpec)\n        var currentHeight = 0\n        var currentWidth = 0\n        var currentChildHookPointx = 0\n        var currentChildHookPointy = 0\n        val childCount = this.childCount\n        for (i in 0 until childCount) {\n            val child = getChildAt(i)\n            if (!child.isVisible) {\n                continue\n            }\n            measureChild(child, widthMeasureSpec, heightMeasureSpec)\n            val childWidth = child.measuredWidth\n            val childHeight = child.measuredHeight\n\n            //check if child can be placed in the current row, else go to next line\n            if (currentChildHookPointx + childWidth - child.marginEnd - child.paddingEnd > realWidth) {\n                //new line\n                currentWidth = max(currentWidth, currentChildHookPointx)\n\n                //reset for new line\n                currentChildHookPointx = 0\n                currentChildHookPointy += childHeight + itemSpacing\n            }\n\n            currentHeight = max(currentHeight, currentChildHookPointy + childHeight)\n            val nextChildHookPointx =\n                currentChildHookPointx + childWidth + if (childWidth == 0) 0 else itemSpacing\n\n            val nextChildHookPointy = currentChildHookPointy\n            val lp = child.layoutParams as LayoutParams\n            lp.x = currentChildHookPointx\n            lp.y = currentChildHookPointy\n            currentChildHookPointx = nextChildHookPointx\n            currentChildHookPointy = nextChildHookPointy\n        }\n        currentWidth = max(currentChildHookPointx, currentWidth)\n        setMeasuredDimension(\n            resolveSize(currentWidth, widthMeasureSpec),\n            resolveSize(currentHeight, heightMeasureSpec)\n        )\n    }\n\n    override fun onLayout(b: Boolean, left: Int, top: Int, right: Int, bottom: Int) {\n        //call layout on children\n        val childCount = this.childCount\n        for (i in 0 until childCount) {\n            val child = getChildAt(i)\n            val lp = child.layoutParams as LayoutParams\n            child.layout(lp.x, lp.y, lp.x + child.measuredWidth, lp.y + child.measuredHeight)\n        }\n    }\n\n    override fun generateLayoutParams(attrs: AttributeSet): LayoutParams {\n        return LayoutParams(context, attrs)\n    }\n\n    override fun generateDefaultLayoutParams(): LayoutParams {\n        return LayoutParams(\n            ViewGroup.LayoutParams.WRAP_CONTENT,\n            ViewGroup.LayoutParams.WRAP_CONTENT\n        )\n    }\n\n    override fun generateLayoutParams(p: ViewGroup.LayoutParams): LayoutParams {\n        return LayoutParams(p)\n    }\n\n    override fun checkLayoutParams(p: ViewGroup.LayoutParams): Boolean {\n        return p is LayoutParams\n    }\n\n    class LayoutParams : MarginLayoutParams {\n        var spacing = -1\n        var x = 0\n        var y = 0\n\n        @SuppressLint(\"CustomViewStyleable\")\n        internal constructor(c: Context, attrs: AttributeSet?) : super(c, attrs) {\n            c.withStyledAttributes(attrs, R.styleable.FlowLayout_Layout) {\n                spacing = 0\n            }\n        }\n\n        internal constructor(width: Int, height: Int) : super(width, height) {\n            spacing = 0\n        }\n\n        constructor(source: MarginLayoutParams?) : super(source)\n        internal constructor(source: ViewGroup.LayoutParams?) : super(source)\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/lagradost/cloudstream3/widget/LinearRecycleViewLayoutManager.kt",
    "content": "package com.lagradost.cloudstream3.widget\n\nimport android.content.Context\nimport android.view.View\nimport androidx.recyclerview.widget.LinearLayoutManager\n\nclass LinearRecycleViewLayoutManager(\n    val context: Context,\n    val nextFocusUp: Int,\n    val nextFocusDown: Int\n) : LinearLayoutManager(context) {\n    override fun onInterceptFocusSearch(focused: View, direction: Int): View? {\n        return try {\n            val position = getPosition(focused)\n            val count = itemCount\n            //println(\"onInterceptFocusSearch position=$position count=$count focused=$focused direction=$direction\")\n\n            (if (position == count - 1 && direction == View.FOCUS_DOWN) {\n                focused.rootView.findViewById(nextFocusDown)\n            } else if (position == 0 && direction == View.FOCUS_UP) {\n                focused.rootView.findViewById(nextFocusUp)\n            } else {\n                super.onInterceptFocusSearch(focused, direction)\n            }) ?: super.onInterceptFocusSearch(focused, direction)\n        } catch (t : Throwable)  {\n            super.onInterceptFocusSearch(focused, direction)\n        }\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/res/anim/enter_anim.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <scale\n            android:interpolator=\"@android:anim/linear_interpolator\"\n            android:duration=\"@integer/config_navAnimTime\"\n            android:fromXScale=\"0.9\"\n            android:toXScale=\"1.0\"\n            android:fromYScale=\"0.9\"\n            android:toYScale=\"1.0\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n    >\n    </scale>\n    <alpha\n            android:interpolator=\"@android:anim/linear_interpolator\"\n            android:duration=\"@integer/config_navAnimTime\"\n            android:fromAlpha=\"0.0\"\n            android:toAlpha=\"1.0\"/>\n</set>"
  },
  {
    "path": "app/src/main/res/anim/exit_anim.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <scale\n            android:interpolator=\"@android:anim/linear_interpolator\"\n            android:duration=\"@integer/config_navAnimTime\"\n            android:fromXScale=\"1.0\"\n            android:toXScale=\"0.9\"\n            android:fromYScale=\"1.0\"\n            android:toYScale=\"0.9\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n    >\n    </scale>\n    <alpha\n            android:interpolator=\"@android:anim/linear_interpolator\"\n            android:duration=\"@integer/config_navAnimTime\"\n            android:fromAlpha=\"1.0\"\n            android:toAlpha=\"0.0\"/>\n</set>"
  },
  {
    "path": "app/src/main/res/anim/go_left.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:interpolator=\"@android:anim/decelerate_interpolator\"\n>\n    <translate\n            android:fromXDelta=\"0%\"\n            android:toXDelta=\"-30%\"\n            android:duration=\"200\"\n    >\n    </translate>\n</set>"
  },
  {
    "path": "app/src/main/res/anim/go_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n     android:interpolator=\"@android:anim/decelerate_interpolator\"\n>\n    <translate\n            android:fromXDelta=\"0%\"\n            android:toXDelta=\"30%\"\n            android:duration=\"200\"\n    >\n    </translate>\n</set>"
  },
  {
    "path": "app/src/main/res/anim/pop_enter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <scale\n            android:interpolator=\"@android:anim/linear_interpolator\"\n            android:duration=\"@integer/config_navAnimTime\"\n            android:fromXScale=\"0.9\"\n            android:toXScale=\"1.0\"\n            android:fromYScale=\"0.9\"\n            android:toYScale=\"1.0\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n    >\n    </scale>\n    <alpha\n            android:interpolator=\"@android:anim/linear_interpolator\"\n            android:duration=\"@integer/config_navAnimTime\"\n            android:fromAlpha=\"0.0\"\n            android:toAlpha=\"1.0\"/>\n</set>"
  },
  {
    "path": "app/src/main/res/anim/pop_exit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <scale\n            android:interpolator=\"@android:anim/linear_interpolator\"\n            android:duration=\"@integer/config_navAnimTime\"\n            android:fromXScale=\"1.0\"\n            android:toXScale=\"0.9\"\n            android:fromYScale=\"1.0\"\n            android:toYScale=\"0.9\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n    >\n    </scale>\n    <alpha\n            android:interpolator=\"@android:anim/linear_interpolator\"\n            android:duration=\"@integer/config_navAnimTime\"\n            android:fromAlpha=\"1.0\"\n            android:toAlpha=\"0.0\"/>\n</set>"
  },
  {
    "path": "app/src/main/res/anim/rotate_around_center_point.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shareInterpolator=\"false\" >\n\n    <rotate\n        android:duration=\"4000\"\n        android:interpolator=\"@android:anim/linear_interpolator\"\n        android:pivotX=\"50%\"\n        android:pivotY=\"50%\"\n        android:repeatCount=\"infinite\"\n        android:repeatMode=\"restart\"\n        android:toDegrees=\"360\" />\n</set>"
  },
  {
    "path": "app/src/main/res/anim/rotate_left.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:interpolator=\"@android:anim/decelerate_interpolator\"\n>\n    <rotate android:fromDegrees=\"0\"\n            android:toDegrees=\"-90\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n            android:duration=\"50\"\n    />\n    <rotate android:fromDegrees=\"0\"\n            android:toDegrees=\"90\"\n            android:startOffset=\"50\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n            android:duration=\"50\"\n    />\n    <scale android:fromXScale=\"1.0\" android:fromYScale=\"0.9\"\n           android:toXScale=\"1.0\" android:toYScale=\"0.9\"\n           android:pivotX=\"50%\" android:pivotY=\"50%\"\n           android:duration=\"50\"/>\n    <scale android:fromXScale=\"0.9\" android:fromYScale=\"1\"\n           android:toXScale=\"0.9\" android:toYScale=\"1\"\n           android:pivotX=\"50%\" android:pivotY=\"50%\"\n           android:duration=\"50\" android:startOffset=\"50\"/>\n</set>"
  },
  {
    "path": "app/src/main/res/anim/rotate_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:interpolator=\"@android:anim/decelerate_interpolator\"\n>\n    <rotate android:fromDegrees=\"0\"\n            android:toDegrees=\"90\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n            android:duration=\"50\"\n    />\n    <rotate android:fromDegrees=\"0\"\n            android:toDegrees=\"-90\"\n            android:startOffset=\"50\"\n            android:pivotX=\"50%\"\n            android:pivotY=\"50%\"\n            android:duration=\"50\"\n    />\n    <scale android:fromXScale=\"1.0\" android:fromYScale=\"0.9\"\n           android:toXScale=\"1.0\" android:toYScale=\"0.9\"\n           android:pivotX=\"50%\" android:pivotY=\"50%\"\n           android:duration=\"50\"/>\n    <scale android:fromXScale=\"0.9\" android:fromYScale=\"1\"\n           android:toXScale=\"0.9\" android:toYScale=\"1\"\n           android:pivotX=\"50%\" android:pivotY=\"50%\"\n           android:duration=\"50\" android:startOffset=\"50\"/>\n</set>"
  },
  {
    "path": "app/src/main/res/color/black_button_ripple.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\r\n    <item android:color=\"@color/transparent\" android:state_focused=\"true\" />\r\n    <item android:color=\"?attr/textColor\" />\r\n</selector>"
  },
  {
    "path": "app/src/main/res/color/button_selector_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_selected=\"true\" android:state_focused=\"true\" android:color=\"@color/black\"/>\n    <item android:state_selected=\"true\" android:state_focused=\"false\" android:color=\"@color/white\"/>\n    <item android:color=\"@color/transparent\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/check_selection_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_activated=\"true\" android:color=\"?attr/textColor\"/>\n    <item android:color=\"@color/transparent\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/chip_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"?attr/colorPrimary\" android:state_checked=\"true\"/>\n    <item android:color=\"?attr/primaryGrayBackground\" android:state_checked=\"false\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/chip_color_text.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"?attr/colorOnPrimary\" android:state_checked=\"true\"/>\n    <item android:color=\"?attr/textColor\" android:state_checked=\"false\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/color_primary_transparent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\r\n    <item android:color=\"?attr/colorPrimary\" android:alpha=\"0.2\"  />\r\n</selector>\r\n"
  },
  {
    "path": "app/src/main/res/color/item_select_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"?attr/colorPrimary\" android:state_checked=\"true\"/>\n    <item android:color=\"?attr/colorPrimary\" android:state_focused=\"true\"/>\n    <item android:color=\"?attr/colorPrimary\" android:state_selected=\"true\"/>\n    <item android:color=\"?attr/textColor\" android:state_checked=\"false\"/>\n</selector>\n"
  },
  {
    "path": "app/src/main/res/color/item_select_color_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\r\n    <item android:color=\"?attr/primaryGrayBackground\" android:state_checked=\"true\"/>\r\n    <item android:color=\"?attr/white\" android:state_checked=\"false\"/>\r\n</selector>\r\n"
  },
  {
    "path": "app/src/main/res/color/player_button_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\" android:color=\"#FFFFFF\"/>\n    <item android:color=\"#33FFFFFF\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/player_on_button_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\" android:color=\"@color/black\"/>\n    <item android:color=\"@color/white\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/player_on_button_tv_attr.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\" android:color=\"?attr/black\"/>\n    <item android:color=\"?attr/white\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/selectable_black.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_selected=\"true\" android:color=\"?attr/iconGrayBackground\" />\n    <item android:color=\"?attr/textColor\" />\n</selector>"
  },
  {
    "path": "app/src/main/res/color/selectable_white.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_selected=\"true\" android:color=\"?attr/textColor\"/>\n    <item android:color=\"?attr/iconGrayBackground\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/tag_stroke_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n  <item android:color=\"?attr/colorPrimary\" android:state_checked=\"true\"/>\n  <item android:color=\"?attr/colorPrimary\" android:state_focused=\"true\"/>\n  <item android:alpha=\"0.12\" android:color=\"?attr/colorOnSurface\" android:state_checked=\"false\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/text_selection_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_activated=\"true\" android:color=\"?attr/textColor\"/>\n    <item android:color=\"?attr/grayTextColor\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/toggle_button.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_selected=\"true\" android:color=\"?attr/colorPrimaryDark\"/>\n    <item android:color=\"@color/transparent\"/>\n</selector>\n"
  },
  {
    "path": "app/src/main/res/color/toggle_button_outline.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_selected=\"true\" android:color=\"?attr/colorPrimary\"/>\n    <item android:color=\"?attr/iconColor\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/toggle_button_text.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_selected=\"true\" android:color=\"@color/white\"/>\n    <item android:color=\"?attr/textColor\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/toggle_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_checked=\"true\" android:color=\"?attr/colorPrimaryDark\"/>\n    <item android:color=\"?attr/grayTextColor\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/color/white_attr_20.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"?attr/white\" android:alpha=\"0.2\" />\n</selector>"
  },
  {
    "path": "app/src/main/res/color/white_transparent_toggle.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\" android:color=\"?attr/white\"/>\n    <item android:color=\"@color/transparent\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/arrow_and_edge_24px.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M480,840L320,680L376,624L440,687L440,520Q440,487 416.5,463.5Q393,440 360,440L120,440Q87,440 63.5,416.5Q40,393 40,360L40,120L120,120L120,360Q120,360 120,360Q120,360 120,360L360,360Q396,360 427,374.5Q458,389 480,414Q502,389 533,374.5Q564,360 600,360L840,360Q840,360 840,360Q840,360 840,360L840,120L920,120L920,360Q920,393 896.5,416.5Q873,440 840,440L600,440Q567,440 543.5,463.5Q520,487 520,520L520,687L583,624L640,680L480,840Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/arrow_or_edge_24px.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M300,840L140,680L196,624L260,687L260,440Q260,440 260,440Q260,440 260,440L120,440Q87,440 63.5,416.5Q40,393 40,360L40,120L120,120L120,360Q120,360 120,360Q120,360 120,360L260,360Q293,360 316.5,383.5Q340,407 340,440L340,687L403,624L460,680L300,840ZM660,840L500,680L556,624L620,687L620,440Q620,407 643.5,383.5Q667,360 700,360L840,360Q840,360 840,360Q840,360 840,360L840,120L920,120L920,360Q920,393 896.5,416.5Q873,440 840,440L700,440Q700,440 700,440Q700,440 700,440L700,688L763,624L820,680L660,840Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/arrows_input_24px.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M156,860L100,804L224,680L120,680L120,600L360,600L360,840L280,840L280,736L156,860ZM804,860L680,736L680,840L600,840L600,600L840,600L840,680L736,680L860,804L804,860ZM120,360L120,280L224,280L100,156L156,100L280,224L280,120L360,120L360,360L120,360ZM600,360L600,120L680,120L680,224L804,100L860,156L736,280L840,280L840,360L600,360ZM480,560Q447,560 423.5,536.5Q400,513 400,480Q400,447 423.5,423.5Q447,400 480,400Q513,400 536.5,423.5Q560,447 560,480Q560,513 536.5,536.5Q513,560 480,560Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/background_shadow.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n            android:angle=\"-90\"\n            android:startColor=\"@color/transparent\"\n            android:endColor=\"?attr/primaryBlackBackground\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/baseline_description_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM16,18L8,18v-2h8v2zM16,14L8,14v-2h8v2zM13,9L13,3.5L18.5,9L13,9z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_downloading_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\" android:height=\"24dp\" android:tint=\"#000000\" android:viewportHeight=\"24\" android:viewportWidth=\"24\" android:width=\"24dp\">\n      \n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M18.32,4.26C16.84,3.05 15.01,2.25 13,2.05v2.02c1.46,0.18 2.79,0.76 3.9,1.62L18.32,4.26zM19.93,11h2.02c-0.2,-2.01 -1,-3.84 -2.21,-5.32L18.31,7.1C19.17,8.21 19.75,9.54 19.93,11zM18.31,16.9l1.43,1.43c1.21,-1.48 2.01,-3.32 2.21,-5.32h-2.02C19.75,14.46 19.17,15.79 18.31,16.9zM13,19.93v2.02c2.01,-0.2 3.84,-1 5.32,-2.21l-1.43,-1.43C15.79,19.17 14.46,19.75 13,19.93zM13,12V7h-2v5H7l5,5l5,-5H13zM11,19.93v2.02c-5.05,-0.5 -9,-4.76 -9,-9.95s3.95,-9.45 9,-9.95v2.02C7.05,4.56 4,7.92 4,12S7.05,19.44 11,19.93z\"/>\n    \n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_fullscreen_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M7,14L5,14v5h5v-2L7,17v-3zM5,10h2L7,7h3L10,5L5,5v5zM17,17h-3v2h5v-5h-2v3zM14,5v2h3v3h2L19,5h-5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_fullscreen_exit_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M5,16h3v3h2v-5L5,14v2zM8,8L5,8v2h5L10,5L8,5v3zM14,19h2v-3h3v-2h-5v5zM16,8L16,5h-2v5h5L19,8h-3z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_grid_view_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24\"\n        android:viewportHeight=\"24\"\n        android:tint=\"?attr/white\">\n    <path\n            android:fillColor=\"@android:color/white\"\n            android:pathData=\"M3,3v8h8L11,3L3,3zM9,9L5,9L5,5h4v4zM3,13v8h8v-8L3,13zM9,19L5,19v-4h4v4zM13,3v8h8L21,3h-8zM19,9h-4L15,5h4v4zM13,13v8h8v-8h-8zM19,19h-4v-4h4v4z\"\n            android:fillType=\"evenOdd\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_headphones_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:width=\"24dp\"\r\n    android:height=\"24dp\"\r\n    android:tint=\"?attr/white\"\r\n    android:viewportWidth=\"24\"\r\n    android:viewportHeight=\"24\">\r\n\r\n    <path\r\n        android:fillColor=\"@android:color/white\"\r\n        android:pathData=\"M12,3c-4.97,0 -9,4.03 -9,9v7c0,1.1 0.9,2 2,2h4v-8H5v-1c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v1h-4v8h4c1.1,0 2,-0.9 2,-2v-7C21,7.03 16.97,3 12,3z\" />\r\n\r\n</vector>\r\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_help_outline_24.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\n    android:tint=\"?attr/white\" android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M11,18h2v-2h-2v2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM12,6c-2.21,0 -4,1.79 -4,4h2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2c0,2 -3,1.75 -3,5h2c0,-2.25 3,-2.5 3,-5 0,-2.21 -1.79,-4 -4,-4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_list_alt_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\"\n    android:autoMirrored=\"true\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M19,5v14L5,19L5,5h14m1.1,-2L3.9,3c-0.5,0 -0.9,0.4 -0.9,0.9v16.2c0,0.4 0.4,0.9 0.9,0.9h16.2c0.4,0 0.9,-0.5 0.9,-0.9L21,3.9c0,-0.5 -0.5,-0.9 -0.9,-0.9zM11,7h6v2h-6L11,7zM11,11h6v2h-6v-2zM11,15h6v2h-6zM7,7h2v2L7,9zM7,11h2v2L7,13zM7,15h2v2L7,17z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_network_ping_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,14.67L3.41,6.09L2,7.5l8.5,8.5H4v2h16v-2h-6.5l5.15,-5.15C18.91,10.95 19.2,11 19.5,11c1.38,0 2.5,-1.12 2.5,-2.5S20.88,6 19.5,6S17,7.12 17,8.5c0,0.35 0.07,0.67 0.2,0.97L12,14.67z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_notifications_none_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM18,16v-5c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.64,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2zM16,17L8,17v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5v6z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_remove_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M19,13H5v-2h14v2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_restore_page_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\" android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M14,2L6,2c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2L18,22c1.1,0 2,-0.9 2,-2L20,8l-6,-6zM12,18c-2.05,0 -3.81,-1.24 -4.58,-3h1.71c0.63,0.9 1.68,1.5 2.87,1.5 1.93,0 3.5,-1.57 3.5,-3.5S13.93,9.5 12,9.5c-1.35,0 -2.52,0.78 -3.1,1.9l1.6,1.6h-4L6.5,9l1.3,1.3C8.69,8.92 10.23,8 12,8c2.76,0 5,2.24 5,5s-2.24,5 -5,5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_save_as_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M21,12.4V7l-4,-4H5C3.89,3 3,3.9 3,5v14c0,1.1 0.89,2 2,2h7.4L21,12.4zM15,15c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3s1.34,-3 3,-3S15,13.34 15,15zM6,6h9v4H6V6zM19.99,16.25l1.77,1.77L16.77,23H15v-1.77L19.99,16.25zM23.25,16.51l-0.85,0.85l-1.77,-1.77l0.85,-0.85c0.2,-0.2 0.51,-0.2 0.71,0l1.06,1.06C23.45,16 23.45,16.32 23.25,16.51z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_skip_previous_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:width=\"24dp\"\r\n    android:height=\"24dp\"\r\n    android:tint=\"?attr/white\"\r\n    android:viewportWidth=\"24\"\r\n    android:viewportHeight=\"24\">\r\n\r\n    <path\r\n        android:fillColor=\"@android:color/white\"\r\n        android:pathData=\"M6,6h2v12L6,18zM9.5,12l8.5,6L18,6z\" />\r\n\r\n</vector>\r\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_stop_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M6,6h12v12H6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_sync_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_text_snippet_24.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\n    android:tint=\"?attr/white\" android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"?attr/white\" android:pathData=\"M20.41,8.41l-4.83,-4.83C15.21,3.21 14.7,3 14.17,3H5C3.9,3 3,3.9 3,5v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2V9.83C21,9.3 20.79,8.79 20.41,8.41zM7,7h7v2H7V7zM17,17H7v-2h10V17zM17,13H7v-2h10V13z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/baseline_theaters_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M18,3v2h-2L16,3L8,3v2L6,5L6,3L4,3v18h2v-2h2v2h8v-2h2v2h2L20,3h-2zM8,17L6,17v-2h2v2zM8,13L6,13v-2h2v2zM8,9L6,9L6,7h2v2zM18,17h-2v-2h2v2zM18,13h-2v-2h2v2zM18,9h-2L16,7h2v2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/benene.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"36dp\"\n    android:height=\"36dp\"\n    android:viewportWidth=\"36\"\n    android:viewportHeight=\"36\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 28 2 C 30.684 0.658 33 6 31 15 C 29.894 19.977 26 24 22 27 C 18 30 11 26 15 22 C 19 18 23 15 25 9 C 26.304 5.088 26 3 28 2 Z\"\n        android:fillColor=\"#ffe8b6\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 31 8 C 31 11 30 17 27 21 C 24 25 20 26 23 22 C 26 18 28 15 29 11 C 30 7 31 4 31 8 Z\"\n        android:fillColor=\"#ffd983\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 22 20 C 21.704 20.592 23.167 16.167 19 14 C 17.016 12.968 9 15 15 15 C 18 15 19 17 17 19 C 16.709 19.292 16.511 19.603 16.378 19.912 C 15.961 20.258 15.505 20.621 15 21 C 12.737 22.697 9.16 25.227 5 28 C 2 30 1 31 1 32 C 1 35 10 35 15 33 C 20 31 25 26 25 26 L 29 22 C 26 18 22 20 22 20 Z\"\n        android:fillColor=\"#ffcc4d\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_3\"\n        android:pathData=\"M 22 20 C 22 20 23.792 15.271 19 13 C 14.958 11.084 11 12 8 14 C 5 16 6 18 5 19 C 4 20 6 21 8 19 C 10 17 16.316 14.105 19 15 C 22 16 21 17.999 22 20 Z\"\n        android:fillColor=\"#ffe8b6\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_4\"\n        android:pathData=\"M 26 35 L 22 35 C 20 35 19 36 18 36 C 17 36 16 34 18 34 C 20 34 22 34 23 33 C 24 32 28 35 26 35 Z\"\n        android:fillColor=\"#a6d388\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_5\"\n        android:pathData=\"M 18 34 C 17.735 34 17.48 34.105 17.293 34.293 C 17.105 34.48 17 34.735 17 35 C 17 35.265 17.105 35.52 17.293 35.707 C 17.48 35.895 17.735 36 18 36 C 18.265 36 18.52 35.895 18.707 35.707 C 18.895 35.52 19 35.265 19 35 C 19 34.735 18.895 34.48 18.707 34.293 C 18.52 34.105 18.265 34 18 34 Z\"\n        android:fillColor=\"#3e721d\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_6\"\n        android:pathData=\"M 32.208 28 C 32.208 28 28 35 26 35 L 22 35 C 20 35 22 34 23 33 C 24 32 28 33 28 27 C 28 24 32.208 28 32.208 28 Z\"\n        android:fillColor=\"#ffcc4d\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_7\"\n        android:pathData=\"M 26 19 C 29 19 34 22 33 28 C 32 34 28 35 26 35 L 24 35 C 22 35 23 34 24 33 C 25 32 28 33 28 27 C 28 24 24 20 22 20 C 22 20 24 19 26 19 Z\"\n        android:fillColor=\"#ffe8b6\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_8\"\n        android:pathData=\"M 17 21 C 20 21 22 22 20 24 C 18.419 25.581 14 29 10 30 C 6 31 2 31 5 29 C 8 27 14.764 21 17 21 Z\"\n        android:fillColor=\"#ffd983\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_9\"\n        android:pathData=\"M 2 31 C 3 31 3 31 3 31.667 C 3 32.333 3 33 2 33 C 1 33 1 31.667 1 31.667 C 1 31.667 1 31 2 31 Z\"\n        android:fillColor=\"#c1694f\"\n        android:strokeWidth=\"1\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/bg_color_both.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/primaryGrayBackground\" />\n    <corners android:radius=\"@dimen/rounded_image_radius\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/bg_color_bottom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/primaryGrayBackground\" />\n    <corners\n        android:bottomLeftRadius=\"@dimen/rounded_image_radius\"\n        android:bottomRightRadius=\"@dimen/rounded_image_radius\"\n        android:topLeftRadius=\"@dimen/rounded_button_radius\"\n        android:topRightRadius=\"@dimen/rounded_button_radius\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/bg_color_center.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/primaryGrayBackground\"/>\n    <corners android:radius=\"@dimen/rounded_button_radius\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/bg_color_top.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/primaryGrayBackground\" />\n    <corners\n        android:bottomLeftRadius=\"@dimen/rounded_button_radius\"\n        android:bottomRightRadius=\"@dimen/rounded_button_radius\"\n        android:topLeftRadius=\"@dimen/rounded_image_radius\"\n        android:topRightRadius=\"@dimen/rounded_image_radius\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/bg_imdb_badge.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n    <solid android:color=\"#F5C518\" />\n    <corners android:radius=\"4dp\" />\n    <padding\n        android:bottom=\"2dp\"\n        android:left=\"4dp\"\n        android:right=\"4dp\"\n        android:top=\"2dp\" />\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/bookmark_star_24px.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M389,560L480,505L571,560L547,456L627,387L522,378L480,280L438,378L333,387L413,456L389,560ZM200,840L200,200Q200,167 223.5,143.5Q247,120 280,120L680,120Q713,120 736.5,143.5Q760,167 760,200L760,840L480,720L200,840ZM280,718L480,632L680,718L680,200Q680,200 680,200Q680,200 680,200L280,200Q280,200 280,200Q280,200 280,200L280,718ZM280,200L280,200Q280,200 280,200Q280,200 280,200L680,200Q680,200 680,200Q680,200 680,200L680,200L480,200L280,200Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/circle_shape.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:shape=\"ring\"\n        android:innerRadiusRatio=\"2.5\"\n        android:thickness=\"2dp\"\n        android:useLevel=\"false\">\n\n    <solid android:color=\"?attr/white\" />\n\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/circle_shape_dotted.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:innerRadiusRatio=\"2.5\"\n    android:shape=\"ring\"\n    android:thickness=\"0dp\"\n    android:useLevel=\"false\">\n    <stroke\n        tools:color=\"#FFF\"\n        android:width=\"2dp\"\n        android:color=\"?attr/download_outline_color\"\n        android:dashWidth=\"10px\"\n        android:dashGap=\"10px\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/circular_progress_bar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<rotate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:fromDegrees=\"270\"\n        android:toDegrees=\"270\">\n    <shape\n            android:innerRadiusRatio=\"2.5\"\n            android:shape=\"ring\"\n            android:thickness=\"2dp\"\n            android:useLevel=\"true\"><!-- this line fixes the issue for lollipop api 21 -->\n\n        <gradient\n                android:angle=\"0\"\n                android:endColor=\"?attr/colorPrimary\"\n                android:startColor=\"?attr/colorPrimary\"\n                android:type=\"sweep\"\n                android:useLevel=\"false\" />\n    </shape>\n</rotate>"
  },
  {
    "path": "app/src/main/res/drawable/circular_progress_bar_clockwise.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<rotate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:fromDegrees=\"270\"\n    android:toDegrees=\"270\">\n    <shape\n        android:innerRadiusRatio=\"50\"\n        android:shape=\"ring\"\n        android:innerRadius=\"0dp\"\n        android:thicknessRatio=\"2.65\"\n        android:useLevel=\"true\"><!-- this line fixes the issue for lollipop api 21 -->\n        <solid android:color=\"?attr/download_fill_color\" tools:color=\"#FFF\" />\n    </shape>\n</rotate>"
  },
  {
    "path": "app/src/main/res/drawable/circular_progress_bar_counter_clockwise.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<rotate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:fromDegrees=\"270\"\n    android:toDegrees=\"-90\">\n    <shape\n        android:innerRadiusRatio=\"50\"\n        android:shape=\"ring\"\n        android:innerRadius=\"0dp\"\n        android:thicknessRatio=\"2.65\"\n        android:useLevel=\"true\"><!-- this line fixes the issue for lollipop api 21 -->\n        <solid android:color=\"?attr/download_fill_color\" tools:color=\"#FFF\" />\n    </shape>\n</rotate>"
  },
  {
    "path": "app/src/main/res/drawable/circular_progress_bar_filled.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<rotate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:fromDegrees=\"270\"\n        android:toDegrees=\"270\">\n    <shape android:shape=\"oval\" />\n    <shape\n            android:innerRadiusRatio=\"100\"\n            android:shape=\"ring\"\n            android:thickness=\"11dp\"\n            android:useLevel=\"true\"><!-- this line fixes the issue for lollipop api 21 -->\n\n        <gradient\n                android:angle=\"0\"\n                android:endColor=\"?attr/white\"\n                android:startColor=\"?attr/white\"\n                android:type=\"sweep\"\n                android:useLevel=\"false\" />\n    </shape>\n</rotate>"
  },
  {
    "path": "app/src/main/res/drawable/circular_progress_bar_small_to_large.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<scale xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:scaleGravity=\"center\"\n    android:scaleHeight=\"100%\"\n    android:scaleWidth=\"100%\">\n    <shape\n        android:shape=\"ring\"\n        android:innerRadius=\"0dp\"\n        android:thicknessRatio=\"2.5\"\n        android:useLevel=\"false\"><!-- this line fixes the issue for lollipop api 21 -->\n        <solid\n            android:color=\"?attr/download_fill_color\"\n            tools:color=\"#FFF\" />\n    </shape>\n</scale>"
  },
  {
    "path": "app/src/main/res/drawable/circular_progress_bar_top_to_bottom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list>\n    <item>\n        <scale xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            xmlns:tools=\"http://schemas.android.com/tools\"\n            android:scaleGravity=\"top\"\n            android:scaleHeight=\"100%\"\n            android:scaleWidth=\"100%\">\n            <shape\n                android:shape=\"rectangle\"\n                android:innerRadius=\"0dp\"\n                android:thicknessRatio=\"2.5\"\n                android:useLevel=\"false\"><!-- this line fixes the issue for lollipop api 21 -->\n                <solid\n                    android:color=\"?attr/download_fill_color\"\n                    tools:color=\"#FFF\" />\n            </shape>\n        </scale>\n    </item>\n    <item>\n        <scale xmlns:android=\"http://schemas.android.com/apk/res/android\"\n            xmlns:tools=\"http://schemas.android.com/tools\"\n            android:scaleGravity=\"right\"\n            android:scaleHeight=\"100%\"\n            android:scaleWidth=\"100%\">\n            <shape\n                android:shape=\"rectangle\"\n                android:innerRadius=\"0dp\"\n                android:thicknessRatio=\"2.5\"\n                android:useLevel=\"false\"><!-- this line fixes the issue for lollipop api 21 -->\n                <solid\n                    android:color=\"?attr/download_fill_color\"\n                    tools:color=\"#FFF\" />\n            </shape>\n        </scale>\n    </item>\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/clear_all_24px.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M120,680L120,600L680,600L680,680L120,680ZM200,520L200,440L760,440L760,520L200,520ZM280,360L280,280L840,280L840,360L280,360Z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/cloud_2.xml",
    "content": "<vector xmlns:tools=\"http://schemas.android.com/tools\" android:name=\"vector\"\n        android:width=\"200dp\" android:height=\"200dp\" android:viewportWidth=\"283\"\n        android:viewportHeight=\"283\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:name=\"path\"\n          android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n          android:fillColor=\"#2309db\" android:strokeWidth=\"1\"\n          tools:ignore=\"VectorPath\"/>\n    <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n          android:fillColor=\"#2149d8\" android:strokeWidth=\"1\"/>\n    <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n          android:fillColor=\"#5c89f7\" android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/cloud_2_gradient.xml",
    "content": "<vector xmlns:tools=\"http://schemas.android.com/tools\" xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:name=\"vector\" android:width=\"200dp\" android:height=\"200dp\" android:viewportWidth=\"283\"\n        android:viewportHeight=\"283\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:name=\"path\"\n          android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n          android:strokeWidth=\"1\"\n          tools:ignore=\"VectorPath\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"0\"\n                    android:startX=\"200\"\n                    android:endY=\"0\"\n                    android:endX=\"300\"\n                    android:type=\"linear\">\n                <item android:offset=\"0\" android:color=\"#2309db\"/>\n                <item android:offset=\"1\" android:color=\"#1B08A1\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n\n    <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n          android:strokeWidth=\"1\">\n    <aapt:attr name=\"android:fillColor\">\n        <gradient\n                android:startY=\"0\"\n                android:startX=\"200\"\n                android:endY=\"0\"\n                android:endX=\"000\"\n                android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#254cdb\"/>\n            <item android:offset=\"1\" android:color=\"#1138DD\"/>\n        </gradient>\n    </aapt:attr>\n    </path>\n\n    <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n           android:strokeWidth=\"1\">\n    <aapt:attr name=\"android:fillColor\">\n        <gradient\n                android:startY=\"0\"\n                android:startX=\"150\"\n                android:endY=\"0\"\n                android:endX=\"000\"\n                android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#407EF1\"/>\n            <item android:offset=\"1\" android:color=\"#428CC5\"/>\n        </gradient>\n    </aapt:attr>\n</path>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/cloud_2_gradient_beta.xml",
    "content": "<vector xmlns:tools=\"http://schemas.android.com/tools\" xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:name=\"vector\" android:width=\"200dp\" android:height=\"200dp\" android:viewportWidth=\"283\"\n        android:viewportHeight=\"283\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:name=\"path\"\n          android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n          android:strokeWidth=\"1\"\n          tools:ignore=\"VectorPath\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"0\"\n                    android:startX=\"200\"\n                    android:endY=\"0\"\n                    android:endX=\"300\"\n                    android:type=\"linear\">\n                <item android:offset=\"0\" android:color=\"#DB0909\"/>\n                <item android:offset=\"1\" android:color=\"#A10808\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n\n    <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n          android:strokeWidth=\"1\">\n    <aapt:attr name=\"android:fillColor\">\n        <gradient\n                android:startY=\"0\"\n                android:startX=\"200\"\n                android:endY=\"0\"\n                android:endX=\"000\"\n                android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#E23A3A\"/>\n            <item android:offset=\"1\" android:color=\"#DD1130\"/>\n        </gradient>\n    </aapt:attr>\n    </path>\n\n    <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n           android:strokeWidth=\"1\">\n    <aapt:attr name=\"android:fillColor\">\n        <gradient\n                android:startY=\"0\"\n                android:startX=\"150\"\n                android:endY=\"0\"\n                android:endX=\"000\"\n                android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#E44D4D\"/>\n            <item android:offset=\"1\" android:color=\"#E76161\"/>\n        </gradient>\n    </aapt:attr>\n</path>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/cloud_2_gradient_beta_old.xml",
    "content": "<vector xmlns:tools=\"http://schemas.android.com/tools\" xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:name=\"vector\" android:width=\"200dp\" android:height=\"200dp\" android:viewportWidth=\"283\"\n        android:viewportHeight=\"283\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:name=\"path\"\n          android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n          android:strokeWidth=\"1\"\n          tools:ignore=\"VectorPath\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"0\"\n                    android:startX=\"200\"\n                    android:endY=\"0\"\n                    android:endX=\"300\"\n                    android:type=\"linear\">\n                <item android:offset=\"0\" android:color=\"#DB9509\"/>\n                <item android:offset=\"1\" android:color=\"#A17B08\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n\n    <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n          android:strokeWidth=\"1\">\n    <aapt:attr name=\"android:fillColor\">\n        <gradient\n                android:startY=\"0\"\n                android:startX=\"200\"\n                android:endY=\"0\"\n                android:endX=\"000\"\n                android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#DBA725\"/>\n            <item android:offset=\"1\" android:color=\"#DDB111\"/>\n        </gradient>\n    </aapt:attr>\n    </path>\n\n    <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n           android:strokeWidth=\"1\">\n    <aapt:attr name=\"android:fillColor\">\n        <gradient\n                android:startY=\"0\"\n                android:startX=\"150\"\n                android:endY=\"0\"\n                android:endX=\"000\"\n                android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#F1C540\"/>\n            <item android:offset=\"1\" android:color=\"#C5A442\"/>\n        </gradient>\n    </aapt:attr>\n</path>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/cloud_2_gradient_debug.xml",
    "content": "<vector xmlns:tools=\"http://schemas.android.com/tools\" xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:name=\"vector\" android:width=\"200dp\" android:height=\"200dp\" android:viewportWidth=\"283\"\n        android:viewportHeight=\"283\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:name=\"path\"\n          android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n          android:strokeWidth=\"1\"\n          tools:ignore=\"VectorPath\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"0\"\n                    android:startX=\"200\"\n                    android:endY=\"0\"\n                    android:endX=\"300\"\n                    android:type=\"linear\">\n                <item android:offset=\"0\" android:color=\"#3FAA11\"/>\n                <item android:offset=\"1\" android:color=\"#39A11D\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n\n    <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n          android:strokeWidth=\"1\">\n    <aapt:attr name=\"android:fillColor\">\n        <gradient\n                android:startY=\"0\"\n                android:startX=\"200\"\n                android:endY=\"0\"\n                android:endX=\"000\"\n                android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#37DB25\"/>\n            <item android:offset=\"1\" android:color=\"#11DD6D\"/>\n        </gradient>\n    </aapt:attr>\n    </path>\n\n    <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n           android:strokeWidth=\"1\">\n    <aapt:attr name=\"android:fillColor\">\n        <gradient\n                android:startY=\"0\"\n                android:startX=\"150\"\n                android:endY=\"0\"\n                android:endX=\"000\"\n                android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#40F15D\"/>\n            <item android:offset=\"1\" android:color=\"#42C54F\"/>\n        </gradient>\n    </aapt:attr>\n</path>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/cloud_2_solid.xml",
    "content": "<vector xmlns:tools=\"http://schemas.android.com/tools\" android:name=\"vector\"\n        android:width=\"200dp\" android:height=\"200dp\" android:viewportWidth=\"283\"\n        android:viewportHeight=\"283\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:name=\"path\"\n          android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n          android:fillColor=\"?attr/textColor\" android:strokeWidth=\"1\"\n          tools:ignore=\"VectorPath\"/>\n   </vector>"
  },
  {
    "path": "app/src/main/res/drawable/custom_rating_bar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:id=\"@android:id/background\"\n            android:drawable=\"@drawable/rating_empty\"/>\n\n    <item android:id=\"@android:id/secondaryProgress\"\n            android:drawable=\"@drawable/rating_empty\"\n            />\n    <item android:id=\"@android:id/progress\"\n            android:drawable=\"@drawable/rating_fill\"\n            />\n\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/dashed_line_horizontal.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"line\">\n\n    <stroke\n        android:width=\"2dp\"\n        android:color=\"?attr/white\"\n        android:dashWidth=\"8dp\"\n        android:dashGap=\"4dp\" />\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/default_cover.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"324dp\"\n    android:height=\"511dp\"\n    android:viewportWidth=\"324\"\n    android:viewportHeight=\"511\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 0.5 0.5 L 323.65 0.5 L 323.65 510.74 L 0.5 510.74 Z\"\n        android:fillColor=\"#878787\"\n        android:strokeColor=\"#231f20\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 211.94 176.85 L 211.94 189.1 C 211.94 189.887 211.631 190.643 211.079 191.204 C 210.527 191.765 209.777 192.087 208.99 192.1 L 196.73 192.1 C 195.943 192.087 195.193 191.765 194.641 191.204 C 194.089 190.643 193.78 189.887 193.78 189.1 L 193.78 176.85 C 193.78 176.323 193.641 175.806 193.378 175.35 C 193.115 174.894 192.736 174.515 192.28 174.252 C 191.824 173.989 191.307 173.85 190.78 173.85 L 124.09 173.85 C 123.295 173.85 122.531 174.166 121.969 174.729 C 121.406 175.291 121.09 176.055 121.09 176.85 L 121.09 189.1 C 121.09 189.887 120.781 190.643 120.229 191.204 C 119.677 191.765 118.927 192.087 118.14 192.1 L 105.93 192.1 C 105.135 192.1 104.371 191.784 103.809 191.221 C 103.246 190.659 102.93 189.895 102.93 189.1 L 102.93 176.85 C 102.93 176.055 102.614 175.291 102.051 174.729 C 101.489 174.166 100.725 173.85 99.93 173.85 L 87.77 173.85 C 86.975 173.85 86.211 174.166 85.649 174.729 C 85.086 175.291 84.77 176.055 84.77 176.85 L 84.77 334.39 C 84.783 335.177 85.105 335.927 85.666 336.479 C 86.227 337.031 86.983 337.34 87.77 337.34 L 100.02 337.34 C 100.807 337.34 101.563 337.031 102.124 336.479 C 102.685 335.927 103.007 335.177 103.02 334.39 L 103.02 322.14 C 103.02 321.345 103.336 320.581 103.899 320.019 C 104.461 319.456 105.225 319.14 106.02 319.14 L 118.27 319.14 C 119.057 319.153 119.807 319.475 120.359 320.036 C 120.911 320.597 121.22 321.353 121.22 322.14 L 121.22 334.39 C 121.233 335.177 121.555 335.927 122.116 336.479 C 122.677 337.031 123.433 337.34 124.22 337.34 L 190.95 337.34 C 191.737 337.34 192.493 337.031 193.054 336.479 C 193.615 335.927 193.937 335.177 193.95 334.39 L 193.95 322.14 C 193.95 321.353 194.259 320.597 194.811 320.036 C 195.363 319.475 196.113 319.153 196.9 319.14 L 209.16 319.14 C 209.947 319.153 210.697 319.475 211.249 320.036 C 211.801 320.597 212.11 321.353 212.11 322.14 L 212.11 334.39 C 212.123 335.177 212.445 335.927 213.006 336.479 C 213.567 337.031 214.323 337.34 215.11 337.34 L 227.36 337.34 C 228.138 337.327 228.881 337.012 229.432 336.462 C 229.982 335.911 230.297 335.168 230.31 334.39 L 230.31 176.85 C 230.31 176.063 230.001 175.307 229.449 174.746 C 228.897 174.185 228.147 173.863 227.36 173.85 L 214.9 173.85 C 214.112 173.861 213.358 174.181 212.804 174.743 C 212.251 175.304 211.94 176.062 211.94 176.85 Z M 118.18 301.02 L 105.93 301.02 C 105.143 301.02 104.387 300.711 103.826 300.159 C 103.265 299.607 102.943 298.857 102.93 298.07 L 102.93 285.82 C 102.93 285.025 103.246 284.261 103.809 283.699 C 104.371 283.136 105.135 282.82 105.93 282.82 L 118.18 282.82 C 118.967 282.833 119.717 283.155 120.269 283.716 C 120.821 284.277 121.13 285.033 121.13 285.82 L 121.13 298.07 C 121.117 298.848 120.802 299.591 120.252 300.142 C 119.701 300.692 118.958 301.007 118.18 301.02 Z M 118.18 264.7 L 105.93 264.7 C 105.135 264.7 104.371 264.384 103.809 263.821 C 103.246 263.259 102.93 262.495 102.93 261.7 L 102.93 249.5 C 102.93 248.705 103.246 247.941 103.809 247.379 C 104.371 246.816 105.135 246.5 105.93 246.5 L 118.18 246.5 C 118.967 246.513 119.717 246.835 120.269 247.396 C 120.821 247.957 121.13 248.713 121.13 249.5 L 121.13 261.75 C 121.117 262.528 120.802 263.271 120.252 263.822 C 119.701 264.372 118.958 264.687 118.18 264.7 Z M 118.18 228.38 L 105.93 228.38 C 105.135 228.38 104.371 228.064 103.809 227.501 C 103.246 226.939 102.93 226.175 102.93 225.38 L 102.93 213.17 C 102.93 212.375 103.246 211.611 103.809 211.049 C 104.371 210.486 105.135 210.17 105.93 210.17 L 118.18 210.17 C 118.967 210.183 119.717 210.505 120.269 211.066 C 120.821 211.627 121.13 212.383 121.13 213.17 L 121.13 225.42 C 121.12 226.2 120.806 226.946 120.255 227.498 C 119.705 228.051 118.96 228.367 118.18 228.38 Z M 208.99 301.02 L 196.73 301.02 C 195.952 301.007 195.209 300.692 194.658 300.142 C 194.108 299.591 193.793 298.848 193.78 298.07 L 193.78 285.82 C 193.78 285.033 194.089 284.277 194.641 283.716 C 195.193 283.155 195.943 282.833 196.73 282.82 L 208.99 282.82 C 209.777 282.833 210.527 283.155 211.079 283.716 C 211.631 284.277 211.94 285.033 211.94 285.82 L 211.94 298.07 C 211.927 298.848 211.612 299.591 211.062 300.142 C 210.511 300.692 209.768 301.007 208.99 301.02 Z M 208.99 264.7 L 196.73 264.7 C 195.943 264.687 195.193 264.365 194.641 263.804 C 194.089 263.243 193.78 262.487 193.78 261.7 L 193.78 249.5 C 193.78 248.713 194.089 247.957 194.641 247.396 C 195.193 246.835 195.943 246.513 196.73 246.5 L 208.99 246.5 C 209.777 246.513 210.527 246.835 211.079 247.396 C 211.631 247.957 211.94 248.713 211.94 249.5 L 211.94 261.75 C 211.927 262.528 211.612 263.271 211.062 263.822 C 210.511 264.372 209.768 264.687 208.99 264.7 Z M 208.99 228.38 L 196.73 228.38 C 195.943 228.367 195.193 228.045 194.641 227.484 C 194.089 226.923 193.78 226.167 193.78 225.38 L 193.78 213.17 C 193.78 212.383 194.089 211.627 194.641 211.066 C 195.193 210.505 195.943 210.183 196.73 210.17 L 208.99 210.17 C 209.777 210.183 210.527 210.505 211.079 211.066 C 211.631 211.627 211.94 212.383 211.94 213.17 L 211.94 225.42 C 211.93 226.2 211.616 226.946 211.065 227.498 C 210.515 228.051 209.77 228.367 208.99 228.38 Z\"\n        android:fillColor=\"#dbd0d0\"\n        android:strokeWidth=\"1\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/delete_all.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M30,36.5V33.5H37.25V36.5ZM30,18.1V15.1H44V18.1ZM30,27.3V24.3H41.75V27.3ZM6.25,14.25H4V11.25H12.5V9H19.25V11.25H27.75V14.25H25.5V35Q25.5,36.2 24.6,37.1Q23.7,38 22.5,38H9.25Q8.05,38 7.15,37.1Q6.25,36.2 6.25,35ZM9.25,14.25V35Q9.25,35 9.25,35Q9.25,35 9.25,35H22.5Q22.5,35 22.5,35Q22.5,35 22.5,35V14.25ZM9.25,14.25V35Q9.25,35 9.25,35Q9.25,35 9.25,35Q9.25,35 9.25,35Q9.25,35 9.25,35Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/dialog__window_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <shape android:shape=\"rectangle\">\n        <corners android:radius=\"10dp\" />\n        <solid android:color=\"?attr/primaryBlackBackground\" />\n    </shape>\n</inset>"
  },
  {
    "path": "app/src/main/res/drawable/download_icon_done.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 17 1.01 L 7 1 C 5.9 1 5 1.9 5 3 L 5 21 C 5 22.1 5.9 23 7 23 L 17 23 C 18.1 23 19 22.1 19 21 L 19 3 C 19 1.9 18.1 1.01 17 1.01 Z M 17 19 L 7 19 L 7 5 L 17 5 Z\"\n        android:fillColor=\"@android:color/white\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 7.488 13.004 L 9.132 11.36 L 12.492 14.72 L 10.848 16.364 Z\"\n        android:fillColor=\"@android:color/white\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 10.848 16.364 L 9.203 14.72 L 14.894 9.029 L 16.539 10.673 Z\"\n        android:fillColor=\"@android:color/white\"\n        android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/download_icon_error.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 17 1.01 L 7 1 C 5.9 1 5 1.9 5 3 L 5 21 C 5 22.1 5.9 23 7 23 L 17 23 C 18.1 23 19 22.1 19 21 L 19 3 C 19 1.9 18.1 1.01 17 1.01 Z M 17 19 L 7 19 L 7 5 L 17 5 Z M 10.101 13.289 L 10.513 10.311 L 9.848 9.33 L 9.496 8.867 L 11 13 L 9.706 13 L 9.745 15.93 Z\"\n        android:fillColor=\"@android:color/white\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 15.801 14.763 L 14.157 16.407 L 7.873 10.124 L 9.518 8.479 Z\"\n        android:fillColor=\"@android:color/white\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 14.157 8.479 L 15.801 10.124 L 9.518 16.407 L 7.873 14.763 Z\"\n        android:fillColor=\"@android:color/white\"\n        android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/download_icon_load.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM16,13h-3L13,8h-2v5L8,13l4,4 4,-4z\" />\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/download_icon_pause.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 17 1.01 L 7 1 C 5.9 1 5 1.9 5 3 L 5 21 C 5 22.1 5.9 23 7 23 L 17 23 C 18.1 23 19 22.1 19 21 L 19 3 C 19 1.9 18.1 1.01 17 1.01 Z M 17 19 L 7 19 L 7 5 L 17 5 Z M 10.101 13.289 L 10.513 10.311 L 9.848 9.33 L 9.496 8.867 L 11 13 L 9.706 13 L 9.745 15.93 Z\"\n        android:fillColor=\"@android:color/white\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 9.104 8.931 L 11.129 8.931 L 11.129 15.956 L 9.104 15.956 Z M 12.871 8.931 L 14.896 8.931 L 14.896 15.956 L 12.871 15.956 Z\"\n        android:fillColor=\"@android:color/white\"\n        android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/dub_bg_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"@color/dubColorBg\"/>\n    <corners android:radius=\"@dimen/rounded_image_radius\"/>\n  <!--  <stroke android:color=\"@color/dubColor\" android:width=\"2dp\"/>-->\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/episodes_shadow.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n        android:centerColor=\"?attr/primaryBlackBackground\"\n        android:centerX=\"0.2\"\n        android:endColor=\"?attr/primaryBlackBackground\"\n        android:startColor=\"@color/transparent\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/go_back_30.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:name=\"vector\"\n    android:tint=\"?attr/white\"\n    android:width=\"21.378dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"636\"\n    android:viewportHeight=\"714\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 318.05 106.07 C 478.51 106.07 608.6 236.16 608.6 396.62 C 608.6 557.08 478.51 687.17 318.05 687.17 C 157.59 687.17 27.5 557.09 27.5 396.62 C 27.427 349.18 39.026 302.442 61.27 260.54 M 385.11 197.86 L 279.12 91.87 M 385.11 24.61 L 279.12 130.6 M 245.77 192.7 L 139.79 86.71 M 245.77 19.45 L 139.79 125.43\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"55\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n            android:name=\"path_1\"\n            android:pathData=\"M 138.13 485.27 L 158.46 457.96 C 172.78 472.21 190.74 483.78 214.41 483.78 C 240.23 483.78 258.03 470.43 258.03 448.17 C 258.03 423.83 242.38 408.11 188.73 408.11 L 188.73 376.94 C 234.88 376.94 250.02 360.94 250.02 339.25 C 250.02 319.52 236.89 307.65 215.15 307.65 C 196.9 307.65 182.21 316.4 167.96 329.9 L 145.85 303.49 C 165.85 285.68 188.59 273.67 216.93 273.67 C 262.04 273.67 293.05 296.22 293.05 336.06 C 293.05 362.4 277.47 380.21 251.95 390.3 L 251.95 391.78 C 279.85 399.05 301.06 419.09 301.06 450.54 C 301.06 493.54 263.52 518.66 218.12 518.66 C 180.05 518.66 154.75 503.96 138.13 485.27 Z M 334.45 395.2 C 334.45 315.44 365.61 273.67 414.58 273.67 C 463.55 273.67 494.71 315.67 494.71 395.2 C 494.71 474.95 463.55 518.66 414.58 518.66 C 365.61 518.66 334.45 474.95 334.45 395.2 Z M 453.9 395.2 C 453.9 328.42 437.43 307.2 414.58 307.2 C 391.73 307.2 375.25 328.42 375.25 395.2 C 375.25 461.98 391.73 485.12 414.58 485.12 C 437.43 485.12 453.9 461.97 453.9 395.2 Z\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\" tools:ignore=\"VectorPath\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/go_forward_30.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\" android:name=\"vector\"\n    android:tint=\"?attr/white\"\n    android:width=\"21.378dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"636\"\n    android:viewportHeight=\"714\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 318.05 106.07 C 157.58 106.07 27.5 236.16 27.5 396.62 C 27.5 557.08 157.58 687.17 318.05 687.17 C 478.52 687.17 608.6 557.09 608.6 396.62 C 608.675 349.182 597.083 302.445 574.85 260.54 M 250.99 197.86 L 356.98 91.87 M 250.99 24.61 L 356.98 130.6 M 390.33 192.7 L 496.32 86.71 M 390.33 19.45 L 496.32 125.43\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"55\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n            android:name=\"path_1\"\n            android:pathData=\"M 138.13 485.27 L 158.46 457.96 C 172.78 472.21 190.74 483.78 214.41 483.78 C 240.23 483.78 258.03 470.43 258.03 448.17 C 258.03 423.83 242.38 408.11 188.73 408.11 L 188.73 376.94 C 234.88 376.94 250.02 360.94 250.02 339.25 C 250.02 319.52 236.89 307.65 215.15 307.65 C 196.9 307.65 182.21 316.4 167.96 329.9 L 145.85 303.49 C 165.85 285.68 188.59 273.67 216.93 273.67 C 262.04 273.67 293.05 296.22 293.05 336.06 C 293.05 362.4 277.47 380.21 251.95 390.3 L 251.95 391.78 C 279.85 399.05 301.06 419.09 301.06 450.54 C 301.06 493.54 263.52 518.66 218.12 518.66 C 180.05 518.66 154.75 503.96 138.13 485.27 Z M 334.45 395.2 C 334.45 315.44 365.61 273.67 414.58 273.67 C 463.55 273.67 494.71 315.67 494.71 395.2 C 494.71 474.95 463.55 518.66 414.58 518.66 C 365.61 518.66 334.45 474.95 334.45 395.2 Z M 453.9 395.2 C 453.9 328.42 437.43 307.2 414.58 307.2 C 391.73 307.2 375.25 328.42 375.25 395.2 C 375.25 461.98 391.73 485.12 414.58 485.12 C 437.43 485.12 453.9 461.97 453.9 395.2 Z\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\" tools:ignore=\"VectorPath\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/home_alt.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M11.05,39H17.95V26.15H30.1V39H36.95V19.55L24,9.85L11.05,19.55ZM11.05,42.65Q9.5,42.65 8.45,41.6Q7.4,40.55 7.4,39V19.55Q7.4,18.7 7.775,17.925Q8.15,17.15 8.85,16.65L21.8,6.9Q22.3,6.55 22.875,6.375Q23.45,6.2 24,6.2Q24.6,6.2 25.15,6.375Q25.7,6.55 26.2,6.9L39.15,16.65Q39.85,17.15 40.225,17.925Q40.6,18.7 40.6,19.55V39Q40.6,40.55 39.55,41.6Q38.5,42.65 36.95,42.65H26.45V29.8H21.6V42.65ZM24,24.4Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/home_icon_filled_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"M160,840v-480l320,-240 320,240v480L560,840v-280L400,560v280L160,840Z\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/home_icon_outline_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"M240,760h120v-240h240v240h120v-360L480,220 240,400v360ZM160,840v-480l320,-240 320,240v480L520,840v-240h-80v240L160,840ZM480,490Z\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/home_icon_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/home_icon_filled_24\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/home_icon_filled_24\" android:state_focused=\"true\"/>\n    <item android:drawable=\"@drawable/home_icon_outline_24\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/hourglass_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:fillColor=\"#9BA0A4\"\n      android:pathData=\"M320,800h320v-120q0,-66 -47,-113t-113,-47q-66,0 -113,47t-47,113v120ZM480,440q66,0 113,-47t47,-113v-120L320,160v120q0,66 47,113t113,47ZM160,880v-80h80v-120q0,-61 28.5,-114.5T348,480q-51,-32 -79.5,-85.5T240,280v-120h-80v-80h640v80h-80v120q0,61 -28.5,114.5T612,480q51,32 79.5,85.5T720,680v120h80v80L160,880ZM480,800ZM480,160Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_anilist_icon.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"20dp\"\n        android:height=\"20dp\"\n        android:viewportWidth=\"172\"\n        android:viewportHeight=\"172\"\n        android:tint=\"?attr/white\"\n>\n    <path\n            android:pathData=\"M111.322,111.157L111.322,41.029C111.322,37.01 109.105,34.792 105.086,34.792L91.365,34.792C87.346,34.792 85.128,37.01 85.128,41.029C85.128,41.029 85.128,56.337 85.128,74.333C85.128,75.271 94.165,79.626 94.401,80.547C101.286,107.449 95.897,128.98 89.37,129.985C100.042,130.513 101.216,135.644 93.267,132.138C94.483,117.784 99.228,117.812 112.869,131.61C112.986,131.729 115.666,137.351 115.833,137.351C131.17,137.351 148.05,137.351 148.05,137.351C152.069,137.351 154.286,135.134 154.286,131.115L154.286,117.394C154.286,113.375 152.069,111.157 148.05,111.157L111.322,111.157Z\"\n            android:fillColor=\"@color/black\"\n            android:fillType=\"evenOdd\"/>\n    <path\n            android:pathData=\"M54.365,34.792L18.331,137.351L46.327,137.351L52.425,119.611L82.915,119.611L88.875,137.351L116.732,137.351L80.836,34.792L54.365,34.792ZM58.8,96.882L67.531,68.47L77.094,96.882L58.8,96.882Z\"\n            android:fillColor=\"@color/white\"\n            android:fillType=\"evenOdd\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_banner_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"320dp\"\n    android:height=\"180dp\"\n    android:viewportWidth=\"320\"\n    android:viewportHeight=\"180\"\n    android:name=\"vector\">\n  <group android:scaleX=\"0.6666667\"\n      android:scaleY=\"0.6666667\"\n      android:translateX=\"53.333332\"\n      android:translateY=\"30\">\n    <group android:scaleX=\"0.13764706\"\n        android:scaleY=\"0.13764706\"\n        android:translateX=\"15.1\"\n        android:translateY=\"31.5\">\n        <group android:name=\"group_6\">\n            <path\n                android:name=\"path_2\"\n                android:pathData=\"M 698.92 450.33 C 697.92 440.99 690.27 432.74 679.92 430.25 L 653.67 430.75 C 655.17 407.75 636.67 386.63 618.79 384 C 611.804 381.871 604.367 381.698 597.29 383.5 C 597.91 379.77 602.74 347.16 578.79 322 C 558.72 300.92 532.54 299.13 517.67 299.31 L 500.37 298.92 C 494.76 293.4 460.65 262.47 412.62 266.67 C 382.23 269.32 354.96 277.67 334.79 302.67 C 333.11 304.74 327.6 311.81 321.17 320.81 C 318.82 323.81 316.91 327.43 314.79 330.5 C 314.63 330.74 288.79 326.44 272.79 331 C 247.52 338.2 224.79 358.54 217.29 385.5 C 215.44 392.18 209.08 415.09 219.79 435 C 222.101 439.202 223.081 444.009 222.6 448.78 C 219.48 450.41 205.02 450.94 182.29 450 C 164.43 449.27 149.83 463.6 149.79 480 C 149.74 497.17 165.23 510.58 184.29 510 C 205.93 510.23 605.96 510.67 637.04 510.56 C 650.12 510.56 656.79 499.17 656.79 499.17 C 661.24 493.35 661.09 486.09 661.04 481.5 L 661.04 477 L 664.79 477 L 675.96 476.33 C 690.35 474.78 700.21 462.36 698.92 450.33 Z M 407.54 456 L 407.54 349.25 L 483.75 402.63 Z\"\n                android:fillColor=\"#ffffff\"\n                android:strokeWidth=\"1\"/>\n        </group>\n    </group>\n\n    <group android:scaleX=\"0.17275657\"\n        android:scaleY=\"0.17275657\"\n        android:translateX=\"128\"\n        android:translateY=\"74.202896\">\n      <group android:translateY=\"146.25\">\n        <path android:pathData=\"M88,-5.25Q75.984375,2,57.984375,2Q35.0625,2,21.03125,-13.171875Q7,-28.34375,7,-52.421875Q7,-77.6875,22.390625,-94.34375Q37.796875,-111,62.40625,-111Q77.875,-111,88,-106.75L88,-93.75Q76.328125,-100,62.28125,-100Q43,-100,31.5,-86.890625Q20,-73.78125,20,-53.203125Q20,-33.671875,30.765625,-21.328125Q41.53125,-9,59.625,-9Q75.984375,-9,88,-16.25L88,-5.25Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M109,0L109,-115L121,-115L121,0L109,0Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M140,-38.015625Q140,-57.546875,150.71875,-68.765625Q161.4375,-80,179.89062,-80Q197.26562,-80,207.125,-69.15625Q217,-58.328125,217,-39.21875Q217,-20.65625,206.3125,-9.328125Q195.625,2,178.03125,2Q161.01562,2,150.5,-8.90625Q140,-19.8125,140,-38.015625ZM152,-38.5Q152,-24.59375,159.32812,-16.296875Q166.65625,-8,178.89062,-8Q191.34375,-8,198.17188,-16.078125Q205,-24.171875,205,-38.78125Q205,-53.75,198.23438,-61.875Q191.48438,-70,178.89062,-70Q166.59375,-70,159.29688,-61.59375Q152,-53.1875,152,-38.5Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M299,0L287,0L287,-12.15625L286.71875,-12.15625Q279.0625,2,262.79688,2Q235,2,235,-31.28125L235,-78L247,-78L247,-33.25Q247,-8,265.89062,-8Q275.1875,-8,281.09375,-15Q287,-22,287,-32.953125L287,-78L299,-78L299,0Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M390,0L378,0L378,-13.359375L377.71875,-13.359375Q369.125,2,351.01562,2Q336.34375,2,327.67188,-8.578125Q319,-19.171875,319,-37.15625Q319,-56.421875,328.71875,-68.203125Q338.4375,-80,354.375,-80Q370.3125,-80,377.71875,-66.875L378,-66.875L378,-115L390,-115L390,0ZM378,-47.015625Q378,-56.65625,371.54688,-63.328125Q365.09375,-70,355.75,-70Q344.17188,-70,337.57812,-61.3125Q331,-52.625,331,-37.796875Q331,-24.25,337.3125,-16.125Q343.625,-8,354.29688,-8Q364.54688,-8,371.26562,-15.625Q378,-23.25,378,-35.09375L378,-47.015625Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M413,-19.25Q417.5,-14.875,425.96875,-11.9375Q434.4375,-9,441.625,-9Q465,-9,465,-26.265625Q465,-31.09375,462.5625,-34.875Q460.14062,-38.671875,456.01562,-41.4375Q451.89062,-44.21875,439.76562,-50.53125Q422.29688,-59.671875,417.64062,-66.46875Q413,-73.28125,413,-81.859375Q413,-95.125,423.5625,-103.0625Q434.14062,-111,450.125,-111Q466.25,-111,473,-106.75L473,-92.75Q463.65625,-100,448.875,-100Q438.78125,-100,432.39062,-95.53125Q426,-91.0625,426,-82.96875Q426,-77.96875,428.25,-74.28125Q430.51562,-70.59375,434.39062,-67.875Q438.28125,-65.15625,449.53125,-59.46875Q465.35938,-51.53125,471.67188,-43.96875Q478,-36.421875,478,-27.078125Q478,-13.171875,467.9375,-5.578125Q457.875,2,439.76562,2Q434.25,2,425.40625,-0.109375Q416.5625,-2.234375,413,-5.25L413,-19.25Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M533,-1.25Q528.7656,2,521.8125,2Q502,2,502,-20.78125L502,-68L489,-68L489,-78L502,-78L502,-97.1875L514,-101L514,-78L533,-78L533,-68L514,-68L514,-22.859375Q514,-14.828125,516.5781,-11.40625Q519.15625,-8,525.2031,-8Q529.875,-8,533,-11.25L533,-1.25Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M590,-66.75Q586.78125,-70,580.71875,-70Q572.5469,-70,567.2656,-61.953125Q562,-53.90625,562,-40.84375L562,0L550,0L550,-78L562,-78L562,-63.46875L562.34375,-63.46875Q565,-71.328125,570.4375,-75.65625Q575.8906,-80,582.4531,-80Q587.4219,-80,590,-78.75L590,-66.75Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M665,-36L610,-36Q610.3594,-22.453125,617.125,-15.21875Q623.8906,-8,635.6719,-8Q648.8594,-8,660,-17L660,-6Q649.8125,2,633,2Q616.7656,2,607.375,-8.6875Q598,-19.390625,598,-38.78125Q598,-56.625,608.1094,-68.3125Q618.2344,-80,633.4219,-80Q648.34375,-80,656.6719,-70.0625Q665,-60.125,665,-42.390625L665,-36ZM653,-46Q652.9375,-57.375,647.7344,-63.6875Q642.53125,-70,633.1875,-70Q624.6875,-70,618.25,-63.65625Q611.8281,-57.3125,610.1406,-46L653,-46Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M687,-72Q698.3906,-80,713.0781,-80Q740,-80,740,-51.09375L740,0L728,0L728,-12L727.5781,-12Q719.5156,2,703.75,2Q692.25,2,685.625,-4.140625Q679,-10.296875,679,-20.40625Q679,-41.96875,704.5156,-45.625L727.9375,-49Q727.9375,-70,711.9844,-70Q698.03125,-70,687,-60L687,-72ZM708.8281,-36.46875Q698.8281,-35.140625,694.90625,-31.6875Q691,-28.234375,691,-21.046875Q691,-15.25,695.1875,-11.625Q699.3906,-8,706.15625,-8Q715.53125,-8,721.7344,-14.625Q727.9375,-21.265625,727.9375,-31.1875L727.9375,-39L708.8281,-36.46875Z\"\n            android:fillColor=\"#FFFFFF\"/>\n        <path android:pathData=\"M873,0L861,0L861,-44.90625Q861,-58.546875,857.0156,-64.265625Q853.03125,-70,843.84375,-70Q836.15625,-70,830.5781,-62.5Q825,-55.015625,825,-44.6875L825,0L813,0L813,-46.53125Q813,-70,795.0625,-70Q786.8281,-70,781.40625,-62.859375Q776,-55.71875,776,-44.6875L776,0L764,0L764,-78L776,-78L776,-65.859375L776.34375,-65.859375Q784.5,-80,800.3906,-80Q807.9844,-80,814.0625,-75.53125Q820.15625,-71.0625,822.3281,-63.75Q830.8281,-80,847.7656,-80Q873,-80,873,-48.125L873,0Z\"\n            android:fillColor=\"#FFFFFF\"/>\n      </group>\n    </group>\n  </group>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_add_24.xml",
    "content": "<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M24,38.35Q23.25,38.35 22.725,37.825Q22.2,37.3 22.2,36.5V25.8H11.45Q10.7,25.8 10.175,25.25Q9.65,24.7 9.65,23.95Q9.65,23.2 10.175,22.675Q10.7,22.15 11.45,22.15H22.2V11.4Q22.2,10.65 22.725,10.125Q23.25,9.6 24,9.6Q24.75,9.6 25.3,10.125Q25.85,10.65 25.85,11.4V22.15H36.55Q37.3,22.15 37.85,22.675Q38.4,23.2 38.4,23.95Q38.4,24.75 37.85,25.275Q37.3,25.8 36.55,25.8H25.85V36.5Q25.85,37.3 25.3,37.825Q24.75,38.35 24,38.35Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_arrow_back_24.xml",
    "content": "<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    android:autoMirrored=\"true\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M22,39.35 L7.95,25.3Q7.65,25.05 7.525,24.725Q7.4,24.4 7.4,24Q7.4,23.65 7.525,23.325Q7.65,23 7.95,22.75L22.05,8.6Q22.6,8.1 23.325,8.125Q24.05,8.15 24.6,8.7Q25.1,9.25 25.1,10Q25.1,10.75 24.55,11.3L13.65,22.2H38.1Q38.85,22.2 39.375,22.725Q39.9,23.25 39.9,24Q39.9,24.8 39.375,25.325Q38.85,25.85 38.1,25.85H13.65L24.65,36.8Q25.15,37.35 25.125,38.075Q25.1,38.8 24.55,39.35Q24,39.9 23.25,39.9Q22.5,39.9 22,39.35Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_arrow_back_ios_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:autoMirrored=\"true\"\n    android:tint=\"#FFFFFF\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M11.67,3.87L9.9,2.1 0,12l9.9,9.9 1.77,-1.77L3.54,12z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_arrow_forward_24.xml",
    "content": "<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    android:autoMirrored=\"true\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M22.7,39.3Q22.15,38.75 22.175,38Q22.2,37.25 22.75,36.7L33.6,25.85H9.2Q8.45,25.85 7.925,25.325Q7.4,24.8 7.4,24Q7.4,23.25 7.925,22.725Q8.45,22.2 9.2,22.2H33.6L22.75,11.35Q22.2,10.8 22.175,10.025Q22.15,9.25 22.7,8.7Q23.25,8.15 24,8.15Q24.75,8.15 25.3,8.7L39.35,22.75Q39.65,23.05 39.8,23.35Q39.95,23.65 39.95,24Q39.95,24.35 39.8,24.675Q39.65,25 39.35,25.3L25.3,39.35Q24.75,39.9 24,39.875Q23.25,39.85 22.7,39.3Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_aspect_ratio_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M19,12h-2v3h-3v2h5v-5zM7,9h3L10,7L5,7v5h2L7,9zM21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19.01L3,19.01L3,4.99h18v14.02z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_autorenew_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,6v3l4,-4 -4,-4v3c-4.42,0 -8,3.58 -8,8 0,1.57 0.46,3.03 1.24,4.26L6.7,14.8c-0.45,-0.83 -0.7,-1.79 -0.7,-2.8 0,-3.31 2.69,-6 6,-6zM18.76,7.74L17.3,9.2c0.44,0.84 0.7,1.79 0.7,2.8 0,3.31 -2.69,6 -6,6v-3l-4,4 4,4v-3c4.42,0 8,-3.58 8,-8 0,-1.57 -0.46,-3.03 -1.24,-4.26z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_bookmark_24.xml",
    "content": "<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M11.75,41.85Q10.85,42.25 10.05,41.725Q9.25,41.2 9.25,40.25V8.5Q9.25,7.05 10.35,5.95Q11.45,4.85 12.9,4.85H35.1Q36.55,4.85 37.65,5.95Q38.75,7.05 38.75,8.5V40.25Q38.75,41.2 37.95,41.725Q37.15,42.25 36.25,41.85L24,36.65Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_bookmark_border_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M17,3L7,3c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3L19,5c0,-1.1 -0.9,-2 -2,-2zM17,18l-5,-2.18L7,18L7,5h10v13z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_brightness_1_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,12m-10,0a10,10 0,1 1,20 0a10,10 0,1 1,-20 0\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_brightness_2_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M10,2c-1.82,0 -3.53,0.5 -5,1.35C7.99,5.08 10,8.3 10,12s-2.01,6.92 -5,8.65C6.47,21.5 8.18,22 10,22c5.52,0 10,-4.48 10,-10S15.52,2 10,2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_brightness_3_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M9,2c-1.05,0 -2.05,0.16 -3,0.46 4.06,1.27 7,5.06 7,9.54 0,4.48 -2.94,8.27 -7,9.54 0.95,0.3 1.95,0.46 3,0.46 5.52,0 10,-4.48 10,-10S14.52,2 9,2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_brightness_4_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69L23.31,12 20,8.69zM12,18c-0.89,0 -1.74,-0.2 -2.5,-0.55C11.56,16.5 13,14.42 13,12s-1.44,-4.5 -3.5,-5.45C10.26,6.2 11.11,6 12,6c3.31,0 6,2.69 6,6s-2.69,6 -6,6z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_brightness_5_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,15.31L23.31,12 20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_brightness_6_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,15.31L23.31,12 20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69zM12,18V6c3.31,0 6,2.69 6,6s-2.69,6 -6,6z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_brightness_7_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,8.69L20,4h-4.69L12,0.69 8.69,4L4,4v4.69L0.69,12 4,15.31L4,20h4.69L12,23.31 15.31,20L20,20v-4.69L23.31,12 20,8.69zM12,18c-3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6 6,2.69 6,6 -2.69,6 -6,6zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_check_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_check_24_listview.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"@color/check_selection_color\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_clear_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_close_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_collections_bookmark_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#000000\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M4,6H2v14c0,1.1 0.9,2 2,2h14v-2H4V6z\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM20,12l-2.5,-1.5L15,12L15,4h5v8z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_color_lens_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.39 -0.15,-0.74 -0.39,-1.01 -0.23,-0.26 -0.38,-0.61 -0.38,-0.99 0,-0.83 0.67,-1.5 1.5,-1.5L16,16c2.76,0 5,-2.24 5,-5 0,-4.42 -4.03,-8 -9,-8zM6.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,9 6.5,9 8,9.67 8,10.5 7.33,12 6.5,12zM9.5,8C8.67,8 8,7.33 8,6.5S8.67,5 9.5,5s1.5,0.67 1.5,1.5S10.33,8 9.5,8zM14.5,8c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,5 14.5,5s1.5,0.67 1.5,1.5S15.33,8 14.5,8zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_construction_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M13.783,15.172l2.121,-2.121l5.996,5.996l-2.121,2.121z\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M17.5,10c1.93,0 3.5,-1.57 3.5,-3.5c0,-0.58 -0.16,-1.12 -0.41,-1.6l-2.7,2.7L16.4,6.11l2.7,-2.7C18.62,3.16 18.08,3 17.5,3C15.57,3 14,4.57 14,6.5c0,0.41 0.08,0.8 0.21,1.16l-1.85,1.85l-1.78,-1.78l0.71,-0.71L9.88,5.61L12,3.49c-1.17,-1.17 -3.07,-1.17 -4.24,0L4.22,7.03l1.41,1.41H2.81L2.1,9.15l3.54,3.54l0.71,-0.71V9.15l1.41,1.41l0.71,-0.71l1.78,1.78l-7.41,7.41l2.12,2.12L16.34,9.79C16.7,9.92 17.09,10 17.5,10z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_delete_outline_24.xml",
    "content": "<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12.95,42.8Q11.5,42.8 10.4,41.7Q9.3,40.6 9.3,39.15V10.4H8.75Q8,10.4 7.475,9.85Q6.95,9.3 6.95,8.55Q6.95,7.8 7.475,7.275Q8,6.75 8.75,6.75H17.35Q17.35,6 17.875,5.525Q18.4,5.05 19.15,5.05H28.9Q29.65,5.05 30.175,5.525Q30.7,6 30.7,6.75H39.3Q40.05,6.75 40.6,7.275Q41.15,7.8 41.15,8.55Q41.15,9.35 40.6,9.875Q40.05,10.4 39.3,10.4H38.75V39.15Q38.75,40.6 37.65,41.7Q36.55,42.8 35.1,42.8ZM12.95,10.4V39.15Q12.95,39.15 12.95,39.15Q12.95,39.15 12.95,39.15H35.1Q35.1,39.15 35.1,39.15Q35.1,39.15 35.1,39.15V10.4ZM17.85,33Q17.85,33.75 18.375,34.275Q18.9,34.8 19.65,34.8Q20.4,34.8 20.95,34.275Q21.5,33.75 21.5,33V16.5Q21.5,15.75 20.95,15.2Q20.4,14.65 19.65,14.65Q18.9,14.65 18.375,15.2Q17.85,15.75 17.85,16.5ZM26.6,33Q26.6,33.75 27.125,34.275Q27.65,34.8 28.4,34.8Q29.15,34.8 29.7,34.275Q30.25,33.75 30.25,33V16.5Q30.25,15.75 29.7,15.2Q29.15,14.65 28.4,14.65Q27.65,14.65 27.125,15.2Q26.6,15.75 26.6,16.5ZM12.95,10.4V39.15Q12.95,39.15 12.95,39.15Q12.95,39.15 12.95,39.15Q12.95,39.15 12.95,39.15Q12.95,39.15 12.95,39.15V10.4Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_developer_mode_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M7,5h10v2h2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99L7,1c-1.1,0 -2,0.9 -2,2v4h2L7,5zM15.41,16.59L20,12l-4.59,-4.59L14,8.83 17.17,12 14,15.17l1.41,1.42zM10,15.17L6.83,12 10,8.83 8.59,7.41 4,12l4.59,4.59L10,15.17zM17,19L7,19v-2L5,17v4c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2v-4h-2v2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_discord_24.xml",
    "content": "<vector android:height=\"27.5dp\" android:tint=\"?attr/white\"\n        android:viewportHeight=\"293\" android:viewportWidth=\"256\"\n        android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\"\n          android:pathData=\"M226.011429,0 L29.9885714,0 C13.4582857,0 0,13.4582857 0,30.1348571 L0,227.913143 C0,244.589714 13.4582857,258.048 29.9885714,258.048 L195.876571,258.048 L188.123429,230.985143 L206.848,248.393143 L224.548571,264.777143 L256,292.571429 L256,30.1348571 C256,13.4582857 242.541714,0 226.011429,0 Z M169.545143,191.049143 C169.545143,191.049143 164.278857,184.758857 159.890286,179.2 C179.053714,173.787429 186.368,161.792 186.368,161.792 C180.370286,165.741714 174.665143,168.521143 169.545143,170.422857 C162.230857,173.494857 155.209143,175.542857 148.333714,176.713143 C134.290286,179.346286 121.417143,178.614857 110.445714,176.566857 C102.107429,174.957714 94.9394286,172.617143 88.9417143,170.276571 C85.5771429,168.96 81.92,167.350857 78.2628571,165.302857 C77.824,165.010286 77.3851429,164.864 76.9462857,164.571429 C76.6537143,164.425143 76.5074286,164.278857 76.3611429,164.132571 C73.728,162.669714 72.2651429,161.645714 72.2651429,161.645714 C72.2651429,161.645714 79.2868571,173.348571 97.8651429,178.907429 C93.4765714,184.466286 88.064,191.049143 88.064,191.049143 C55.7348571,190.025143 43.4468571,168.813714 43.4468571,168.813714 C43.4468571,121.709714 64.512,83.5291429 64.512,83.5291429 C85.5771429,67.7302857 105.618286,68.1691429 105.618286,68.1691429 L107.081143,69.9245714 C80.7497143,77.5314286 68.608,89.088 68.608,89.088 C68.608,89.088 71.8262857,87.3325714 77.2388571,84.8457143 C92.8914286,77.9702857 105.325714,76.0685714 110.445714,75.6297143 C111.323429,75.4834286 112.054857,75.3371429 112.932571,75.3371429 C121.856,74.1668571 131.949714,73.8742857 142.482286,75.0445714 C156.379429,76.6537143 171.300571,80.7497143 186.514286,89.088 C186.514286,89.088 174.957714,78.1165714 150.089143,70.5097143 L152.137143,68.1691429 C152.137143,68.1691429 172.178286,67.7302857 193.243429,83.5291429 C193.243429,83.5291429 214.308571,121.709714 214.308571,168.813714 C214.308571,168.813714 201.874286,190.025143 169.545143,191.049143 Z M101.522286,122.733714 C93.184,122.733714 86.6011429,130.048 86.6011429,138.971429 C86.6011429,147.894857 93.3302857,155.209143 101.522286,155.209143 C109.860571,155.209143 116.443429,147.894857 116.443429,138.971429 C116.589714,130.048 109.860571,122.733714 101.522286,122.733714 M154.916571,122.733714 C146.578286,122.733714 139.995429,130.048 139.995429,138.971429 C139.995429,147.894857 146.724571,155.209143 154.916571,155.209143 C163.254857,155.209143 169.837714,147.894857 169.837714,138.971429 C169.837714,130.048 163.254857,122.733714 154.916571,122.733714\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_dns_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M20,13H4c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1zM7,19c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM20,3H4c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1zM7,9c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_edit_24.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_equalizer_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"M160,800v-320h160v320L160,800ZM400,800v-640h160v640L400,800ZM640,800v-440h160v440L640,800Z\"\n      android:fillColor=\"#5f6368\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_exit_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:autoMirrored=\"true\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:width=\"24dp\">\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M17,7l-1.41,1.41L18.17,11H8v2h10.17l-2.58,2.58L17,17l5,-5zM4,5h8V3H4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h8v-2H4V5z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_extension_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20.5,11H19V7c0,-1.1 -0.9,-2 -2,-2h-4V3.5C13,2.12 11.88,1 10.5,1S8,2.12 8,3.5V5H4c-1.1,0 -1.99,0.9 -1.99,2v3.8H3.5c1.49,0 2.7,1.21 2.7,2.7s-1.21,2.7 -2.7,2.7H2V20c0,1.1 0.9,2 2,2h3.8v-1.5c0,-1.49 1.21,-2.7 2.7,-2.7 1.49,0 2.7,1.21 2.7,2.7V22H17c1.1,0 2,-0.9 2,-2v-4h1.5c1.38,0 2.5,-1.12 2.5,-2.5S21.88,11 20.5,11z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_fast_forward_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_favorite_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_favorite_border_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3 4.42,3 2,5.42 2,8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5 22,5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1 -0.1,-0.1C7.14,14.24 4,11.39 4,8.5 4,6.5 5.5,5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5 0,2.89 -3.14,5.74 -7.9,10.05z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_film_roll_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M240,760L240,800Q240,817 228.5,828.5Q217,840 200,840Q183,840 171.5,828.5Q160,817 160,800L160,160Q160,143 171.5,131.5Q183,120 200,120Q217,120 228.5,131.5Q240,143 240,160L240,200L320,200L320,160Q320,143 331.5,131.5Q343,120 360,120L600,120Q617,120 628.5,131.5Q640,143 640,160L640,200L720,200L720,160Q720,143 731.5,131.5Q743,120 760,120Q777,120 788.5,131.5Q800,143 800,160L800,800Q800,817 788.5,828.5Q777,840 760,840Q743,840 731.5,828.5Q720,817 720,800L720,760L640,760L640,800Q640,817 628.5,828.5Q617,840 600,840L360,840Q343,840 331.5,828.5Q320,817 320,800L320,760L240,760ZM240,680L320,680L320,600L240,600L240,680ZM240,520L320,520L320,440L240,440L240,520ZM240,360L320,360L320,280L240,280L240,360ZM640,680L720,680L720,600L640,600L640,680ZM640,520L720,520L720,440L640,440L640,520ZM640,360L720,360L720,280L640,280L640,360Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_filter_list_24.xml",
    "content": "<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M21.5,37.35Q20.7,37.35 20.175,36.825Q19.65,36.3 19.65,35.55Q19.65,34.8 20.175,34.25Q20.7,33.7 21.5,33.7H26.5Q27.25,33.7 27.8,34.25Q28.35,34.8 28.35,35.55Q28.35,36.3 27.8,36.825Q27.25,37.35 26.5,37.35ZM7.35,13.1Q6.55,13.1 6.025,12.575Q5.5,12.05 5.5,11.3Q5.5,10.55 6.025,10Q6.55,9.45 7.35,9.45H40.65Q41.4,9.45 41.95,10Q42.5,10.55 42.5,11.3Q42.5,12.05 41.95,12.575Q41.4,13.1 40.65,13.1ZM13.4,25.25Q12.6,25.25 12.075,24.7Q11.55,24.15 11.55,23.4Q11.55,22.65 12.075,22.125Q12.6,21.6 13.4,21.6H34.6Q35.35,21.6 35.875,22.125Q36.4,22.65 36.4,23.4Q36.4,24.2 35.875,24.725Q35.35,25.25 34.6,25.25Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_folder_open_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M20,6h-8l-2,-2L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,8c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,8h16v10z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_hd_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M19,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM11,15L9.5,15v-2h-2v2L6,15L6,9h1.5v2.5h2L9.5,9L11,9v6zM13,9h4c0.55,0 1,0.45 1,1v4c0,0.55 -0.45,1 -1,1h-4L13,9zM14.5,13.5h2v-3h-2v3z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_hearing_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M17,20c-0.29,0 -0.56,-0.06 -0.76,-0.15 -0.71,-0.37 -1.21,-0.88 -1.71,-2.38 -0.51,-1.56 -1.47,-2.29 -2.39,-3 -0.79,-0.61 -1.61,-1.24 -2.32,-2.53C9.29,10.98 9,9.93 9,9c0,-2.8 2.2,-5 5,-5s5,2.2 5,5h2c0,-3.93 -3.07,-7 -7,-7S7,5.07 7,9c0,1.26 0.38,2.65 1.07,3.9 0.91,1.65 1.98,2.48 2.85,3.15 0.81,0.62 1.39,1.07 1.71,2.05 0.6,1.82 1.37,2.84 2.73,3.55 0.51,0.23 1.07,0.35 1.64,0.35 2.21,0 4,-1.79 4,-4h-2c0,1.1 -0.9,2 -2,2zM7.64,2.64L6.22,1.22C4.23,3.21 3,5.96 3,9s1.23,5.79 3.22,7.78l1.41,-1.41C6.01,13.74 5,11.49 5,9s1.01,-4.74 2.64,-6.36zM11.5,9c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5 -1.12,-2.5 -2.5,-2.5 -2.5,1.12 -2.5,2.5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_keyboard_arrow_down_24.xml",
    "content": "<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M24,30.55Q23.65,30.55 23.325,30.4Q23,30.25 22.75,29.95L12.8,20.05Q12.3,19.55 12.325,18.725Q12.35,17.9 12.85,17.4Q13.45,16.8 14.175,16.875Q14.9,16.95 15.45,17.45L24,26.05L32.6,17.45Q33.1,16.95 33.9,16.9Q34.7,16.85 35.25,17.45Q35.8,17.95 35.75,18.75Q35.7,19.55 35.2,20.05L25.3,29.95Q25,30.25 24.675,30.4Q24.35,30.55 24,30.55Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_keyboard_arrow_left_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:autoMirrored=\"true\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13.3,17.3 L8.7,12.7Q8.55,12.55 8.488,12.375Q8.425,12.2 8.425,12Q8.425,11.8 8.488,11.625Q8.55,11.45 8.7,11.3L13.3,6.7Q13.575,6.425 14,6.425Q14.425,6.425 14.7,6.7Q14.975,6.975 14.975,7.4Q14.975,7.825 14.7,8.1L10.8,12L14.7,15.9Q14.975,16.175 14.975,16.6Q14.975,17.025 14.7,17.3Q14.425,17.575 14,17.575Q13.575,17.575 13.3,17.3Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_keyboard_arrow_right_24.xml",
    "content": "<vector android:autoMirrored=\"true\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:width=\"24dp\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M8.7,17.3Q8.425,17.025 8.425,16.6Q8.425,16.175 8.7,15.9L12.6,12L8.7,8.1Q8.425,7.825 8.425,7.4Q8.425,6.975 8.7,6.7Q8.975,6.425 9.4,6.425Q9.825,6.425 10.1,6.7L14.7,11.3Q14.85,11.45 14.913,11.625Q14.975,11.8 14.975,12Q14.975,12.2 14.913,12.375Q14.85,12.55 14.7,12.7L10.1,17.3Q9.825,17.575 9.4,17.575Q8.975,17.575 8.7,17.3Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_language_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-1.25 -0.78,-2.45 -1.38,-3.56 1.84,0.63 3.37,1.91 4.33,3.56zM12,4.04c0.83,1.2 1.48,2.53 1.91,3.96h-3.82c0.43,-1.43 1.08,-2.76 1.91,-3.96zM4.26,14C4.1,13.36 4,12.69 4,12s0.1,-1.36 0.26,-2h3.38c-0.08,0.66 -0.14,1.32 -0.14,2 0,0.68 0.06,1.34 0.14,2L4.26,14zM5.08,16h2.95c0.32,1.25 0.78,2.45 1.38,3.56 -1.84,-0.63 -3.37,-1.9 -4.33,-3.56zM8.03,8L5.08,8c0.96,-1.66 2.49,-2.93 4.33,-3.56C8.81,5.55 8.35,6.75 8.03,8zM12,19.96c-0.83,-1.2 -1.48,-2.53 -1.91,-3.96h3.82c-0.43,1.43 -1.08,2.76 -1.91,3.96zM14.34,14L9.66,14c-0.09,-0.66 -0.16,-1.32 -0.16,-2 0,-0.68 0.07,-1.35 0.16,-2h4.68c0.09,0.65 0.16,1.32 0.16,2 0,0.68 -0.07,1.34 -0.16,2zM14.59,19.56c0.6,-1.11 1.06,-2.31 1.38,-3.56h2.95c-0.96,1.65 -2.49,2.93 -4.33,3.56zM16.36,14c0.08,-0.66 0.14,-1.32 0.14,-2 0,-0.68 -0.06,-1.34 -0.14,-2h3.38c0.16,0.64 0.26,1.31 0.26,2s-0.1,1.36 -0.26,2h-3.38z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_more_vert_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_north_west_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M5,15h2v-4.586l7.293,7.293l1.414,-1.414L8.414,9H13V7H5V15z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_notifications_active_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M7.58,4.08L6.15,2.65C3.75,4.48 2.17,7.3 2.03,10.5h2c0.15,-2.65 1.51,-4.97 3.55,-6.42zM19.97,10.5h2c-0.15,-3.2 -1.73,-6.02 -4.12,-7.85l-1.42,1.43c2.02,1.45 3.39,3.77 3.54,6.42zM18,11c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2v-5zM12,22c0.14,0 0.27,-0.01 0.4,-0.04 0.65,-0.14 1.18,-0.58 1.44,-1.18 0.1,-0.24 0.15,-0.5 0.15,-0.78h-4c0.01,1.1 0.9,2 2.01,2z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_ondemand_video_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M21,3L3,3c-1.11,0 -2,0.89 -2,2v12c0,1.1 0.89,2 2,2h5v2h8v-2h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.11 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12zM16,11l-7,4L9,7z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_open_in_new_24.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\r\n    android:tint=\"?attr/white\" android:viewportHeight=\"24\"\r\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\r\n    <path android:fillColor=\"?attr/white\" android:pathData=\"M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z\"/>\r\n</vector>\r\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_pause_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_people_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n\n    <path\n        android:strokeColor=\"@android:color/white\"\n        android:strokeWidth=\"1.2\"\n        android:pathData=\"M12,2c5.52,0 10,4.48 10,10s-4.48,10 -10,10S2,17.52 2,12 6.48,2 12,2z\"/>\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,11.5c1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3 1.34,3 3,3z M12,13c-2.33,0 -7,1.17 -7,3.5 0,1.2 0.7,2.3 2,3.1 1.4,0.9 3.2,1.4 5,1.4s3.6,-0.5 5,-1.4c1.3,-0.8 2,-1.9 2,-3.1C19,14.17 14.33,13 12,13z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_picture_in_picture_alt_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M19,11h-8v6h8v-6zM23,19L23,4.98C23,3.88 22.1,3 21,3L3,3c-1.1,0 -2,0.88 -2,1.98L1,19c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2zM21,19.02L3,19.02L3,4.97h18v14.05z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_play_arrow_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M8,5v14l11,-7z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_playlist_play_24.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\n    android:tint=\"?attr/white\" android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M3,10h11v2h-11z\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M3,6h11v2h-11z\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M3,14h7v2h-7z\"/>\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M16,13l0,8l6,-4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_public_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM11,19.93c-3.95,-0.49 -7,-3.85 -7,-7.93 0,-0.62 0.08,-1.21 0.21,-1.79L9,15v1c0,1.1 0.9,2 2,2v1.93zM17.9,17.39c-0.26,-0.81 -1,-1.39 -1.9,-1.39h-1v-3c0,-0.55 -0.45,-1 -1,-1L8,12v-2h2c0.55,0 1,-0.45 1,-1L11,7h2c1.1,0 2,-0.9 2,-2v-0.41c2.93,1.19 5,4.06 5,7.41 0,2.08 -0.8,3.97 -2.1,5.39z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_remove_red_eye_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_replay_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M12,5V2.21c0,-0.45 -0.54,-0.67 -0.85,-0.35l-3.8,3.79c-0.2,0.2 -0.2,0.51 0,0.71l3.79,3.79c0.32,0.31 0.86,0.09 0.86,-0.36V7c3.73,0 6.68,3.42 5.86,7.29 -0.47,2.27 -2.31,4.1 -4.57,4.57 -3.57,0.75 -6.75,-1.7 -7.23,-5.01 -0.07,-0.48 -0.49,-0.85 -0.98,-0.85 -0.6,0 -1.08,0.53 -1,1.13 0.62,4.39 4.8,7.64 9.53,6.72 3.12,-0.61 5.63,-3.12 6.24,-6.24C20.84,9.48 16.94,5 12,5z\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_restart_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"M440,838q-121,-15 -200.5,-105.5T160,520q0,-66 26,-126.5T260,288l57,57q-38,34 -57.5,79T240,520q0,88 56,155.5T440,758v80ZM520,838v-80q87,-16 143.5,-83T720,520q0,-100 -70,-170t-170,-70h-3l44,44 -56,56 -140,-140 140,-140 56,56 -44,44h3q134,0 227,93t93,227q0,121 -79.5,211.5T520,838Z\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_resume_arrow.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"m8.46,5l0,14l11,-7l-11,-7z\"\n      android:strokeLineJoin=\"round\"\n      android:strokeWidth=\"0.006\"\n      android:fillColor=\"#000000\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_resume_arrow2.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"m8.46,5l0,14l11,-7l-11,-7z\"/>\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M4.92,5.04h2.31v13.98h-2.31z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_skip_next_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M6,18l8.5,-6L6,6v12zM16,6v12h2V6h-2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_skip_next_24_big.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M2.775,21.225 L15.844,12 2.775,2.775ZM18.15,2.775v18.45h3.075V2.775Z\"\n      android:strokeWidth=\"1.5375\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_skip_next_rounded_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n  <path\n      android:pathData=\"M7.58,16.89l5.77,-4.07c0.56,-0.4 0.56,-1.24 0,-1.63L7.58,7.11C6.91,6.65 6,7.12 6,7.93v8.14c0,0.81 0.91,1.28 1.58,0.82zM16,7v10c0,0.55 0.45,1 1,1s1,-0.45 1,-1V7c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1z\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_sort_24.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\n    android:tint=\"?attr/white\" android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_speed_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20.38,8.57l-1.23,1.85a8,8 0,0 1,-0.22 7.58L5.07,18A8,8 0,0 1,15.58 6.85l1.85,-1.23A10,10 0,0 0,3.35 19a2,2 0,0 0,1.72 1h13.85a2,2 0,0 0,1.74 -1,10 10,0 0,0 -0.27,-10.44zM10.59,15.41a2,2 0,0 0,2.83 0l5.66,-8.49 -8.49,5.66a2,2 0,0 0,0 2.83z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_star_24.xml",
    "content": "<vector android:height=\"12dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"12dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_star_border_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M22,9.24l-7.19,-0.62L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21 12,17.27 18.18,21l-1.63,-7.03L22,9.24zM12,15.4l-3.76,2.27 1,-4.28 -3.32,-2.88 4.38,-0.38L12,6.1l1.71,4.04 4.38,0.38 -3.32,2.88 1,4.28L12,15.4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_storage_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:height=\"24dp\"\n        android:tint=\"?attr/white\"\n        android:viewportHeight=\"24\"\n        android:viewportWidth=\"24\"\n        android:width=\"24dp\">\n    <path\n            android:fillColor=\"@android:color/white\"\n            android:pathData=\"M2,20h20v-4L2,16v4zM4,17h2v2L4,19v-2zM2,4v4h20L22,4L2,4zM6,7L4,7L4,5h2v2zM2,14h20v-4L2,10v4zM4,11h2v2L4,13v-2z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_subtitles_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM4,12h4v2L4,14v-2zM14,18L4,18v-2h10v2zM20,18h-4v-2h4v2zM20,14L10,14v-2h10v2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_system_update_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM16,13h-3L13,8h-2v5L8,13l4,4 4,-4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_text_format_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M5,17v2h14v-2L5,17zM9.5,12.8h5l0.9,2.2h2.1L12.75,4h-1.5L6.5,15h2.1l0.9,-2.2zM12,5.98L13.87,11h-3.74L12,5.98z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_thumb_down_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M15,3L6,3c-0.83,0 -1.54,0.5 -1.84,1.22l-3.02,7.05c-0.09,0.23 -0.14,0.47 -0.14,0.73v2c0,1.1 0.9,2 2,2h6.31l-0.95,4.57 -0.03,0.32c0,0.41 0.17,0.79 0.44,1.06L9.83,23l6.59,-6.59c0.36,-0.36 0.58,-0.86 0.58,-1.41L17,5c0,-1.1 -0.9,-2 -2,-2zM19,3v12h4L23,3h-4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_thumb_up_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M1,21h4L5,9L1,9v12zM23,10c0,-1.1 -0.9,-2 -2,-2h-6.31l0.95,-4.57 0.03,-0.32c0,-0.41 -0.17,-0.79 -0.44,-1.06L14.17,1 7.59,7.59C7.22,7.95 7,8.45 7,9v10c0,1.1 0.9,2 2,2h9c0.83,0 1.54,-0.5 1.84,-1.22l3.02,-7.05c0.09,-0.23 0.14,-0.47 0.14,-0.73v-2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_touch_app_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M9,11.24V7.5C9,6.12 10.12,5 11.5,5S14,6.12 14,7.5v3.74c1.21,-0.81 2,-2.18 2,-3.74C16,5.01 13.99,3 11.5,3S7,5.01 7,7.5C7,9.06 7.79,10.43 9,11.24zM18.84,15.87l-4.54,-2.26c-0.17,-0.07 -0.35,-0.11 -0.54,-0.11H13v-6C13,6.67 12.33,6 11.5,6S10,6.67 10,7.5v10.74c-3.6,-0.76 -3.54,-0.75 -3.67,-0.75c-0.31,0 -0.59,0.13 -0.79,0.33l-0.79,0.8l4.94,4.94C9.96,23.83 10.34,24 10.75,24h6.79c0.75,0 1.33,-0.55 1.44,-1.28l0.75,-5.27c0.01,-0.07 0.02,-0.14 0.02,-0.2C19.75,16.63 19.37,16.09 18.84,15.87z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_tune_24.xml",
    "content": "<vector android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M7.35,38.4Q6.55,38.4 6.025,37.85Q5.5,37.3 5.5,36.55Q5.5,35.8 6.025,35.275Q6.55,34.75 7.35,34.75H16.95Q17.7,34.75 18.225,35.275Q18.75,35.8 18.75,36.55Q18.75,37.35 18.225,37.875Q17.7,38.4 16.95,38.4ZM7.35,13.25Q6.55,13.25 6.025,12.7Q5.5,12.15 5.5,11.4Q5.5,10.65 6.025,10.125Q6.55,9.6 7.35,9.6H24.9Q25.65,9.6 26.2,10.125Q26.75,10.65 26.75,11.4Q26.75,12.2 26.2,12.725Q25.65,13.25 24.9,13.25ZM23.1,42.5Q22.3,42.5 21.775,41.975Q21.25,41.45 21.25,40.7V32.4Q21.25,31.65 21.8,31.1Q22.35,30.55 23.1,30.55Q23.85,30.55 24.375,31.1Q24.9,31.65 24.9,32.4V34.75H40.65Q41.4,34.75 41.95,35.275Q42.5,35.8 42.5,36.55Q42.5,37.35 41.95,37.875Q41.4,38.4 40.65,38.4H24.9V40.7Q24.9,41.45 24.375,41.975Q23.85,42.5 23.1,42.5ZM16.95,29.95Q16.15,29.95 15.625,29.425Q15.1,28.9 15.1,28.1V25.8H7.35Q6.55,25.8 6.025,25.275Q5.5,24.75 5.5,24Q5.5,23.25 6.025,22.7Q6.55,22.15 7.35,22.15H15.1V19.75Q15.1,19 15.65,18.475Q16.2,17.95 16.95,17.95Q17.7,17.95 18.225,18.475Q18.75,19 18.75,19.75V28.1Q18.75,28.9 18.225,29.425Q17.7,29.95 16.95,29.95ZM23.1,25.8Q22.3,25.8 21.775,25.275Q21.25,24.75 21.25,24Q21.25,23.25 21.775,22.7Q22.3,22.15 23.1,22.15H40.65Q41.4,22.15 41.95,22.7Q42.5,23.25 42.5,24Q42.5,24.75 41.95,25.275Q41.4,25.8 40.65,25.8ZM31.05,17.4Q30.3,17.4 29.775,16.875Q29.25,16.35 29.25,15.6V7.3Q29.25,6.55 29.775,6Q30.3,5.45 31.05,5.45Q31.8,5.45 32.35,6Q32.9,6.55 32.9,7.3V9.6H40.65Q41.4,9.6 41.95,10.125Q42.5,10.65 42.5,11.4Q42.5,12.2 41.95,12.725Q41.4,13.25 40.65,13.25H32.9V15.6Q32.9,16.35 32.35,16.875Q31.8,17.4 31.05,17.4Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_tv_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v2h8v-2h5c1.1,0 1.99,-0.9 1.99,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_visibility_off_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_volume_down_24.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\n    android:tint=\"#FFFFFF\" android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M18.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM5,9v6h4l5,5V4L9,9H5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_volume_mute_24.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\n    android:tint=\"#FFFFFF\" android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M7,9v6h4l5,5V4l-5,5H7z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_volume_up_24.xml",
    "content": "<vector android:autoMirrored=\"true\" android:height=\"24dp\"\n    android:tint=\"?attr/white\" android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M3,9v6h4l5,5L12,4L7,9L3,9zM16.5,12c0,-1.77 -1.02,-3.29 -2.5,-4.03v8.05c1.48,-0.73 2.5,-2.25 2.5,-4.02zM14,3.23v2.06c2.89,0.86 5,3.54 5,6.71s-2.11,5.85 -5,6.71v2.06c4.01,-0.91 7,-4.49 7,-8.77s-2.99,-7.86 -7,-8.77z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_baseline_warning_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M1,21h22L12,2 1,21zM13,18h-2v-2h2v2zM13,14h-2v-4h2v4z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_battery.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M15.67,4L14,4L14,3c0,-0.55 -0.45,-1 -1,-1h-2c-0.55,0 -1,0.45 -1,1v1L8.33,4C7.6,4 7,4.6 7,5.33v15.33C7,21.4 7.6,22 8.34,22h7.32c0.74,0 1.34,-0.6 1.34,-1.33L17,5.33C17,4.6 16.4,4 15.67,4zM13,18h-2v-2h2v2zM13,13c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-3c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v3z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_cloudstream_monochrome.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\"\n    android:name=\"vector\">\n    <group android:scaleX=\"0.1755477\"\n        android:scaleY=\"0.1755477\"\n        android:translateX=\"29.16\"\n        android:translateY=\"29.16\">\n        <path android:name=\"path\"\n\n            android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n            android:fillColor=\"#FFFFFF\" android:strokeWidth=\"1\"\n            tools:ignore=\"VectorPath\"\n            android:fillAlpha=\"0.55\"/>\n        <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n            android:fillColor=\"#FFFFFF\" android:strokeWidth=\"1\"\n            android:fillAlpha=\"0.55\"/>\n        <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n            android:fillColor=\"#FFFFFF\" android:strokeWidth=\"1\"\n            android:fillAlpha=\"1\"/>\n    </group>\n\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_cloudstream_monochrome_big.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"50\"\n    android:viewportHeight=\"50\"\n    android:name=\"vector\">\n    <group android:scaleX=\"0.1755477\"\n        android:scaleY=\"0.1755477\"\n        android:translateX=\"0\"\n        android:translateY=\"0\">\n        <path android:name=\"path\"\n\n            android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n            android:fillColor=\"#FFFFFF\" android:strokeWidth=\"1\"\n            tools:ignore=\"VectorPath\"\n            android:fillAlpha=\"0.55\"/>\n        <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n            android:fillColor=\"#FFFFFF\" android:strokeWidth=\"1\"\n            android:fillAlpha=\"0.55\"/>\n        <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n            android:fillColor=\"#FFFFFF\" android:strokeWidth=\"1\"\n            android:fillAlpha=\"1\"/>\n    </group>\n\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_cloudstreamlogotv.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:width=\"907.09dp\"\n        android:height=\"510.24dp\"\n        android:viewportWidth=\"907.09\"\n        android:viewportHeight=\"510.24\">\n    <path\n            android:strokeWidth=\"1\"\n            android:pathData=\"M-20.09,-10.91h949.79v534.26h-949.79z\"\n            android:fillColor=\"#121212\"\n            android:strokeColor=\"#fff\" />\n    <path android:pathData=\"M354.67,257.16A18.81,18.81 0,0 0,349 258a26.55,26.55 0,0 0,-24.72 -21.51,40.84 40.84,0 0,0 -69,-13.08A32.06,32.06 0,0 0,213 253.82c0,1.13 0.06,2.25 0.17,3.35H213a18.9,18.9 0,0 0,0 37.8H354.67a18.9,18.9 0,0 0,0 -37.8Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M329.74,241c0,-1.22 0,-2.43 -0.09,-3.63a26.9,26.9 0,0 0,-5.35 -0.85,40.84 40.84,0 0,0 -69,-13.08A32.06,32.06 0,0 0,213 253.82c0,1.13 0.06,2.25 0.17,3.35H213a18.9,18.9 0,0 0,0 37.8h96.48A81.79,81.79 0,0 0,329.74 241Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.3\"\n                    android:endX=\"329.74\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF4F6DFB\" />\n                <item\n                        android:offset=\"0.6\"\n                        android:color=\"#FF3559E7\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2149D8\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M255.34,223.43A32.06,32.06 0,0 0,213 253.82c0,1.13 0.06,2.25 0.17,3.35H213a18.89,18.89 0,0 0,-1.18 37.74A81.52,81.52 0,0 0,291 213.41c0,-1.15 0,-2.29 -0.08,-3.43a41.46,41.46 0,0 0,-5 -0.33A40.73,40.73 0,0 0,255.34 223.43Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.27\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.27\"\n                    android:endX=\"291.01\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF56B6FE\" />\n                <item\n                        android:offset=\"0.61\"\n                        android:color=\"#FF599CFA\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF5C89F7\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n            android:pathData=\"M425.54,288.63A19.26,19.26 0,0 1,412 256a18.21,18.21 0,0 1,13.56 -5.51,16.9 16.9,0 0,1 13.42,6l-3.37,3.26a12.48,12.48 0,0 0,-10 -4.74,13.79 13.79,0 0,0 -10.15,4.08 15.74,15.74 0,0 0,0 21,13.79 13.79,0 0,0 10.15,4.08q6.38,0 11.07,-5.36L440,282.1a17.81,17.81 0,0 1,-6.38 4.82A19.4,19.4 0,0 1,425.54 288.63Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M448.9,251.3v36.51h-4.69V251.3Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M452.93,275.32a13.24,13.24 0,0 1,3.62 -9.54,12.34 12.34,0 0,1 9.23,-3.78 12.16,12.16 0,0 1,9.18 3.78,14.22 14.22,0 0,1 0,19.07 12.16,12.16 0,0 1,-9.18 3.78,12.34 12.34,0 0,1 -9.23,-3.78A13.21,13.21 0,0 1,452.93 275.32ZM457.62,275.32a9.11,9.11 0,0 0,2.35 6.52,8 8,0 0,0 11.63,0 10.2,10.2 0,0 0,0 -13,7.91 7.91,0 0,0 -11.63,0A9.06,9.06 0,0 0,457.62 275.32Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M504.59,287.81h-4.48v-3.47h-0.21a8.23,8.23 0,0 1,-3.29 3.06,9.4 9.4,0 0,1 -4.61,1.23q-4.59,0 -7.07,-2.63t-2.47,-7.47V262.82h4.69v15.4q0.15,6.12 6.17,6.12a5.83,5.83 0,0 0,4.69 -2.27,8.2 8.2,0 0,0 1.89,-5.43V262.82h4.69Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M520.51,288.63a11,11 0,0 1,-8.42 -3.88,14.56 14.56,0 0,1 0,-18.87 11,11 0,0 1,8.42 -3.88,10.8 10.8,0 0,1 5,1.18 8.76,8.76 0,0 1,3.49 3.11h0.21l-0.21,-3.47L529,251.3h4.69v36.51h-4.48v-3.47L529,284.34a8.68,8.68 0,0 1,-3.49 3.11A10.68,10.68 0,0 1,520.51 288.63ZM521.27,284.34a7.17,7.17 0,0 0,5.66 -2.5,10.33 10.33,0 0,0 0,-13 7.2,7.2 0,0 0,-5.66 -2.55,7.32 7.32,0 0,0 -5.66,2.55 9.32,9.32 0,0 0,-2.29 6.48,9.17 9.17,0 0,0 2.29,6.47A7.32,7.32 0,0 0,521.27 284.34Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M562.78,278.05a9.52,9.52 0,0 1,-3.51 7.71,13.42 13.42,0 0,1 -8.67,2.87 12.86,12.86 0,0 1,-8 -2.65,13.64 13.64,0 0,1 -4.8,-7.25l4.49,-1.83a11.62,11.62 0,0 0,1.28 3,9.63 9.63,0 0,0 1.91,2.27 8.72,8.72 0,0 0,2.42 1.47,7.4 7.4,0 0,0 2.81,0.54 8,8 0,0 0,5.25 -1.66,5.38 5.38,0 0,0 2,-4.41 5.29,5.29 0,0 0,-1.68 -3.93q-1.59,-1.58 -5.92,-3.06a58.57,58.57 0,0 1,-5.46 -2.14q-5.8,-3 -5.81,-8.72a8.89,8.89 0,0 1,3.21 -6.88,11.72 11.72,0 0,1 8,-2.86 12.28,12.28 0,0 1,7.24 2.14,10.07 10.07,0 0,1 4.08,5.25l-4.38,1.84a6.49,6.49 0,0 0,-2.43 -3.39,7.86 7.86,0 0,0 -9.05,0.17 4.42,4.42 0,0 0,-1.88 3.71,4.31 4.31,0 0,0 1.47,3.25q1.64,1.37 7.09,3.25t7.93,4.62A9.93,9.93 0,0 1,562.78 278.05Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M576.25,288.22a7.15,7.15 0,0 1,-5.08 -1.89,7 7,0 0,1 -2.06,-5.25v-14h-4.39v-4.29h4.39v-7.65h4.69v7.65h6.12v4.29H573.8v12.44c0,1.67 0.32,2.8 1,3.39a3.14,3.14 0,0 0,2.19 0.89,5 5,0 0,0 1.1,-0.12 5.48,5.48 0,0 0,1 -0.34l1.48,4.19A12.62,12.62 0,0 1,576.25 288.22Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M589.1,287.81h-4.69v-25h4.49v4.08h0.2a6.82,6.82 0,0 1,2.93 -3.39,8.17 8.17,0 0,1 4.36,-1.4 8.76,8.76 0,0 1,3.47 0.61l-1.43,4.54a7.69,7.69 0,0 0,-2.75 -0.36,6.11 6.11,0 0,0 -4.62,2.14 7.17,7.17 0,0 0,-2 5Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M612.61,288.63a12,12 0,0 1,-9.08 -3.78,13.3 13.3,0 0,1 -3.57,-9.53 13.61,13.61 0,0 1,3.47 -9.52,12.46 12.46,0 0,1 17.72,-0.2q3.3,3.6 3.29,10.07l-0.05,0.51L604.76,276.18a8.13,8.13 0,0 0,2.44 5.92,7.83 7.83,0 0,0 5.61,2.24c3,0 5.34,-1.49 7,-4.48l4.18,2a12.46,12.46 0,0 1,-4.66 4.94A12.91,12.91 0,0 1,612.61 288.63ZM605.11,272.31h14.33a6.2,6.2 0,0 0,-2.11 -4.31,7.43 7.43,0 0,0 -5.13,-1.71 6.77,6.77 0,0 0,-4.56 1.63A7.79,7.79 0,0 0,605.11 272.31Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M638.47,262a11.62,11.62 0,0 1,8.21 2.79,9.87 9.87,0 0,1 3,7.62v15.4L645.2,287.81v-3.47L645,284.34a9,9 0,0 1,-7.76 4.29,10.09 10.09,0 0,1 -6.91,-2.45 7.82,7.82 0,0 1,-2.78 -6.12,7.43 7.43,0 0,1 2.94,-6.17 12.33,12.33 0,0 1,7.82 -2.3,13.86 13.86,0 0,1 6.89,1.53v-1.07a5.34,5.34 0,0 0,-1.94 -4.15,6.63 6.63,0 0,0 -4.54,-1.71 7.18,7.18 0,0 0,-6.22 3.31l-4.13,-2.6Q631.79,262 638.47,262ZM632.4,280.16a3.74,3.74 0,0 0,1.55 3.06,5.73 5.73,0 0,0 3.65,1.23 7.51,7.51 0,0 0,5.28 -2.2,6.89 6.89,0 0,0 2.32,-5.15 9.67,9.67 0,0 0,-6.12 -1.73,8 8,0 0,0 -4.77,1.37A4.11,4.11 0,0 0,632.4 280.16Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M659.68,287.81H655v-25h4.49v3.47h0.2a8.36,8.36 0,0 1,3.29 -3.06,9 9,0 0,1 4.41,-1.23 9.15,9.15 0,0 1,4.85 1.28,7.55 7.55,0 0,1 3.06,3.52 9.75,9.75 0,0 1,8.62 -4.8,8.45 8.45,0 0,1 6.68,2.66c1.56,1.77 2.34,4.28 2.34,7.55v15.6h-4.69V272.92q0,-3.53 -1.27,-5.08c-0.85,-1 -2.28,-1.55 -4.29,-1.55a5.61,5.61 0,0 0,-4.54 2.29,8.43 8.43,0 0,0 -1.83,5.41v13.82h-4.69V272.92q0,-3.53 -1.28,-5.08c-0.85,-1 -2.28,-1.55 -4.28,-1.55a5.58,5.58 0,0 0,-4.54 2.29,8.38 8.38,0 0,0 -1.84,5.41Z\"\n            android:fillColor=\"#5252ff\" />\n    <path android:pathData=\"M-13.76,555.76c10.3,-20.89 58.91,-113.94 157.31,-139.7C261.3,385.24 405.9,462.43 469.89,613.28\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M318.2,592.15c52.89,-55.46 139,-131.3 263,-187.83 223.69,-102 495.29,-119.94 515.35,-62.21 13,37.39 -73.5,124.43 -496.69,339.65\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"400.11\"\n                    android:endX=\"900\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M-57.58,195c206.91,86.6 494,-219.13 453.91,-347.48C353.52,-289.67 -103.15,-353.41 -203.15,-176 -265.5,-65.35 -189.57,139.73 -57.58,195Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"-100\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M698.42,648.89C625.71,546 764,320.79 920.68,218.45c46.61,-30.44 110.17,-72 164.35,-50.08 102.25,41.28 158.19,303.22 28.17,446.08C996.65,742.52 762.64,739.78 698.42,648.89Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"700.11\"\n                    android:endX=\"900.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M339.91,-42.46a246.52,141.46 0,1 0,493.04 0a246.52,141.46 0,1 0,-493.04 0z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"400.11\"\n                    android:endX=\"800.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_cloudstreamlogotv_2.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:width=\"907.09dp\"\n        android:height=\"510.24dp\"\n        android:viewportWidth=\"907.09\"\n        android:viewportHeight=\"510.24\">\n    <path\n            android:strokeWidth=\"1\"\n            android:pathData=\"M-20.09,-10.91h949.79v534.26h-949.79z\"\n            android:fillColor=\"#121212\"\n            android:strokeColor=\"#fff\" />\n    <path android:pathData=\"M273.68,250.58a18.79,18.79 0,0 0,-5.64 0.86,26.56 26.56,0 0,0 -24.73,-21.51 40.83,40.83 0,0 0,-68.95 -13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H273.68a18.9,18.9 0,0 0,0 -37.8Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"245.72\"\n                    android:startX=\"113.12\"\n                    android:endY=\"245.72\"\n                    android:endX=\"292.58\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M248.76,234.41c0,-1.22 0,-2.42 -0.09,-3.63a27,27 0,0 0,-5.36 -0.85,40.83 40.83,0 0,0 -68.95,-13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H228.5A81.75,81.75 0,0 0,248.76 234.41Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"245.72\"\n                    android:startX=\"113.12\"\n                    android:endY=\"245.72\"\n                    android:endX=\"248.76\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF4F6DFB\" />\n                <item\n                        android:offset=\"0.6\"\n                        android:color=\"#FF3559E7\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2149D8\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M174.36,216.85A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.89,18.89 0,0 0,-1.18 37.74A81.53,81.53 0,0 0,210 206.83c0,-1.15 0,-2.29 -0.09,-3.43a41.33,41.33 0,0 0,-5 -0.33A40.71,40.71 0,0 0,174.36 216.85Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"245.69\"\n                    android:startX=\"113.12\"\n                    android:endY=\"245.69\"\n                    android:endX=\"210.03\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF56B6FE\" />\n                <item\n                        android:offset=\"0.61\"\n                        android:color=\"#FF599CFA\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF5C89F7\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n\n    <path\n            android:pathData=\"M358.81,285q-13.53,0 -22.64,-9.1t-9,-22.72q0,-13.62 9,-22.64 9,-9.18 22.64,-9.19 13.79,0 22.38,10l-5.62,5.44a20.82,20.82 0,0 0,-16.76 -7.91,23 23,0 0,0 -16.94,6.81q-6.72,6.72 -6.72,17.53t6.72,17.53a23,23 0,0 0,16.94 6.81q10.63,0 18.46,-8.94l5.7,5.53a29.57,29.57 0,0 1,-10.63 8A32.44,32.44 0,0 1,358.81 285Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M397.78,222.69v60.93H390V222.69Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M404.5,262.77q0,-9.61 6,-15.91a20.6,20.6 0,0 1,15.41 -6.3,20.31 20.31,0 0,1 15.31,6.3 21.87,21.87 0,0 1,6.13 15.91q0,9.71 -6.13,15.92A20.3,20.3 0,0 1,426 285a20.6,20.6 0,0 1,-15.41 -6.29Q404.5,272.39 404.5,262.77ZM412.33,262.77a15.31,15.31 0,0 0,3.91 10.9,13.38 13.38,0 0,0 19.41,0 17,17 0,0 0,0 -21.7,13.18 13.18,0 0,0 -19.41,0A15.18,15.18 0,0 0,412.33 262.77Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M490.7,283.62h-7.48v-5.78h-0.35a13.86,13.86 0,0 1,-5.48 5.1,15.77 15.77,0 0,1 -7.7,2q-7.67,0 -11.79,-4.38t-4.13,-12.47v-26.2h7.83v25.69q0.25,10.22 10.3,10.22a9.81,9.81 0,0 0,7.83 -3.79,13.7 13.7,0 0,0 3.14,-9.06V241.93h7.83Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M517.25,285a18.34,18.34 0,0 1,-14 -6.46,24.34 24.34,0 0,1 0,-31.49 18.35,18.35 0,0 1,14 -6.47,18.07 18.07,0 0,1 8.39,2 14.84,14.84 0,0 1,5.83 5.19h0.34l-0.34,-5.78L531.47,222.69h7.82v60.93h-7.48v-5.78h-0.34a14.84,14.84 0,0 1,-5.83 5.19A18.07,18.07 0,0 1,517.25 285ZM518.53,277.86a12,12 0,0 0,9.45 -4.17q3.82,-4.17 3.83,-10.9A15.54,15.54 0,0 0,528 252a12.05,12.05 0,0 0,-9.45 -4.26,12.19 12.19,0 0,0 -9.44,4.26 15.5,15.5 0,0 0,-3.83 10.8,15.32 15.32,0 0,0 3.83,10.81A12.19,12.19 0,0 0,518.53 277.84Z\"\n            android:fillColor=\"#2e24ff\" />\n    <path\n            android:pathData=\"M587.8,267.33a15.91,15.91 0,0 1,-5.87 12.88A22.43,22.43 0,0 1,567.46 285a21.39,21.39 0,0 1,-13.36 -4.42,22.65 22.65,0 0,1 -8,-12.08l7.49,-3.07a19.3,19.3 0,0 0,2.13 4.94,15.72 15.72,0 0,0 3.19,3.78 14.25,14.25 0,0 0,4 2.47,12.26 12.26,0 0,0 4.68,0.9 13.47,13.47 0,0 0,8.76 -2.77,9 9,0 0,0 3.41,-7.36 8.8,8.8 0,0 0,-2.81 -6.55q-2.64,-2.64 -9.87,-5.11 -7.32,-2.64 -9.11,-3.57 -9.69,-4.94 -9.7,-14.55a14.84,14.84 0,0 1,5.37 -11.49A19.53,19.53 0,0 1,567 221.33a20.5,20.5 0,0 1,12.09 3.58,16.67 16.67,0 0,1 6.8,8.76l-7.31,3.06a10.84,10.84 0,0 0,-4 -5.65,13.1 13.1,0 0,0 -15.11,0.28 7.41,7.41 0,0 0,-3.15 6.19,7.14 7.14,0 0,0 2.47,5.42q2.73,2.29 11.83,5.42 9.27,3.17 13.23,7.72A16.53,16.53 0,0 1,587.8 267.33Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M610.26,284.3a11.88,11.88 0,0 1,-8.46 -3.15c-2.25,-2.09 -3.4,-5 -3.45,-8.76V249.07H591v-7.14h7.32V229.16h7.83v12.77h10.21v7.14H606.18v20.77c0,2.78 0.54,4.66 1.61,5.66a5.27,5.27 0,0 0,3.66 1.48,7.9 7.9,0 0,0 1.83,-0.21 9,9 0,0 0,1.66 -0.55l2.47,7A21.23,21.23 0,0 1,610.26 284.3Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M631.71,283.62h-7.83V241.93h7.48v6.8h0.35a11.31,11.31 0,0 1,4.89 -5.66,13.66 13.66,0 0,1 7.27,-2.34 14.7,14.7 0,0 1,5.79 1l-2.38,7.57a12.93,12.93 0,0 0,-4.6 -0.6,10.11 10.11,0 0,0 -7.7,3.58 12,12 0,0 0,-3.27 8.34Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M670.93,285a19.93,19.93 0,0 1,-15.14 -6.29q-6,-6.3 -6,-15.92a22.65,22.65 0,0 1,5.79 -15.87,19.15 19.15,0 0,1 14.8,-6.34q9.29,0 14.77,6t5.49,16.81l-0.09,0.85L657.83,264.24a13.56,13.56 0,0 0,4.08 9.87,13.06 13.06,0 0,0 9.36,3.75q7.49,0 11.75,-7.49l7,3.4a20.69,20.69 0,0 1,-7.78 8.25A21.51,21.51 0,0 1,670.93 285ZM658.42,257.77h23.92a10.43,10.43 0,0 0,-3.53 -7.19,12.38 12.38,0 0,0 -8.56,-2.85 11.34,11.34 0,0 0,-7.61 2.72A13.09,13.09 0,0 0,658.42 257.75Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M714.08,240.56q8.67,0 13.7,4.64c3.34,3.1 5,7.33 5,12.72v25.7h-7.49v-5.78H725Q720.11,285 712,285a16.83,16.83 0,0 1,-11.53 -4.08,13 13,0 0,1 -4.63,-10.21 12.38,12.38 0,0 1,4.89 -10.3q4.89,-3.83 13.06,-3.83a23.16,23.16 0,0 1,11.49 2.55v-1.78a8.9,8.9 0,0 0,-3.24 -6.94,11.08 11.08,0 0,0 -7.57,-2.85 12,12 0,0 0,-10.38 5.53l-6.89,-4.34Q702.93,240.57 714.08,240.56ZM704,270.86a6.24,6.24 0,0 0,2.59 5.1,9.57 9.57,0 0,0 6.09,2.05 12.5,12.5 0,0 0,8.81 -3.66,11.47 11.47,0 0,0 3.87,-8.6q-3.66,-2.88 -10.21,-2.89a13.22,13.22 0,0 0,-8 2.3A6.81,6.81 0,0 0,704 270.86Z\"\n            android:fillColor=\"#5252ff\" />\n    <path\n            android:pathData=\"M749.47,283.62h-7.82V241.93h7.48v5.78h0.34a14,14 0,0 1,5.49 -5.1,15.06 15.06,0 0,1 7.36,-2.05 15.22,15.22 0,0 1,8.09 2.13,12.56 12.56,0 0,1 5.1,5.87q5.19,-8 14.39,-8 7.23,0 11.14,4.43T805,257.58v26h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.06,9v23.06h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.07,9Z\"\n            android:fillColor=\"#5252ff\" />\n    <path android:pathData=\"M-13.76,555.76c10.3,-20.89 58.91,-113.94 157.31,-139.7C261.3,385.24 405.9,462.43 469.89,613.28\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M318.2,592.15c52.89,-55.46 139,-131.3 263,-187.83 223.69,-102 495.29,-119.94 515.35,-62.21 13,37.39 -73.5,124.43 -496.69,339.65\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"400.11\"\n                    android:endX=\"900\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M-57.58,195c206.91,86.6 494,-219.13 453.91,-347.48C353.52,-289.67 -103.15,-353.41 -203.15,-176 -265.5,-65.35 -189.57,139.73 -57.58,195Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"-100\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M698.42,648.89C625.71,546 764,320.79 920.68,218.45c46.61,-30.44 110.17,-72 164.35,-50.08 102.25,41.28 158.19,303.22 28.17,446.08C996.65,742.52 762.64,739.78 698.42,648.89Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"700.11\"\n                    android:endX=\"900.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M339.91,-42.46a246.52,141.46 0,1 0,493.04 0a246.52,141.46 0,1 0,-493.04 0z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"400.11\"\n                    android:endX=\"800.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#FF5D49EA\" />\n                <item\n                        android:offset=\"0.45\"\n                        android:color=\"#FF452FE4\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#FF2309DB\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_cloudstreamlogotv_pre.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:width=\"907.09dp\"\n        android:height=\"510.24dp\"\n        android:viewportWidth=\"907.09\"\n        android:viewportHeight=\"510.24\">\n    <path\n            android:strokeWidth=\"1\"\n            android:pathData=\"M-20.09,-10.91h949.79v534.26h-949.79z\"\n            android:fillColor=\"#121212\"\n            android:strokeColor=\"#fff\" />\n    <path android:pathData=\"M354.67,257.16A18.81,18.81 0,0 0,349 258a26.55,26.55 0,0 0,-24.72 -21.51,40.84 40.84,0 0,0 -69,-13.08A32.06,32.06 0,0 0,213 253.82c0,1.13 0.06,2.25 0.17,3.35H213a18.9,18.9 0,0 0,0 37.8H354.67a18.9,18.9 0,0 0,0 -37.8Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#DB0909\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#A10808\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M329.74,241c0,-1.22 0,-2.43 -0.09,-3.63a26.9,26.9 0,0 0,-5.35 -0.85,40.84 40.84,0 0,0 -69,-13.08A32.06,32.06 0,0 0,213 253.82c0,1.13 0.06,2.25 0.17,3.35H213a18.9,18.9 0,0 0,0 37.8h96.48A81.79,81.79 0,0 0,329.74 241Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.3\"\n                    android:endX=\"329.74\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E23A3A\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#DD1130\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M255.34,223.43A32.06,32.06 0,0 0,213 253.82c0,1.13 0.06,2.25 0.17,3.35H213a18.89,18.89 0,0 0,-1.18 37.74A81.52,81.52 0,0 0,291 213.41c0,-1.15 0,-2.29 -0.08,-3.43a41.46,41.46 0,0 0,-5 -0.33A40.73,40.73 0,0 0,255.34 223.43Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.27\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.27\"\n                    android:endX=\"291.01\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E44D4D\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E76161\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path\n            android:pathData=\"M425.54,288.63A19.26,19.26 0,0 1,412 256a18.21,18.21 0,0 1,13.56 -5.51,16.9 16.9,0 0,1 13.42,6l-3.37,3.26a12.48,12.48 0,0 0,-10 -4.74,13.79 13.79,0 0,0 -10.15,4.08 15.74,15.74 0,0 0,0 21,13.79 13.79,0 0,0 10.15,4.08q6.38,0 11.07,-5.36L440,282.1a17.81,17.81 0,0 1,-6.38 4.82A19.4,19.4 0,0 1,425.54 288.63Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M448.9,251.3v36.51h-4.69V251.3Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M452.93,275.32a13.24,13.24 0,0 1,3.62 -9.54,12.34 12.34,0 0,1 9.23,-3.78 12.16,12.16 0,0 1,9.18 3.78,14.22 14.22,0 0,1 0,19.07 12.16,12.16 0,0 1,-9.18 3.78,12.34 12.34,0 0,1 -9.23,-3.78A13.21,13.21 0,0 1,452.93 275.32ZM457.62,275.32a9.11,9.11 0,0 0,2.35 6.52,8 8,0 0,0 11.63,0 10.2,10.2 0,0 0,0 -13,7.91 7.91,0 0,0 -11.63,0A9.06,9.06 0,0 0,457.62 275.32Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M504.59,287.81h-4.48v-3.47h-0.21a8.23,8.23 0,0 1,-3.29 3.06,9.4 9.4,0 0,1 -4.61,1.23q-4.59,0 -7.07,-2.63t-2.47,-7.47V262.82h4.69v15.4q0.15,6.12 6.17,6.12a5.83,5.83 0,0 0,4.69 -2.27,8.2 8.2,0 0,0 1.89,-5.43V262.82h4.69Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M520.51,288.63a11,11 0,0 1,-8.42 -3.88,14.56 14.56,0 0,1 0,-18.87 11,11 0,0 1,8.42 -3.88,10.8 10.8,0 0,1 5,1.18 8.76,8.76 0,0 1,3.49 3.11h0.21l-0.21,-3.47L529,251.3h4.69v36.51h-4.48v-3.47L529,284.34a8.68,8.68 0,0 1,-3.49 3.11A10.68,10.68 0,0 1,520.51 288.63ZM521.27,284.34a7.17,7.17 0,0 0,5.66 -2.5,10.33 10.33,0 0,0 0,-13 7.2,7.2 0,0 0,-5.66 -2.55,7.32 7.32,0 0,0 -5.66,2.55 9.32,9.32 0,0 0,-2.29 6.48,9.17 9.17,0 0,0 2.29,6.47A7.32,7.32 0,0 0,521.27 284.34Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M562.78,278.05a9.52,9.52 0,0 1,-3.51 7.71,13.42 13.42,0 0,1 -8.67,2.87 12.86,12.86 0,0 1,-8 -2.65,13.64 13.64,0 0,1 -4.8,-7.25l4.49,-1.83a11.62,11.62 0,0 0,1.28 3,9.63 9.63,0 0,0 1.91,2.27 8.72,8.72 0,0 0,2.42 1.47,7.4 7.4,0 0,0 2.81,0.54 8,8 0,0 0,5.25 -1.66,5.38 5.38,0 0,0 2,-4.41 5.29,5.29 0,0 0,-1.68 -3.93q-1.59,-1.58 -5.92,-3.06a58.57,58.57 0,0 1,-5.46 -2.14q-5.8,-3 -5.81,-8.72a8.89,8.89 0,0 1,3.21 -6.88,11.72 11.72,0 0,1 8,-2.86 12.28,12.28 0,0 1,7.24 2.14,10.07 10.07,0 0,1 4.08,5.25l-4.38,1.84a6.49,6.49 0,0 0,-2.43 -3.39,7.86 7.86,0 0,0 -9.05,0.17 4.42,4.42 0,0 0,-1.88 3.71,4.31 4.31,0 0,0 1.47,3.25q1.64,1.37 7.09,3.25t7.93,4.62A9.93,9.93 0,0 1,562.78 278.05Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M576.25,288.22a7.15,7.15 0,0 1,-5.08 -1.89,7 7,0 0,1 -2.06,-5.25v-14h-4.39v-4.29h4.39v-7.65h4.69v7.65h6.12v4.29H573.8v12.44c0,1.67 0.32,2.8 1,3.39a3.14,3.14 0,0 0,2.19 0.89,5 5,0 0,0 1.1,-0.12 5.48,5.48 0,0 0,1 -0.34l1.48,4.19A12.62,12.62 0,0 1,576.25 288.22Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M589.1,287.81h-4.69v-25h4.49v4.08h0.2a6.82,6.82 0,0 1,2.93 -3.39,8.17 8.17,0 0,1 4.36,-1.4 8.76,8.76 0,0 1,3.47 0.61l-1.43,4.54a7.69,7.69 0,0 0,-2.75 -0.36,6.11 6.11,0 0,0 -4.62,2.14 7.17,7.17 0,0 0,-2 5Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M612.61,288.63a12,12 0,0 1,-9.08 -3.78,13.3 13.3,0 0,1 -3.57,-9.53 13.61,13.61 0,0 1,3.47 -9.52,12.46 12.46,0 0,1 17.72,-0.2q3.3,3.6 3.29,10.07l-0.05,0.51L604.76,276.18a8.13,8.13 0,0 0,2.44 5.92,7.83 7.83,0 0,0 5.61,2.24c3,0 5.34,-1.49 7,-4.48l4.18,2a12.46,12.46 0,0 1,-4.66 4.94A12.91,12.91 0,0 1,612.61 288.63ZM605.11,272.31h14.33a6.2,6.2 0,0 0,-2.11 -4.31,7.43 7.43,0 0,0 -5.13,-1.71 6.77,6.77 0,0 0,-4.56 1.63A7.79,7.79 0,0 0,605.11 272.31Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M638.47,262a11.62,11.62 0,0 1,8.21 2.79,9.87 9.87,0 0,1 3,7.62v15.4L645.2,287.81v-3.47L645,284.34a9,9 0,0 1,-7.76 4.29,10.09 10.09,0 0,1 -6.91,-2.45 7.82,7.82 0,0 1,-2.78 -6.12,7.43 7.43,0 0,1 2.94,-6.17 12.33,12.33 0,0 1,7.82 -2.3,13.86 13.86,0 0,1 6.89,1.53v-1.07a5.34,5.34 0,0 0,-1.94 -4.15,6.63 6.63,0 0,0 -4.54,-1.71 7.18,7.18 0,0 0,-6.22 3.31l-4.13,-2.6Q631.79,262 638.47,262ZM632.4,280.16a3.74,3.74 0,0 0,1.55 3.06,5.73 5.73,0 0,0 3.65,1.23 7.51,7.51 0,0 0,5.28 -2.2,6.89 6.89,0 0,0 2.32,-5.15 9.67,9.67 0,0 0,-6.12 -1.73,8 8,0 0,0 -4.77,1.37A4.11,4.11 0,0 0,632.4 280.16Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M659.68,287.81H655v-25h4.49v3.47h0.2a8.36,8.36 0,0 1,3.29 -3.06,9 9,0 0,1 4.41,-1.23 9.15,9.15 0,0 1,4.85 1.28,7.55 7.55,0 0,1 3.06,3.52 9.75,9.75 0,0 1,8.62 -4.8,8.45 8.45,0 0,1 6.68,2.66c1.56,1.77 2.34,4.28 2.34,7.55v15.6h-4.69V272.92q0,-3.53 -1.27,-5.08c-0.85,-1 -2.28,-1.55 -4.29,-1.55a5.61,5.61 0,0 0,-4.54 2.29,8.43 8.43,0 0,0 -1.83,5.41v13.82h-4.69V272.92q0,-3.53 -1.28,-5.08c-0.85,-1 -2.28,-1.55 -4.28,-1.55a5.58,5.58 0,0 0,-4.54 2.29,8.38 8.38,0 0,0 -1.84,5.41Z\"\n            android:fillColor=\"#E76161\" />\n    <path android:pathData=\"M-13.76,555.76c10.3,-20.89 58.91,-113.94 157.31,-139.7C261.3,385.24 405.9,462.43 469.89,613.28\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M318.2,592.15c52.89,-55.46 139,-131.3 263,-187.83 223.69,-102 495.29,-119.94 515.35,-62.21 13,37.39 -73.5,124.43 -496.69,339.65\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"400.11\"\n                    android:endX=\"900\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M-57.58,195c206.91,86.6 494,-219.13 453.91,-347.48C353.52,-289.67 -103.15,-353.41 -203.15,-176 -265.5,-65.35 -189.57,139.73 -57.58,195Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"-100\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M698.42,648.89C625.71,546 764,320.79 920.68,218.45c46.61,-30.44 110.17,-72 164.35,-50.08 102.25,41.28 158.19,303.22 28.17,446.08C996.65,742.52 762.64,739.78 698.42,648.89Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"700.11\"\n                    android:endX=\"900.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M339.91,-42.46a246.52,141.46 0,1 0,493.04 0a246.52,141.46 0,1 0,-493.04 0z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"400.11\"\n                    android:endX=\"800.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_cloudstreamlogotv_pre_2.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:aapt=\"http://schemas.android.com/aapt\"\n        android:width=\"907.09dp\"\n        android:height=\"510.24dp\"\n        android:viewportWidth=\"907.09\"\n        android:viewportHeight=\"510.24\">\n    <path\n            android:strokeWidth=\"1\"\n            android:pathData=\"M-20.09,-10.91h949.79v534.26h-949.79z\"\n            android:fillColor=\"#121212\"\n            android:strokeColor=\"#fff\" />\n    <path android:pathData=\"M273.68,250.58a18.79,18.79 0,0 0,-5.64 0.86,26.56 26.56,0 0,0 -24.73,-21.51 40.83,40.83 0,0 0,-68.95 -13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H273.68a18.9,18.9 0,0 0,0 -37.8Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"245.72\"\n                    android:startX=\"113.12\"\n                    android:endY=\"245.72\"\n                    android:endX=\"292.58\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#DB0909\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#A10808\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M248.76,234.41c0,-1.22 0,-2.42 -0.09,-3.63a27,27 0,0 0,-5.36 -0.85,40.83 40.83,0 0,0 -68.95,-13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H228.5A81.75,81.75 0,0 0,248.76 234.41Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"245.72\"\n                    android:startX=\"113.12\"\n                    android:endY=\"245.72\"\n                    android:endX=\"248.76\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E23A3A\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#DD1130\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M174.36,216.85A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.89,18.89 0,0 0,-1.18 37.74A81.53,81.53 0,0 0,210 206.83c0,-1.15 0,-2.29 -0.09,-3.43a41.33,41.33 0,0 0,-5 -0.33A40.71,40.71 0,0 0,174.36 216.85Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"245.69\"\n                    android:startX=\"113.12\"\n                    android:endY=\"245.69\"\n                    android:endX=\"210.03\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E44D4D\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E76161\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n\n    <path\n            android:pathData=\"M358.81,285q-13.53,0 -22.64,-9.1t-9,-22.72q0,-13.62 9,-22.64 9,-9.18 22.64,-9.19 13.79,0 22.38,10l-5.62,5.44a20.82,20.82 0,0 0,-16.76 -7.91,23 23,0 0,0 -16.94,6.81q-6.72,6.72 -6.72,17.53t6.72,17.53a23,23 0,0 0,16.94 6.81q10.63,0 18.46,-8.94l5.7,5.53a29.57,29.57 0,0 1,-10.63 8A32.44,32.44 0,0 1,358.81 285Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M397.78,222.69v60.93H390V222.69Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M404.5,262.77q0,-9.61 6,-15.91a20.6,20.6 0,0 1,15.41 -6.3,20.31 20.31,0 0,1 15.31,6.3 21.87,21.87 0,0 1,6.13 15.91q0,9.71 -6.13,15.92A20.3,20.3 0,0 1,426 285a20.6,20.6 0,0 1,-15.41 -6.29Q404.5,272.39 404.5,262.77ZM412.33,262.77a15.31,15.31 0,0 0,3.91 10.9,13.38 13.38,0 0,0 19.41,0 17,17 0,0 0,0 -21.7,13.18 13.18,0 0,0 -19.41,0A15.18,15.18 0,0 0,412.33 262.77Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M490.7,283.62h-7.48v-5.78h-0.35a13.86,13.86 0,0 1,-5.48 5.1,15.77 15.77,0 0,1 -7.7,2q-7.67,0 -11.79,-4.38t-4.13,-12.47v-26.2h7.83v25.69q0.25,10.22 10.3,10.22a9.81,9.81 0,0 0,7.83 -3.79,13.7 13.7,0 0,0 3.14,-9.06V241.93h7.83Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M517.25,285a18.34,18.34 0,0 1,-14 -6.46,24.34 24.34,0 0,1 0,-31.49 18.35,18.35 0,0 1,14 -6.47,18.07 18.07,0 0,1 8.39,2 14.84,14.84 0,0 1,5.83 5.19h0.34l-0.34,-5.78L531.47,222.69h7.82v60.93h-7.48v-5.78h-0.34a14.84,14.84 0,0 1,-5.83 5.19A18.07,18.07 0,0 1,517.25 285ZM518.53,277.86a12,12 0,0 0,9.45 -4.17q3.82,-4.17 3.83,-10.9A15.54,15.54 0,0 0,528 252a12.05,12.05 0,0 0,-9.45 -4.26,12.19 12.19,0 0,0 -9.44,4.26 15.5,15.5 0,0 0,-3.83 10.8,15.32 15.32,0 0,0 3.83,10.81A12.19,12.19 0,0 0,518.53 277.84Z\"\n            android:fillColor=\"#E23A3A\" />\n    <path\n            android:pathData=\"M587.8,267.33a15.91,15.91 0,0 1,-5.87 12.88A22.43,22.43 0,0 1,567.46 285a21.39,21.39 0,0 1,-13.36 -4.42,22.65 22.65,0 0,1 -8,-12.08l7.49,-3.07a19.3,19.3 0,0 0,2.13 4.94,15.72 15.72,0 0,0 3.19,3.78 14.25,14.25 0,0 0,4 2.47,12.26 12.26,0 0,0 4.68,0.9 13.47,13.47 0,0 0,8.76 -2.77,9 9,0 0,0 3.41,-7.36 8.8,8.8 0,0 0,-2.81 -6.55q-2.64,-2.64 -9.87,-5.11 -7.32,-2.64 -9.11,-3.57 -9.69,-4.94 -9.7,-14.55a14.84,14.84 0,0 1,5.37 -11.49A19.53,19.53 0,0 1,567 221.33a20.5,20.5 0,0 1,12.09 3.58,16.67 16.67,0 0,1 6.8,8.76l-7.31,3.06a10.84,10.84 0,0 0,-4 -5.65,13.1 13.1,0 0,0 -15.11,0.28 7.41,7.41 0,0 0,-3.15 6.19,7.14 7.14,0 0,0 2.47,5.42q2.73,2.29 11.83,5.42 9.27,3.17 13.23,7.72A16.53,16.53 0,0 1,587.8 267.33Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M610.26,284.3a11.88,11.88 0,0 1,-8.46 -3.15c-2.25,-2.09 -3.4,-5 -3.45,-8.76V249.07H591v-7.14h7.32V229.16h7.83v12.77h10.21v7.14H606.18v20.77c0,2.78 0.54,4.66 1.61,5.66a5.27,5.27 0,0 0,3.66 1.48,7.9 7.9,0 0,0 1.83,-0.21 9,9 0,0 0,1.66 -0.55l2.47,7A21.23,21.23 0,0 1,610.26 284.3Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M631.71,283.62h-7.83V241.93h7.48v6.8h0.35a11.31,11.31 0,0 1,4.89 -5.66,13.66 13.66,0 0,1 7.27,-2.34 14.7,14.7 0,0 1,5.79 1l-2.38,7.57a12.93,12.93 0,0 0,-4.6 -0.6,10.11 10.11,0 0,0 -7.7,3.58 12,12 0,0 0,-3.27 8.34Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M670.93,285a19.93,19.93 0,0 1,-15.14 -6.29q-6,-6.3 -6,-15.92a22.65,22.65 0,0 1,5.79 -15.87,19.15 19.15,0 0,1 14.8,-6.34q9.29,0 14.77,6t5.49,16.81l-0.09,0.85L657.83,264.24a13.56,13.56 0,0 0,4.08 9.87,13.06 13.06,0 0,0 9.36,3.75q7.49,0 11.75,-7.49l7,3.4a20.69,20.69 0,0 1,-7.78 8.25A21.51,21.51 0,0 1,670.93 285ZM658.42,257.77h23.92a10.43,10.43 0,0 0,-3.53 -7.19,12.38 12.38,0 0,0 -8.56,-2.85 11.34,11.34 0,0 0,-7.61 2.72A13.09,13.09 0,0 0,658.42 257.75Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M714.08,240.56q8.67,0 13.7,4.64c3.34,3.1 5,7.33 5,12.72v25.7h-7.49v-5.78H725Q720.11,285 712,285a16.83,16.83 0,0 1,-11.53 -4.08,13 13,0 0,1 -4.63,-10.21 12.38,12.38 0,0 1,4.89 -10.3q4.89,-3.83 13.06,-3.83a23.16,23.16 0,0 1,11.49 2.55v-1.78a8.9,8.9 0,0 0,-3.24 -6.94,11.08 11.08,0 0,0 -7.57,-2.85 12,12 0,0 0,-10.38 5.53l-6.89,-4.34Q702.93,240.57 714.08,240.56ZM704,270.86a6.24,6.24 0,0 0,2.59 5.1,9.57 9.57,0 0,0 6.09,2.05 12.5,12.5 0,0 0,8.81 -3.66,11.47 11.47,0 0,0 3.87,-8.6q-3.66,-2.88 -10.21,-2.89a13.22,13.22 0,0 0,-8 2.3A6.81,6.81 0,0 0,704 270.86Z\"\n            android:fillColor=\"#E76161\" />\n    <path\n            android:pathData=\"M749.47,283.62h-7.82V241.93h7.48v5.78h0.34a14,14 0,0 1,5.49 -5.1,15.06 15.06,0 0,1 7.36,-2.05 15.22,15.22 0,0 1,8.09 2.13,12.56 12.56,0 0,1 5.1,5.87q5.19,-8 14.39,-8 7.23,0 11.14,4.43T805,257.58v26h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.06,9v23.06h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.07,9Z\"\n            android:fillColor=\"#E76161\" />\n\n    <path android:pathData=\"M-13.76,555.76c10.3,-20.89 58.91,-113.94 157.31,-139.7C261.3,385.24 405.9,462.43 469.89,613.28\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"194.11\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M318.2,592.15c52.89,-55.46 139,-131.3 263,-187.83 223.69,-102 495.29,-119.94 515.35,-62.21 13,37.39 -73.5,124.43 -496.69,339.65\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"400.11\"\n                    android:endX=\"900\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M-57.58,195c206.91,86.6 494,-219.13 453.91,-347.48C353.52,-289.67 -103.15,-353.41 -203.15,-176 -265.5,-65.35 -189.57,139.73 -57.58,195Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"252.3\"\n                    android:startX=\"-100\"\n                    android:endY=\"252.3\"\n                    android:endX=\"373.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M698.42,648.89C625.71,546 764,320.79 920.68,218.45c46.61,-30.44 110.17,-72 164.35,-50.08 102.25,41.28 158.19,303.22 28.17,446.08C996.65,742.52 762.64,739.78 698.42,648.89Z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"700.11\"\n                    android:endX=\"900.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n    <path android:pathData=\"M339.91,-42.46a246.52,141.46 0,1 0,493.04 0a246.52,141.46 0,1 0,-493.04 0z\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startX=\"400.11\"\n                    android:endX=\"800.57\"\n                    android:type=\"linear\">\n                <item\n                        android:offset=\"0\"\n                        android:color=\"#E76161\" />\n                <item\n                        android:offset=\"1\"\n                        android:color=\"#E23A3A\" />\n            </gradient>\n        </aapt:attr>\n    </path>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_dashboard_black_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24.0\"\n        android:viewportHeight=\"24.0\">\n    <path\n            android:fillColor=\"#FF000000\"\n            android:pathData=\"M3,13h8L11,3L3,3v10zM3,21h8v-6L3,15v6zM13,21h8L21,11h-8v10zM13,3v6h8L21,3h-8z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_filled_notifications_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"M160,760v-80h80v-280q0,-83 50,-147.5T420,168v-28q0,-25 17.5,-42.5T480,80q25,0 42.5,17.5T540,140v28q80,20 130,84.5T720,400v280h80v80L160,760ZM480,880q-33,0 -56.5,-23.5T400,800h160q0,33 -23.5,56.5T480,880Z\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_fingerprint.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:width=\"24dp\">\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M17.81,4.47c-0.08,0 -0.16,-0.02 -0.23,-0.06C15.66,3.42 14,3 12.01,3c-1.98,0 -3.86,0.47 -5.57,1.41 -0.24,0.13 -0.54,0.04 -0.68,-0.2 -0.13,-0.24 -0.04,-0.55 0.2,-0.68C7.82,2.52 9.86,2 12.01,2c2.13,0 3.99,0.47 6.03,1.52 0.25,0.13 0.34,0.43 0.21,0.67 -0.09,0.18 -0.26,0.28 -0.44,0.28zM3.5,9.72c-0.1,0 -0.2,-0.03 -0.29,-0.09 -0.23,-0.16 -0.28,-0.47 -0.12,-0.7 0.99,-1.4 2.25,-2.5 3.75,-3.27C9.98,4.04 14,4.03 17.15,5.65c1.5,0.77 2.76,1.86 3.75,3.25 0.16,0.22 0.11,0.54 -0.12,0.7 -0.23,0.16 -0.54,0.11 -0.7,-0.12 -0.9,-1.26 -2.04,-2.25 -3.39,-2.94 -2.87,-1.47 -6.54,-1.47 -9.4,0.01 -1.36,0.7 -2.5,1.7 -3.4,2.96 -0.08,0.14 -0.23,0.21 -0.39,0.21zM9.75,21.79c-0.13,0 -0.26,-0.05 -0.35,-0.15 -0.87,-0.87 -1.34,-1.43 -2.01,-2.64 -0.69,-1.23 -1.05,-2.73 -1.05,-4.34 0,-2.97 2.54,-5.39 5.66,-5.39s5.66,2.42 5.66,5.39c0,0.28 -0.22,0.5 -0.5,0.5s-0.5,-0.22 -0.5,-0.5c0,-2.42 -2.09,-4.39 -4.66,-4.39s-4.66,1.97 -4.66,4.39c0,1.44 0.32,2.77 0.93,3.85 0.64,1.15 1.08,1.64 1.85,2.42 0.19,0.2 0.19,0.51 0,0.71 -0.11,0.1 -0.24,0.15 -0.37,0.15zM16.92,19.94c-1.19,0 -2.24,-0.3 -3.1,-0.89 -1.49,-1.01 -2.38,-2.65 -2.38,-4.39 0,-0.28 0.22,-0.5 0.5,-0.5s0.5,0.22 0.5,0.5c0,1.41 0.72,2.74 1.94,3.56 0.71,0.48 1.54,0.71 2.54,0.71 0.24,0 0.64,-0.03 1.04,-0.1 0.27,-0.05 0.53,0.13 0.58,0.41 0.05,0.27 -0.13,0.53 -0.41,0.58 -0.57,0.11 -1.07,0.12 -1.21,0.12zM14.91,22c-0.04,0 -0.09,-0.01 -0.13,-0.02 -1.59,-0.44 -2.63,-1.03 -3.72,-2.1 -1.4,-1.39 -2.17,-3.24 -2.17,-5.22 0,-1.62 1.38,-2.94 3.08,-2.94s3.08,1.32 3.08,2.94c0,1.07 0.93,1.94 2.08,1.94s2.08,-0.87 2.08,-1.94c0,-3.77 -3.25,-6.83 -7.25,-6.83 -2.84,0 -5.44,1.58 -6.61,4.03 -0.39,0.81 -0.59,1.76 -0.59,2.8 0,0.78 0.07,2.01 0.67,3.61 0.1,0.26 -0.03,0.55 -0.29,0.64 -0.26,0.1 -0.55,-0.04 -0.64,-0.29 -0.49,-1.31 -0.73,-2.61 -0.73,-3.96 0,-1.2 0.23,-2.29 0.68,-3.24 1.33,-2.79 4.28,-4.6 7.51,-4.6 4.55,0 8.25,3.51 8.25,7.83 0,1.62 -1.38,2.94 -3.08,2.94s-3.08,-1.32 -3.08,-2.94c0,-1.07 -0.93,-1.94 -2.08,-1.94s-2.08,0.87 -2.08,1.94c0,1.71 0.66,3.31 1.87,4.51 0.95,0.94 1.86,1.46 3.27,1.85 0.27,0.07 0.42,0.35 0.35,0.61 -0.05,0.23 -0.26,0.38 -0.47,0.38z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_github_logo.xml",
    "content": "<vector android:tint=\"?attr/white\" xmlns:tools=\"http://schemas.android.com/tools\" android:height=\"24dp\" android:viewportHeight=\"1000\"\n        android:viewportWidth=\"1000\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"?attr/white\" android:pathData=\"M455.34,24.62c-61.96,5.16 -121.85,22.37 -176.93,49.91c-80.55,40.62 -140.44,94.66 -190.36,170.73c-35.8,54.39 -60.24,116 -72.29,182.78C7.85,471.07 8.2,555.75 16.11,597.4c33.05,172.45 148.36,312.21 307.73,372.1c26.16,9.98 36.49,10.33 45.44,1.38c6.2,-6.2 6.88,-11.36 6.88,-52.67l0,-45.44l-43.72,-0c-37.86,-0 -46.47,-1.03 -60.24,-7.57c-27.19,-12.39 -45.44,-32.35 -62.65,-68.16c-15.15,-31.67 -34.42,-55.42 -58.17,-72.29c-23.75,-16.87 -5.16,-29.95 28.57,-20.31c14.8,4.48 23.06,9.64 37.86,25.13c10.33,10.67 24.44,26.85 30.98,36.14c7.57,10.67 18.93,20.65 30.98,27.54c16.52,9.29 22.03,10.67 44.75,10.33c14.11,-0.35 31.67,-2.76 38.9,-5.16c12.05,-4.48 13.77,-7.23 20.65,-27.54c4.13,-12.05 11.02,-26.85 15.49,-32.36l7.92,-9.98l-35.46,-7.57c-63.68,-13.43 -99.82,-32.01 -132.52,-68.16c-33.73,-36.83 -52.67,-94.31 -52.67,-160.4c0,-51.63 9.98,-84.68 36.83,-121.17l11.7,-16.18l-4.13,-21c-7.23,-37.52 2.75,-103.96 16.52,-109.12c14.46,-5.51 72.97,15.83 112.21,40.96l16.18,10.33l32.01,-6.2c44.06,-8.95 139.41,-9.29 183.47,-0.34l31.33,6.54l30.29,-17.56c33.73,-19.28 64.71,-30.64 87.43,-32.01l15.49,-1.03l6.54,17.21c8.61,22.03 11.71,70.91 5.85,93.97l-4.13,17.56l15.49,23.41c27.54,41.99 31.67,57.14 31.67,116.35c-0.34,43.37 -1.38,56.11 -7.92,79.17c-19.28,67.12 -60.24,110.84 -125.3,134.59c-8.26,3.1 -30.64,8.95 -50.25,13.08l-35.46,7.57l7.57,9.29c4.13,5.51 10.67,17.9 14.46,27.54c6.88,16.18 7.57,26.16 8.61,107.4c0.69,59.9 2.41,90.88 5.16,93.97c11.71,14.46 27.88,11.71 83.65,-14.8c67.12,-31.32 136.31,-88.12 182.09,-149.39c42.68,-56.45 77.11,-136.31 89.84,-206.88c7.92,-43.72 7.92,-121.51 0,-165.23c-19.96,-110.5 -81.58,-218.24 -165.57,-288.8C716.26,54.91 586.14,12.92 455.34,24.62z\"\n          tools:ignore=\"VectorPath\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_home_black_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24.0\"\n        android:viewportHeight=\"24.0\">\n    <path\n            android:fillColor=\"#FF000000\"\n            android:pathData=\"M10,20v-6h4v6h5v-8h3L12,3 2,12h3v8z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:height=\"108dp\"\n        android:width=\"108dp\"\n        android:viewportHeight=\"108\"\n        android:viewportWidth=\"108\">\n    <path android:fillColor=\"#3DDC84\"\n          android:pathData=\"M0,0h108v108h-108z\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M9,0L9,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,0L19,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,0L29,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,0L39,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,0L49,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,0L59,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,0L69,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,0L79,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M89,0L89,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M99,0L99,108\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,9L108,9\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,19L108,19\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,29L108,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,39L108,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,49L108,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,59L108,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,69L108,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,79L108,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,89L108,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M0,99L108,99\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,29L89,29\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,39L89,39\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,49L89,49\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,59L89,59\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,69L89,69\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M19,79L89,79\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M29,19L29,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M39,19L39,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M49,19L49,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M59,19L59,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M69,19L69,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n    <path android:fillColor=\"#00000000\" android:pathData=\"M79,19L79,89\"\n          android:strokeColor=\"#33FFFFFF\" android:strokeWidth=\"0.8\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\"\n    android:name=\"vector\">\n  <group android:scaleX=\"0.1755477\"\n      android:scaleY=\"0.1755477\"\n      android:translateX=\"29.16\"\n      android:translateY=\"29.16\">\n      <path android:name=\"path\"\n\n            android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n            android:fillColor=\"#2309db\" android:strokeWidth=\"1\"\n            tools:ignore=\"VectorPath\"/>\n      <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n            android:fillColor=\"#2149d8\" android:strokeWidth=\"1\"/>\n      <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n            android:fillColor=\"#5c89f7\" android:strokeWidth=\"1\"/>\n  </group>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_mic.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,14c1.66,0 3,-1.34 3,-3v-4c0,-1.66 -1.34,-3 -3,-3 -1.66,0 -3,1.34 -3,3v4c0,1.66 1.34,3 3,3zM19,11h-2c0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5h-2c0,3.45 2.68,6.29 6,6.92v2.08h-3v2h8v-2h-3v-2.08c3.32,-0.63 6,-3.47 6,-6.92z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/ic_network_stream.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n\n    <path\n        android:fillColor=\"?attr/white\"\n        android:pathData=\"M3.9,12c0,-1.71 1.39,-3.1 3.1,-3.1h4L11,7L7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1zM8,13h8v-2L8,11v2zM17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1s-1.39,3.1 -3.1,3.1h-4L13,17h4c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_notifications_black_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"24.0\"\n        android:viewportHeight=\"24.0\">\n    <path\n            android:fillColor=\"#FF000000\"\n            android:pathData=\"M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_offline_pin_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"M320,680h320v-80L320,600v80ZM438,560 L664,334 607,279 438,448 352,362 296,418 438,560ZM480,880q-83,0 -156,-31.5T197,763q-54,-54 -85.5,-127T80,480q0,-83 31.5,-156T197,197q54,-54 127,-85.5T480,80q83,0 156,31.5T763,197q54,54 85.5,127T880,480q0,83 -31.5,156T763,763q-54,54 -127,85.5T480,880ZM480,800q134,0 227,-93t93,-227q0,-134 -93,-227t-227,-93q-134,0 -227,93t-93,227q0,134 93,227t227,93ZM480,480Z\"\n      android:fillColor=\"#e3e3e3\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_outline_account_circle_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10s10,-4.48 10,-10S17.52,2 12,2zM7.35,18.5C8.66,17.56 10.26,17 12,17s3.34,0.56 4.65,1.5C15.34,19.44 13.74,20 12,20S8.66,19.44 7.35,18.5zM18.14,17.12L18.14,17.12C16.45,15.8 14.32,15 12,15s-4.45,0.8 -6.14,2.12l0,0C4.7,15.73 4,13.95 4,12c0,-4.42 3.58,-8 8,-8s8,3.58 8,8C20,13.95 19.3,15.73 18.14,17.12z\" />\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,6c-1.93,0 -3.5,1.57 -3.5,3.5S10.07,13 12,13s3.5,-1.57 3.5,-3.5S13.93,6 12,6zM12,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S11.17,8 12,8s1.5,0.67 1.5,1.5S12.83,11 12,11z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_outline_home_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,5.69l5,4.5V18h-2v-6H9v6H7v-7.81l5,-4.5M12,3L2,12h3v8h6v-6h2v6h6v-8h3L12,3z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_outline_info_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M11,7h2v2h-2zM11,11h2v6h-2zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_outline_notifications_24dp.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"M160,760v-80h80v-280q0,-83 50,-147.5T420,168v-28q0,-25 17.5,-42.5T480,80q25,0 42.5,17.5T540,140v28q80,20 130,84.5T720,400v280h80v80L160,760ZM480,460ZM480,880q-33,0 -56.5,-23.5T400,800h160q0,33 -23.5,56.5T480,880ZM320,680h320v-280q0,-66 -47,-113t-113,-47q-66,0 -113,47t-47,113v280Z\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_outline_remove_red_eye_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M12,6.5c3.79,0 7.17,2.13 8.82,5.5 -1.65,3.37 -5.02,5.5 -8.82,5.5S4.83,15.37 3.18,12C4.83,8.63 8.21,6.5 12,6.5m0,-2C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,9.5c1.38,0 2.5,1.12 2.5,2.5s-1.12,2.5 -2.5,2.5 -2.5,-1.12 -2.5,-2.5 1.12,-2.5 2.5,-2.5m0,-2c-2.48,0 -4.5,2.02 -4.5,4.5s2.02,4.5 4.5,4.5 4.5,-2.02 4.5,-4.5 -2.02,-4.5 -4.5,-4.5z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_outline_settings_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M19.43,12.98c0.04,-0.32 0.07,-0.64 0.07,-0.98 0,-0.34 -0.03,-0.66 -0.07,-0.98l2.11,-1.65c0.19,-0.15 0.24,-0.42 0.12,-0.64l-2,-3.46c-0.09,-0.16 -0.26,-0.25 -0.44,-0.25 -0.06,0 -0.12,0.01 -0.17,0.03l-2.49,1c-0.52,-0.4 -1.08,-0.73 -1.69,-0.98l-0.38,-2.65C14.46,2.18 14.25,2 14,2h-4c-0.25,0 -0.46,0.18 -0.49,0.42l-0.38,2.65c-0.61,0.25 -1.17,0.59 -1.69,0.98l-2.49,-1c-0.06,-0.02 -0.12,-0.03 -0.18,-0.03 -0.17,0 -0.34,0.09 -0.43,0.25l-2,3.46c-0.13,0.22 -0.07,0.49 0.12,0.64l2.11,1.65c-0.04,0.32 -0.07,0.65 -0.07,0.98 0,0.33 0.03,0.66 0.07,0.98l-2.11,1.65c-0.19,0.15 -0.24,0.42 -0.12,0.64l2,3.46c0.09,0.16 0.26,0.25 0.44,0.25 0.06,0 0.12,-0.01 0.17,-0.03l2.49,-1c0.52,0.4 1.08,0.73 1.69,0.98l0.38,2.65c0.03,0.24 0.24,0.42 0.49,0.42h4c0.25,0 0.46,-0.18 0.49,-0.42l0.38,-2.65c0.61,-0.25 1.17,-0.59 1.69,-0.98l2.49,1c0.06,0.02 0.12,0.03 0.18,0.03 0.17,0 0.34,-0.09 0.43,-0.25l2,-3.46c0.12,-0.22 0.07,-0.49 -0.12,-0.64l-2.11,-1.65zM17.45,11.27c0.04,0.31 0.05,0.52 0.05,0.73 0,0.21 -0.02,0.43 -0.05,0.73l-0.14,1.13 0.89,0.7 1.08,0.84 -0.7,1.21 -1.27,-0.51 -1.04,-0.42 -0.9,0.68c-0.43,0.32 -0.84,0.56 -1.25,0.73l-1.06,0.43 -0.16,1.13 -0.2,1.35h-1.4l-0.19,-1.35 -0.16,-1.13 -1.06,-0.43c-0.43,-0.18 -0.83,-0.41 -1.23,-0.71l-0.91,-0.7 -1.06,0.43 -1.27,0.51 -0.7,-1.21 1.08,-0.84 0.89,-0.7 -0.14,-1.13c-0.03,-0.31 -0.05,-0.54 -0.05,-0.74s0.02,-0.43 0.05,-0.73l0.14,-1.13 -0.89,-0.7 -1.08,-0.84 0.7,-1.21 1.27,0.51 1.04,0.42 0.9,-0.68c0.43,-0.32 0.84,-0.56 1.25,-0.73l1.06,-0.43 0.16,-1.13 0.2,-1.35h1.39l0.19,1.35 0.16,1.13 1.06,0.43c0.43,0.18 0.83,0.41 1.23,0.71l0.91,0.7 1.06,-0.43 1.27,-0.51 0.7,1.21 -1.07,0.85 -0.89,0.7 0.14,1.13zM12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_outline_share_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92s2.92,-1.31 2.92,-2.92c0,-1.61 -1.31,-2.92 -2.92,-2.92zM18,4c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM6,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM18,20.02c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_outline_subtitles_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M20,4L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,18L4,18L4,6h16v12zM6,10h2v2L6,12zM6,14h8v2L6,16zM16,14h2v2h-2zM10,10h8v2h-8z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_outline_voice_over_off_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/white\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M16.76,5.36l-1.68,1.69c0.8,1.13 0.83,2.58 0.09,3.74l1.7,1.7c1.9,-2.02 1.87,-4.98 -0.11,-7.13zM20.07,2l-1.63,1.63c2.72,2.97 2.76,7.39 0.14,10.56l1.64,1.64c3.74,-3.89 3.71,-9.84 -0.15,-13.83zM9.43,5.04l3.53,3.53c-0.2,-1.86 -1.67,-3.33 -3.53,-3.53zM4.41,2.86L3,4.27l2.62,2.62C5.23,7.5 5,8.22 5,9c0,2.21 1.79,4 4,4 0.78,0 1.5,-0.23 2.11,-0.62l4.4,4.4C13.74,15.6 10.78,15 9,15c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-0.37 -0.11,-0.7 -0.29,-1.02L19.73,21l1.41,-1.41L4.41,2.86zM3,19c0.22,-0.72 3.31,-2 6,-2 2.7,0 5.8,1.29 6,2L3,19zM9,11c-1.1,0 -2,-0.9 -2,-2 0,-0.22 0.04,-0.42 0.11,-0.62l2.51,2.51c-0.2,0.07 -0.4,0.11 -0.62,0.11z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_refresh.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"M480,800q-134,0 -227,-93t-93,-227q0,-134 93,-227t227,-93q69,0 132,28.5T720,270v-110h80v280L520,440v-80h168q-32,-56 -87.5,-88T480,240q-100,0 -170,70t-70,170q0,100 70,170t170,70q77,0 139,-44t87,-116h84q-28,106 -114,173t-196,67Z\"\n      android:fillColor=\"#e3e3e3\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/indicator_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:shape=\"rectangle\">\n    <solid android:color=\"@color/textColor\"/>\n    <corners android:radius=\"16dp\" />\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/kid_star_24px.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"10dp\"\n    android:height=\"10dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M305,256L417,111Q429,95 445.5,87.5Q462,80 480,80Q498,80 514.5,87.5Q531,95 543,111L655,256L825,313Q851,321 866,342.5Q881,364 881,390Q881,402 877.5,414Q874,426 866,437L756,593L760,757Q761,792 737,816Q713,840 681,840Q679,840 659,837L480,787L301,837Q296,839 290,839.5Q284,840 279,840Q247,840 223,816Q199,792 200,757L204,592L95,437Q87,426 83.5,414Q80,402 80,390Q80,365 94.5,343.5Q109,322 135,313L305,256Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/kitsu_icon.xml",
    "content": "<vector xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:height=\"24dp\"\n        android:tint=\"?attr/white\"\n        android:viewportHeight=\"225\"\n        android:viewportWidth=\"225\"\n        android:width=\"24dp\">\n    <path\n            android:fillColor=\"@android:color/white\"\n            android:pathData=\"M152.7 48.5c-6.8-2.5-14.1-4.1-21.8-4.4-12.7-0.6-24.8 2.2-35.4 7.6-0.6 0.3-1.3 0.6-2 1v36.4c0 0.5 0 2.4-0.3 4-0.7 3.7-2.9 7-6 9.1-2.6 1.8-5.6 2.6-8.8 2.5-0.6 0-1.3-0.1-1.9-0.2-1.6-0.3-3.3-0.9-3.8-1.1-1.4-0.5-21.8-8.4-31.6-12.2-1.2-0.5-2.2-0.9-3-1.2-11.7 9.9-24 21.7-35.5 35.6-0.1 0.1-0.6 0.7-0.7 0.8-1.5 2.1-1.6 5.1 0 7.4 1.2 1.7 3.1 2.7 5 2.8 1.3 0.1 2.7-0.3 3.9-1.1 0.1-0.1 0.2-0.2 0.4-0.3 12.2-8.8 25.6-15.9 39.8-21.6 1-0.5 2.2-0.8 3.3-0.7 1.6 0.1 3.1 0.7 4.3 1.9 2.3 2.3 2.4 6 0.5 8.5-0.8 1.2-1.5 2.4-2.2 3.6-7.6 12.4-13.7 25.9-18.3 40-0.1 0.4-0.2 0.7-0.3 1.1v0.1c-0.4 1.7-0.1 3.5 1 5 1.2 1.7 3.1 2.7 5.1 2.8 1.4 0.1 2.7-0.3 3.9-1.1 0.5-0.4 1-0.8 1.4-1.3 0.1-0.2 0.3-0.4 0.4-0.6 5-7.1 10.5-13.8 16.4-20 26.3-28.2 61.2-48.1 100.3-55.9 0.3-0.1 0.6-0.1 0.9-0.1 2.2 0.1 3.9 2 3.8 4.2-0.1 1.9-1.4 3.3-3.2 3.7-36.3 7.7-101.7 50.8-78.8 113.4 0.4 1 0.7 1.6 1.2 2.5 1.2 1.7 3.1 2.7 5 2.8 1.1 0 4.2-0.3 6.1-3.7 3.7-7 10.7-14.8 30.9-23.2 56.3-23.3 65.6-56.6 66.6-77.7v-1.2c0.9-31.4-18.6-58.8-46.6-69.2zm-56.5 165C91 198 91.5 183 97.6 168.7c11.7 18.9 32.1 20.5 32.1 20.5-20.9 8.7-29.1 17.3-33.5 24.3z\"\n            tools:ignore=\"VectorPath\" />\n    <path\n            android:fillColor=\"@android:color/white\"\n            android:pathData=\"M1.1 50.6c0.1 0.2 0.3 0.4 0.4 0.5 5.3 7.2 11.3 13.5 17.8 19.1 0.1 0.1 0.2 0.1 0.2 0.2 4.2 3.6 12.2 8.8 18 10.9 0 0 36.1 13.9 38 14.7 0.7 0.3 1.7 0.6 2.2 0.7 1.6 0.3 3.3 0 4.8-1s2.4-2.5 2.7-4.1c0.1-0.6 0.2-1.6 0.2-2.3V48.5c0.1-6.2-1.9-15.6-3.7-20.8 0-0.1-0.1-0.2-0.1-0.3-2.8-8.1-6.6-16-11.4-23.5l-0.3-0.6-0.1-0.1c-2-2.8-6-3.5-8.9-1.5-0.5 0.3-0.8 0.7-1.2 1.1-0.3 0.4-0.5 0.7-0.8 1.1-6.4 9.3-9 20.6-7.3 31.7-3.3 1.7-6.8 4-7.2 4.3-0.4 0.3-3.9 2.7-6.6 5.2-9.7-5.5-21.3-7.2-32.2-4.6-0.4 0.1-0.9 0.2-1.3 0.3-0.5 0.2-1 0.4-1.4 0.7-2.9 2-3.7 5.9-1.8 8.9v0.2zm63.5-40.1c3.4 5.7 6.3 11.6 8.6 17.8-4.6 0.8-9.1 2-13.5 3.6-0.6-7.5 1.1-14.9 4.9-21.4zM31.5 51.3c-3.2 3.5-5.9 7.3-8.3 11.3-4.9-4.3-9.4-9.2-13.5-14.4 7.5-1.3 15-0.2 21.8 3.1z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/library_icon.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:width=\"24dp\"\r\n    android:height=\"24dp\"\r\n    android:viewportWidth=\"960\"\r\n    android:viewportHeight=\"960\"\r\n    android:tint=\"?attr/white\">\r\n    <path\r\n        android:fillColor=\"@android:color/white\"\r\n        android:pathData=\"M160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L400,160L480,240L800,240Q833,240 856.5,263.5Q880,287 880,320L447,320L367,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720L256,400L940,400L837,743Q829,769 807.5,784.5Q786,800 760,800L160,800ZM244,720L760,720L832,480L316,480L244,720ZM244,720L316,480L316,480L244,720L244,720ZM160,320L160,240Q160,240 160,240Q160,240 160,240L160,240L160,320L160,320Z\"/>\r\n</vector>\r\n"
  },
  {
    "path": "app/src/main/res/drawable/library_icon_filled.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:pathData=\"M160,800q-33,0 -56.5,-23.5T80,720v-480q0,-33 23.5,-56.5T160,160h240l80,80h320q33,0 56.5,23.5T880,320L160,320v400l96,-320h684L837,743q-8,26 -29.5,41.5T760,800L160,800Z\"\n      android:fillColor=\"@android:color/white\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/library_icon_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/library_icon_filled\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/library_icon_filled\" android:state_focused=\"true\"/>\n    <item android:drawable=\"@drawable/library_icon\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/mal_logo.xml",
    "content": "<vector\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:name=\"vector\"\n        android:width=\"30dp\"\n        android:height=\"30dp\"\n        android:viewportWidth=\"850\"\n        android:viewportHeight=\"850\"\n        android:tint=\"?attr/white\"\n>\n    <path\n            android:name=\"path\"\n            android:pathData=\"M 402 556 C 401.57 555.28 401 554.28 400.25 553 C 387.65 531.12 334.6 431 378.5 352.25 C 385.214 340.432 393.638 329.673 403.5 320.32 C 423 303 449 293.09 460.38 290.67 L 554.88 290.67 L 570 342.59 L 474 342.59 C 439.5 353.17 427.17 389 428 395.8 L 494.67 395.8 L 494.67 349 L 560.33 349 L 560.33 522.67 L 494.67 522.67 L 494.67 445.67 L 423 445.67 C 422.007 448.508 421.834 451.568 422.5 454.5 C 427.77 479.68 441.74 506.43 450 521 Z M 606.67 523.33 L 606.67 290.67 L 669.33 290.67 L 669.33 471.33 L 750.67 471.33 L 738 523.33 L 606.67 523.33 Z M 268.5 523.33 L 268.5 384 L 214 445.5 L 163.5 384 L 163.5 523.33 L 102.5 523.33 L 102.5 290.67 L 165.5 290.67 L 213.5 362.5 L 266.5 290.67 L 329 290.67 L 329 523.33 L 268.5 523.33 Z\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/material_outline_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/primaryBlackBackground\"/>\n    <stroke android:width=\"@dimen/mtrl_btn_stroke_size\" android:color=\"@color/mtrl_btn_stroke_color_selector\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/monke_benene.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"36\"\n    android:viewportWidth=\"33.91\" android:width=\"22.606667dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M8.57,13.19c0,-3.37 -4.21,-2.53 -3.37,0.84s2.53,4.2 2.53,4.2ZM30.44,13.19c0,-3.37 4.2,-2.53 3.36,0.84s-2.52,4.2 -2.52,4.2Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M31.83,18c0,9.16 -4,11.85 -12.33,11.85S7.18,27.17 7.18,18 11.13,0 19.5,0 31.83,8.85 31.83,18Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M27.55,19.08c1.25,-3.75 1.76,-6.16 -0.37,-6.16L11.83,12.92c-2.13,0 -1.63,2.41 -0.38,6.16C7.31,28.5 18.8,29 19.5,29S31.53,28.13 27.55,19.08Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M16.98,14.87a1.69,1.69 0,0 1,-3.37 0c0,-0.93 0.76,-0.84 1.69,-0.84S16.98,13.94 16.98,14.87ZM25.39,14.87a1.68,1.68 0,0 1,-3.36 0c0,-0.93 0.75,-0.84 1.68,-0.84S25.39,13.94 25.39,14.87Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M16.26,19.63a1.2,0.84 0,1 0,2.4 0a1.2,0.84 0,1 0,-2.4 0z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M22.75,19.63c0,0.46 -0.54,0.84 -1.21,0.84s-1.2,-0.38 -1.2,-0.84 0.54,-0.84 1.2,-0.84S22.75,19.16 22.75,19.63Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M22.04,17.43a3.06,3.06 0,0 0,-2.54 0.7,3 3,0 0,0 -2.54,-0.7c-2.65,0.35 -2.76,2.76 -1.63,2.61 0.64,-0.09 0.11,-0.79 1.44,-1.31a3.16,3.16 0,0 1,2.73 0.56,3.16 3.16,0 0,1 2.73,-0.56c1.33,0.52 0.8,1.22 1.44,1.31C24.81,20.19 24.7,17.78 22.04,17.43Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M7.94,13.71c1.18,-1 -0.91,-3.16 -1.85,-2.14 -0.29,0.32 0.78,-0.15 1.13,0.92C7.47,13.28 7.22,14.34 7.94,13.71ZM31.07,13.71c-1.18,-1 0.9,-3.16 1.84,-2.14 0.29,0.32 -0.77,-0.15 -1.12,0.92C31.53,13.28 31.79,14.34 31.07,13.71Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M24.13,23.59a16.07,16.07 0,0 1,-3.21 0.52,15.89 15.89,0 0,1 -2.9,-0.09l0,-0.91a16.84,16.84 0,0 0,2.9 0.09A16.19,16.19 0,0 0,24.13 22.68Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M25.7,24.84c0.17,-0.58 -0.82,-0.91 -1.08,-1.8 -0.34,-1.14 0.86,-2.22 0.49,-2.57a0.67,0.67 0,0 0,-0.82 0.1,4.37 4.37,0 0,0 -0.49,2.57 4.49,4.49 0,0 0,1.09 1.8c0.12,0.13 0.3,0.31 0.49,0.27A0.48,0.48 0,0 0,25.7 24.84Z\"/>\n    <path android:fillColor=\"#ffe8b6\" android:pathData=\"M18.21,16.52c-0.48,0.07 -0.89,1 -1.25,0.91s-0.22,-0.86 -0.43,-0.89 -0.33,0.75 -0.73,0.83c-0.19,0.05 -0.37,-0.09 -0.55,-0.28 -0.17,0.65 -0.33,1.47 -0.68,2.52 -1.22,3.64 -3.64,5.47 -6.07,7.89s1.82,4.86 4.25,3 4.79,-4.26 5.46,-7.29S18.75,17.87 18.21,16.52Z\"/>\n    <path android:fillColor=\"#ffd983\" android:pathData=\"M18.21,19a14.71,14.71 0,0 1,-2.43 7.89c-1.82,2.42 -4.25,3 -2.43,0.6s3,-4.25 3.65,-6.67S18.21,16.58 18.21,19Z\"/>\n    <path android:fillColor=\"#ffcc4d\" android:pathData=\"M12.75,26.29a3.56,3.56 0,0 0,-1.82 -3.64c-1.21,-0.63 -6.07,0.6 -2.43,0.6 1.82,0 2.43,1.22 1.21,2.43a1.87,1.87 0,0 0,-0.37 0.56c-0.26,0.21 -0.53,0.43 -0.84,0.66 -1.37,1 -3.55,2.56 -6.07,4.24C0.61,32.36 0,33 0,33.57c0,1.82 5.46,1.82 8.5,0.61a22.15,22.15 0,0 0,6.07 -4.25l2.43,-2.43A3.43,3.43 0,0 0,12.75 26.29Z\"/>\n    <path android:fillColor=\"#ffe8b6\" android:pathData=\"M12.75,26.29A3.35,3.35 0,0 0,10.93 22a6.62,6.62 0,0 0,-6.68 0.61c-1.82,1.21 -1.21,2.43 -1.82,3s0.61,1.22 1.82,0 5.05,-3 6.68,-2.43C12.75,23.86 12.13,25.07 12.75,26.29Z\"/>\n    <path android:fillColor=\"#a6d388\" android:pathData=\"M15.18,35.39L12.75,35.39c-1.22,0 -1.82,0.61 -2.43,0.61s-1.21,-1.21 0,-1.21 2.43,0 3,-0.61S16.39,35.39 15.18,35.39Z\"/>\n    <path android:fillColor=\"#3e721d\" android:pathData=\"M10.32,35.39m-0.61,0a0.61,0.61 0,1 1,1.22 0a0.61,0.61 0,1 1,-1.22 0\"/>\n    <path android:fillColor=\"#ffcc4d\" android:pathData=\"M18.94,31.14s-2.55,4.25 -3.76,4.25L12.75,35.39c-1.22,0 0,-0.6 0.6,-1.21s3,0 3,-3.64C16.39,28.72 18.94,31.14 18.94,31.14Z\"/>\n    <path android:fillColor=\"#ffe8b6\" android:pathData=\"M15.18,25.68a4.56,4.56 0,0 1,4.24 5.46c-0.6,3.65 -3,4.25 -4.24,4.25L13.96,35.39c-1.21,0 -0.61,-0.6 0,-1.21s2.43,0 2.43,-3.64c0,-1.82 -2.43,-4.25 -3.64,-4.25A6.23,6.23 0,0 1,15.18 25.68Z\"/>\n    <path android:fillColor=\"#ffd983\" android:pathData=\"M9.71,26.9c1.82,0 3,0.6 1.82,1.82a15.81,15.81 0,0 1,-6.07 3.64c-2.42,0.61 -4.85,0.61 -3,-0.61S8.36,26.9 9.71,26.9Z\"/>\n    <path android:fillColor=\"#c1694f\" android:pathData=\"M0.61,33c0.61,0 0.61,0 0.61,0.4s0,0.81 -0.61,0.81 -0.61,-0.81 -0.61,-0.81S0,33 0.61,33Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/monke_burrito.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"34.64\"\n    android:viewportWidth=\"29.82\" android:width=\"20.660507dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M4.48,13.19c0,-3.37 -4.21,-2.53 -3.37,0.84s2.53,4.2 2.53,4.2ZM26.35,13.19c0,-3.37 4.2,-2.53 3.36,0.84s-2.52,4.2 -2.52,4.2Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M27.74,18c0,9.16 -4,11.85 -12.33,11.85S3.09,27.17 3.09,18 7.04,0 15.41,0 27.74,8.85 27.74,18Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M23.46,19.08c1.25,-3.75 1.76,-6.16 -0.37,-6.16L7.74,12.92c-2.13,0 -1.63,2.41 -0.38,6.16C3.22,28.5 14.71,29 15.41,29S27.44,28.13 23.46,19.08Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M12.89,14.87a1.69,1.69 0,0 1,-3.37 0c0,-0.93 0.76,-0.84 1.69,-0.84S12.89,13.94 12.89,14.87ZM21.3,14.87a1.68,1.68 0,0 1,-3.36 0c0,-0.93 0.75,-0.84 1.68,-0.84S21.3,13.94 21.3,14.87Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M12.17,19.63a1.2,0.84 0,1 0,2.4 0a1.2,0.84 0,1 0,-2.4 0z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M18.66,19.63c0,0.46 -0.54,0.84 -1.21,0.84s-1.2,-0.38 -1.2,-0.84 0.54,-0.84 1.2,-0.84S18.66,19.16 18.66,19.63Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M17.95,17.43a3.06,3.06 0,0 0,-2.54 0.7,3 3,0 0,0 -2.54,-0.7c-2.65,0.35 -2.76,2.76 -1.63,2.61 0.64,-0.09 0.11,-0.79 1.44,-1.31a3.16,3.16 0,0 1,2.73 0.56,3.16 3.16,0 0,1 2.73,-0.56c1.33,0.52 0.8,1.22 1.44,1.31C20.72,20.19 20.61,17.78 17.95,17.43Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M3.85,13.71c1.18,-1 -0.91,-3.16 -1.85,-2.14 -0.29,0.32 0.78,-0.15 1.13,0.92C3.38,13.28 3.13,14.34 3.85,13.71ZM26.98,13.71c-1.18,-1 0.9,-3.16 1.84,-2.14 0.29,0.32 -0.77,-0.15 -1.12,0.92C27.44,13.28 27.7,14.34 26.98,13.71Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M20.04,23.59a16.07,16.07 0,0 1,-3.21 0.52,15.89 15.89,0 0,1 -2.9,-0.09l0,-0.91a16.84,16.84 0,0 0,2.9 0.09A16.19,16.19 0,0 0,20.04 22.68Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M21.61,24.84c0.17,-0.58 -0.82,-0.91 -1.08,-1.8 -0.34,-1.14 0.86,-2.22 0.49,-2.57a0.67,0.67 0,0 0,-0.82 0.1,4.37 4.37,0 0,0 -0.49,2.57 4.49,4.49 0,0 0,1.09 1.8c0.12,0.13 0.3,0.31 0.49,0.27A0.48,0.48 0,0 0,21.61 24.84Z\"/>\n    <path android:fillColor=\"#ffcc4d\" android:pathData=\"M3.54,26.08v0a2,2 0,0 0,0.22 1.54A1.94,1.94 0,0 0,5.04 28.73a1.41,1.41 0,0 0,0.58 0,3.46 3.46,0 0,1 2.14,0.22 0.42,0.42 0,0 1,0.22 0.37c0,0.26 0.32,0.41 0.76,0.42a2.72,2.72 0,0 0,1.9 -0.72l1,-1 2.19,-2.23a4.58,4.58 0,0 1,-5.19 0.21,2.82 2.82,0 0,1 -0.68,-4.32L4.14,25.49 4.04,25.56Z\"/>\n    <path android:fillColor=\"#ffac33\" android:pathData=\"M7.21,27.73a0.62,0.62 0,0 0,0.68 -0.09,0.3 0.3,0 0,0 -0.09,-0.5 0.62,0.62 0,0 0,-0.68 0.09A0.29,0.29 0,0 0,7.21 27.73Z\"/>\n    <path android:fillColor=\"#d99e82\" android:pathData=\"M4.72,27.43c0.11,0.23 0.32,0.28 0.48,0.12a0.68,0.68 0,0 0,0.12 -0.71,0.28 0.28,0 0,0 -0.48,-0.11A0.66,0.66 0,0 0,4.72 27.43Z\"/>\n    <path android:fillColor=\"#ffac33\" android:pathData=\"M6.04,24.22a0.3,0.3 0,0 1,0.5 0.09,0.6 0.6,0 0,1 -0.1,0.68 0.28,0.28 0,0 1,-0.49 -0.09A0.59,0.59 0,0 1,6.04 24.22Z\"/>\n    <path android:fillColor=\"#d99e82\" android:pathData=\"M9.59,28.29a0.81,0.81 0,0 1,0.74 -0.14c0.25,0.08 0.31,0.28 0.15,0.44a0.8,0.8 0,0 1,-0.74 0.15C9.5,28.66 9.43,28.46 9.59,28.29Z\"/>\n    <path android:fillColor=\"#bdbdbd\" android:pathData=\"M0.63,33.12a3.6,3.6 0,0 0,1.66 1.29L7.75,29a3.47,3.47 0,0 0,-2.14 -0.22,1.41 1.41,0 0,1 -0.58,0ZM0.04,31.38l3.74,-3.74a2.13,2.13 0,0 1,-0.21 -1.56L4.04,25.56c-0.59,0 -1.44,-0.31 -1.73,0s0.45,0.85 0,1.73L0.89,28.74h0A3.58,3.58 0,0 0,0.04 31.38Z\"/>\n    <path android:fillColor=\"#808285\" android:pathData=\"M3.85,34.63a3.77,3.77 0,0 0,2.06 -0.88l2.06,-2.06c0.59,-0.59 1.57,-0.2 2.36,-0.59 1.18,-0.59 0.59,-1.77 0.89,-2.07a0.86,0.86 0,0 0,0.15 -0.74l-0.74,0.74a2.72,2.72 0,0 1,-1.9 0.72Z\"/>\n    <path android:fillColor=\"#a6a6a6\" android:pathData=\"M2.29,34.41a3.5,3.5 0,0 0,1.56 0.22l4.88,-4.88c-0.44,0 -0.77,-0.16 -0.76,-0.42a0.42,0.42 0,0 0,-0.22 -0.37Z\"/>\n    <path android:fillColor=\"#d8d8d8\" android:pathData=\"M0.04,31.38a3.78,3.78 0,0 0,0.62 1.74L5.04,28.73a2,2 0,0 1,-1.28 -1.09Z\"/>\n    <path android:fillColor=\"#ffac33\" android:pathData=\"M14.13,23.1a2.27,2.27 0,0 0,-1 -1.54,3.48 3.48,0 0,0 -4.22,0.38 2.48,2.48 0,0 0,-0.38 0.49l3,0a1.86,1.86 0,0 1,1.05 -0.28,1.6 1.6,0 0,1 1.08,0.55 0.73,0.73 0,0 1,0.18 0.35A0.39,0.39 0,0 1,14.13 23.1ZM8.49,22.43ZM13.88,24.43h0a2.09,2.09 0,0 0,0.25 -1.35,1.67 1.67,0 0,1 0,0.63 0.31,0.31 0,0 1,-0.15 0.08,0.44 0.44,0 0,1 -0.11,0.2l0,0A0.56,0.56 0,0 1,13.88 24.46Z\"/>\n    <path android:fillColor=\"#c1694f\" android:pathData=\"M14.13,23.1h0Z\"/>\n    <path android:fillColor=\"#ffe8b6\" android:pathData=\"M8.66,26a4.58,4.58 0,0 0,5.19 -0.21,3 3,0 0,0 -0.17,-4.8 4.53,4.53 0,0 0,-5.52 0.49l-0.18,0.2A2.82,2.82 0,0 0,8.66 26ZM8.49,22.45a2.48,2.48 0,0 1,0.38 -0.49,3.48 3.48,0 0,1 4.22,-0.38 2.27,2.27 0,0 1,1 1.54h0a2,2 0,0 1,-0.25 1.35,2.32 2.32,0 0,1 -0.41,0.55 3.48,3.48 0,0 1,-4.22 0.38,2.16 2.16,0 0,1 -0.77,-3h0\"/>\n    <path android:fillColor=\"#c1694f\" android:pathData=\"M13.47,25a2.32,2.32 0,0 0,0.41 -0.55h0a0.56,0.56 0,0 0,0 -0.42l0,0a0.44,0.44 0,0 0,0.11 -0.2,0.31 0.31,0 0,0 0.15,-0.08 1.67,1.67 0,0 0,0 -0.63h0a0.39,0.39 0,0 0,-0.37 -0.08,0.73 0.73,0 0,0 -0.18,-0.35 1.6,1.6 0,0 0,-1.08 -0.55,1.86 1.86,0 0,0 -1.05,0.28l-3,0h0a2.16,2.16 0,0 0,0.77 3A3.48,3.48 0,0 0,13.47 25Z\"/>\n    <path android:fillColor=\"#f4900c\" android:pathData=\"M12.5,22.16h0a3.52,3.52 0,0 0,-3.9 0.1,2.57 2.57,0 0,0 -0.2,0.35l3.05,-0.11A1.89,1.89 0,0 1,12.5 22.16Z\"/>\n    <path android:fillColor=\"#d99e82\" android:pathData=\"M12.69,23.43m-0.42,0a0.42,0.42 0,1 1,0.84 0a0.42,0.42 0,1 1,-0.84 0\"/>\n    <path android:fillColor=\"#d99e82\" android:pathData=\"M12.1,24.31m-0.63,0a0.63,0.63 0,1 1,1.26 0a0.63,0.63 0,1 1,-1.26 0\"/>\n    <path android:fillColor=\"#d99e82\" android:pathData=\"M10.92,24.61m-0.42,0a0.42,0.42 0,1 1,0.84 0a0.42,0.42 0,1 1,-0.84 0\"/>\n    <path android:fillColor=\"#d99e82\" android:pathData=\"M13.28,23.13m-0.21,0a0.21,0.21 0,1 1,0.42 0a0.21,0.21 0,1 1,-0.42 0\"/>\n    <path android:fillColor=\"#d99e82\" android:pathData=\"M11.81,25.49m-0.42,0a0.42,0.42 0,1 1,0.84 0a0.42,0.42 0,1 1,-0.84 0\"/>\n    <path android:fillColor=\"#ffd983\" android:pathData=\"M12.4,22.25m-0.63,0a0.63,0.63 0,1 1,1.26 0a0.63,0.63 0,1 1,-1.26 0\"/>\n    <path android:fillColor=\"#d99e82\" android:pathData=\"M10.52,25.88a3,3 0,0 0,0.79 0,0.43 0.43,0 0,0 -0.09,-0.43 0.42,0.42 0,0 0,-0.59 0A0.42,0.42 0,0 0,10.52 25.88Z\"/>\n    <path android:fillColor=\"#77b255\" android:pathData=\"M8.27,23.72a0.37,0.37 0,0 0,0.2 0.11v0.05a0.42,0.42 0,0 0,0.09 0.14,0.42 0.42,0 0,0 0,0.59 0.43,0.43 0,0 0,0.47 0.08h0l0.1,-0.07A0.42,0.42 0,0 0,9.74 24a0.51,0.51 0,0 0,0.09 -0.13,0.58 0.58,0 0,0 0.61,-0.13 0.52,0.52 0,0 0,0.14 -0.22,0.4 0.4,0 0,0 0.34,-0.11 0.4,0.4 0,0 0,0 -0.59l0.07,-0.09a0.83,0.83 0,0 0,0.82 -1.39,0.84 0.84,0 0,0 -1.42,0.47A0.39,0.39 0,0 0,10.04 22a0.37,0.37 0,0 0,-0.11 0.19,0.5 0.5,0 0,0 -0.19,0.1 0.42,0.42 0,0 0,-0.59 0h0a0.41,0.41 0,0 0,0 0.58,0.44 0.44,0 0,0 0,0.6 0.37,0.37 0,0 0,-0.19 -0.11,0.44 0.44,0 0,0 -0.1,-0.19 0.42,0.42 0,0 0,-0.59 0A0.41,0.41 0,0 0,8.27 23.72Z\"/>\n    <path android:fillColor=\"#a6d388\" android:pathData=\"M8.85,23.43m-0.21,0a0.21,0.21 0,1 1,0.42 0a0.21,0.21 0,1 1,-0.42 0\"/>\n    <path android:fillColor=\"#ffd983\" android:pathData=\"M9.74,25.2m-0.42,0a0.42,0.42 0,1 1,0.84 0a0.42,0.42 0,1 1,-0.84 0\"/>\n    <path android:fillColor=\"#ffd983\" android:pathData=\"M9.89,24.75a0.61,0.61 0,0 0,0.88 0,0.52 0.52,0 0,0 0.14,-0.19 0.62,0.62 0,0 0,0.85 -0.85,0.67 0.67,0 0,0 0.19,-0.14 0.62,0.62 0,1 0,-1 -0.13,0.63 0.63,0 0,0 -0.2,0.13 0.86,0.86 0,0 0,-0.13 0.2,0.62 0.62,0 0,0 -0.75,1Z\"/>\n    <path android:fillColor=\"#ffe8b6\" android:pathData=\"M10.7,24.24m-0.52,0a0.52,0.52 0,1 1,1.04 0a0.52,0.52 0,1 1,-1.04 0\"/>\n    <path android:fillColor=\"#ffe8b6\" android:pathData=\"M11.29,23.35m-0.31,0a0.31,0.31 0,1 1,0.62 0a0.31,0.31 0,1 1,-0.62 0\"/>\n    <path android:fillColor=\"#ffe8b6\" android:pathData=\"M11.88,22.76m-0.31,0a0.31,0.31 0,1 1,0.62 0a0.31,0.31 0,1 1,-0.62 0\"/>\n    <path android:fillColor=\"#a6d388\" android:pathData=\"M11.51,21.95m-0.21,0a0.21,0.21 0,1 1,0.42 0a0.21,0.21 0,1 1,-0.42 0\"/>\n    <path android:fillColor=\"#77b255\" android:pathData=\"M8.85,22.54m-0.42,0a0.42,0.42 0,1 1,0.84 0a0.42,0.42 0,1 1,-0.84 0\"/>\n    <path android:fillColor=\"#a6d388\" android:pathData=\"M9.15,23.43m-0.42,0a0.42,0.42 0,1 1,0.84 0a0.42,0.42 0,1 1,-0.84 0\"/>\n    <path android:fillColor=\"#a6d388\" android:pathData=\"M9.59,23.28a0.63,0.63 0,0 0,1 -0.72l0,0a0.42,0.42 0,1 0,0 -0.59A0.42,0.42 0,0 0,10.04 22a0.37,0.37 0,0 0,-0.12 0.27,0.66 0.66,0 0,0 -0.33,0.17A0.64,0.64 0,0 0,9.59 23.28Z\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M10.7,21.58m-0.31,0a0.31,0.31 0,1 1,0.62 0a0.31,0.31 0,1 1,-0.62 0\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M8.93,22.76m-0.31,0a0.31,0.31 0,1 1,0.62 0a0.31,0.31 0,1 1,-0.62 0\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M9.15,24.02m-0.42,0a0.42,0.42 0,1 1,0.84 0a0.42,0.42 0,1 1,-0.84 0\"/>\n    <path android:fillColor=\"#77b255\" android:pathData=\"M9.45,22a0.41,0.41 0,0 0,0 0.59A0.42,0.42 0,0 0,10.04 22a0.42,0.42 0,0 0,-0.59 -0.59A0.41,0.41 0,0 0,9.45 22Z\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M10.03,22.54m-0.42,0a0.42,0.42 0,1 1,0.84 0a0.42,0.42 0,1 1,-0.84 0\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M9.44,21.66m-0.21,0a0.21,0.21 0,1 1,0.42 0a0.21,0.21 0,1 1,-0.42 0\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/monke_coco.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"33.77\"\n    android:viewportWidth=\"29.51\" android:width=\"20.972462dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M4.16,13.19c0,-3.37 -4.21,-2.53 -3.37,0.84s2.53,4.2 2.53,4.2ZM26.03,13.19c0,-3.37 4.2,-2.53 3.36,0.84s-2.52,4.2 -2.52,4.2Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M27.42,18c0,9.16 -4,11.85 -12.33,11.85S2.77,27.17 2.77,18 6.72,0 15.09,0 27.42,8.85 27.42,18Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M23.14,19.08c1.25,-3.75 1.76,-6.16 -0.37,-6.16L7.42,12.92c-2.13,0 -1.63,2.41 -0.38,6.16C2.9,28.5 14.39,29 15.09,29S27.12,28.13 23.14,19.08Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M12.57,14.87a1.69,1.69 0,0 1,-3.37 0c0,-0.93 0.76,-0.84 1.69,-0.84S12.57,13.94 12.57,14.87ZM20.98,14.87a1.68,1.68 0,0 1,-3.36 0c0,-0.93 0.75,-0.84 1.68,-0.84S20.98,13.94 20.98,14.87Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M11.85,19.63a1.2,0.84 0,1 0,2.4 0a1.2,0.84 0,1 0,-2.4 0z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M18.34,19.63c0,0.46 -0.54,0.84 -1.21,0.84s-1.2,-0.38 -1.2,-0.84 0.54,-0.84 1.2,-0.84S18.34,19.16 18.34,19.63Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M17.63,17.43a3.06,3.06 0,0 0,-2.54 0.7,3 3,0 0,0 -2.54,-0.7c-2.65,0.35 -2.76,2.76 -1.63,2.61 0.64,-0.09 0.11,-0.79 1.44,-1.31a3.16,3.16 0,0 1,2.73 0.56,3.16 3.16,0 0,1 2.73,-0.56c1.33,0.52 0.8,1.22 1.44,1.31C20.4,20.19 20.29,17.78 17.63,17.43Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M3.53,13.71c1.18,-1 -0.91,-3.16 -1.85,-2.14 -0.29,0.32 0.78,-0.15 1.13,0.92C3.06,13.28 2.81,14.34 3.53,13.71ZM26.66,13.71c-1.18,-1 0.9,-3.16 1.84,-2.14 0.29,0.32 -0.77,-0.15 -1.12,0.92C27.12,13.28 27.38,14.34 26.66,13.71Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M19.72,23.59a16.07,16.07 0,0 1,-3.21 0.52,15.89 15.89,0 0,1 -2.9,-0.09l0,-0.91a16.84,16.84 0,0 0,2.9 0.09A16.19,16.19 0,0 0,19.72 22.68Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M21.29,24.84c0.17,-0.58 -0.82,-0.91 -1.08,-1.8 -0.34,-1.14 0.86,-2.22 0.49,-2.57a0.67,0.67 0,0 0,-0.82 0.1,4.37 4.37,0 0,0 -0.49,2.57 4.49,4.49 0,0 0,1.09 1.8c0.12,0.13 0.3,0.31 0.49,0.27A0.48,0.48 0,0 0,21.29 24.84Z\"/>\n    <path android:fillColor=\"#c1694f\" android:pathData=\"M14.22,23.82c-0.11,-0.44 0.63,-0.91 0.46,-1.28s-1.05,-0.09 -1.28,-0.42 0,-0.57 0.51,-1.31l-2.37,-2.37c-0.69,-0.69 -1.19,-0.69 -1.89,0L1.15,27a1.77,1.77 0,0 0,0 2.52l3.15,3.15a1.79,1.79 0,0 0,2.52 0l8.27,-8.28C14.51,24.21 14.27,24 14.22,23.82Z\"/>\n    <path android:fillColor=\"#8a4b38\" android:pathData=\"M9.27,25.12l2.18,-2.18 2.52,2.52 0.63,-0.63 -2.52,-2.52L13.72,20.65 13.12,20l-1.67,1.66 -2.52,-2.52 -0.63,0.63 2.52,2.52 -2.17,2.18Z\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M0.52,29.47A1.77,1.77 0,0 1,0.52 27l4.41,-4.41 6.3,6.3L6.82,33.25a1.79,1.79 0,0 1,-2.52 0Z\"/>\n    <path android:fillColor=\"#be1931\" android:pathData=\"M5.6,22.12l-0.67,0.42 -0.24,0.23 3.55,9.06 2.08,-2.08Z\"/>\n    <path android:fillColor=\"#ccd6dd\" android:pathData=\"M7.13,21.59l5.67,5.67a1,1 0,0 1,0 1.26l-2.36,2.36c-0.79,0.79 -1.1,-0.15 -1.1,-0.15 -0.63,-1.26 -4.1,-7.25 -4.41,-8.19l0.94,-0.95A0.87,0.87 0,0 1,7.13 21.59Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/monke_cookie.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"33.12\"\n    android:viewportWidth=\"28.82\" android:width=\"20.884058dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M3.48,13.19c0,-3.37 -4.21,-2.53 -3.37,0.84s2.53,4.2 2.53,4.2ZM25.35,13.19c0,-3.37 4.2,-2.53 3.36,0.84s-2.52,4.2 -2.52,4.2Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M26.74,18c0,9.16 -4,11.85 -12.33,11.85S2.09,27.17 2.09,18 6.04,0 14.41,0 26.74,8.85 26.74,18Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M22.46,19.08c1.25,-3.75 1.76,-6.16 -0.37,-6.16L6.74,12.92c-2.13,0 -1.63,2.41 -0.38,6.16C2.22,28.5 13.71,29 14.41,29S26.44,28.13 22.46,19.08Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M11.89,14.87a1.69,1.69 0,0 1,-3.37 0c0,-0.93 0.76,-0.84 1.69,-0.84S11.89,13.94 11.89,14.87ZM20.3,14.87a1.68,1.68 0,0 1,-3.36 0c0,-0.93 0.75,-0.84 1.68,-0.84S20.3,13.94 20.3,14.87Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M11.17,19.63a1.2,0.84 0,1 0,2.4 0a1.2,0.84 0,1 0,-2.4 0z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M17.66,19.63c0,0.46 -0.54,0.84 -1.21,0.84s-1.2,-0.38 -1.2,-0.84 0.54,-0.84 1.2,-0.84S17.66,19.16 17.66,19.63Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M16.95,17.43a3.06,3.06 0,0 0,-2.54 0.7,3 3,0 0,0 -2.54,-0.7c-2.65,0.35 -2.76,2.76 -1.63,2.61 0.64,-0.09 0.11,-0.79 1.44,-1.31a3.16,3.16 0,0 1,2.73 0.56,3.16 3.16,0 0,1 2.73,-0.56c1.33,0.52 0.8,1.22 1.44,1.31C19.72,20.19 19.61,17.78 16.95,17.43Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M2.85,13.71c1.18,-1 -0.91,-3.16 -1.85,-2.14 -0.29,0.32 0.78,-0.15 1.13,0.92C2.38,13.28 2.13,14.34 2.85,13.71ZM25.98,13.71c-1.18,-1 0.9,-3.16 1.84,-2.14 0.29,0.32 -0.77,-0.15 -1.12,0.92C26.44,13.28 26.7,14.34 25.98,13.71Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M19.04,23.59a16.07,16.07 0,0 1,-3.21 0.52,15.89 15.89,0 0,1 -2.9,-0.09l0,-0.91a16.84,16.84 0,0 0,2.9 0.09A16.19,16.19 0,0 0,19.04 22.68Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M20.61,24.84c0.17,-0.58 -0.82,-0.91 -1.08,-1.8 -0.34,-1.14 0.86,-2.22 0.49,-2.57a0.67,0.67 0,0 0,-0.82 0.1,4.37 4.37,0 0,0 -0.49,2.57 4.49,4.49 0,0 0,1.09 1.8c0.12,0.13 0.3,0.31 0.49,0.27A0.48,0.48 0,0 0,20.61 24.84Z\"/>\n    <path android:fillColor=\"#da9f83\" android:pathData=\"M15.25,24a1.4,1.4 0,0 1,-1 -0.06c-0.74,-0.38 -0.54,-1.4 -1.17,-1.63s-1.57,0.93 -2.12,0.62c-0.38,-0.22 -0.06,-0.86 -0.52,-1.37s-1.65,-0.27 -1.83,-0.72 0.78,-1 0.59,-1.47 -1.05,-0.1 -1.31,-0.49a0.94,0.94 0,0 1,0.06 -0.79h-0.14A8.2,8.2 0,0 0,6.33 18a7.51,7.51 0,0 0,-1.37 0.58,7.26 7.26,0 0,0 -1.39,0.53 7,7 0,0 0,-1 1.08,6 6,0 0,0 -1.59,2.44A7.54,7.54 0,0 0,0.34 24a7.38,7.38 0,0 0,0.62 4.33A7.29,7.29 0,0 0,3.54 31.92a8.17,8.17 0,0 0,1.41 0.52,5.39 5.39,0 0,0 4.32,0.4 6.91,6.91 0,0 0,4 -1.91c1.22,-1.54 2.33,-3.36 2.15,-5.43A11.14,11.14 0,0 0,15.25 24Z\"/>\n    <path android:fillColor=\"#8a4b38\" android:pathData=\"M9.89,25.09a1,1 0,0 1,0.62 1.9c-0.52,0.17 -1.72,0.09 -1.89,-0.44S9.37,25.26 9.89,25.09ZM13.71,24.79a0.48,0.48 0,0 1,-0.73 -0.61c0.17,-0.2 0.67,-0.47 0.87,-0.3S13.88,24.59 13.71,24.79ZM3.92,21.68a0.48,0.48 0,0 1,-0.73 -0.62c0.17,-0.2 0.67,-0.47 0.87,-0.3S4.09,21.47 3.92,21.68ZM5.77,23.6a1,1 0,1 1,1.72 -0.83c0.23,0.48 0.31,1.62 -0.17,1.85S6.04,24.08 5.77,23.6ZM6.23,29.87a0.86,0.86 0,0 1,1.19 -0.22,0.85 0.85,0 0,1 0.21,1.19c-0.26,0.39 -1.12,1 -1.51,0.69S5.96,30.26 6.23,29.87ZM10.68,29.69a0.65,0.65 0,1 1,0.71 -1.1c0.3,0.19 0.76,0.83 0.57,1.14S11.04,29.89 10.68,29.69ZM2.28,25.69A0.92,0.92 0,0 1,3.66 27c-0.34,0.38 -1.34,0.87 -1.71,0.53S1.94,26.12 2.28,25.74Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/monke_drink.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"35.86\"\n    android:viewportWidth=\"26.7\" android:width=\"17.869492dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M4.12,11.75c0,-3 -3.74,-2.25 -3,0.75s2.24,3.74 2.24,3.74ZM23.61,11.75c0,-3 3.74,-2.25 3,0.75s-2.25,3.74 -2.25,3.74Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M24.84,16.05c0,8.16 -3.51,10.55 -11,10.55s-11,-2.39 -11,-10.55 3.51,-16 11,-16S24.84,7.93 24.84,16.05Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M21.03,16.99c1.12,-3.34 1.57,-5.48 -0.33,-5.48L7.03,11.51c-1.9,0 -1.45,2.14 -0.33,5.48 -3.7,8.4 6.54,8.86 7.16,8.86S24.58,25.06 21.03,16.99Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M11.62,13.25a1.5,1.5 0,1 1,-3 0c0,-0.83 0.67,-0.75 1.5,-0.75S11.62,12.42 11.62,13.25ZM19.11,13.25a1.5,1.5 0,1 1,-3 0c0,-0.83 0.67,-0.75 1.5,-0.75S19.11,12.42 19.11,13.25Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M10.97,17.48a1.07,0.75 0,1 0,2.14 0a1.07,0.75 0,1 0,-2.14 0z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M16.75,17.48c0,0.42 -0.47,0.75 -1.07,0.75s-1.07,-0.33 -1.07,-0.75 0.48,-0.75 1.07,-0.75S16.75,17.07 16.75,17.48Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M16.13,15.52a2.76,2.76 0,0 0,-2.27 0.63,2.73 2.73,0 0,0 -2.26,-0.63c-2.36,0.32 -2.46,2.47 -1.45,2.33 0.57,-0.08 0.1,-0.7 1.28,-1.17a2.83,2.83 0,0 1,2.43 0.5,2.82 2.82,0 0,1 2.44,-0.49c1.18,0.46 0.71,1.08 1.28,1.16C18.59,17.99 18.49,15.84 16.13,15.52Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M3.56,12.22c1.06,-0.92 -0.8,-2.83 -1.64,-1.91 -0.26,0.28 0.69,-0.14 1,0.81C3.2,11.83 2.92,12.78 3.56,12.22ZM24.16,12.22c-1.05,-0.92 0.81,-2.83 1.65,-1.91 0.26,0.28 -0.69,-0.14 -1,0.81C24.58,11.83 24.81,12.78 24.2,12.22Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M12.49,20.89a1.37,1.72 0,1 0,2.74 0a1.37,1.72 0,1 0,-2.74 0z\"/>\n    <path android:fillColor=\"#8b5e3c\" android:pathData=\"M5.58,35.69c-4,-0.9 -6.35,-5.2 -5.35,-9.59l14.33,3.27C13.55,33.76 9.53,36.59 5.58,35.69Z\"/>\n    <path android:fillColor=\"#603913\" android:pathData=\"M0.2,26.1c-0.5,2.2 2.3,4.71 6.26,5.61s7.56,-0.14 8.07,-2.34 -2.3,-4.71 -6.26,-5.61S0.73,23.93 0.2,26.1Z\"/>\n    <path android:fillColor=\"#f5f8fa\" android:pathData=\"M13.3,27.93a0.39,0.39 0,0 0,0.37 -0.1,0.41 0.41,0 0,0 0.11,-0.42 5.16,5.16 0,0 0,-3.49 -3.24A13.06,13.06 0,0 1,8.2 23.35c-0.23,-0.06 -0.31,0.06 -0.74,0 -0.2,0 -1,-0.47 -1.4,1.18a0.41,0.41 0,0 0,0.24 0.47l7,3Z\"/>\n    <path android:fillColor=\"#603913\" android:pathData=\"M7.2,23.81l0.82,0.17s1.43,0.45 2.23,0.63a4.75,4.75 0,0 1,3.19 3l-7.43,-2.88S6.7,23.72 7.2,23.81ZM7.35,23.06a2,2 0,0 0,-1.82 1.33,0.94 0.94,0 0,0 0.64,0.94l7,3 0.14,0.05a0.79,0.79 0,0 0,0.73 -0.2,0.78 0.78,0 0,0 0.22,-0.85 5.52,5.52 0,0 0,-3.78 -3.51,16.15 16.15,0 0,1 -1.64,-0.37 11.24,11.24 0,0 0,-1.22 -0.36Z\"/>\n    <path android:fillColor=\"#f5f8fa\" android:pathData=\"M1.03,26.28C0.63,28.04 3.2,30.11 6.67,30.93s6.69,0 7.09,-1.73 -2.12,-3.84 -5.64,-4.64S1.43,24.52 1.03,26.28Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M2.2,26.58c-0.3,1.3 1.77,2.89 4.63,3.54s5.41,0.12 5.71,-1.18 -1.78,-2.89 -4.63,-3.54S2.51,25.27 2.2,26.58Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M6.26,25.51l0.34,-0.37a0.65,0.65 0,0 1,0.69 -0.35l0.69,0.17c0.35,0.12 1.13,0.32 1.74,0.46a3.75,3.75 0,0 1,2.71 2.6,0.21 0.21,0 0,1 -0.06,0.21 0.23,0.23 0,0 1,-0.18 0h0l-5.79,-2.47a0.19,0.19 0,0 1,-0.11 -0.12A0.22,0.22 0,0 1,6.26 25.51Z\"/>\n    <path android:fillColor=\"#e1e8ed\" android:pathData=\"M13.45,20.28l-3.11,0.77a3.09,3.09 0,0 0,-1.11 0.57,2.9 2.9,0 0,0 -1,1.75l-1.87,6.49h1.42l1.76,-6.11a2.1,2.1 0,0 1,0.51 -1,2.64 2.64,0 0,1 1,-0.45l2.72,-0.68a0.68,0.68 0,1 0,-0.32 -1.32Z\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M7.12,27.17l-0.36,1.22 0.63,1.12 0.22,0.05 0.28,-0.15 0.17,-0.57ZM13.69,20.27a0.65,0.65 0,0 0,-0.24 0l-0.78,0.19L12.2,21.99l1,-0.25ZM7.45,25.99 L8.39,27.66 8.75,26.43 7.81,24.76ZM9.2,21.63a2.53,2.53 0,0 0,-0.73 0.92l0.6,2.72 0.44,-1.52 0.09,-0.3Z\"/>\n    <path android:fillColor=\"#f5f8fa\" android:pathData=\"M10.99,30.31a4.72,4.72 0,0 1,-2.12 -0.49c-0.63,-0.51 -2.1,0.24 -2.73,-0.28a24.59,24.59 0,0 0,-2.06 -1.55c-0.45,-0.28 -0.43,0.27 -1.06,-0.25a3.66,3.66 0,0 0,-1.33 -0.67s1.91,3 3,3.28 5.3,1.21 5.38,0.86S10.99,30.31 10.99,30.31Z\"/>\n    <path android:fillColor=\"#603913\" android:pathData=\"M11.04,31.09a5.93,5.93 0,0 1,-2.43 -0.55c-0.65,-0.54 -2.39,0.24 -3.05,-0.29S3.82,28.7 3.62,28.63c-0.57,-0.21 -0.45,0.28 -1.1,-0.26a3.81,3.81 0,0 0,-1.39 -0.7s2,3.17 3.09,3.42 5.53,1.26 5.61,0.89S11.04,31.09 11.04,31.09Z\"/>\n    <path android:fillColor=\"#8b5e3c\" android:pathData=\"M11.04,31.93a5.25,5.25 0,0 1,-2.38 -0.55c-0.71,-0.58 -3,0.16 -3.68,-0.42s-1.31,-1.56 -1.71,-1.65 -0.49,0.31 -1.2,-0.27a4,4 0,0 0,-1.5 -0.76S2.72,31.69 3.92,31.93s6,1.37 6.06,1S11.04,31.93 11.04,31.93Z\"/>\n    <path android:fillColor=\"#a97c50\" android:pathData=\"M7.99,35.47c0,-0.12 0.28,-0.21 0.39,-0.24a6.82,6.82 0,0 0,3.74 -3,0.21 0.21,0 0,1 0.29,-0.08 0.26,0.26 0,0 1,0.05 0.32,7.59 7.59,0 0,1 -4,3s-0.28,0.11 -0.31,0.11S8.01,35.55 7.99,35.47ZM2.99,33.84c0.06,0 0.08,0.05 0.14,0s0,-0.24 -0.09,-0.33a8.27,8.27 0,0 1,-1.61 -4,0.2 0.2,0 0,0 -0.24,-0.16 0.23,0.23 0,0 0,-0.16 0.28,8.66 8.66,0 0,0 1.86,4.14A0.21,0.21 0,0 0,2.94 33.84ZM8.56,34.76a0.2,0.2 0,0 0,0.13 0,5.54 5.54,0 0,0 2.16,-1.94 0.24,0.24 0,0 0,0 -0.31,0.2 0.2,0 0,0 -0.29,0.07 4.08,4.08 0,0 1,-1.82 1.84c-0.1,0.05 -0.29,0.18 -0.25,0.29S8.45,34.75 8.51,34.76Z\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M10.69,20.93 L10.2,22.62a2.94,2.94 0,0 1,0.87 -0.35l0.2,0 0.47,-1.52Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/monke_flusdered.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"35.5\"\n    android:viewportWidth=\"34.26\" android:width=\"23.16169dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M4.13,15.68c0,-4 -5,-3 -4,1s3,5 3,5ZM30.13,15.68c0,-4 5,-3 4,1s-3,5 -3,5Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M31.78,21.42C31.78,32.31 27.13,35.5 17.13,35.5S2.48,32.31 2.48,21.42 7.13,0 17.13,0 31.78,10.52 31.78,21.42Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M26.7,22.68c1.49,-4.46 2.08,-7.31 -0.45,-7.31L8.01,15.37c-2.54,0 -1.94,2.85 -0.45,7.31C2.63,33.88 16.3,34.5 17.13,34.5S31.43,33.44 26.7,22.68Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M3.38,16.31c1.41,-1.23 -1.08,-3.77 -2.19,-2.55 -0.34,0.37 0.92,-0.19 1.33,1.09C2.83,15.79 2.52,17.06 3.38,16.31ZM30.88,16.31c-1.41,-1.23 1.07,-3.77 2.19,-2.55 0.34,0.37 -0.92,-0.19 -1.34,1.09C31.43,15.79 31.73,17.06 30.88,16.31Z\"/>\n    <path android:fillColor=\"#ff7892\" android:pathData=\"M24.17,25.43m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0\"/>\n    <path android:fillColor=\"#ff7892\" android:pathData=\"M10.09,25.43m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0\"/>\n    <path android:fillColor=\"#f5f8fa\" android:pathData=\"M21.29,21.27m-3.52,0a3.52,3.52 0,1 1,7.04 0a3.52,3.52 0,1 1,-7.04 0\"/>\n    <path android:fillColor=\"#f5f8fa\" android:pathData=\"M12.97,21.27m-3.52,0a3.52,3.52 0,1 1,7.04 0a3.52,3.52 0,1 1,-7.04 0\"/>\n    <path android:fillColor=\"#292f33\" android:pathData=\"M12.97,21.27m-1.6,0a1.6,1.6 0,1 1,3.2 0a1.6,1.6 0,1 1,-3.2 0\"/>\n    <path android:fillColor=\"#292f33\" android:pathData=\"M21.29,21.27m-1.6,0a1.6,1.6 0,1 1,3.2 0a1.6,1.6 0,1 1,-3.2 0\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M19.69,30.68L14.57,30.68a0.64,0.64 0,1 1,0 -1.28h5.12a0.64,0.64 0,0 1,0 1.28ZM24.81,19.51a0.65,0.65 0,0 1,-0.51 -0.25,5.38 5.38,0 0,0 -4,-2.31 0.64,0.64 0,0 1,-0.64 -0.64A0.64,0.64 0,0 1,20.33 15.68a6.65,6.65 0,0 1,5 2.82,0.63 0.63,0 0,1 -0.13,0.89A0.6,0.6 0,0 1,24.81 19.47ZM9.45,19.35a0.6,0.6 0,0 1,-0.38 -0.13,0.63 0.63,0 0,1 -0.13,-0.89 6.65,6.65 0,0 1,5 -2.82,0.64 0.64,0 0,1 0.64,0.64 0.63,0.63 0,0 1,-0.64 0.64,5.41 5.41,0 0,0 -4,2.31A0.65,0.65 0,0 1,9.45 19.31Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/monke_funny.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"35.5\"\n    android:viewportWidth=\"34.26\" android:width=\"23.16169dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M4.13,15.68c0,-4 -5,-3 -4,1s3,5 3,5ZM30.13,15.68c0,-4 5,-3 4,1s-3,5 -3,5Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M31.78,21.42C31.78,32.31 27.13,35.5 17.13,35.5S2.48,32.31 2.48,21.42 7.13,0 17.13,0 31.78,10.52 31.78,21.42Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M26.7,22.68c1.49,-4.46 2.08,-7.31 -0.45,-7.31L8.01,15.37c-2.54,0 -1.94,2.85 -0.45,7.31C2.63,33.88 16.3,34.5 17.13,34.5S31.43,33.44 26.7,22.68Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M13.27,23.33a1.43,1 0,1 0,2.86 0a1.43,1 0,1 0,-2.86 0z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M20.99,23.34c0,0.55 -0.64,1 -1.43,1s-1.43,-0.45 -1.43,-1 0.64,-1 1.43,-1S20.99,22.78 20.99,23.34Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M20.13,20.68a3.65,3.65 0,0 0,-3 0.83A3.65,3.65 0,0 0,14.13 20.68c-3.16,0.42 -3.29,3.29 -1.94,3.11 0.77,-0.11 0.14,-0.94 1.71,-1.56a3.77,3.77 0,0 1,3.25 0.66,3.77 3.77,0 0,1 3.25,-0.66c1.58,0.62 0.94,1.45 1.71,1.56C23.44,24.01 23.31,21.14 20.13,20.68Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M3.38,16.31c1.41,-1.23 -1.08,-3.77 -2.19,-2.55 -0.34,0.37 0.92,-0.19 1.33,1.09C2.83,15.79 2.52,17.06 3.38,16.31ZM30.88,16.31c-1.41,-1.23 1.07,-3.77 2.19,-2.55 0.34,0.37 -0.92,-0.19 -1.34,1.09C31.43,15.79 31.73,17.06 30.88,16.31Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M17.13,26a29.86,29.86 0,0 1,-6.29 -0.7c-0.47,-0.09 -1.4,0 -1.4,1.4 0,2.79 3.21,6.28 7.69,6.28s7.69,-3.49 7.69,-6.28c0,-1.4 -0.93,-1.49 -1.4,-1.4A29.86,29.86 0,0 1,17.13 26Z\"/>\n    <path android:fillColor=\"#fff\" android:pathData=\"M10.84,26.68a22.23,22.23 0,0 0,6.29 0.69A22.23,22.23 0,0 0,23.42 26.68s-1.4,2.79 -6.29,2.79S10.84,26.68 10.84,26.68Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M25.93,20.56a12.53,12.53 0,0 0,-3.24 -1.64,1 1,0 0,0 0,-0.25 1,1 0,0 0,-0.25 -0.67,9.49 9.49,0 0,1 2.35,-0.38 0.7,0.7 0,0 0,0 -1.39c-0.16,0 -3.81,0 -6.09,2.3A0.7,0.7 0,0 0,19.23 19.68,11.08 11.08,0 0,1 25.13,21.68a0.7,0.7 0,0 0,0.41 0.14,0.69 0.69,0 0,0 0.56,-0.28A0.7,0.7 0,0 0,25.93 20.56ZM15.53,18.56c-2.28,-2.28 -5.93,-2.3 -6.09,-2.3a0.7,0.7 0,0 0,0 1.39,9.49 9.49,0 0,1 2.35,0.38 1,1 0,0 0,-0.25 0.67,1 1,0 0,0 0,0.25A12.13,12.13 0,0 0,8.33 20.56a0.7,0.7 0,0 0,0.42 1.26A0.7,0.7 0,0 0,9.13 21.68a11,11 0,0 1,5.87 -2,0.7 0.7,0 0,0 0.5,-1.19Z\"/>\n    <path android:fillColor=\"#5dadec\" android:pathData=\"M10.74,25.14a2.3,2.3 0,0 1,-4.32 -1.58c0.43,-1.19 3.3,-3.69 3.73,-3.54S11.18,23.94 10.74,25.14Z\"/>\n    <path android:fillColor=\"#5dadec\" android:pathData=\"M24.13,20.02c0.43,-0.15 3.3,2.35 3.74,3.54a2.3,2.3 0,0 1,-4.33 1.58C23.13,23.94 23.73,20.18 24.13,20.02Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/monke_like.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"37.51\"\n    android:viewportWidth=\"35.77\" android:width=\"22.886698dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M4.28,15.68c0,-4 -5,-3 -4,1s3,5 3,5ZM30.28,15.68c0,-4 5,-3 4,1s-3,5 -3,5Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M31.93,21.42C31.93,32.31 27.28,35.5 17.28,35.5S2.63,32.31 2.63,21.42 7.28,0 17.28,0 31.93,10.52 31.93,21.42Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M26.85,22.68c1.49,-4.46 2.08,-7.31 -0.45,-7.31L8.16,15.37c-2.54,0 -1.94,2.85 -0.45,7.31C2.78,33.88 16.45,34.5 17.28,34.5S31.58,33.44 26.85,22.68Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M13.42,23.33a1.43,1 0,1 0,2.86 0a1.43,1 0,1 0,-2.86 0z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M21.14,23.34c0,0.55 -0.64,1 -1.43,1s-1.43,-0.45 -1.43,-1 0.64,-1 1.43,-1S21.14,22.78 21.14,23.34Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M20.28,20.68a3.65,3.65 0,0 0,-3 0.83A3.65,3.65 0,0 0,14.28 20.68c-3.16,0.42 -3.29,3.29 -1.94,3.11 0.77,-0.11 0.14,-0.94 1.71,-1.56a3.77,3.77 0,0 1,3.25 0.66,3.77 3.77,0 0,1 3.25,-0.66c1.58,0.62 0.94,1.45 1.71,1.56C23.59,24.01 23.46,21.14 20.28,20.68Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M3.53,16.31c1.41,-1.23 -1.08,-3.77 -2.19,-2.55 -0.34,0.37 0.92,-0.19 1.33,1.09C2.98,15.79 2.67,17.06 3.53,16.31ZM31.03,16.31c-1.41,-1.23 1.07,-3.77 2.19,-2.55 0.34,0.37 -0.92,-0.19 -1.34,1.09C31.58,15.79 31.88,17.06 31.03,16.31Z\"/>\n    <path android:fillAlpha=\"0.5\" android:fillColor=\"#31373d\"\n        android:pathData=\"M26.79,12.07a9.22,9.22 0,0 0,3.14 -2.18,17 17,0 0,0 -5.11,-7.33c-0.35,-0.14 -0.7,-0.27 -1.06,-0.39a3.05,3.05 0,0 0,-2.52 3,3.19 3.19,0 0,0 0.08,0.7C21.74,8.51 24.68,11.3 26.79,12.07Z\" android:strokeAlpha=\"0.5\"/>\n    <path android:fillAlpha=\"0.5\" android:fillColor=\"#31373d\"\n        android:pathData=\"M31.69,25.27A2.31,2.31 0,0 0,30.28 26.18a2.3,2.3 0,0 0,-4.17 1.34,2.24 2.24,0 0,0 0.06,0.52 6.77,6.77 0,0 0,2.78 3.9A11.82,11.82 0,0 0,31.69 25.27Z\" android:strokeAlpha=\"0.5\"/>\n    <path android:fillAlpha=\"0.5\" android:fillColor=\"#31373d\"\n        android:pathData=\"M10.52,26.23a3.3,3.3 0,0 0,-2.69 1.39,3.33 3.33,0 0,0 -2.7,-1.39 3.29,3.29 0,0 0,-2 0.66c1,4.58 3.63,7 7.85,8a8.79,8.79 0,0 0,2.74 -4.58,3.08 3.08,0 0,0 0.09,-0.75A3.32,3.32 0,0 0,10.52 26.23Z\" android:strokeAlpha=\"0.5\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M14.41,19.68a0.61,0.61 0,0 1,-0.57 -0.41c-0.12,-0.36 -0.61,-1.39 -1.23,-1.39s-1.13,1.1 -1.23,1.39a0.6,0.6 0,0 1,-0.76 0.38,0.61 0.61,0 0,1 -0.38,-0.76C10.28,18.68 11.03,16.68 12.61,16.68s2.3,2 2.37,2.21a0.6,0.6 0,0 1,-0.38 0.76A0.58,0.58 0,0 1,14.41 19.68ZM24.41,19.68a0.61,0.61 0,0 1,-0.57 -0.41c-0.12,-0.36 -0.61,-1.39 -1.23,-1.39s-1.13,1.1 -1.23,1.39a0.6,0.6 0,0 1,-0.76 0.38,0.61 0.61,0 0,1 -0.38,-0.76C20.28,18.68 21.03,16.68 22.61,16.68s2.3,2 2.37,2.21a0.6,0.6 0,0 1,-0.38 0.76A0.58,0.58 0,0 1,24.41 19.68ZM25.08,26.8a0.51,0.51 0,0 0,-0.51 0,16 16,0 0,1 -7,1.71 16.08,16.08 0,0 1,-7 -1.71,0.52 0.52,0 0,0 -0.51,0 0.24,0.24 0,0 0,-0.07 0.37,9.91 9.91,0 0,0 7.54,3.09 10,10 0,0 0,7.55 -3.09A0.25,0.25 0,0 0,25.08 26.81Z\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M33.45,4.91a3.07,3.07 0,0 0,-5.56 -1.78,3.06 3.06,0 0,0 -5.55,1.78 3.27,3.27 0,0 0,0.08 0.7c0.43,2.64 3.37,5.43 5.47,6.19 2.11,-0.76 5,-3.55 5.47,-6.19A2.74,2.74 0,0 0,33.45 4.91ZM12.03,30.05a3.32,3.32 0,0 0,-6 -1.93,3.31 3.31,0 0,0 -6,1.93 3.08,3.08 0,0 0,0.09 0.75C0.55,33.68 3.73,36.68 6.01,37.52 8.28,36.68 11.48,33.68 11.94,30.81A3.22,3.22 0,0 0,12.03 30.05ZM35.77,27.77a2.3,2.3 0,0 0,-4.17 -1.34,2.3 2.3,0 0,0 -4.17,1.34 2.25,2.25 0,0 0,0.07 0.52c0.32,2 2.52,4.08 4.1,4.65 1.58,-0.57 3.79,-2.67 4.11,-4.65A2.24,2.24 0,0 0,35.77 27.77Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/monke_party.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"36\"\n    android:viewportWidth=\"36\" android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M3.8,17.6c-0.7,-3.9 -5.4,-2.1 -3.8,1.7s3.8,4.4 3.8,4.4ZM29.4,13.1c-0.7,-3.9 4.4,-3.8 4.1,0.3s-2.1,5.4 -2.1,5.4Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M32,18.4c1.9,10.7 -2.2,14.7 -12,16.4S5,34.2 3.1,23.5 4.1,1.6 13.9,-0.1 30.1,7.7 32,18.4Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M27.2,20.6c0.7,-4.6 0.8,-7.6 -1.7,-7.1l-18,3.2c-2.5,0.4 -1.4,3.1 0.8,7.3C5.5,35.8 19,34 19.9,33.9S33.8,30.3 27.2,20.6Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M14.1235,23.5474a1,1.4 80,1 0,2.7575 -0.4862a1,1.4 80,1 0,-2.7575 0.4862z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M21.7,22.2c0.1,0.5 -0.5,1.1 -1.2,1.2s-1.5,-0.2 -1.6,-0.7 0.5,-1.1 1.2,-1.2A1.26,1.26 0,0 1,21.7 22.2Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M20.4,19.8a3.58,3.58 0,0 0,-2.8 1.3,3.55 3.55,0 0,0 -3.1,-0.3c-3,1 -2.7,3.8 -1.4,3.4 0.7,-0.2 0,-0.9 1.4,-1.8s3.3,0.1 3.3,0.1a3.87,3.87 0,0 1,3.1 -1.2c1.7,0.3 1.2,1.3 2,1.2C24.2,22.4 23.6,19.6 20.4,19.8Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M3.7,16.9c1.4,-1.2 -1.1,-3.8 -2.2,-2.5 -0.3,0.4 0.9,-0.2 1.3,1.1C3.1,16.4 2.8,17.6 3.7,16.9ZM30.7,14.5c-1.6,-1 0.4,-3.9 1.7,-2.9 0.4,0.3 -0.9,0 -1.1,1.3C31.2,13.7 28.9,13.4 30.7,14.5Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M15.9,26.2a2,2.5 0,1 0,4 0a2,2.5 0,1 0,-4 0z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M8.6,21.2a0.9,0.9 0,0 1,-0.5 -0.1,1 1,0 0,1 -0.3,-1.2 6.53,6.53 0,0 1,6.9 -2.7,0.92 0.92,0 0,1 -0.4,1.8 4.79,4.79 0,0 0,-5 1.9A0.78,0.78 0,0 1,8.6 21.2ZM19.4,17.9a0.91,0.91 0,0 1,-0.7 -0.3,0.93 0.93,0 0,1 0.1,-1.3 6.58,6.58 0,0 1,7.4 -0.6,0.87 0.87,0 1,1 -0.9,1.5 4.71,4.71 0,0 0,-5.3 0.4A0.86,0.86 0,0 1,19.4 17.9Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M14,31.9h-0.2a0.72,0.72 0,0 1,-0.5 -0.9,4.81 4.81,0 0,0 -0.5,-4.1 2.85,2.85 0,0 0,-1.9 -1.2,0.77 0.77,0 0,1 -0.7,-0.8 0.71,0.71 0,0 1,0.8 -0.7A4.22,4.22 0,0 1,14.1 26a6.24,6.24 0,0 1,0.7 5.4C14.6,31.6 14.3,31.9 14,31.9ZM25,28.8a0.6,0.6 0,0 1,-0.4 -0.1A4.21,4.21 0,0 1,22.8 25a4.6,4.6 0,0 1,2 -3.9,0.74 0.74,0 0,1 0.7,1.3A3.45,3.45 0,0 0,24.2 25a2.78,2.78 0,0 0,1.1 2.4,0.78 0.78,0 0,1 0.2,1C25.5,28.7 25.2,28.8 25,28.8Z\"/>\n    <path android:fillColor=\"#dd2e44\" android:pathData=\"M17.1,2.9a0.35,0.35 0,0 0,-0.2 -0.1S1,-0.2 0.3,0.4 0.7,17.2 0.7,17.2s0,0.1 0.1,0.2c0.6,0.7 4.8,-2 9.3,-6S17.7,3.6 17.1,2.9Z\"/>\n    <path android:fillColor=\"#ea596e\" android:pathData=\"M0.3,0.5V0.6C0.4,2 1.9,13.3 2.9,16.8a34,34 0,0 0,4.6 -3.3C6,10.9 1.1,0.4 0.3,0.5Z\"/>\n    <path android:fillColor=\"#3b88c3\" android:pathData=\"M29.8,29.5 L19.2,28.2c-1.1,-0.1 -3.1,-0.1 -3,-1.9 0.1,-1.6 2,-1.4 3.5,-1.2l10.6,1.8Z\"/>\n    <path android:fillColor=\"#88c9f9\" android:pathData=\"M30.4,26.9l-4.2,-0.7c-0.5,-0.1 -0.9,0.6 -1,1.4s0.2,1.3 0.7,1.4l4.1,0.5A23.36,23.36 0,0 0,30.4 26.9Z\"/>\n    <path android:fillColor=\"#3b88c3\" android:pathData=\"M34.8,26.6 L32.2,29l-4.7,-5.1 2.6,-2.4a3.35,3.35 0,0 1,4.8 0.2l0.1,0.1A3.35,3.35 0,0 1,34.8 26.6Z\"/>\n    <path android:fillColor=\"#88c9f9\" android:pathData=\"M27.8089,28.2826a3.5,2.8 47.4,1 0,4.1221 -3.7905a3.5,2.8 47.4,1 0,-4.1221 3.7905z\"/>\n    <path android:fillColor=\"#269\" android:pathData=\"M28.8394,27.3349a2.1,1.4 47.4,1 0,2.0611 -1.8953a2.1,1.4 47.4,1 0,-2.0611 1.8953z\"/>\n    <path android:fillColor=\"#55acee\" android:pathData=\"M2.4,33.7m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0\"/>\n    <path android:fillColor=\"#55acee\" android:pathData=\"M28.9,2.2m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0\"/>\n    <path android:fillColor=\"#ea596e\" android:pathData=\"M4.8,29.5 L2.5,23.9l-2.1,6ZM25.9,5.2l-4,1 1,-4Z\"/>\n    <path android:fillColor=\"#77b255\" android:pathData=\"M31.9,13.2l4,-5 -3,-2Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/monke_sob.xml",
    "content": "<vector android:height=\"24dp\" android:viewportHeight=\"35.68\"\n    android:viewportWidth=\"34.51\" android:width=\"23.213005dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"#31373d\" android:pathData=\"M4.37,15.68c0,-4 -5,-3 -4,1s3,5 3,5ZM30.37,15.68c0,-4 5,-3 4,1s-3,5 -3,5Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M32.02,21.42C32.02,32.31 27.37,35.5 17.37,35.5S2.72,32.31 2.72,21.42 7.37,0 17.37,0 32.02,10.52 32.02,21.42Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M26.94,22.68c1.49,-4.46 2.08,-7.31 -0.45,-7.31L8.25,15.37c-2.54,0 -1.94,2.85 -0.45,7.31C2.87,33.88 16.54,34.5 17.37,34.5S31.67,33.44 26.94,22.68Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M13.52,23.33a1.43,1 0,1 0,2.86 0a1.43,1 0,1 0,-2.86 0z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M21.23,23.34c0,0.55 -0.64,1 -1.43,1s-1.43,-0.45 -1.43,-1 0.64,-1 1.43,-1S21.23,22.78 21.23,23.34Z\"/>\n    <path android:fillColor=\"#99aab5\" android:pathData=\"M20.37,20.68a3.65,3.65 0,0 0,-3 0.83A3.65,3.65 0,0 0,14.37 20.68c-3.16,0.42 -3.29,3.29 -1.94,3.11 0.77,-0.11 0.14,-0.94 1.71,-1.56a3.77,3.77 0,0 1,3.25 0.66,3.77 3.77,0 0,1 3.25,-0.66c1.58,0.62 0.94,1.45 1.71,1.56C23.68,24.01 23.55,21.14 20.37,20.68Z\"/>\n    <path android:fillColor=\"#66757f\" android:pathData=\"M3.62,16.31c1.41,-1.23 -1.08,-3.77 -2.19,-2.55 -0.34,0.37 0.92,-0.19 1.33,1.09C3.07,15.79 2.76,17.06 3.62,16.31ZM31.12,16.31c-1.41,-1.23 1.07,-3.77 2.19,-2.55 0.34,0.37 -0.92,-0.19 -1.34,1.09C31.67,15.79 31.97,17.06 31.12,16.31Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M19.93,28.98c0,2 -1.3,2.17 -2.89,2.17s-2.89,-0.17 -2.89,-2.17S15.44,24.68 17.04,24.68 19.93,26.99 19.93,28.98ZM25.7,18.49a0.58,0.58 0,0 1,-0.26 0,11.88 11.88,0 0,1 -5.39,-3.88 0.71,0.71 0,0 1,0.2 -1,0.72 0.72,0 0,1 1,0.2 10.72,10.72 0,0 0,4.72 3.34,0.72 0.72,0 0,1 -0.27,1.39ZM8.37,18.49a0.72,0.72 0,0 1,-0.27 -1.39,10.88 10.88,0 0,0 4.73,-3.34 0.72,0.72 0,1 1,1.2 0.8,12 12,0 0,1 -5.39,3.88A0.65,0.65 0,0 1,8.37 18.49Z\"/>\n    <path android:fillColor=\"#5dadec\" android:pathData=\"M21.37,19h2.89L24.26,32.68L21.37,32.68ZM9.81,32.68l2.89,0L12.7,19L9.81,19Z\"/>\n    <path android:fillColor=\"#31373d\" android:pathData=\"M14.87,20.45a0.72,0.72 0,0 1,-0.32 -0.08,6.24 6.24,0 0,0 -5.13,0A0.72,0.72 0,0 1,8.77 19.08a7.63,7.63 0,0 1,6.42 0,0.73 0.73,0 0,1 0.33,1A0.74,0.74 0,0 1,14.87 20.45ZM24.98,20.45a0.72,0.72 0,0 1,-0.32 -0.08,6.24 6.24,0 0,0 -5.13,0 0.73,0.73 0,0 1,-1 -0.32,0.72 0.72,0 0,1 0.32,-1 7.65,7.65 0,0 1,6.43 0,0.72 0.72,0 0,1 -0.33,1.37Z\"/>\n    <path android:fillColor=\"#5dadec\" android:pathData=\"M0,33.81a16.83,1.87 0,1 0,33.66 0a16.83,1.87 0,1 0,-33.66 0z\"/>\n    <path android:fillColor=\"#e75a70\" android:pathData=\"M14.87,29.15a2.17,1.44 0,1 0,4.34 0a2.17,1.44 0,1 0,-4.34 0z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/netflix_download.xml",
    "content": "<vector\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:name=\"vector\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"850\"\n        android:viewportHeight=\"850\">\n    <path\n            android:name=\"path_2\"\n            android:pathData=\"M 233.86 666.14 L 616.54 666.14 M 425.2 539.08 L 425.2 159.6 M 410.14 554.17 L 581.98 454.96 M 268.41 454.96 L 440.25 554.17\"\n            android:strokeColor=\"?attr/white\"\n            android:strokeWidth=\"60\"\n            android:strokeMiterLimit=\"10\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/netflix_download_batch.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"850\"\n    android:viewportHeight=\"850\">\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 233.86 666.14 L 616.54 666.14 M 425.2 539.08 L 425.2 210 M 410.14 554.17 L 581.98 454.96 M 268.41 454.96 L 440.25 554.17\"\n        android:strokeWidth=\"60\"\n        android:strokeColor=\"?attr/white\"\n        android:strokeMiterLimit=\"10\" />\n    <path\n        android:pathData=\"M 233.86 776.14 L 616.54 776.14\"\n        android:strokeWidth=\"60\"\n        android:strokeColor=\"?attr/white\"\n        android:strokeMiterLimit=\"10\" />\n</vector>\n\n"
  },
  {
    "path": "app/src/main/res/drawable/netflix_pause.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:tint=\"?attr/white\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"850.39\"\n        android:viewportHeight=\"850.39\">\n    <path\n            android:pathData=\"M267.01,189.64h99.74v470.26h-99.74z M463.01,188.79h99.74v470.26h-99.74z\"\n            android:fillColor=\"#fff\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/netflix_play.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"850.4\"\n        android:viewportHeight=\"850.4\">\n    <path\n            android:pathData=\"M674.6,424.6l-417.7,-241.2l0,482.4z\"\n            android:fillColor=\"?attr/white\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/netflix_skip_back.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"850.39dp\"\n    android:height=\"850.39dp\"\n    android:viewportWidth=\"850.39\"\n    android:viewportHeight=\"850.39\">\n    <path\n        android:fillColor=\"#00000000\"\n        android:pathData=\"M143.05,279.28A317.41,317.41 0,0 0,106.3 428c0,176.13 142.77,318.9 318.9,318.9S744.09,604.16 744.09,428 601.32,109.14 425.2,109.14q-14.15,0 -28,1.2\"\n        android:strokeWidth=\"45\"\n        android:strokeColor=\"#fff\" />\n    <path\n        android:fillColor=\"#fff\"\n        android:pathData=\"M483.083,223.108l-111.666,-111.666l25.442,-25.442l111.666,111.666z\" />\n    <path\n        android:fillColor=\"#fff\"\n        android:pathData=\"M371.421,111.662l111.666,-111.666l25.442,25.442l-111.666,111.666z\" />\n    <path\n        android:fillColor=\"#fff\"\n        android:pathData=\"M398.087,223.272l-111.666,-111.666l25.442,-25.442l111.666,111.666z\" />\n    <path\n        android:fillColor=\"#fff\"\n        android:pathData=\"M286.427,111.826l111.666,-111.666l25.442,25.442l-111.666,111.666z\" />\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/netflix_skip_forward.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"850.39dp\"\n        android:height=\"850.39dp\"\n        android:viewportWidth=\"850.39\"\n        android:viewportHeight=\"850.39\">\n    <path\n            android:pathData=\"M707.35,279.28A317.52,317.52 0,0 1,744.09 428c0,176.13 -142.77,318.9 -318.89,318.9S106.3,604.16 106.3,428 249.07,109.14 425.2,109.14q14.13,0 28,1.2\"\n            android:strokeWidth=\"45\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#fff\"/>\n    <path\n            android:pathData=\"M341.86,197.665l111.666,-111.666l25.442,25.442l-111.666,111.666z\"\n            android:fillColor=\"#fff\"/>\n    <path\n            android:pathData=\"M453.524,137.111l-111.666,-111.666l25.442,-25.442l111.666,111.666z\"\n            android:fillColor=\"#fff\"/>\n    <path\n            android:pathData=\"M426.864,197.831l111.666,-111.666l25.442,25.442l-111.666,111.666z\"\n            android:fillColor=\"#fff\"/>\n    <path\n            android:pathData=\"M538.53,137.277l-111.666,-111.666l25.442,-25.442l111.666,111.666z\"\n            android:fillColor=\"#fff\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/notifications_icon_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/ic_filled_notifications_24dp\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/ic_filled_notifications_24dp\" android:state_focused=\"true\"/>\n    <item android:drawable=\"@drawable/ic_outline_notifications_24dp\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/open_subtitles_icon.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:name=\"vector\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"283\"\n        android:viewportHeight=\"283\"\n        android:tint=\"?attr/white\">\n    <group android:name=\"group\">\n        <path\n                android:name=\"path\"\n                android:pathData=\"M 16.72 227.55 L 53.82 227.55 L 53.82 264.65 L 16.72 264.65 Z M 70.41 227.55 L 107.51 227.55 L 107.51 264.65 L 70.41 264.65 Z M 123.18 227.55 L 160.28 227.55 L 160.28 264.65 L 123.18 264.65 Z\"\n                android:fillColor=\"@color/white\"\n                android:strokeWidth=\"1\" />\n        <path\n                android:name=\"path_1\"\n                android:pathData=\"M 123.18 227.55 L 160.28 227.55 L 160.28 264.65 L 123.18 264.65 Z M 176.87 227.55 L 213.97 227.55 L 213.97 264.65 L 176.87 264.65 Z M 229.65 227.55 L 266.75 227.55 L 266.75 264.65 L 229.65 264.65 Z M 16.22 15.49 L 53.32 15.49 L 53.32 52.59 L 16.22 52.59 Z M 69.91 15.49 L 107.01 15.49 L 107.01 52.59 L 69.91 52.59 Z M 122.68 15.49 L 159.78 15.49 L 159.78 52.59 L 122.68 52.59 Z\"\n                android:fillColor=\"@color/white\"\n                android:strokeWidth=\"1\" />\n        <path\n                android:name=\"path_2\"\n                android:pathData=\"M 122.68 15.49 L 159.78 15.49 L 159.78 52.59 L 122.68 52.59 Z M 176.38 15.49 L 213.48 15.49 L 213.48 52.59 L 176.38 52.59 Z M 229.15 15.49 L 266.25 15.49 L 266.25 52.59 L 229.15 52.59 Z\"\n                android:fillColor=\"@color/white\"\n                android:strokeWidth=\"1\" />\n    </group>\n    <group android:name=\"text\">\n        <path\n                android:name=\"path_3\"\n                android:pathData=\"M 35 139.88 Q 35 113.69 52.32 96.64 Q 69.64 79.59 93.39 79.58 Q 119.67 79.58 136.86 96.73 Q 154.05 113.88 154.05 140.06 Q 154.05 166.06 137.05 183.26 Q 120.05 200.46 94.2 200.45 Q 68.37 200.45 51.68 183.35 Q 34.99 166.25 35 139.88 Z M 94.57 103.16 Q 79.72 102.89 70.64 113.42 Q 61.56 123.95 61.54 140.6 Q 61.54 156.35 70.81 166.7 C 73.705 170.042 77.303 172.703 81.347 174.493 C 85.39 176.282 89.78 177.155 94.2 177.05 Q 109.05 177.05 118.2 166.83 Q 127.35 156.61 127.33 139.83 Q 127.33 123.36 118.38 113.37 Q 109.43 103.38 94.56 103.16 Z M 245.3 91.55 L 229.46 108.92 Q 216.95 101.54 211.46 101.54 C 210.088 101.531 208.73 101.812 207.474 102.363 C 206.218 102.914 205.092 103.724 204.17 104.74 C 203.182 105.741 202.402 106.928 201.877 108.233 C 201.352 109.537 201.091 110.934 201.11 112.34 Q 201.11 121.07 216.95 127.46 C 223.058 129.928 228.932 132.94 234.5 136.46 C 238.642 139.329 242.048 143.136 244.44 147.57 C 247.095 152.262 248.475 157.569 248.44 162.96 Q 248.44 178.17 236.16 189.42 C 228.316 196.779 217.915 200.814 207.16 200.67 Q 188.8 200.67 170.9 183.39 L 187.63 163.86 Q 198.88 175.47 208.69 175.47 Q 213.28 175.47 217.51 171.38 Q 221.74 167.29 221.74 162.81 Q 221.74 153.57 202.21 146.51 Q 191.05 142.44 186.37 138.89 C 182.948 136.128 180.247 132.576 178.5 128.54 C 176.412 124.199 175.319 119.447 175.3 114.63 Q 175.3 98.88 185.56 89.07 Q 195.82 79.26 212.38 79.27 Q 232 79.23 245.3 91.55 Z\"\n                android:fillColor=\"@color/white\"\n                android:strokeWidth=\"1\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/outline.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <stroke android:width=\"2dp\"\n            android:color=\"?attr/white\"/>\n    <corners\n            android:bottomLeftRadius=\"@dimen/rounded_image_radius\"\n            android:bottomRightRadius=\"@dimen/rounded_image_radius\"\n            android:topLeftRadius=\"@dimen/rounded_image_radius\"\n            android:topRightRadius=\"@dimen/rounded_image_radius\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/outline_big_15_gray.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\r\n    <stroke\r\n        android:width=\"2dp\"\r\n        android:color=\"@color/white_attr_20\" />\r\n    <corners\r\n        android:bottomLeftRadius=\"15dp\"\r\n        android:bottomRightRadius=\"15dp\"\r\n        android:topLeftRadius=\"15dp\"\r\n        android:topRightRadius=\"15dp\" />\r\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/outline_big_20.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <stroke android:width=\"2dp\"\n            android:color=\"?attr/white\"/>\n    <corners\n            android:bottomLeftRadius=\"20dp\"\n            android:bottomRightRadius=\"20dp\"\n            android:topLeftRadius=\"20dp\"\n            android:topRightRadius=\"20dp\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/outline_big_20_gray.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\r\n    <stroke android:width=\"2dp\"\r\n            android:color=\"@color/white_attr_20\"/>\r\n    <corners\r\n            android:bottomLeftRadius=\"20dp\"\r\n            android:bottomRightRadius=\"20dp\"\r\n            android:topLeftRadius=\"20dp\"\r\n            android:topRightRadius=\"20dp\" />\r\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/outline_big_25_gray.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\r\n    <stroke\r\n        android:width=\"2dp\"\r\n        android:color=\"@color/white_attr_20\" />\r\n    <corners\r\n        android:bottomLeftRadius=\"25dp\"\r\n        android:bottomRightRadius=\"25dp\"\r\n        android:topLeftRadius=\"25dp\"\r\n        android:topRightRadius=\"25dp\" />\r\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/outline_big_35_gray.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\r\n    <stroke android:width=\"2dp\"\r\n            android:color=\"@color/white_attr_20\"/>\r\n    <corners\r\n            android:bottomLeftRadius=\"35dp\"\r\n            android:bottomRightRadius=\"35dp\"\r\n            android:topLeftRadius=\"35dp\"\r\n            android:topRightRadius=\"35dp\" />\r\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/outline_bookmark_add_24.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"#FFFFFF\"\n    android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n    android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M17,11v6.97l-5,-2.14l-5,2.14V5h6V3H7C5.9,3 5,3.9 5,5v16l7,-3l7,3V11H17zM21,7h-2v2h-2V7h-2V5h2V3h2v2h2V7z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/outline_card.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"@android:color/white\">\n\n    <item>\n        <shape android:shape=\"rectangle\">\n            <stroke\n                android:width=\"2dp\"\n                android:color=\"@android:color/white\" />\n            <corners android:radius=\"@dimen/rounded_image_radius\" />\n        </shape>\n    </item>\n\n    <item android:id=\"@android:id/mask\">\n        <shape android:shape=\"rectangle\">\n            <corners android:radius=\"@dimen/rounded_image_radius\" />\n            <solid android:color=\"?attr/iconGrayBackground\" />\n        </shape>\n    </item>\n</ripple>"
  },
  {
    "path": "app/src/main/res/drawable/outline_drawable.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\"\n          android:drawable=\"@drawable/outline\"/> <!-- focused -->\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/outline_drawable_forced.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\"\n          android:drawable=\"@drawable/outline\"/> <!-- focused -->\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/outline_drawable_forced_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\"\n          android:drawable=\"@drawable/outline_card\"/> <!-- focused -->\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/outline_drawable_less.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n   <item android:state_focused=\"true\" android:drawable=\"@drawable/outline_less\" /> <!-- focused -->\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/outline_drawable_less_inset.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<inset xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    android:drawable=\"@drawable/outline_drawable_less\"\r\n    android:insetTop=\"@dimen/dialog_buttons_inset\"\r\n    android:insetBottom=\"@dimen/dialog_buttons_inset\" />"
  },
  {
    "path": "app/src/main/res/drawable/outline_drawable_round_20.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\"\n          android:drawable=\"@drawable/outline_big_20\"/> <!-- focused -->\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/outline_less.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" >\n    <stroke android:width=\"2dp\"\n            android:color=\"?attr/white\"/>\n    <corners\n            android:bottomLeftRadius=\"@dimen/rounded_button_radius\"\n            android:bottomRightRadius=\"@dimen/rounded_button_radius\"\n            android:topLeftRadius=\"@dimen/rounded_button_radius\"\n            android:topRightRadius=\"@dimen/rounded_button_radius\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/pause_to_play.xml",
    "content": "<animated-vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\">\n    <aapt:attr name=\"android:drawable\">\n        <vector\n            android:name=\"vector\"\n            android:width=\"850dp\"\n            android:height=\"850dp\"\n            android:viewportWidth=\"850\"\n            android:viewportHeight=\"850\">\n            <path\n                android:name=\"path\"\n                android:pathData=\"M 267.01 189.64 L 366.75 189.64 L 366.75 659.9 L 267.01 659.9 Z M 463.01 188.79 L 562.75 188.79 L 562.75 659.05 L 463.01 659.05 Z\"\n                android:fillColor=\"#ffffff\"/>\n        </vector>\n    </aapt:attr>\n    <target android:name=\"path\">\n        <aapt:attr name=\"android:animation\">\n            <objectAnimator\n                android:propertyName=\"pathData\"\n                android:duration=\"200\"\n                android:valueFrom=\"M 463.01 659.05 L 562.75 659.05 L 562.75 188.79 L 463.01 188.79 L 463.01 659.05 M 366.75 189.64 L 366.75 659.9 L 267.01 659.9 L 267.01 189.64 L 366.75 189.64\"\n                android:valueTo=\"M 425.844 568.243 L 674.6 424.6 L 551.156 353.317 L 427.712 282.035 L 425.844 568.243 M 427.712 282.035 L 425.844 568.243 L 256.9 665.8 L 256.9 183.4 L 427.712 282.035\"\n                android:valueType=\"pathType\"\n                android:interpolator=\"@android:interpolator/fast_out_slow_in\"/>\n        </aapt:attr>\n    </target>\n</animated-vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/pin_ic.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:pathData=\"m640,480 l80,80v80L520,640v240l-40,40 -40,-40v-240L240,640v-80l80,-80v-280h-40v-80h400v80h-40v280ZM354,560h252l-46,-46v-314L400,200v314l-46,46ZM480,560Z\"\n      android:fillColor=\"#e3e3e3\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/play_button.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"842dp\"\n    android:height=\"842dp\"\n    android:viewportWidth=\"842\"\n    android:viewportHeight=\"842\">\n    <!--70% https://stackoverflow.com/questions/11285961/how-to-make-a-background-20-transparent-on-android -->\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 421.44 17.5 C 336.15 17.5 253.011 44.513 184.01 94.646 C 115.009 144.778 63.626 215.5 37.27 296.616 C 10.914 377.732 10.914 465.148 37.27 546.264 C 63.626 627.38 115.009 698.102 184.01 748.234 C 253.011 798.367 336.15 825.38 421.44 825.38 C 506.73 825.38 589.869 798.367 658.87 748.234 C 727.871 698.102 779.254 627.38 805.61 546.264 C 831.966 465.148 831.966 377.732 805.61 296.616 C 779.254 215.5 727.871 144.778 658.87 94.646 C 589.869 44.513 506.73 17.5 421.44 17.5 Z\"\n        android:fillColor=\"#B3000000\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 598.91 419.24 L 333.91 266.24 L 333.91 572.24 L 598.91 419.24 Z\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/play_button_transparent.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"842dp\"\n    android:height=\"842dp\"\n    android:viewportWidth=\"842\"\n    android:viewportHeight=\"842\"\n    android:tint=\"?attr/white\">\n  <!--70% https://stackoverflow.com/questions/11285961/how-to-make-a-background-20-transparent-on-android -->\n  <path\n      android:name=\"path_2\"\n      android:pathData=\"M 598.91 419.24 L 333.91 266.24 L 333.91 572.24 L 598.91 419.24 Z\"\n      android:fillColor=\"#ffffff\"\n      android:strokeWidth=\"1\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/play_to_pause.xml",
    "content": "<animated-vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\">\n    <aapt:attr name=\"android:drawable\">\n        <vector\n            android:name=\"vector\"\n            android:width=\"850dp\"\n            android:height=\"850dp\"\n            android:viewportWidth=\"850\"\n            android:viewportHeight=\"850\">\n            <path\n                android:name=\"path\"\n                android:pathData=\"M 674.6 424.6 L 256.9 183.4 L 256.9 665.8 Z\"\n                android:fillColor=\"#ffffff\"/>\n        </vector>\n    </aapt:attr>\n    <target android:name=\"path\">\n        <aapt:attr name=\"android:animation\">\n            <objectAnimator\n                android:propertyName=\"pathData\"\n                android:duration=\"200\"\n                android:valueFrom=\"M 425.844 568.243 L 674.6 424.6 L 551.156 353.317 L 427.712 282.035 L 425.844 568.243 M 427.712 282.035 L 425.844 568.243 L 256.9 665.8 L 256.9 183.4 L 427.712 282.035\"\n                android:valueTo=\"M 463.01 659.05 L 562.75 659.05 L 562.75 188.79 L 463.01 188.79 L 463.01 659.05 M 366.75 189.64 L 366.75 659.9 L 267.01 659.9 L 267.01 189.64 L 366.75 189.64\"\n                android:valueType=\"pathType\"\n                android:interpolator=\"@android:interpolator/fast_out_slow_in\"/>\n        </aapt:attr>\n    </target>\n</animated-vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/player_button_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"#FFFFFF\" />\n            <corners android:radius=\"3dp\"/>\n        </shape>\n    </item>\n    <item>\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"#33FFFFFF\" />\n            <corners android:radius=\"3dp\"/>\n        </shape>\n    </item>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/player_button_tv_attr.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"?attr/white\" />\n            <corners android:radius=\"@dimen/rounded_image_radius\"/>\n        </shape>\n    </item>\n    <item>\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"@color/white_attr_20\" />\n            <corners android:radius=\"@dimen/rounded_image_radius\"/>\n        </shape>\n    </item>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/player_button_tv_attr_no_bg.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_focused=\"true\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"?attr/white\" />\n            <corners android:radius=\"@dimen/rounded_image_radius\"/>\n        </shape>\n    </item>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/player_gradient_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item>\n        <shape>\n            <gradient\n                android:angle=\"90\"\n                android:startColor=\"#FF000000\"\n                android:centerColor=\"#00000000\"\n                android:endColor=\"#00000000\"\n                android:centerY=\"0.3\"\n                />\n        </shape>\n    </item>\n    <item>\n        <shape>\n            <gradient\n                android:angle=\"270\"\n                android:startColor=\"#66000000\"\n                android:centerColor=\"#00000000\"\n                android:endColor=\"#00000000\"\n                android:centerY=\"0.5\"\n                />\n        </shape>\n    </item>\n\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/preview_seekbar_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:pathData=\"m480,540 l240,-160 -240,-160v320ZM508,760h224q-7,26 -24,42t-44,20L228,875q-33,5 -59.5,-15.5T138,806L85,369q-4,-33 16,-59t53,-30l46,-6v80l-36,5 54,437 290,-36ZM360,680q-33,0 -56.5,-23.5T280,600v-440q0,-33 23.5,-56.5T360,80h440q33,0 56.5,23.5T880,160v440q0,33 -23.5,56.5T800,680L360,680ZM360,600h440v-440L360,160v440ZM580,380ZM218,796Z\"\n      android:fillColor=\"@android:color/white\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/progress_drawable_vertical.xml",
    "content": "<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:id=\"@android:id/background\">\n        <shape>\n            <corners android:radius=\"8dp\"/>\n            <solid android:color=\"@color/progressBackgroundColor\"/>\n        </shape>\n    </item>\n\n    <item android:id=\"@android:id/progress\">\n        <scale android:scaleGravity=\"bottom\" android:scaleWidth=\"0%\" android:scaleHeight=\"100%\">\n            <shape>\n                <solid android:color=\"@color/white\"/>\n                <corners android:radius=\"3dp\"/>\n            </shape>\n        </scale>\n    </item>\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/question_mark_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M11.07,12.85c0.77,-1.39 2.25,-2.21 3.11,-3.44c0.91,-1.29 0.4,-3.7 -2.18,-3.7c-1.69,0 -2.52,1.28 -2.87,2.34L6.54,6.96C7.25,4.83 9.18,3 11.99,3c2.35,0 3.96,1.07 4.78,2.41c0.7,1.15 1.11,3.3 0.03,4.9c-1.2,1.77 -2.35,2.31 -2.97,3.45c-0.25,0.46 -0.35,0.76 -0.35,2.24h-2.89C10.58,15.22 10.46,13.95 11.07,12.85zM14,20c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2S14,18.9 14,20z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/quick_novel_icon.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"108\"\n        android:viewportHeight=\"108\"\n        android:name=\"vector\"\n        android:tint=\"?attr/white\"\n>\n    <!-- ScaleX = 108/24 -->\n    <group\n            android:scaleX=\"0.22\"\n            android:scaleY=\"0.22\"\n    >\n        <path android:name=\"path\"\n              android:pathData=\"M 475.35 304.28 C 432.112 306.219 389.584 315.994 349.84 333.13 C 311.168 349.86 275.547 372.909 244.44 401.33 L 244.44 97.04 C 275.547 68.619 311.168 45.57 349.84 28.84 C 389.589 11.727 432.116 1.968 475.35 0.04 L 475.35 304.28\"\n              android:fillColor=\"@color/white\"\n              android:strokeWidth=\"1\"/>\n        <path android:name=\"path_1\"\n              android:pathData=\"M 348.22 364.24 C 310.074 381.02 275.008 404.073 244.48 432.44 L 244.48 411.44 C 275.006 383.062 310.072 359.999 348.22 343.21 M 348.22 364.24 C 387.267 347.125 429.132 337.342 471.72 335.38 L 471.72 314.38 C 429.134 316.333 387.269 326.106 348.22 343.21\"\n              android:fillColor=\"@color/white\"\n              android:strokeWidth=\"1\"/>\n        <path android:name=\"path_2\"\n              android:pathData=\"M 127.44 364.24 C 165.5 381.028 200.476 404.082 230.91 432.44 L 230.91 411.44 C 200.476 383.082 165.5 360.028 127.44 343.24 M 127.44 364.24 C 88.492 347.123 46.718 337.339 4.22 335.38 L 4.22 314.38 C 46.718 316.339 88.492 326.123 127.44 343.24\"\n              android:fillColor=\"@color/white\"\n              android:strokeWidth=\"1\"/>\n        <path android:name=\"path_3\"\n              android:pathData=\"M 0 304.28 C 43.238 306.218 85.766 315.994 125.51 333.13 C 164.182 349.86 199.803 372.909 230.91 401.33 L 230.91 97.04 C 199.803 68.619 164.182 45.57 125.51 28.84 C 85.761 11.725 43.234 1.967 0 0.04 L 0 304.28\"\n              android:fillColor=\"@color/white\"\n              android:strokeWidth=\"1\"/>\n    </group>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/rating_bg_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/colorPrimary\"/>\n    <corners android:radius=\"4dp\"/>\n   <!-- <stroke android:color=\"@color/subColor\" android:width=\"2dp\"/>-->\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/rating_empty.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"true\"\n            android:state_window_focused=\"true\"\n            android:drawable=\"@drawable/ic_baseline_star_border_24\"/>\n\n    <item android:state_focused=\"true\"\n            android:state_window_focused=\"true\"\n            android:drawable=\"@drawable/ic_baseline_star_border_24\"/>\n\n    <item android:state_selected=\"true\"\n            android:state_window_focused=\"true\"\n            android:drawable=\"@drawable/ic_baseline_star_border_24\"/>\n\n    <item\n            android:drawable=\"@drawable/ic_baseline_star_border_24\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/rating_fill.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_pressed=\"true\"\n            android:state_window_focused=\"true\"\n            android:drawable=\"@drawable/ic_baseline_star_24\"/>\n\n    <item android:state_focused=\"true\"\n            android:state_window_focused=\"true\"\n            android:drawable=\"@drawable/ic_baseline_star_24\"/>\n\n    <item android:state_selected=\"true\"\n            android:state_window_focused=\"true\"\n            android:drawable=\"@drawable/ic_baseline_star_24\"/>\n\n    <item\n            android:drawable=\"@drawable/ic_baseline_star_24\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/rddone.xml",
    "content": "<vector\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:name=\"vector\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:tint=\"?attr/colorPrimary\"\n        android:viewportWidth=\"24\"\n        android:viewportHeight=\"24\">\n    <path\n            android:name=\"path\"\n            android:pathData=\"M 17 1.01 L 7 1 C 5.9 1 5 1.9 5 3 L 5 21 C 5 22.1 5.9 23 7 23 L 17 23 C 18.1 23 19 22.1 19 21 L 19 3 C 19 1.9 18.1 1.01 17 1.01 Z M 17 19 L 7 19 L 7 5 L 17 5 Z\"\n            android:fillColor=\"@color/white\"\n            android:strokeWidth=\"1\"/>\n    <path\n            android:name=\"path_1\"\n            android:pathData=\"M 7.488 13.004 L 9.132 11.36 L 12.492 14.72 L 10.848 16.364 Z\"\n            android:fillColor=\"@color/white\"\n            android:strokeWidth=\"1\"/>\n    <path\n            android:name=\"path_2\"\n            android:pathData=\"M 10.848 16.364 L 9.203 14.72 L 14.894 9.029 L 16.539 10.673 Z\"\n            android:fillColor=\"@color/white\"\n            android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/rderror.xml",
    "content": "<vector\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:name=\"vector\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:tint=\"?attr/colorPrimary\"\n        android:viewportWidth=\"24\"\n        android:viewportHeight=\"24\">\n    <path\n            android:name=\"path\"\n            android:pathData=\"M 17 1.01 L 7 1 C 5.9 1 5 1.9 5 3 L 5 21 C 5 22.1 5.9 23 7 23 L 17 23 C 18.1 23 19 22.1 19 21 L 19 3 C 19 1.9 18.1 1.01 17 1.01 Z M 17 19 L 7 19 L 7 5 L 17 5 Z M 10.101 13.289 L 10.513 10.311 L 9.848 9.33 L 9.496 8.867 L 11 13 L 9.706 13 L 9.745 15.93 Z\"\n            android:fillColor=\"@color/white\"\n            android:strokeWidth=\"1\"/>\n    <path\n            android:name=\"path_1\"\n            android:pathData=\"M 15.801 14.763 L 14.157 16.407 L 7.873 10.124 L 9.518 8.479 Z\"\n            android:fillColor=\"@color/white\"\n            android:strokeWidth=\"1\"/>\n    <path\n            android:name=\"path_2\"\n            android:pathData=\"M 14.157 8.479 L 15.801 10.124 L 9.518 16.407 L 7.873 14.763 Z\"\n            android:fillColor=\"@color/white\"\n            android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/rdload.xml",
    "content": "<vector android:height=\"24dp\" android:tint=\"?attr/colorPrimary\"\n        android:viewportHeight=\"24\" android:viewportWidth=\"24\"\n        android:width=\"24dp\" xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17,19L7,19L7,5h10v14zM16,13h-3L13,8h-2v5L8,13l4,4 4,-4z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/rdpause.xml",
    "content": "<vector\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:name=\"vector\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:tint=\"?attr/colorPrimary\"\n        android:viewportWidth=\"24\"\n        android:viewportHeight=\"24\">\n    <path\n            android:name=\"path\"\n            android:pathData=\"M 17 1.01 L 7 1 C 5.9 1 5 1.9 5 3 L 5 21 C 5 22.1 5.9 23 7 23 L 17 23 C 18.1 23 19 22.1 19 21 L 19 3 C 19 1.9 18.1 1.01 17 1.01 Z M 17 19 L 7 19 L 7 5 L 17 5 Z M 10.101 13.289 L 10.513 10.311 L 9.848 9.33 L 9.496 8.867 L 11 13 L 9.706 13 L 9.745 15.93 Z\"\n            android:fillColor=\"@color/white\"\n            android:strokeWidth=\"1\"/>\n    <path\n            android:name=\"path_1\"\n            android:pathData=\"M 9.104 8.931 L 11.129 8.931 L 11.129 15.956 L 9.104 15.956 Z M 12.871 8.931 L 14.896 8.931 L 14.896 15.956 L 12.871 15.956 Z\"\n            android:fillColor=\"@color/white\"\n            android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/round_keyboard_arrow_up_24.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/white\"\n    >\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M8.12,14.71L12,10.83l3.88,3.88c0.39,0.39 1.02,0.39 1.41,0 0.39,-0.39 0.39,-1.02 0,-1.41L12.7,8.71c-0.39,-0.39 -1.02,-0.39 -1.41,0L6.7,13.3c-0.39,0.39 -0.39,1.02 0,1.41 0.39,0.38 1.03,0.39 1.42,0z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/rounded_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n       android:shape=\"rectangle\">\n    <solid android:color=\"?attr/boxItemBackground\"/>\n    <corners android:topLeftRadius=\"16dp\"\n             android:topRightRadius=\"16dp\"/>\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/rounded_outline.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"@android:color/white\">\n\n    <item>\n        <shape android:shape=\"oval\">\n            <stroke\n                android:width=\"2dp\"\n                android:color=\"?attr/white\" />\n            <corners android:radius=\"10dp\" />\n        </shape>\n    </item>\n</ripple>\n"
  },
  {
    "path": "app/src/main/res/drawable/rounded_progress.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/colorPrimary\" />\n    <corners android:radius=\"5dp\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/rounded_select_ripple.xml",
    "content": "<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"?attr/colorControlHighlight\">\n    <item>\n        <shape android:shape=\"oval\">\n            <solid android:color=\"@android:color/transparent\" />\n        </shape>\n    </item>\n\n    <item android:id=\"@android:id/mask\">\n        <shape android:shape=\"oval\">\n            <solid android:color=\"#FFFFFF\" />\n        </shape>\n    </item>\n</ripple>\n"
  },
  {
    "path": "app/src/main/res/drawable/screen_rotation.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M496,778L182,464Q159,441 159,410Q159,379 182,356L356,182Q379,159 410,159Q441,159 464,182L778,496Q801,519 801,550Q801,581 778,604L604,778Q581,801 550,801Q519,801 496,778ZM550,720Q550,720 550,720Q550,720 550,720L720,550Q720,550 720,550Q720,550 720,550L410,240Q410,240 410,240Q410,240 410,240L240,410Q240,410 240,410Q240,410 240,410L550,720ZM480,960Q381,960 293.5,922.5Q206,885 140.5,819.5Q75,754 37.5,666.5Q0,579 0,480L80,480Q80,551 104,616Q128,681 170.5,733Q213,785 272,821.5Q331,858 401,873L296,768L352,712L588,948Q562,954 534.5,957Q507,960 480,960ZM880,480Q880,409 856,344Q832,279 789.5,227Q747,175 688,138.5Q629,102 559,87L664,192L608,248L372,12Q398,6 425.5,3Q453,0 480,0Q579,0 666.5,37.5Q754,75 819.5,140.5Q885,206 922.5,293.5Q960,381 960,480L880,480ZM480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480L480,480Q480,480 480,480Q480,480 480,480Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/search_background.xml",
    "content": "<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" android:shape=\"rectangle\">\n    <corners android:radius=\"20dp\" />\n    <solid android:color=\"?attr/primaryBlackBackground\"/>\n    <!--<stroke android:width=\"0.5dp\" android:color=\"@color/searchColorTransparent\" />-->\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/search_icon.xml",
    "content": "<vector android:name=\"vector\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"850\"\n    android:viewportHeight=\"850\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:name=\"path\" android:pathData=\"M 425.2 172.91 C 363.2 172.91 303.676 197.566 259.836 241.406 C 215.996 285.246 191.34 344.77 191.34 406.77 C 191.34 468.77 215.996 528.294 259.836 572.134 C 303.676 615.974 363.2 640.63 425.2 640.63 C 487.2 640.63 546.724 615.974 590.564 572.134 C 634.404 528.294 659.06 468.77 659.06 406.77 C 659.06 344.77 634.404 285.246 590.564 241.406 C 546.724 197.566 487.2 172.91 425.2 172.91 Z\" android:strokeColor=\"#ffffff\" android:strokeWidth=\"60\" android:strokeMiterLimit=\"10\"/>\n    <path android:name=\"path_1\" android:pathData=\"M 583.631 547.663 L 583.624 547.67 C 587.388 543.906 592.078 541.198 597.22 539.82 C 602.363 538.442 607.778 538.442 612.92 539.82 C 618.063 541.198 622.752 543.906 626.517 547.67 L 719.049 640.202 C 722.813 643.966 725.521 648.656 726.899 653.798 C 728.277 658.941 728.277 664.356 726.899 669.498 C 725.521 674.641 722.813 679.331 719.049 683.095 L 719.056 683.088 C 713.37 688.774 705.65 691.971 697.609 691.971 C 689.568 691.971 681.849 688.774 676.163 683.088 L 583.631 590.556 C 577.945 584.87 574.747 577.15 574.747 569.109 C 574.747 561.068 577.945 553.349 583.631 547.663\" android:fillColor=\"#ffffff\" android:strokeWidth=\"1\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/settings_alt.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector android:width=\"48dp\"\n    android:height=\"48dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/white\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path android:fillColor=\"@android:color/white\" android:pathData=\"M27.6,44.8H20.4Q19.7,44.8 19.175,44.4Q18.65,44 18.6,43.3L17.8,38.3Q17,38 16.025,37.475Q15.05,36.95 14.35,36.35L9.75,38.45Q9.15,38.8 8.45,38.55Q7.75,38.3 7.4,37.65L3.8,31.15Q3.4,30.55 3.6,29.9Q3.8,29.25 4.35,28.85L8.5,25.75Q8.45,25.4 8.425,24.85Q8.4,24.3 8.4,23.9Q8.4,23.55 8.425,23.025Q8.45,22.5 8.5,22.1L4.35,19.1Q3.75,18.7 3.6,18.025Q3.45,17.35 3.8,16.75L7.4,10.3Q7.8,9.7 8.45,9.45Q9.1,9.2 9.75,9.5L14.25,11.6Q14.95,11.05 15.95,10.475Q16.95,9.9 17.8,9.6L18.6,4.65Q18.65,3.95 19.175,3.55Q19.7,3.15 20.4,3.15H27.6Q28.3,3.15 28.825,3.55Q29.35,3.95 29.45,4.65L30.2,9.6Q31.05,9.9 32.075,10.475Q33.1,11.05 33.75,11.6L38.25,9.5Q38.85,9.2 39.55,9.45Q40.25,9.7 40.6,10.3L44.2,16.7Q44.55,17.3 44.4,18Q44.25,18.7 43.7,19.1L39.45,22.05Q39.5,22.5 39.55,23.05Q39.6,23.6 39.6,24Q39.6,24.4 39.55,24.925Q39.5,25.45 39.5,25.85L43.65,28.85Q44.2,29.25 44.375,29.925Q44.55,30.6 44.2,31.2L40.6,37.7Q40.2,38.35 39.525,38.575Q38.85,38.8 38.25,38.45L33.65,36.35Q32.95,36.9 32,37.475Q31.05,38.05 30.25,38.3L29.45,43.3Q29.35,44 28.825,44.4Q28.3,44.8 27.6,44.8ZM23.95,31.15Q26.95,31.15 29.05,29.05Q31.15,26.95 31.15,23.95Q31.15,20.95 29.05,18.85Q26.95,16.75 23.95,16.75Q20.95,16.75 18.85,18.85Q16.75,20.95 16.75,23.95Q16.75,26.95 18.85,29.05Q20.95,31.15 23.95,31.15ZM23.9,27.5Q22.45,27.5 21.425,26.45Q20.4,25.4 20.4,23.95Q20.4,22.45 21.425,21.425Q22.45,20.4 23.95,20.4Q25.4,20.4 26.45,21.45Q27.5,22.5 27.5,23.95Q27.5,25.45 26.45,26.475Q25.4,27.5 23.9,27.5ZM24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95Q24,23.95 24,23.95ZM21.8,41.15H26.2L26.9,35.5Q28.6,35.1 30.1,34.25Q31.6,33.4 32.85,32.15L38.1,34.45L40.1,30.85L35.45,27.4Q35.65,26.55 35.8,25.7Q35.95,24.85 35.95,23.95Q35.95,23.05 35.825,22.225Q35.7,21.4 35.5,20.5L40.1,17.1L38.15,13.5L32.85,15.75Q31.7,14.45 30.2,13.525Q28.7,12.6 26.9,12.35L26.25,6.8H21.75L21.1,12.35Q19.3,12.75 17.775,13.625Q16.25,14.5 15.1,15.75L9.9,13.5L7.85,17.1L12.5,20.55Q12.3,21.45 12.175,22.275Q12.05,23.1 12.05,23.9Q12.05,24.75 12.175,25.6Q12.3,26.45 12.5,27.4L7.85,30.85L9.9,34.45L15.15,32.15Q16.45,33.45 17.95,34.3Q19.45,35.15 21.1,35.55Z\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/settings_icon_filled.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"m370,880 l-16,-128q-13,-5 -24.5,-12T307,725l-119,50L78,585l103,-78q-1,-7 -1,-13.5v-27q0,-6.5 1,-13.5L78,375l110,-190 119,50q11,-8 23,-15t24,-12l16,-128h220l16,128q13,5 24.5,12t22.5,15l119,-50 110,190 -103,78q1,7 1,13.5v27q0,6.5 -2,13.5l103,78 -110,190 -118,-50q-11,8 -23,15t-24,12L590,880L370,880ZM482,620q58,0 99,-41t41,-99q0,-58 -41,-99t-99,-41q-59,0 -99.5,41T342,480q0,58 40.5,99t99.5,41Z\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/settings_icon_outline.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\">\n  <path\n      android:pathData=\"m370,880 l-16,-128q-13,-5 -24.5,-12T307,725l-119,50L78,585l103,-78q-1,-7 -1,-13.5v-27q0,-6.5 1,-13.5L78,375l110,-190 119,50q11,-8 23,-15t24,-12l16,-128h220l16,128q13,5 24.5,12t22.5,15l119,-50 110,190 -103,78q1,7 1,13.5v27q0,6.5 -2,13.5l103,78 -110,190 -118,-50q-11,8 -23,15t-24,12L590,880L370,880ZM440,800h79l14,-106q31,-8 57.5,-23.5T639,633l99,41 39,-68 -86,-65q5,-14 7,-29.5t2,-31.5q0,-16 -2,-31.5t-7,-29.5l86,-65 -39,-68 -99,42q-22,-23 -48.5,-38.5T533,266l-13,-106h-79l-14,106q-31,8 -57.5,23.5T321,327l-99,-41 -39,68 86,64q-5,15 -7,30t-2,32q0,16 2,31t7,30l-86,65 39,68 99,-42q22,23 48.5,38.5T427,694l13,106ZM482,620q58,0 99,-41t41,-99q0,-58 -41,-99t-99,-41q-59,0 -99.5,41T342,480q0,58 40.5,99t99.5,41ZM480,480Z\"\n      android:fillColor=\"#e8eaed\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/settings_icon_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@drawable/settings_icon_filled\" android:state_checked=\"true\"/>\n    <item android:drawable=\"@drawable/settings_icon_filled\" android:state_focused=\"true\"/>\n    <item android:drawable=\"@drawable/settings_icon_outline\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/simkl_logo.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"20dp\"\n    android:height=\"20dp\"\n    android:viewportWidth=\"1536\"\n    android:viewportHeight=\"1536\">\n    <path\n        android:fillColor=\"?attr/white\"\n        android:pathData=\"M205.8,970.3c0,35.3 1.8,65.9 5.4,91.8 6.7,53.2 28.2,94.4 64.5,123.5 33.6,27.3 88.9,45.7 166,55.1 63.2,8 166,12 308.5,12 234.3,0 377.5,-8 429.4,-23.9 52.9,-16 90.9,-45.8 114.2,-89.5 23.3,-44.2 34.9,-113.4 34.9,-207.8 0,-84.5 -11.9,-145.8 -35.6,-183.9 -15.7,-25.8 -36.6,-45.8 -62.9,-59.9 -26.2,-14.1 -61.5,-24.6 -105.9,-31.7 -43.9,-7 -145.5,-12.9 -304.6,-17.6 -175.8,-5.6 -274.6,-11.5 -296.5,-17.6 -26,-7.5 -39,-28.2 -39,-62 0,-35.2 12.3,-57 37,-65.5 22,-7 92.1,-10.6 210.5,-10.6 119.7,0 195,1.4 225.9,4.2 34.9,3.3 55.6,18 61.8,44.3 2.3,8.9 3.8,24.8 4.7,47.8h271c0.4,-22.4 0.6,-38.8 0.6,-49.1 0,-95.5 -21.5,-161.7 -64.6,-198.7 -31.8,-26.7 -83.9,-45.4 -156,-56.2 -54.7,-7.9 -148.4,-11.9 -281.1,-11.9 -204,0 -333.1,4.7 -387.4,14.1 -60.1,10.8 -104.9,33 -134.5,66.7 -39.5,44.5 -59.2,121.2 -59.2,229.8 0,51.6 4,93.3 12.1,125.1 14.3,57.6 44.8,98.4 91.5,122.3 36.3,18.7 98.9,29.5 187.6,32.4 34.1,0.9 108.4,4.2 223.2,9.8 111.2,5.6 184.2,8.4 219.2,8.4 50.6,0.9 82.7,8.2 96.2,21.8 9.8,9.8 14.8,26.9 14.8,51.3 0,35.6 -7.9,58.6 -23.5,68.9 -11.2,7 -34.5,12 -69.9,14.7 -18.8,1 -87.8,1.7 -207,2.1 -87,-0.5 -138.3,-0.9 -153.9,-1.4 -31.4,-0.9 -53.3,-2.6 -65.9,-4.9 -12.5,-2.3 -23.7,-6.4 -33.6,-13 -18.8,-13.6 -28,-44 -27.6,-91.4H205.8v50.8,-0.3z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/solid_primary.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/colorPrimary\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/speedup.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:pathData=\"M200,680v-160q0,-33 23.5,-56.5T280,440h80v-80L200,360v-80h160q33,0 56.5,23.5T440,360v80q0,33 -23.5,56.5T360,520h-80v80h160v80L200,680ZM480,680 L600,480 480,280h80l80,133 80,-133h80L680,480l120,200h-80l-80,-133 -80,133h-80Z\"\n      android:fillColor=\"#e3e3e3\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/splash_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item>\n        <color android:color=\"?attr/primaryBlackBackground\"/>\n    </item>\n    <item android:width=\"150dp\" android:height=\"150dp\" android:gravity=\"center\" android:drawable=\"@drawable/ic_launcher_foreground\">\n    </item>\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/storage_bar_left.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/white\" />\n    <corners\n        android:bottomLeftRadius=\"@dimen/storage_radius\"\n        android:topLeftRadius=\"@dimen/storage_radius\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/storage_bar_left_box.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/white\" />\n    <corners android:radius=\"@dimen/storage_radius\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/storage_bar_mid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/colorPrimary\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/storage_bar_mid_box.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/colorPrimary\" />\n    <corners android:radius=\"@dimen/storage_radius\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/storage_bar_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/grayTextColor\" />\n    <corners\n        android:bottomRightRadius=\"@dimen/storage_radius\"\n        android:topRightRadius=\"@dimen/storage_radius\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/storage_bar_right_box.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/grayTextColor\" />\n    <corners android:radius=\"@dimen/storage_radius\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/sub_bg_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"@color/subColorBg\"/>\n    <corners android:radius=\"@dimen/rounded_image_radius\"/>\n   <!-- <stroke android:color=\"@color/subColor\" android:width=\"2dp\"/>-->\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/subdl_logo_big.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"20dp\"\n    android:height=\"20dp\"\n    android:tint=\"?attr/white\"\n    android:viewportWidth=\"320\"\n    android:viewportHeight=\"320\">\n\n    <path\n        android:fillColor=\"@color/white\"\n        android:pathData=\"m107.87,39.3l-8.44,8.59l0,35.68l0,35.83l18.95,22.5c10.36,12.44 30.35,36.27 44.41,53l25.46,30.5l0,12.14l0,12.29l-24.43,-0l-24.43,-0l0,-11.84l0,-11.84l-19.99,-0l-19.99,-0l0,23.24l0,23.24l8.44,8.59l8.44,8.59l48.26,-0l48.26,-0l7.7,-7.85l7.7,-7.85l0,-36.86l-0.15,-37.01l-23.98,-28.28c-13.18,-15.54 -33.16,-39.23 -44.26,-52.55l-20.43,-24.13l0,-12.29l0,-12.29l24.43,-0l24.43,-0l0,12.58l0,12.58l19.99,-0l19.99,-0l0,-24.87l0,-24.87l-7.85,-7.7l-7.85,-7.7l-48.11,-0l-48.11,-0l-8.44,8.59z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/subtitles_background_gradient.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n            android:startColor=\"#FFF\"\n            android:endColor=\"#000\"\n            android:angle=\"0\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/sun_1.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"137\"\n    android:viewportHeight=\"137\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 69.24 35.91 C 62.272 35.91 55.48 38.117 49.843 42.212 C 44.206 46.308 40.008 52.086 37.855 58.712 C 35.702 65.339 35.702 72.481 37.855 79.108 C 40.008 85.734 44.206 91.512 49.843 95.608 C 55.48 99.703 62.272 101.91 69.24 101.91 C 76.208 101.91 83 99.703 88.637 95.608 C 94.274 91.512 98.472 85.734 100.625 79.108 C 102.778 72.481 102.778 65.339 100.625 58.712 C 98.472 52.086 94.274 46.308 88.637 42.212 C 83 38.117 76.208 35.91 69.24 35.91 Z\"\n        android:fillColor=\"#ffffff\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 68.91 0.5 L 68.92 0.5 C 70.717 0.5 72.443 1.215 73.714 2.486 C 74.985 3.757 75.7 5.483 75.7 7.28 L 75.7 12.5 C 75.7 13.69 75.387 14.859 74.792 15.89 C 74.197 16.921 73.341 17.777 72.31 18.372 C 71.279 18.967 70.11 19.28 68.92 19.28 L 68.91 19.28 C 67.72 19.28 66.551 18.967 65.52 18.372 C 64.489 17.777 63.633 16.921 63.038 15.89 C 62.443 14.859 62.13 13.69 62.13 12.5 L 62.13 7.28 C 62.13 6.09 62.443 4.921 63.038 3.89 C 63.633 2.859 64.489 2.003 65.52 1.408 C 66.551 0.813 67.72 0.5 68.91 0.5\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 68.91 0.5 L 68.92 0.5 C 70.717 0.5 72.443 1.215 73.714 2.486 C 74.985 3.757 75.7 5.483 75.7 7.28 L 75.7 12.5 C 75.7 13.69 75.387 14.859 74.792 15.89 C 74.197 16.921 73.341 17.777 72.31 18.372 C 71.279 18.967 70.11 19.28 68.92 19.28 L 68.91 19.28 C 67.72 19.28 66.551 18.967 65.52 18.372 C 64.489 17.777 63.633 16.921 63.038 15.89 C 62.443 14.859 62.13 13.69 62.13 12.5 L 62.13 7.28 C 62.13 6.09 62.443 4.921 63.038 3.89 C 63.633 2.859 64.489 2.003 65.52 1.408 C 66.551 0.813 67.72 0.5 68.91 0.5\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_3\"\n        android:pathData=\"M 68.91 118.54 L 68.92 118.54 C 70.717 118.54 72.443 119.255 73.714 120.526 C 74.985 121.797 75.7 123.523 75.7 125.32 L 75.7 130.54 C 75.7 132.337 74.985 134.063 73.714 135.334 C 72.443 136.605 70.717 137.32 68.92 137.32 L 68.91 137.32 C 67.72 137.32 66.551 137.007 65.52 136.412 C 64.489 135.817 63.633 134.961 63.038 133.93 C 62.443 132.899 62.13 131.73 62.13 130.54 L 62.13 125.32 C 62.13 124.13 62.443 122.961 63.038 121.93 C 63.633 120.899 64.489 120.043 65.52 119.448 C 66.551 118.853 67.72 118.54 68.91 118.54\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_4\"\n        android:pathData=\"M 68.91 118.54 L 68.92 118.54 C 70.717 118.54 72.443 119.255 73.714 120.526 C 74.985 121.797 75.7 123.523 75.7 125.32 L 75.7 130.54 C 75.7 132.337 74.985 134.063 73.714 135.334 C 72.443 136.605 70.717 137.32 68.92 137.32 L 68.91 137.32 C 67.72 137.32 66.551 137.007 65.52 136.412 C 64.489 135.817 63.633 134.961 63.038 133.93 C 62.443 132.899 62.13 131.73 62.13 130.54 L 62.13 125.32 C 62.13 124.13 62.443 122.961 63.038 121.93 C 63.633 120.899 64.489 120.043 65.52 119.448 C 66.551 118.853 67.72 118.54 68.91 118.54\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_5\"\n        android:pathData=\"M 104.007 24.222 L 107.698 20.531 C 108.539 19.69 109.588 19.084 110.737 18.776 C 111.887 18.468 113.097 18.468 114.247 18.776 C 115.396 19.084 116.445 19.69 117.286 20.531 L 117.293 20.538 C 118.135 21.38 118.74 22.428 119.048 23.577 C 119.356 24.727 119.356 25.938 119.048 27.087 C 118.74 28.237 118.135 29.285 117.293 30.126 L 113.602 33.818 C 112.761 34.659 111.712 35.264 110.563 35.572 C 109.413 35.88 108.203 35.88 107.053 35.572 C 105.904 35.264 104.855 34.659 104.014 33.818 L 104.007 33.81 C 103.165 32.969 102.56 31.921 102.252 30.771 C 101.944 29.622 101.944 28.411 102.252 27.261 C 102.56 26.112 103.165 25.064 104.007 24.222\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_6\"\n        android:pathData=\"M 104.007 24.222 L 107.698 20.531 C 108.539 19.69 109.588 19.084 110.737 18.776 C 111.887 18.468 113.097 18.468 114.247 18.776 C 115.396 19.084 116.445 19.69 117.286 20.531 L 117.293 20.538 C 118.135 21.38 118.74 22.428 119.048 23.577 C 119.356 24.727 119.356 25.938 119.048 27.087 C 118.74 28.237 118.135 29.285 117.293 30.126 L 113.602 33.818 C 112.761 34.659 111.712 35.264 110.563 35.572 C 109.413 35.88 108.203 35.88 107.053 35.572 C 105.904 35.264 104.855 34.659 104.014 33.818 L 104.007 33.81 C 103.165 32.969 102.56 31.921 102.252 30.771 C 101.944 29.622 101.944 28.411 102.252 27.261 C 102.56 26.112 103.165 25.064 104.007 24.222\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_7\"\n        android:pathData=\"M 20.537 107.696 L 24.228 104.005 C 25.069 103.164 26.118 102.559 27.267 102.251 C 28.417 101.943 29.627 101.943 30.777 102.251 C 31.926 102.559 32.975 103.164 33.816 104.005 L 33.823 104.012 C 34.665 104.854 35.27 105.902 35.578 107.052 C 35.886 108.201 35.886 109.412 35.578 110.561 C 35.27 111.711 34.665 112.759 33.823 113.601 L 30.132 117.292 C 29.291 118.133 28.242 118.739 27.093 119.047 C 25.943 119.355 24.733 119.355 23.583 119.047 C 22.434 118.739 21.385 118.133 20.544 117.292 L 20.537 117.285 C 19.695 116.443 19.09 115.395 18.782 114.245 C 18.474 113.096 18.474 111.885 18.782 110.736 C 19.09 109.586 19.695 108.538 20.537 107.696\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_8\"\n        android:pathData=\"M 20.537 107.696 L 24.228 104.005 C 25.069 103.164 26.118 102.559 27.267 102.251 C 28.417 101.943 29.627 101.943 30.777 102.251 C 31.926 102.559 32.975 103.164 33.816 104.005 L 33.823 104.012 C 34.665 104.854 35.27 105.902 35.578 107.052 C 35.886 108.201 35.886 109.412 35.578 110.561 C 35.27 111.711 34.665 112.759 33.823 113.601 L 30.132 117.292 C 29.291 118.133 28.242 118.739 27.093 119.047 C 25.943 119.355 24.733 119.355 23.583 119.047 C 22.434 118.739 21.385 118.133 20.544 117.292 L 20.537 117.285 C 19.695 116.443 19.09 115.395 18.782 114.245 C 18.474 113.096 18.474 111.885 18.782 110.736 C 19.09 109.586 19.695 108.538 20.537 107.696\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <group android:name=\"group\">\n        <path\n            android:name=\"path_9\"\n            android:pathData=\"M 125.32 62.13 L 130.54 62.13 C 132.337 62.13 134.063 62.845 135.334 64.116 C 136.605 65.387 137.32 67.113 137.32 68.91 L 137.32 68.92 C 137.32 70.717 136.605 72.443 135.334 73.714 C 134.063 74.985 132.337 75.7 130.54 75.7 L 125.32 75.7 C 123.523 75.7 121.797 74.985 120.526 73.714 C 119.255 72.443 118.54 70.717 118.54 68.92 L 118.54 68.91 C 118.54 67.72 118.853 66.551 119.448 65.52 C 120.043 64.489 120.899 63.633 121.93 63.038 C 122.961 62.443 124.13 62.13 125.32 62.13\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_10\"\n            android:pathData=\"M 125.32 62.13 L 130.54 62.13 C 132.337 62.13 134.063 62.845 135.334 64.116 C 136.605 65.387 137.32 67.113 137.32 68.91 L 137.32 68.92 C 137.32 70.717 136.605 72.443 135.334 73.714 C 134.063 74.985 132.337 75.7 130.54 75.7 L 125.32 75.7 C 123.523 75.7 121.797 74.985 120.526 73.714 C 119.255 72.443 118.54 70.717 118.54 68.92 L 118.54 68.91 C 118.54 67.72 118.853 66.551 119.448 65.52 C 120.043 64.489 120.899 63.633 121.93 63.038 C 122.961 62.443 124.13 62.13 125.32 62.13\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_1\">\n        <path\n            android:name=\"path_11\"\n            android:pathData=\"M 7.28 62.13 L 12.5 62.13 C 13.69 62.13 14.859 62.443 15.89 63.038 C 16.921 63.633 17.777 64.489 18.372 65.52 C 18.967 66.551 19.28 67.72 19.28 68.91 L 19.28 68.92 C 19.28 70.11 18.967 71.279 18.372 72.31 C 17.777 73.341 16.921 74.197 15.89 74.792 C 14.859 75.387 13.69 75.7 12.5 75.7 L 7.28 75.7 C 5.483 75.7 3.757 74.985 2.486 73.714 C 1.215 72.443 0.5 70.717 0.5 68.92 L 0.5 68.91 C 0.5 67.72 0.813 66.551 1.408 65.52 C 2.003 64.489 2.859 63.633 3.89 63.038 C 4.921 62.443 6.09 62.13 7.28 62.13\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_12\"\n            android:pathData=\"M 7.28 62.13 L 12.5 62.13 C 13.69 62.13 14.859 62.443 15.89 63.038 C 16.921 63.633 17.777 64.489 18.372 65.52 C 18.967 66.551 19.28 67.72 19.28 68.91 L 19.28 68.92 C 19.28 70.11 18.967 71.279 18.372 72.31 C 17.777 73.341 16.921 74.197 15.89 74.792 C 14.859 75.387 13.69 75.7 12.5 75.7 L 7.28 75.7 C 5.483 75.7 3.757 74.985 2.486 73.714 C 1.215 72.443 0.5 70.717 0.5 68.92 L 0.5 68.91 C 0.5 67.72 0.813 66.551 1.408 65.52 C 2.003 64.489 2.859 63.633 3.89 63.038 C 4.921 62.443 6.09 62.13 7.28 62.13\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_2\">\n        <path\n            android:name=\"path_13\"\n            android:pathData=\"M 104.009 104.017 L 104.016 104.01 C 104.858 103.169 105.906 102.563 107.055 102.255 C 108.205 101.947 109.416 101.947 110.565 102.255 C 111.715 102.563 112.763 103.169 113.604 104.01 L 117.295 107.701 C 118.137 108.543 118.742 109.591 119.05 110.741 C 119.358 111.89 119.358 113.101 119.05 114.25 C 118.742 115.4 118.137 116.448 117.295 117.29 L 117.288 117.297 C 116.447 118.138 115.399 118.744 114.249 119.052 C 113.1 119.36 111.889 119.36 110.739 119.052 C 109.59 118.744 108.542 118.138 107.7 117.297 L 104.009 113.606 C 103.167 112.764 102.562 111.716 102.254 110.566 C 101.946 109.417 101.946 108.206 102.254 107.057 C 102.562 105.907 103.167 104.859 104.009 104.017\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_14\"\n            android:pathData=\"M 104.009 104.017 L 104.016 104.01 C 104.858 103.169 105.906 102.563 107.055 102.255 C 108.205 101.947 109.416 101.947 110.565 102.255 C 111.715 102.563 112.763 103.169 113.604 104.01 L 117.295 107.701 C 118.137 108.543 118.742 109.591 119.05 110.741 C 119.358 111.89 119.358 113.101 119.05 114.25 C 118.742 115.4 118.137 116.448 117.295 117.29 L 117.288 117.297 C 116.447 118.138 115.399 118.744 114.249 119.052 C 113.1 119.36 111.889 119.36 110.739 119.052 C 109.59 118.744 108.542 118.138 107.7 117.297 L 104.009 113.606 C 103.167 112.764 102.562 111.716 102.254 110.566 C 101.946 109.417 101.946 108.206 102.254 107.057 C 102.562 105.907 103.167 104.859 104.009 104.017\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_3\">\n        <path\n            android:name=\"path_15\"\n            android:pathData=\"M 20.542 20.54 L 20.549 20.533 C 21.39 19.692 22.439 19.086 23.588 18.778 C 24.738 18.47 25.948 18.47 27.098 18.778 C 28.247 19.086 29.296 19.692 30.137 20.533 L 33.828 24.224 C 34.67 25.066 35.275 26.114 35.583 27.264 C 35.891 28.413 35.891 29.624 35.583 30.773 C 35.275 31.923 34.67 32.971 33.828 33.813 L 33.821 33.82 C 32.98 34.661 31.931 35.267 30.782 35.575 C 29.632 35.883 28.422 35.883 27.272 35.575 C 26.123 35.267 25.074 34.661 24.233 33.82 L 20.542 30.129 C 19.7 29.287 19.095 28.239 18.787 27.089 C 18.479 25.94 18.479 24.729 18.787 23.58 C 19.095 22.43 19.7 21.382 20.542 20.54\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_16\"\n            android:pathData=\"M 20.542 20.54 L 20.549 20.533 C 21.39 19.692 22.439 19.086 23.588 18.778 C 24.738 18.47 25.948 18.47 27.098 18.778 C 28.247 19.086 29.296 19.692 30.137 20.533 L 33.828 24.224 C 34.67 25.066 35.275 26.114 35.583 27.264 C 35.891 28.413 35.891 29.624 35.583 30.773 C 35.275 31.923 34.67 32.971 33.828 33.813 L 33.821 33.82 C 32.98 34.661 31.931 35.267 30.782 35.575 C 29.632 35.883 28.422 35.883 27.272 35.575 C 26.123 35.267 25.074 34.661 24.233 33.82 L 20.542 30.129 C 19.7 29.287 19.095 28.239 18.787 27.089 C 18.479 25.94 18.479 24.729 18.787 23.58 C 19.095 22.43 19.7 21.382 20.542 20.54\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/sun_2.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"26.14dp\"\n    android:height=\"26.14dp\"\n    android:viewportWidth=\"149\"\n    android:viewportHeight=\"149\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 74.99 41.67 C 66.241 41.67 57.842 45.149 51.655 51.335 C 45.469 57.522 41.99 65.921 41.99 74.67 C 41.99 83.419 45.469 91.818 51.655 98.005 C 57.842 104.191 66.241 107.67 74.99 107.67 C 83.739 107.67 92.138 104.191 98.325 98.005 C 104.511 91.818 107.99 83.419 107.99 74.67 C 107.99 65.921 104.511 57.522 98.325 51.335 C 92.138 45.149 83.739 41.67 74.99 41.67 Z\"\n        android:fillColor=\"#ffffff\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 74.66 0.5 L 74.67 0.5 C 76.467 0.5 78.193 1.215 79.464 2.486 C 80.735 3.757 81.45 5.483 81.45 7.28 L 81.45 18.26 C 81.45 20.057 80.735 21.783 79.464 23.054 C 78.193 24.325 76.467 25.04 74.67 25.04 L 74.66 25.04 C 72.863 25.04 71.137 24.325 69.866 23.054 C 68.595 21.783 67.88 20.057 67.88 18.26 L 67.88 7.28 C 67.88 5.483 68.595 3.757 69.866 2.486 C 71.137 1.215 72.863 0.5 74.66 0.5\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 74.66 0.5 L 74.67 0.5 C 76.467 0.5 78.193 1.215 79.464 2.486 C 80.735 3.757 81.45 5.483 81.45 7.28 L 81.45 18.26 C 81.45 20.057 80.735 21.783 79.464 23.054 C 78.193 24.325 76.467 25.04 74.67 25.04 L 74.66 25.04 C 72.863 25.04 71.137 24.325 69.866 23.054 C 68.595 21.783 67.88 20.057 67.88 18.26 L 67.88 7.28 C 67.88 5.483 68.595 3.757 69.866 2.486 C 71.137 1.215 72.863 0.5 74.66 0.5\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_3\"\n        android:pathData=\"M 74.66 124.3 L 74.67 124.3 C 76.467 124.3 78.193 125.015 79.464 126.286 C 80.735 127.557 81.45 129.283 81.45 131.08 L 81.45 142.06 C 81.45 143.857 80.735 145.583 79.464 146.854 C 78.193 148.125 76.467 148.84 74.67 148.84 L 74.66 148.84 C 72.863 148.84 71.137 148.125 69.866 146.854 C 68.595 145.583 67.88 143.857 67.88 142.06 L 67.88 131.08 C 67.88 129.283 68.595 127.557 69.866 126.286 C 71.137 125.015 72.863 124.3 74.66 124.3\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_4\"\n        android:pathData=\"M 74.66 124.3 L 74.67 124.3 C 76.467 124.3 78.193 125.015 79.464 126.286 C 80.735 127.557 81.45 129.283 81.45 131.08 L 81.45 142.06 C 81.45 143.857 80.735 145.583 79.464 146.854 C 78.193 148.125 76.467 148.84 74.67 148.84 L 74.66 148.84 C 72.863 148.84 71.137 148.125 69.866 146.854 C 68.595 145.583 67.88 143.857 67.88 142.06 L 67.88 131.08 C 67.88 129.283 68.595 127.557 69.866 126.286 C 71.137 125.015 72.863 124.3 74.66 124.3\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_5\"\n        android:pathData=\"M 109.76 29.988 L 117.524 22.224 C 118.366 21.382 119.414 20.777 120.564 20.469 C 121.713 20.161 122.924 20.161 124.073 20.469 C 125.223 20.777 126.271 21.382 127.113 22.224 L 127.12 22.231 C 127.961 23.072 128.567 24.121 128.875 25.27 C 129.183 26.42 129.183 27.63 128.875 28.78 C 128.567 29.929 127.961 30.978 127.12 31.819 L 119.356 39.583 C 118.514 40.425 117.466 41.03 116.316 41.338 C 115.167 41.646 113.956 41.646 112.807 41.338 C 111.657 41.03 110.609 40.425 109.767 39.583 L 109.76 39.576 C 108.919 38.735 108.314 37.686 108.005 36.537 C 107.697 35.387 107.697 34.177 108.005 33.027 C 108.314 31.878 108.919 30.829 109.76 29.988\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_6\"\n        android:pathData=\"M 109.76 29.988 L 117.524 22.224 C 118.366 21.382 119.414 20.777 120.564 20.469 C 121.713 20.161 122.924 20.161 124.073 20.469 C 125.223 20.777 126.271 21.382 127.113 22.224 L 127.12 22.231 C 127.961 23.072 128.567 24.121 128.875 25.27 C 129.183 26.42 129.183 27.63 128.875 28.78 C 128.567 29.929 127.961 30.978 127.12 31.819 L 119.356 39.583 C 118.514 40.425 117.466 41.03 116.316 41.338 C 115.167 41.646 113.956 41.646 112.807 41.338 C 111.657 41.03 110.609 40.425 109.767 39.583 L 109.76 39.576 C 108.919 38.735 108.314 37.686 108.005 36.537 C 107.697 35.387 107.697 34.177 108.005 33.027 C 108.314 31.878 108.919 30.829 109.76 29.988\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_7\"\n        android:pathData=\"M 22.22 117.528 L 29.984 109.764 C 30.826 108.922 31.874 108.317 33.024 108.009 C 34.173 107.701 35.384 107.701 36.533 108.009 C 37.683 108.317 38.731 108.922 39.573 109.764 L 39.58 109.771 C 40.421 110.612 41.027 111.661 41.335 112.81 C 41.643 113.96 41.643 115.17 41.335 116.32 C 41.027 117.469 40.421 118.518 39.58 119.359 L 31.816 127.123 C 30.974 127.965 29.926 128.57 28.776 128.878 C 27.627 129.186 26.416 129.186 25.267 128.878 C 24.117 128.57 23.069 127.965 22.227 127.123 L 22.22 127.116 C 21.379 126.275 20.774 125.226 20.465 124.077 C 20.157 122.927 20.157 121.717 20.465 120.567 C 20.774 119.418 21.379 118.369 22.22 117.528\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_8\"\n        android:pathData=\"M 22.22 117.528 L 29.984 109.764 C 30.826 108.922 31.874 108.317 33.024 108.009 C 34.173 107.701 35.384 107.701 36.533 108.009 C 37.683 108.317 38.731 108.922 39.573 109.764 L 39.58 109.771 C 40.421 110.612 41.027 111.661 41.335 112.81 C 41.643 113.96 41.643 115.17 41.335 116.32 C 41.027 117.469 40.421 118.518 39.58 119.359 L 31.816 127.123 C 30.974 127.965 29.926 128.57 28.776 128.878 C 27.627 129.186 26.416 129.186 25.267 128.878 C 24.117 128.57 23.069 127.965 22.227 127.123 L 22.22 127.116 C 21.379 126.275 20.774 125.226 20.465 124.077 C 20.157 122.927 20.157 121.717 20.465 120.567 C 20.774 119.418 21.379 118.369 22.22 117.528\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <group android:name=\"group\">\n        <path\n            android:name=\"path_9\"\n            android:pathData=\"M 131.08 67.88 L 142.06 67.88 C 143.857 67.88 145.583 68.595 146.854 69.866 C 148.125 71.137 148.84 72.863 148.84 74.66 L 148.84 74.67 C 148.84 76.467 148.125 78.193 146.854 79.464 C 145.583 80.735 143.857 81.45 142.06 81.45 L 131.08 81.45 C 129.283 81.45 127.557 80.735 126.286 79.464 C 125.015 78.193 124.3 76.467 124.3 74.67 L 124.3 74.66 C 124.3 72.863 125.015 71.137 126.286 69.866 C 127.557 68.595 129.283 67.88 131.08 67.88\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_10\"\n            android:pathData=\"M 131.08 67.88 L 142.06 67.88 C 143.857 67.88 145.583 68.595 146.854 69.866 C 148.125 71.137 148.84 72.863 148.84 74.66 L 148.84 74.67 C 148.84 76.467 148.125 78.193 146.854 79.464 C 145.583 80.735 143.857 81.45 142.06 81.45 L 131.08 81.45 C 129.283 81.45 127.557 80.735 126.286 79.464 C 125.015 78.193 124.3 76.467 124.3 74.67 L 124.3 74.66 C 124.3 72.863 125.015 71.137 126.286 69.866 C 127.557 68.595 129.283 67.88 131.08 67.88\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_1\">\n        <path\n            android:name=\"path_11\"\n            android:pathData=\"M 7.28 67.88 L 18.26 67.88 C 20.057 67.88 21.783 68.595 23.054 69.866 C 24.325 71.137 25.04 72.863 25.04 74.66 L 25.04 74.67 C 25.04 76.467 24.325 78.193 23.054 79.464 C 21.783 80.735 20.057 81.45 18.26 81.45 L 7.28 81.45 C 5.483 81.45 3.757 80.735 2.486 79.464 C 1.215 78.193 0.5 76.467 0.5 74.67 L 0.5 74.66 C 0.5 72.863 1.215 71.137 2.486 69.866 C 3.757 68.595 5.483 67.88 7.28 67.88\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_12\"\n            android:pathData=\"M 7.28 67.88 L 18.26 67.88 C 20.057 67.88 21.783 68.595 23.054 69.866 C 24.325 71.137 25.04 72.863 25.04 74.66 L 25.04 74.67 C 25.04 76.467 24.325 78.193 23.054 79.464 C 21.783 80.735 20.057 81.45 18.26 81.45 L 7.28 81.45 C 5.483 81.45 3.757 80.735 2.486 79.464 C 1.215 78.193 0.5 76.467 0.5 74.67 L 0.5 74.66 C 0.5 72.863 1.215 71.137 2.486 69.866 C 3.757 68.595 5.483 67.88 7.28 67.88\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_2\">\n        <path\n            android:name=\"path_13\"\n            android:pathData=\"M 109.76 109.764 L 109.767 109.757 C 110.609 108.915 111.657 108.31 112.807 108.002 C 113.956 107.694 115.167 107.694 116.316 108.002 C 117.466 108.31 118.514 108.915 119.356 109.757 L 127.12 117.521 C 127.961 118.362 128.567 119.411 128.875 120.56 C 129.183 121.71 129.183 122.92 128.875 124.07 C 128.567 125.219 127.961 126.268 127.12 127.109 L 127.113 127.116 C 126.271 127.958 125.223 128.563 124.073 128.871 C 122.924 129.179 121.713 129.179 120.564 128.871 C 119.414 128.563 118.366 127.958 117.524 127.116 L 109.76 119.352 C 108.919 118.511 108.314 117.462 108.006 116.313 C 107.698 115.163 107.698 113.953 108.006 112.803 C 108.314 111.654 108.919 110.605 109.76 109.764\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_14\"\n            android:pathData=\"M 109.76 109.764 L 109.767 109.757 C 110.609 108.915 111.657 108.31 112.807 108.002 C 113.956 107.694 115.167 107.694 116.316 108.002 C 117.466 108.31 118.514 108.915 119.356 109.757 L 127.12 117.521 C 127.961 118.362 128.567 119.411 128.875 120.56 C 129.183 121.71 129.183 122.92 128.875 124.07 C 128.567 125.219 127.961 126.268 127.12 127.109 L 127.113 127.116 C 126.271 127.958 125.223 128.563 124.073 128.871 C 122.924 129.179 121.713 129.179 120.564 128.871 C 119.414 128.563 118.366 127.958 117.524 127.116 L 109.76 119.352 C 108.919 118.511 108.314 117.462 108.006 116.313 C 107.698 115.163 107.698 113.953 108.006 112.803 C 108.314 111.654 108.919 110.605 109.76 109.764\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_3\">\n        <path\n            android:name=\"path_15\"\n            android:pathData=\"M 22.22 22.224 L 22.227 22.217 C 23.069 21.375 24.117 20.77 25.267 20.462 C 26.416 20.154 27.627 20.154 28.776 20.462 C 29.926 20.77 30.974 21.375 31.816 22.217 L 39.58 29.981 C 40.421 30.822 41.026 31.871 41.334 33.02 C 41.642 34.17 41.642 35.38 41.334 36.53 C 41.026 37.679 40.421 38.728 39.58 39.569 L 39.573 39.576 C 38.731 40.418 37.683 41.023 36.533 41.331 C 35.384 41.639 34.173 41.639 33.024 41.331 C 31.874 41.023 30.826 40.418 29.984 39.576 L 22.22 31.812 C 21.379 30.971 20.773 29.922 20.465 28.773 C 20.157 27.623 20.157 26.413 20.465 25.263 C 20.773 24.114 21.379 23.065 22.22 22.224\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_16\"\n            android:pathData=\"M 22.22 22.224 L 22.227 22.217 C 23.069 21.375 24.117 20.77 25.267 20.462 C 26.416 20.154 27.627 20.154 28.776 20.462 C 29.926 20.77 30.974 21.375 31.816 22.217 L 39.58 29.981 C 40.421 30.822 41.026 31.871 41.334 33.02 C 41.642 34.17 41.642 35.38 41.334 36.53 C 41.026 37.679 40.421 38.728 39.58 39.569 L 39.573 39.576 C 38.731 40.418 37.683 41.023 36.533 41.331 C 35.384 41.639 34.173 41.639 33.024 41.331 C 31.874 41.023 30.826 40.418 29.984 39.576 L 22.22 31.812 C 21.379 30.971 20.773 29.922 20.465 28.773 C 20.157 27.623 20.157 26.413 20.465 25.263 C 20.773 24.114 21.379 23.065 22.22 22.224\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/sun_3.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"27.19dp\"\n    android:height=\"27.19dp\"\n    android:viewportWidth=\"155\"\n    android:viewportHeight=\"155\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 77.86 44.54 C 69.111 44.54 60.712 48.019 54.525 54.205 C 48.339 60.392 44.86 68.791 44.86 77.54 C 44.86 86.289 48.339 94.688 54.525 100.875 C 60.712 107.061 69.111 110.54 77.86 110.54 C 86.609 110.54 95.008 107.061 101.195 100.875 C 107.381 94.688 110.86 86.289 110.86 77.54 C 110.86 68.791 107.381 60.392 101.195 54.205 C 95.008 48.019 86.609 44.54 77.86 44.54 Z\"\n        android:fillColor=\"#ffffff\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 77.53 0.5 L 77.54 0.5 C 79.337 0.5 81.063 1.215 82.334 2.486 C 83.605 3.757 84.32 5.483 84.32 7.28 L 84.32 21.13 C 84.32 22.32 84.007 23.489 83.412 24.52 C 82.817 25.551 81.961 26.407 80.93 27.002 C 79.899 27.597 78.73 27.91 77.54 27.91 L 77.53 27.91 C 75.733 27.91 74.007 27.195 72.736 25.924 C 71.465 24.653 70.75 22.927 70.75 21.13 L 70.75 7.28 C 70.75 5.483 71.465 3.757 72.736 2.486 C 74.007 1.215 75.733 0.5 77.53 0.5\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 77.53 0.5 L 77.54 0.5 C 79.337 0.5 81.063 1.215 82.334 2.486 C 83.605 3.757 84.32 5.483 84.32 7.28 L 84.32 21.13 C 84.32 22.32 84.007 23.489 83.412 24.52 C 82.817 25.551 81.961 26.407 80.93 27.002 C 79.899 27.597 78.73 27.91 77.54 27.91 L 77.53 27.91 C 75.733 27.91 74.007 27.195 72.736 25.924 C 71.465 24.653 70.75 22.927 70.75 21.13 L 70.75 7.28 C 70.75 5.483 71.465 3.757 72.736 2.486 C 74.007 1.215 75.733 0.5 77.53 0.5\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_3\"\n        android:pathData=\"M 77.53 127.17 L 77.54 127.17 C 79.337 127.17 81.063 127.885 82.334 129.156 C 83.605 130.427 84.32 132.153 84.32 133.95 L 84.32 147.8 C 84.32 149.597 83.605 151.323 82.334 152.594 C 81.063 153.865 79.337 154.58 77.54 154.58 L 77.53 154.58 C 75.733 154.58 74.007 153.865 72.736 152.594 C 71.465 151.323 70.75 149.597 70.75 147.8 L 70.75 133.95 C 70.75 132.153 71.465 130.427 72.736 129.156 C 74.007 127.885 75.733 127.17 77.53 127.17\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_4\"\n        android:pathData=\"M 77.53 127.17 L 77.54 127.17 C 79.337 127.17 81.063 127.885 82.334 129.156 C 83.605 130.427 84.32 132.153 84.32 133.95 L 84.32 147.8 C 84.32 149.597 83.605 151.323 82.334 152.594 C 81.063 153.865 79.337 154.58 77.54 154.58 L 77.53 154.58 C 75.733 154.58 74.007 153.865 72.736 152.594 C 71.465 151.323 70.75 149.597 70.75 147.8 L 70.75 133.95 C 70.75 132.153 71.465 130.427 72.736 129.156 C 74.007 127.885 75.733 127.17 77.53 127.17\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_5\"\n        android:pathData=\"M 112.629 32.861 L 122.423 23.067 C 123.694 21.796 125.419 21.081 127.217 21.081 C 129.014 21.081 130.74 21.796 132.011 23.067 L 132.018 23.074 C 132.859 23.916 133.465 24.964 133.773 26.114 C 134.081 27.263 134.081 28.474 133.773 29.623 C 133.465 30.773 132.859 31.821 132.018 32.663 L 122.225 42.456 C 121.383 43.297 120.335 43.903 119.185 44.211 C 118.036 44.519 116.825 44.519 115.676 44.211 C 114.526 43.903 113.478 43.297 112.636 42.456 L 112.629 42.449 C 111.788 41.607 111.182 40.559 110.874 39.409 C 110.566 38.26 110.566 37.049 110.874 35.9 C 111.182 34.75 111.788 33.702 112.629 32.861\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_6\"\n        android:pathData=\"M 112.629 32.861 L 122.423 23.067 C 123.694 21.796 125.419 21.081 127.217 21.081 C 129.014 21.081 130.74 21.796 132.011 23.067 L 132.018 23.074 C 132.859 23.916 133.465 24.964 133.773 26.114 C 134.081 27.263 134.081 28.474 133.773 29.623 C 133.465 30.773 132.859 31.821 132.018 32.663 L 122.225 42.456 C 121.383 43.297 120.335 43.903 119.185 44.211 C 118.036 44.519 116.825 44.519 115.676 44.211 C 114.526 43.903 113.478 43.297 112.636 42.456 L 112.629 42.449 C 111.788 41.607 111.182 40.559 110.874 39.409 C 110.566 38.26 110.566 37.049 110.874 35.9 C 111.182 34.75 111.788 33.702 112.629 32.861\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_7\"\n        android:pathData=\"M 23.059 122.417 L 32.853 112.624 C 34.124 111.353 35.849 110.638 37.647 110.638 C 39.444 110.638 41.17 111.353 42.441 112.624 L 42.448 112.631 C 43.289 113.473 43.895 114.521 44.203 115.671 C 44.511 116.82 44.511 118.031 44.203 119.18 C 43.895 120.33 43.289 121.378 42.448 122.219 L 32.655 132.013 C 31.813 132.854 30.765 133.46 29.615 133.768 C 28.466 134.076 27.255 134.076 26.106 133.768 C 24.956 133.46 23.908 132.854 23.066 132.013 L 23.059 132.006 C 22.218 131.164 21.612 130.116 21.304 128.966 C 20.996 127.817 20.996 126.606 21.304 125.457 C 21.612 124.307 22.218 123.259 23.059 122.417\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_8\"\n        android:pathData=\"M 23.059 122.417 L 32.853 112.624 C 34.124 111.353 35.849 110.638 37.647 110.638 C 39.444 110.638 41.17 111.353 42.441 112.624 L 42.448 112.631 C 43.289 113.473 43.895 114.521 44.203 115.671 C 44.511 116.82 44.511 118.031 44.203 119.18 C 43.895 120.33 43.289 121.378 42.448 122.219 L 32.655 132.013 C 31.813 132.854 30.765 133.46 29.615 133.768 C 28.466 134.076 27.255 134.076 26.106 133.768 C 24.956 133.46 23.908 132.854 23.066 132.013 L 23.059 132.006 C 22.218 131.164 21.612 130.116 21.304 128.966 C 20.996 127.817 20.996 126.606 21.304 125.457 C 21.612 124.307 22.218 123.259 23.059 122.417\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <group android:name=\"group\">\n        <path\n            android:name=\"path_9\"\n            android:pathData=\"M 133.95 70.75 L 147.8 70.75 C 149.597 70.75 151.323 71.465 152.594 72.736 C 153.865 74.007 154.58 75.733 154.58 77.53 L 154.58 77.54 C 154.58 79.337 153.865 81.063 152.594 82.334 C 151.323 83.605 149.597 84.32 147.8 84.32 L 133.95 84.32 C 132.153 84.32 130.427 83.605 129.156 82.334 C 127.885 81.063 127.17 79.337 127.17 77.54 L 127.17 77.53 C 127.17 75.733 127.885 74.007 129.156 72.736 C 130.427 71.465 132.153 70.75 133.95 70.75\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_10\"\n            android:pathData=\"M 133.95 70.75 L 147.8 70.75 C 149.597 70.75 151.323 71.465 152.594 72.736 C 153.865 74.007 154.58 75.733 154.58 77.53 L 154.58 77.54 C 154.58 79.337 153.865 81.063 152.594 82.334 C 151.323 83.605 149.597 84.32 147.8 84.32 L 133.95 84.32 C 132.153 84.32 130.427 83.605 129.156 82.334 C 127.885 81.063 127.17 79.337 127.17 77.54 L 127.17 77.53 C 127.17 75.733 127.885 74.007 129.156 72.736 C 130.427 71.465 132.153 70.75 133.95 70.75\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_1\">\n        <path\n            android:name=\"path_11\"\n            android:pathData=\"M 7.28 70.75 L 21.13 70.75 C 22.32 70.75 23.489 71.063 24.52 71.658 C 25.551 72.253 26.407 73.109 27.002 74.14 C 27.597 75.171 27.91 76.34 27.91 77.53 L 27.91 77.54 C 27.91 78.73 27.597 79.899 27.002 80.93 C 26.407 81.961 25.551 82.817 24.52 83.412 C 23.489 84.007 22.32 84.32 21.13 84.32 L 7.28 84.32 C 5.483 84.32 3.757 83.605 2.486 82.334 C 1.215 81.063 0.5 79.337 0.5 77.54 L 0.5 77.53 C 0.5 75.733 1.215 74.007 2.486 72.736 C 3.757 71.465 5.483 70.75 7.28 70.75\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_12\"\n            android:pathData=\"M 7.28 70.75 L 21.13 70.75 C 22.32 70.75 23.489 71.063 24.52 71.658 C 25.551 72.253 26.407 73.109 27.002 74.14 C 27.597 75.171 27.91 76.34 27.91 77.53 L 27.91 77.54 C 27.91 78.73 27.597 79.899 27.002 80.93 C 26.407 81.961 25.551 82.817 24.52 83.412 C 23.489 84.007 22.32 84.32 21.13 84.32 L 7.28 84.32 C 5.483 84.32 3.757 83.605 2.486 82.334 C 1.215 81.063 0.5 79.337 0.5 77.54 L 0.5 77.53 C 0.5 75.733 1.215 74.007 2.486 72.736 C 3.757 71.465 5.483 70.75 7.28 70.75\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_2\">\n        <path\n            android:name=\"path_13\"\n            android:pathData=\"M 112.628 112.633 L 112.635 112.626 C 113.476 111.784 114.525 111.179 115.674 110.871 C 116.824 110.563 118.034 110.563 119.184 110.871 C 120.333 111.179 121.382 111.784 122.223 112.626 L 132.016 122.419 C 132.858 123.26 133.463 124.309 133.771 125.458 C 134.079 126.608 134.079 127.818 133.771 128.968 C 133.463 130.117 132.858 131.166 132.016 132.007 L 132.009 132.014 C 130.738 133.285 129.013 134 127.215 134 C 125.418 134 123.692 133.285 122.421 132.014 L 112.628 122.221 C 111.786 121.38 111.181 120.331 110.873 119.182 C 110.565 118.032 110.565 116.822 110.873 115.672 C 111.181 114.523 111.786 113.474 112.628 112.633\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_14\"\n            android:pathData=\"M 112.628 112.633 L 112.635 112.626 C 113.476 111.784 114.525 111.179 115.674 110.871 C 116.824 110.563 118.034 110.563 119.184 110.871 C 120.333 111.179 121.382 111.784 122.223 112.626 L 132.016 122.419 C 132.858 123.26 133.463 124.309 133.771 125.458 C 134.079 126.608 134.079 127.818 133.771 128.968 C 133.463 130.117 132.858 131.166 132.016 132.007 L 132.009 132.014 C 130.738 133.285 129.013 134 127.215 134 C 125.418 134 123.692 133.285 122.421 132.014 L 112.628 122.221 C 111.786 121.38 111.181 120.331 110.873 119.182 C 110.565 118.032 110.565 116.822 110.873 115.672 C 111.181 114.523 111.786 113.474 112.628 112.633\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_3\">\n        <path\n            android:name=\"path_15\"\n            android:pathData=\"M 23.071 23.063 L 23.078 23.056 C 23.919 22.214 24.968 21.609 26.117 21.301 C 27.267 20.993 28.477 20.993 29.627 21.301 C 30.776 21.609 31.825 22.214 32.666 23.056 L 42.46 32.849 C 43.301 33.69 43.906 34.739 44.214 35.888 C 44.522 37.038 44.522 38.248 44.214 39.398 C 43.906 40.547 43.301 41.596 42.46 42.437 L 42.452 42.444 C 41.611 43.286 40.563 43.891 39.413 44.199 C 38.264 44.507 37.053 44.507 35.903 44.199 C 34.754 43.891 33.706 43.286 32.864 42.444 L 23.071 32.651 C 22.229 31.81 21.624 30.761 21.316 29.612 C 21.008 28.462 21.008 27.252 21.316 26.102 C 21.624 24.953 22.229 23.904 23.071 23.063\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_16\"\n            android:pathData=\"M 23.071 23.063 L 23.078 23.056 C 23.919 22.214 24.968 21.609 26.117 21.301 C 27.267 20.993 28.477 20.993 29.627 21.301 C 30.776 21.609 31.825 22.214 32.666 23.056 L 42.46 32.849 C 43.301 33.69 43.906 34.739 44.214 35.888 C 44.522 37.038 44.522 38.248 44.214 39.398 C 43.906 40.547 43.301 41.596 42.46 42.437 L 42.452 42.444 C 41.611 43.286 40.563 43.891 39.413 44.199 C 38.264 44.507 37.053 44.507 35.903 44.199 C 34.754 43.891 33.706 43.286 32.864 42.444 L 23.071 32.651 C 22.229 31.81 21.624 30.761 21.316 29.612 C 21.008 28.462 21.008 27.252 21.316 26.102 C 21.624 24.953 22.229 23.904 23.071 23.063\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/sun_4.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"29.12dp\"\n    android:height=\"29.12dp\"\n    android:viewportWidth=\"166\"\n    android:viewportHeight=\"166\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 83.34 50.01 C 76.372 50.01 69.58 52.217 63.943 56.312 C 58.306 60.408 54.108 66.186 51.955 72.812 C 49.802 79.439 49.802 86.581 51.955 93.208 C 54.108 99.834 58.306 105.612 63.943 109.708 C 69.58 113.803 76.372 116.01 83.34 116.01 C 92.089 116.01 100.488 112.531 106.675 106.345 C 112.861 100.158 116.34 91.759 116.34 83.01 C 116.34 74.261 112.861 65.862 106.675 59.675 C 100.488 53.489 92.089 50.01 83.34 50.01 Z\"\n        android:fillColor=\"#ffffff\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 83.01 0.5 L 83.02 0.5 C 84.817 0.5 86.543 1.215 87.814 2.486 C 89.085 3.757 89.8 5.483 89.8 7.28 L 89.8 26.6 C 89.8 28.397 89.085 30.123 87.814 31.394 C 86.543 32.665 84.817 33.38 83.02 33.38 L 83.01 33.38 C 81.213 33.38 79.487 32.665 78.216 31.394 C 76.945 30.123 76.23 28.397 76.23 26.6 L 76.23 7.28 C 76.23 5.483 76.945 3.757 78.216 2.486 C 79.487 1.215 81.213 0.5 83.01 0.5\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 83.01 0.5 L 83.02 0.5 C 84.817 0.5 86.543 1.215 87.814 2.486 C 89.085 3.757 89.8 5.483 89.8 7.28 L 89.8 26.6 C 89.8 28.397 89.085 30.123 87.814 31.394 C 86.543 32.665 84.817 33.38 83.02 33.38 L 83.01 33.38 C 81.213 33.38 79.487 32.665 78.216 31.394 C 76.945 30.123 76.23 28.397 76.23 26.6 L 76.23 7.28 C 76.23 5.483 76.945 3.757 78.216 2.486 C 79.487 1.215 81.213 0.5 83.01 0.5\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_3\"\n        android:pathData=\"M 83.01 132.65 L 83.02 132.65 C 84.817 132.65 86.543 133.365 87.814 134.636 C 89.085 135.907 89.8 137.633 89.8 139.43 L 89.8 158.75 C 89.8 160.547 89.085 162.273 87.814 163.544 C 86.543 164.815 84.817 165.53 83.02 165.53 L 83.01 165.53 C 81.213 165.53 79.487 164.815 78.216 163.544 C 76.945 162.273 76.23 160.547 76.23 158.75 L 76.23 139.43 C 76.23 137.633 76.945 135.907 78.216 134.636 C 79.487 133.365 81.213 132.65 83.01 132.65\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_4\"\n        android:pathData=\"M 83.01 132.65 L 83.02 132.65 C 84.817 132.65 86.543 133.365 87.814 134.636 C 89.085 135.907 89.8 137.633 89.8 139.43 L 89.8 158.75 C 89.8 160.547 89.085 162.273 87.814 163.544 C 86.543 164.815 84.817 165.53 83.02 165.53 L 83.01 165.53 C 81.213 165.53 79.487 164.815 78.216 163.544 C 76.945 162.273 76.23 160.547 76.23 158.75 L 76.23 139.43 C 76.23 137.633 76.945 135.907 78.216 134.636 C 79.487 133.365 81.213 132.65 83.01 132.65\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_5\"\n        android:pathData=\"M 118.112 38.334 L 131.773 24.673 C 132.614 23.832 133.663 23.226 134.812 22.918 C 135.962 22.61 137.172 22.61 138.322 22.918 C 139.471 23.226 140.52 23.832 141.361 24.673 L 141.368 24.68 C 142.21 25.522 142.815 26.57 143.123 27.72 C 143.431 28.869 143.431 30.08 143.123 31.229 C 142.815 32.379 142.21 33.427 141.368 34.269 L 127.707 47.93 C 126.866 48.771 125.817 49.377 124.668 49.685 C 123.518 49.993 122.308 49.993 121.158 49.685 C 120.009 49.377 118.96 48.771 118.119 47.93 L 118.112 47.923 C 117.27 47.081 116.665 46.033 116.357 44.883 C 116.049 43.734 116.049 42.523 116.357 41.374 C 116.665 40.224 117.27 39.176 118.112 38.334\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_6\"\n        android:pathData=\"M 118.112 38.334 L 131.773 24.673 C 132.614 23.832 133.663 23.226 134.812 22.918 C 135.962 22.61 137.172 22.61 138.322 22.918 C 139.471 23.226 140.52 23.832 141.361 24.673 L 141.368 24.68 C 142.21 25.522 142.815 26.57 143.123 27.72 C 143.431 28.869 143.431 30.08 143.123 31.229 C 142.815 32.379 142.21 33.427 141.368 34.269 L 127.707 47.93 C 126.866 48.771 125.817 49.377 124.668 49.685 C 123.518 49.993 122.308 49.993 121.158 49.685 C 120.009 49.377 118.96 48.771 118.119 47.93 L 118.112 47.923 C 117.27 47.081 116.665 46.033 116.357 44.883 C 116.049 43.734 116.049 42.523 116.357 41.374 C 116.665 40.224 117.27 39.176 118.112 38.334\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_7\"\n        android:pathData=\"M 24.662 131.769 L 38.323 118.107 C 39.164 117.266 40.213 116.66 41.362 116.352 C 42.512 116.044 43.722 116.044 44.872 116.352 C 46.021 116.66 47.07 117.266 47.911 118.107 L 47.918 118.114 C 48.76 118.956 49.365 120.004 49.673 121.154 C 49.981 122.303 49.981 123.514 49.673 124.663 C 49.365 125.813 48.76 126.861 47.918 127.703 L 34.257 141.364 C 33.416 142.205 32.367 142.811 31.218 143.119 C 30.068 143.427 28.858 143.427 27.708 143.119 C 26.559 142.811 25.51 142.205 24.669 141.364 L 24.662 141.357 C 23.82 140.515 23.215 139.467 22.907 138.318 C 22.599 137.168 22.599 135.957 22.907 134.808 C 23.215 133.658 23.82 132.61 24.662 131.769\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_8\"\n        android:pathData=\"M 24.662 131.769 L 38.323 118.107 C 39.164 117.266 40.213 116.66 41.362 116.352 C 42.512 116.044 43.722 116.044 44.872 116.352 C 46.021 116.66 47.07 117.266 47.911 118.107 L 47.918 118.114 C 48.76 118.956 49.365 120.004 49.673 121.154 C 49.981 122.303 49.981 123.514 49.673 124.663 C 49.365 125.813 48.76 126.861 47.918 127.703 L 34.257 141.364 C 33.416 142.205 32.367 142.811 31.218 143.119 C 30.068 143.427 28.858 143.427 27.708 143.119 C 26.559 142.811 25.51 142.205 24.669 141.364 L 24.662 141.357 C 23.82 140.515 23.215 139.467 22.907 138.318 C 22.599 137.168 22.599 135.957 22.907 134.808 C 23.215 133.658 23.82 132.61 24.662 131.769\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <group android:name=\"group\">\n        <path\n            android:name=\"path_9\"\n            android:pathData=\"M 139.43 76.23 L 158.75 76.23 C 160.547 76.23 162.273 76.945 163.544 78.216 C 164.815 79.487 165.53 81.213 165.53 83.01 L 165.53 83.02 C 165.53 84.817 164.815 86.543 163.544 87.814 C 162.273 89.085 160.547 89.8 158.75 89.8 L 139.43 89.8 C 137.633 89.8 135.907 89.085 134.636 87.814 C 133.365 86.543 132.65 84.817 132.65 83.02 L 132.65 83.01 C 132.65 81.213 133.365 79.487 134.636 78.216 C 135.907 76.945 137.633 76.23 139.43 76.23\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_10\"\n            android:pathData=\"M 139.43 76.23 L 158.75 76.23 C 160.547 76.23 162.273 76.945 163.544 78.216 C 164.815 79.487 165.53 81.213 165.53 83.01 L 165.53 83.02 C 165.53 84.817 164.815 86.543 163.544 87.814 C 162.273 89.085 160.547 89.8 158.75 89.8 L 139.43 89.8 C 137.633 89.8 135.907 89.085 134.636 87.814 C 133.365 86.543 132.65 84.817 132.65 83.02 L 132.65 83.01 C 132.65 81.213 133.365 79.487 134.636 78.216 C 135.907 76.945 137.633 76.23 139.43 76.23\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_1\">\n        <path\n            android:name=\"path_11\"\n            android:pathData=\"M 7.28 76.23 L 26.6 76.23 C 28.397 76.23 30.123 76.945 31.394 78.216 C 32.665 79.487 33.38 81.213 33.38 83.01 L 33.38 83.02 C 33.38 84.817 32.665 86.543 31.394 87.814 C 30.123 89.085 28.397 89.8 26.6 89.8 L 7.28 89.8 C 6.09 89.8 4.921 89.487 3.89 88.892 C 2.859 88.297 2.003 87.441 1.408 86.41 C 0.813 85.379 0.5 84.21 0.5 83.02 L 0.5 83.01 C 0.5 81.213 1.215 79.487 2.486 78.216 C 3.757 76.945 5.483 76.23 7.28 76.23\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_12\"\n            android:pathData=\"M 7.28 76.23 L 26.6 76.23 C 28.397 76.23 30.123 76.945 31.394 78.216 C 32.665 79.487 33.38 81.213 33.38 83.01 L 33.38 83.02 C 33.38 84.817 32.665 86.543 31.394 87.814 C 30.123 89.085 28.397 89.8 26.6 89.8 L 7.28 89.8 C 6.09 89.8 4.921 89.487 3.89 88.892 C 2.859 88.297 2.003 87.441 1.408 86.41 C 0.813 85.379 0.5 84.21 0.5 83.02 L 0.5 83.01 C 0.5 81.213 1.215 79.487 2.486 78.216 C 3.757 76.945 5.483 76.23 7.28 76.23\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_2\">\n        <path\n            android:name=\"path_13\"\n            android:pathData=\"M 118.104 118.115 L 118.111 118.108 C 118.952 117.267 120.001 116.661 121.15 116.353 C 122.3 116.045 123.51 116.045 124.66 116.353 C 125.809 116.661 126.858 117.267 127.699 118.108 L 141.36 131.769 C 142.202 132.611 142.807 133.659 143.115 134.809 C 143.423 135.958 143.423 137.169 143.115 138.318 C 142.807 139.468 142.202 140.516 141.36 141.358 L 141.353 141.365 C 140.512 142.206 139.463 142.812 138.314 143.12 C 137.164 143.428 135.954 143.428 134.804 143.12 C 133.655 142.812 132.607 142.206 131.765 141.365 L 118.104 127.704 C 116.833 126.433 116.118 124.707 116.118 122.909 C 116.118 121.112 116.833 119.386 118.104 118.115\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_14\"\n            android:pathData=\"M 118.104 118.115 L 118.111 118.108 C 118.952 117.267 120.001 116.661 121.15 116.353 C 122.3 116.045 123.51 116.045 124.66 116.353 C 125.809 116.661 126.858 117.267 127.699 118.108 L 141.36 131.769 C 142.202 132.611 142.807 133.659 143.115 134.809 C 143.423 135.958 143.423 137.169 143.115 138.318 C 142.807 139.468 142.202 140.516 141.36 141.358 L 141.353 141.365 C 140.512 142.206 139.463 142.812 138.314 143.12 C 137.164 143.428 135.954 143.428 134.804 143.12 C 133.655 142.812 132.607 142.206 131.765 141.365 L 118.104 127.704 C 116.833 126.433 116.118 124.707 116.118 122.909 C 116.118 121.112 116.833 119.386 118.104 118.115\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_3\">\n        <path\n            android:name=\"path_15\"\n            android:pathData=\"M 24.67 24.665 L 24.677 24.658 C 25.518 23.817 26.567 23.211 27.716 22.903 C 28.866 22.595 30.076 22.595 31.226 22.903 C 32.375 23.211 33.424 23.817 34.265 24.658 L 47.926 38.319 C 48.768 39.161 49.373 40.209 49.681 41.359 C 49.989 42.508 49.989 43.719 49.681 44.868 C 49.373 46.018 48.768 47.066 47.926 47.908 L 47.919 47.915 C 47.078 48.756 46.029 49.362 44.88 49.67 C 43.73 49.978 42.52 49.978 41.37 49.67 C 40.221 49.362 39.172 48.756 38.331 47.915 L 24.67 34.254 C 23.399 32.983 22.684 31.257 22.684 29.459 C 22.684 27.662 23.399 25.936 24.67 24.665\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_16\"\n            android:pathData=\"M 24.67 24.665 L 24.677 24.658 C 25.518 23.817 26.567 23.211 27.716 22.903 C 28.866 22.595 30.076 22.595 31.226 22.903 C 32.375 23.211 33.424 23.817 34.265 24.658 L 47.926 38.319 C 48.768 39.161 49.373 40.209 49.681 41.359 C 49.989 42.508 49.989 43.719 49.681 44.868 C 49.373 46.018 48.768 47.066 47.926 47.908 L 47.919 47.915 C 47.078 48.756 46.029 49.362 44.88 49.67 C 43.73 49.978 42.52 49.978 41.37 49.67 C 40.221 49.362 39.172 48.756 38.331 47.915 L 24.67 34.254 C 23.399 32.983 22.684 31.257 22.684 29.459 C 22.684 27.662 23.399 25.936 24.67 24.665\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/sun_5.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"31.0dp\"\n    android:height=\"31.0dp\"\n    android:viewportWidth=\"177\"\n    android:viewportHeight=\"177\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 89.21 55.88 C 80.461 55.88 72.062 59.359 65.875 65.545 C 59.689 71.732 56.21 80.131 56.21 88.88 C 56.21 97.629 59.689 106.028 65.875 112.215 C 72.062 118.401 80.461 121.88 89.21 121.88 C 97.959 121.88 106.358 118.401 112.545 112.215 C 118.731 106.028 122.21 97.629 122.21 88.88 C 122.21 80.131 118.731 71.732 112.545 65.545 C 106.358 59.359 97.959 55.88 89.21 55.88 Z\"\n        android:fillColor=\"#ffffff\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 88.88 0.5 L 88.89 0.5 C 90.687 0.5 92.413 1.215 93.684 2.486 C 94.955 3.757 95.67 5.483 95.67 7.28 L 95.67 32.47 C 95.67 34.267 94.955 35.993 93.684 37.264 C 92.413 38.535 90.687 39.25 88.89 39.25 L 88.88 39.25 C 87.083 39.25 85.357 38.535 84.086 37.264 C 82.815 35.993 82.1 34.267 82.1 32.47 L 82.1 7.28 C 82.1 5.483 82.815 3.757 84.086 2.486 C 85.357 1.215 87.083 0.5 88.88 0.5\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 88.88 0.5 L 88.89 0.5 C 90.687 0.5 92.413 1.215 93.684 2.486 C 94.955 3.757 95.67 5.483 95.67 7.28 L 95.67 32.47 C 95.67 34.267 94.955 35.993 93.684 37.264 C 92.413 38.535 90.687 39.25 88.89 39.25 L 88.88 39.25 C 87.083 39.25 85.357 38.535 84.086 37.264 C 82.815 35.993 82.1 34.267 82.1 32.47 L 82.1 7.28 C 82.1 5.483 82.815 3.757 84.086 2.486 C 85.357 1.215 87.083 0.5 88.88 0.5\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_3\"\n        android:pathData=\"M 88.88 138.51 L 88.89 138.51 C 90.687 138.51 92.413 139.225 93.684 140.496 C 94.955 141.767 95.67 143.493 95.67 145.29 L 95.67 170.48 C 95.67 172.277 94.955 174.003 93.684 175.274 C 92.413 176.545 90.687 177.26 88.89 177.26 L 88.88 177.26 C 87.083 177.26 85.357 176.545 84.086 175.274 C 82.815 174.003 82.1 172.277 82.1 170.48 L 82.1 145.29 C 82.1 143.493 82.815 141.767 84.086 140.496 C 85.357 139.225 87.083 138.51 88.88 138.51\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_4\"\n        android:pathData=\"M 88.88 138.51 L 88.89 138.51 C 90.687 138.51 92.413 139.225 93.684 140.496 C 94.955 141.767 95.67 143.493 95.67 145.29 L 95.67 170.48 C 95.67 172.277 94.955 174.003 93.684 175.274 C 92.413 176.545 90.687 177.26 88.89 177.26 L 88.88 177.26 C 87.083 177.26 85.357 176.545 84.086 175.274 C 82.815 174.003 82.1 172.277 82.1 170.48 L 82.1 145.29 C 82.1 143.493 82.815 141.767 84.086 140.496 C 85.357 139.225 87.083 138.51 88.88 138.51\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_5\"\n        android:pathData=\"M 123.973 44.202 L 141.785 26.39 C 142.626 25.548 143.675 24.943 144.824 24.635 C 145.974 24.327 147.184 24.327 148.334 24.635 C 149.483 24.943 150.532 25.548 151.373 26.39 L 151.38 26.397 C 152.222 27.238 152.827 28.287 153.135 29.436 C 153.443 30.586 153.443 31.796 153.135 32.946 C 152.827 34.095 152.222 35.144 151.38 35.985 L 133.568 53.797 C 132.297 55.068 130.571 55.783 128.774 55.783 C 126.977 55.783 125.251 55.068 123.98 53.797 L 123.973 53.79 C 123.131 52.949 122.526 51.9 122.218 50.751 C 121.91 49.601 121.91 48.391 122.218 47.241 C 122.526 46.092 123.131 45.043 123.973 44.202\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_6\"\n        android:pathData=\"M 123.973 44.202 L 141.785 26.39 C 142.626 25.548 143.675 24.943 144.824 24.635 C 145.974 24.327 147.184 24.327 148.334 24.635 C 149.483 24.943 150.532 25.548 151.373 26.39 L 151.38 26.397 C 152.222 27.238 152.827 28.287 153.135 29.436 C 153.443 30.586 153.443 31.796 153.135 32.946 C 152.827 34.095 152.222 35.144 151.38 35.985 L 133.568 53.797 C 132.297 55.068 130.571 55.783 128.774 55.783 C 126.977 55.783 125.251 55.068 123.98 53.797 L 123.973 53.79 C 123.131 52.949 122.526 51.9 122.218 50.751 C 121.91 49.601 121.91 48.391 122.218 47.241 C 122.526 46.092 123.131 45.043 123.973 44.202\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_7\"\n        android:pathData=\"M 26.39 141.792 L 44.202 123.98 C 45.043 123.138 46.092 122.533 47.241 122.225 C 48.391 121.917 49.601 121.917 50.751 122.225 C 51.9 122.533 52.949 123.138 53.79 123.98 L 53.797 123.987 C 54.639 124.828 55.244 125.877 55.552 127.026 C 55.86 128.176 55.86 129.386 55.552 130.536 C 55.244 131.685 54.639 132.734 53.797 133.575 L 35.985 151.387 C 34.714 152.658 32.989 153.373 31.191 153.373 C 29.394 153.373 27.668 152.658 26.397 151.387 L 26.39 151.38 C 25.548 150.539 24.943 149.49 24.635 148.341 C 24.327 147.191 24.327 145.981 24.635 144.831 C 24.943 143.682 25.548 142.633 26.39 141.792\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_8\"\n        android:pathData=\"M 26.39 141.792 L 44.202 123.98 C 45.043 123.138 46.092 122.533 47.241 122.225 C 48.391 121.917 49.601 121.917 50.751 122.225 C 51.9 122.533 52.949 123.138 53.79 123.98 L 53.797 123.987 C 54.639 124.828 55.244 125.877 55.552 127.026 C 55.86 128.176 55.86 129.386 55.552 130.536 C 55.244 131.685 54.639 132.734 53.797 133.575 L 35.985 151.387 C 34.714 152.658 32.989 153.373 31.191 153.373 C 29.394 153.373 27.668 152.658 26.397 151.387 L 26.39 151.38 C 25.548 150.539 24.943 149.49 24.635 148.341 C 24.327 147.191 24.327 145.981 24.635 144.831 C 24.943 143.682 25.548 142.633 26.39 141.792\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <group android:name=\"group\">\n        <path\n            android:name=\"path_9\"\n            android:pathData=\"M 145.29 82.1 L 170.48 82.1 C 172.277 82.1 174.003 82.815 175.274 84.086 C 176.545 85.357 177.26 87.083 177.26 88.88 L 177.26 88.89 C 177.26 90.687 176.545 92.413 175.274 93.684 C 174.003 94.955 172.277 95.67 170.48 95.67 L 145.29 95.67 C 143.493 95.67 141.767 94.955 140.496 93.684 C 139.225 92.413 138.51 90.687 138.51 88.89 L 138.51 88.88 C 138.51 87.083 139.225 85.357 140.496 84.086 C 141.767 82.815 143.493 82.1 145.29 82.1\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_10\"\n            android:pathData=\"M 145.29 82.1 L 170.48 82.1 C 172.277 82.1 174.003 82.815 175.274 84.086 C 176.545 85.357 177.26 87.083 177.26 88.88 L 177.26 88.89 C 177.26 90.687 176.545 92.413 175.274 93.684 C 174.003 94.955 172.277 95.67 170.48 95.67 L 145.29 95.67 C 143.493 95.67 141.767 94.955 140.496 93.684 C 139.225 92.413 138.51 90.687 138.51 88.89 L 138.51 88.88 C 138.51 87.083 139.225 85.357 140.496 84.086 C 141.767 82.815 143.493 82.1 145.29 82.1\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_1\">\n        <path\n            android:name=\"path_11\"\n            android:pathData=\"M 7.28 82.1 L 32.47 82.1 C 34.267 82.1 35.993 82.815 37.264 84.086 C 38.535 85.357 39.25 87.083 39.25 88.88 L 39.25 88.89 C 39.25 90.687 38.535 92.413 37.264 93.684 C 35.993 94.955 34.267 95.67 32.47 95.67 L 7.28 95.67 C 5.483 95.67 3.757 94.955 2.486 93.684 C 1.215 92.413 0.5 90.687 0.5 88.89 L 0.5 88.88 C 0.5 87.083 1.215 85.357 2.486 84.086 C 3.757 82.815 5.483 82.1 7.28 82.1\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_12\"\n            android:pathData=\"M 7.28 82.1 L 32.47 82.1 C 34.267 82.1 35.993 82.815 37.264 84.086 C 38.535 85.357 39.25 87.083 39.25 88.88 L 39.25 88.89 C 39.25 90.687 38.535 92.413 37.264 93.684 C 35.993 94.955 34.267 95.67 32.47 95.67 L 7.28 95.67 C 5.483 95.67 3.757 94.955 2.486 93.684 C 1.215 92.413 0.5 90.687 0.5 88.89 L 0.5 88.88 C 0.5 87.083 1.215 85.357 2.486 84.086 C 3.757 82.815 5.483 82.1 7.28 82.1\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_2\">\n        <path\n            android:name=\"path_13\"\n            android:pathData=\"M 123.976 123.976 L 123.983 123.969 C 124.825 123.128 125.873 122.522 127.023 122.214 C 128.172 121.906 129.383 121.906 130.532 122.214 C 131.682 122.522 132.73 123.128 133.572 123.969 L 151.384 141.781 C 152.655 143.052 153.37 144.778 153.37 146.575 C 153.37 148.373 152.655 150.099 151.384 151.37 L 151.377 151.377 C 150.535 152.218 149.487 152.823 148.337 153.131 C 147.188 153.439 145.977 153.439 144.828 153.131 C 143.678 152.823 142.63 152.218 141.788 151.377 L 123.976 133.565 C 122.705 132.294 121.991 130.568 121.991 128.77 C 121.991 126.973 122.705 125.247 123.976 123.976\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_14\"\n            android:pathData=\"M 123.976 123.976 L 123.983 123.969 C 124.825 123.128 125.873 122.522 127.023 122.214 C 128.172 121.906 129.383 121.906 130.532 122.214 C 131.682 122.522 132.73 123.128 133.572 123.969 L 151.384 141.781 C 152.655 143.052 153.37 144.778 153.37 146.575 C 153.37 148.373 152.655 150.099 151.384 151.37 L 151.377 151.377 C 150.535 152.218 149.487 152.823 148.337 153.131 C 147.188 153.439 145.977 153.439 144.828 153.131 C 143.678 152.823 142.63 152.218 141.788 151.377 L 123.976 133.565 C 122.705 132.294 121.991 130.568 121.991 128.77 C 121.991 126.973 122.705 125.247 123.976 123.976\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_3\">\n        <path\n            android:name=\"path_15\"\n            android:pathData=\"M 26.386 26.393 L 26.393 26.386 C 27.235 25.545 28.283 24.939 29.433 24.631 C 30.582 24.323 31.793 24.323 32.942 24.631 C 34.092 24.939 35.14 25.545 35.982 26.386 L 53.794 44.198 C 55.065 45.469 55.779 47.195 55.779 48.992 C 55.779 50.79 55.065 52.516 53.794 53.787 L 53.787 53.794 C 52.945 54.635 51.897 55.241 50.747 55.549 C 49.598 55.857 48.387 55.857 47.238 55.549 C 46.088 55.241 45.04 54.635 44.198 53.794 L 26.386 35.982 C 25.115 34.711 24.4 32.985 24.4 31.188 C 24.4 29.39 25.115 27.664 26.386 26.393\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_16\"\n            android:pathData=\"M 26.386 26.393 L 26.393 26.386 C 27.235 25.545 28.283 24.939 29.433 24.631 C 30.582 24.323 31.793 24.323 32.942 24.631 C 34.092 24.939 35.14 25.545 35.982 26.386 L 53.794 44.198 C 55.065 45.469 55.779 47.195 55.779 48.992 C 55.779 50.79 55.065 52.516 53.794 53.787 L 53.787 53.794 C 52.945 54.635 51.897 55.241 50.747 55.549 C 49.598 55.857 48.387 55.857 47.238 55.549 C 46.088 55.241 45.04 54.635 44.198 53.794 L 26.386 35.982 C 25.115 34.711 24.4 32.985 24.4 31.188 C 24.4 29.39 25.115 27.664 26.386 26.393\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/sun_6.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"33.15dp\"\n    android:height=\"33.15dp\"\n    android:viewportWidth=\"189\"\n    android:viewportHeight=\"189\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 94.88 61.56 C 86.131 61.56 77.732 65.039 71.545 71.225 C 65.359 77.412 61.88 85.811 61.88 94.56 C 61.88 103.309 65.359 111.708 71.545 117.895 C 77.732 124.081 86.131 127.56 94.88 127.56 C 103.629 127.56 112.028 124.081 118.215 117.895 C 124.401 111.708 127.88 103.309 127.88 94.56 C 127.88 85.811 124.401 77.412 118.215 71.225 C 112.028 65.039 103.629 61.56 94.88 61.56 Z\"\n        android:fillColor=\"#ffffff\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 94.56 0.5 L 94.57 0.5 C 96.367 0.5 98.093 1.215 99.364 2.486 C 100.635 3.757 101.35 5.483 101.35 7.28 L 101.35 38.15 C 101.35 39.947 100.635 41.673 99.364 42.944 C 98.093 44.215 96.367 44.93 94.57 44.93 L 94.56 44.93 C 92.763 44.93 91.037 44.215 89.766 42.944 C 88.495 41.673 87.78 39.947 87.78 38.15 L 87.78 7.28 C 87.78 5.483 88.495 3.757 89.766 2.486 C 91.037 1.215 92.763 0.5 94.56 0.5\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 94.56 0.5 L 94.57 0.5 C 96.367 0.5 98.093 1.215 99.364 2.486 C 100.635 3.757 101.35 5.483 101.35 7.28 L 101.35 38.15 C 101.35 39.947 100.635 41.673 99.364 42.944 C 98.093 44.215 96.367 44.93 94.57 44.93 L 94.56 44.93 C 92.763 44.93 91.037 44.215 89.766 42.944 C 88.495 41.673 87.78 39.947 87.78 38.15 L 87.78 7.28 C 87.78 5.483 88.495 3.757 89.766 2.486 C 91.037 1.215 92.763 0.5 94.56 0.5\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_3\"\n        android:pathData=\"M 94.56 144.19 L 94.57 144.19 C 96.367 144.19 98.093 144.905 99.364 146.176 C 100.635 147.447 101.35 149.173 101.35 150.97 L 101.35 181.84 C 101.35 183.637 100.635 185.363 99.364 186.634 C 98.093 187.905 96.367 188.62 94.57 188.62 L 94.56 188.62 C 92.763 188.62 91.037 187.905 89.766 186.634 C 88.495 185.363 87.78 183.637 87.78 181.84 L 87.78 150.97 C 87.78 149.173 88.495 147.447 89.766 146.176 C 91.037 144.905 92.763 144.19 94.56 144.19\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_4\"\n        android:pathData=\"M 94.56 144.19 L 94.57 144.19 C 96.367 144.19 98.093 144.905 99.364 146.176 C 100.635 147.447 101.35 149.173 101.35 150.97 L 101.35 181.84 C 101.35 183.637 100.635 185.363 99.364 186.634 C 98.093 187.905 96.367 188.62 94.57 188.62 L 94.56 188.62 C 92.763 188.62 91.037 187.905 89.766 186.634 C 88.495 185.363 87.78 183.637 87.78 181.84 L 87.78 150.97 C 87.78 149.173 88.495 147.447 89.766 146.176 C 91.037 144.905 92.763 144.19 94.56 144.19\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_5\"\n        android:pathData=\"M 129.652 49.874 L 151.48 28.046 C 152.322 27.205 153.37 26.599 154.519 26.291 C 155.669 25.983 156.88 25.983 158.029 26.291 C 159.179 26.599 160.227 27.205 161.068 28.046 L 161.075 28.053 C 161.917 28.895 162.522 29.943 162.83 31.092 C 163.138 32.242 163.138 33.453 162.83 34.602 C 162.522 35.752 161.917 36.8 161.075 37.641 L 139.247 59.47 C 138.406 60.311 137.357 60.917 136.208 61.225 C 135.058 61.533 133.848 61.533 132.698 61.225 C 131.549 60.917 130.5 60.311 129.659 59.47 L 129.652 59.463 C 128.81 58.621 128.205 57.573 127.897 56.423 C 127.589 55.274 127.589 54.063 127.897 52.914 C 128.205 51.764 128.81 50.716 129.652 49.874\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_6\"\n        android:pathData=\"M 129.652 49.874 L 151.48 28.046 C 152.322 27.205 153.37 26.599 154.519 26.291 C 155.669 25.983 156.88 25.983 158.029 26.291 C 159.179 26.599 160.227 27.205 161.068 28.046 L 161.075 28.053 C 161.917 28.895 162.522 29.943 162.83 31.092 C 163.138 32.242 163.138 33.453 162.83 34.602 C 162.522 35.752 161.917 36.8 161.075 37.641 L 139.247 59.47 C 138.406 60.311 137.357 60.917 136.208 61.225 C 135.058 61.533 133.848 61.533 132.698 61.225 C 131.549 60.917 130.5 60.311 129.659 59.47 L 129.652 59.463 C 128.81 58.621 128.205 57.573 127.897 56.423 C 127.589 55.274 127.589 54.063 127.897 52.914 C 128.205 51.764 128.81 50.716 129.652 49.874\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_7\"\n        android:pathData=\"M 28.052 151.479 L 49.88 129.65 C 50.722 128.809 51.77 128.203 52.919 127.895 C 54.069 127.587 55.28 127.587 56.429 127.895 C 57.579 128.203 58.627 128.809 59.468 129.65 L 59.475 129.657 C 60.317 130.499 60.922 131.547 61.23 132.697 C 61.538 133.846 61.538 135.057 61.23 136.206 C 60.922 137.356 60.317 138.404 59.475 139.246 L 37.647 161.074 C 36.806 161.915 35.757 162.521 34.608 162.829 C 33.458 163.137 32.248 163.137 31.098 162.829 C 29.949 162.521 28.9 161.915 28.059 161.074 L 28.052 161.067 C 27.21 160.225 26.605 159.177 26.297 158.028 C 25.989 156.878 25.989 155.667 26.297 154.518 C 26.605 153.368 27.21 152.32 28.052 151.479\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_8\"\n        android:pathData=\"M 28.052 151.479 L 49.88 129.65 C 50.722 128.809 51.77 128.203 52.919 127.895 C 54.069 127.587 55.28 127.587 56.429 127.895 C 57.579 128.203 58.627 128.809 59.468 129.65 L 59.475 129.657 C 60.317 130.499 60.922 131.547 61.23 132.697 C 61.538 133.846 61.538 135.057 61.23 136.206 C 60.922 137.356 60.317 138.404 59.475 139.246 L 37.647 161.074 C 36.806 161.915 35.757 162.521 34.608 162.829 C 33.458 163.137 32.248 163.137 31.098 162.829 C 29.949 162.521 28.9 161.915 28.059 161.074 L 28.052 161.067 C 27.21 160.225 26.605 159.177 26.297 158.028 C 25.989 156.878 25.989 155.667 26.297 154.518 C 26.605 153.368 27.21 152.32 28.052 151.479\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <group android:name=\"group\">\n        <path\n            android:name=\"path_9\"\n            android:pathData=\"M 150.97 87.78 L 181.84 87.78 C 183.637 87.78 185.363 88.495 186.634 89.766 C 187.905 91.037 188.62 92.763 188.62 94.56 L 188.62 94.57 C 188.62 96.367 187.905 98.093 186.634 99.364 C 185.363 100.635 183.637 101.35 181.84 101.35 L 150.97 101.35 C 149.173 101.35 147.447 100.635 146.176 99.364 C 144.905 98.093 144.19 96.367 144.19 94.57 L 144.19 94.56 C 144.19 92.763 144.905 91.037 146.176 89.766 C 147.447 88.495 149.173 87.78 150.97 87.78\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_10\"\n            android:pathData=\"M 150.97 87.78 L 181.84 87.78 C 183.637 87.78 185.363 88.495 186.634 89.766 C 187.905 91.037 188.62 92.763 188.62 94.56 L 188.62 94.57 C 188.62 96.367 187.905 98.093 186.634 99.364 C 185.363 100.635 183.637 101.35 181.84 101.35 L 150.97 101.35 C 149.173 101.35 147.447 100.635 146.176 99.364 C 144.905 98.093 144.19 96.367 144.19 94.57 L 144.19 94.56 C 144.19 92.763 144.905 91.037 146.176 89.766 C 147.447 88.495 149.173 87.78 150.97 87.78\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_1\">\n        <path\n            android:name=\"path_11\"\n            android:pathData=\"M 7.28 87.78 L 38.15 87.78 C 39.947 87.78 41.673 88.495 42.944 89.766 C 44.215 91.037 44.93 92.763 44.93 94.56 L 44.93 94.57 C 44.93 96.367 44.215 98.093 42.944 99.364 C 41.673 100.635 39.947 101.35 38.15 101.35 L 7.28 101.35 C 6.09 101.35 4.921 101.037 3.89 100.442 C 2.859 99.847 2.003 98.991 1.408 97.96 C 0.813 96.929 0.5 95.76 0.5 94.57 L 0.5 94.56 C 0.5 92.763 1.215 91.037 2.486 89.766 C 3.757 88.495 5.483 87.78 7.28 87.78\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_12\"\n            android:pathData=\"M 7.28 87.78 L 38.15 87.78 C 39.947 87.78 41.673 88.495 42.944 89.766 C 44.215 91.037 44.93 92.763 44.93 94.56 L 44.93 94.57 C 44.93 96.367 44.215 98.093 42.944 99.364 C 41.673 100.635 39.947 101.35 38.15 101.35 L 7.28 101.35 C 6.09 101.35 4.921 101.037 3.89 100.442 C 2.859 99.847 2.003 98.991 1.408 97.96 C 0.813 96.929 0.5 95.76 0.5 94.57 L 0.5 94.56 C 0.5 92.763 1.215 91.037 2.486 89.766 C 3.757 88.495 5.483 87.78 7.28 87.78\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_2\">\n        <path\n            android:name=\"path_13\"\n            android:pathData=\"M 129.654 129.655 L 129.661 129.648 C 130.502 128.807 131.551 128.201 132.7 127.893 C 133.85 127.585 135.06 127.585 136.21 127.893 C 137.359 128.201 138.408 128.807 139.249 129.648 L 161.078 151.476 C 161.919 152.318 162.524 153.366 162.832 154.516 C 163.14 155.665 163.14 156.876 162.832 158.025 C 162.524 159.175 161.919 160.223 161.078 161.065 L 161.07 161.072 C 160.229 161.913 159.181 162.519 158.031 162.827 C 156.882 163.135 155.671 163.135 154.521 162.827 C 153.372 162.519 152.324 161.913 151.482 161.072 L 129.654 139.244 C 128.812 138.402 128.207 137.354 127.899 136.204 C 127.591 135.055 127.591 133.844 127.899 132.695 C 128.207 131.545 128.812 130.497 129.654 129.655\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_14\"\n            android:pathData=\"M 129.654 129.655 L 129.661 129.648 C 130.502 128.807 131.551 128.201 132.7 127.893 C 133.85 127.585 135.06 127.585 136.21 127.893 C 137.359 128.201 138.408 128.807 139.249 129.648 L 161.078 151.476 C 161.919 152.318 162.524 153.366 162.832 154.516 C 163.14 155.665 163.14 156.876 162.832 158.025 C 162.524 159.175 161.919 160.223 161.078 161.065 L 161.07 161.072 C 160.229 161.913 159.181 162.519 158.031 162.827 C 156.882 163.135 155.671 163.135 154.521 162.827 C 153.372 162.519 152.324 161.913 151.482 161.072 L 129.654 139.244 C 128.812 138.402 128.207 137.354 127.899 136.204 C 127.591 135.055 127.591 133.844 127.899 132.695 C 128.207 131.545 128.812 130.497 129.654 129.655\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_3\">\n        <path\n            android:name=\"path_15\"\n            android:pathData=\"M 28.05 28.055 L 28.057 28.048 C 28.898 27.207 29.947 26.601 31.096 26.293 C 32.246 25.985 33.456 25.985 34.606 26.293 C 35.755 26.601 36.804 27.207 37.645 28.048 L 59.473 49.876 C 60.315 50.718 60.92 51.766 61.228 52.916 C 61.536 54.065 61.536 55.276 61.228 56.425 C 60.92 57.575 60.315 58.623 59.473 59.465 L 59.466 59.472 C 58.625 60.313 57.576 60.919 56.427 61.227 C 55.277 61.535 54.067 61.535 52.917 61.227 C 51.768 60.919 50.719 60.313 49.878 59.472 L 28.05 37.644 C 27.208 36.802 26.603 35.754 26.295 34.604 C 25.987 33.455 25.987 32.244 26.295 31.095 C 26.603 29.945 27.208 28.897 28.05 28.055\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_16\"\n            android:pathData=\"M 28.05 28.055 L 28.057 28.048 C 28.898 27.207 29.947 26.601 31.096 26.293 C 32.246 25.985 33.456 25.985 34.606 26.293 C 35.755 26.601 36.804 27.207 37.645 28.048 L 59.473 49.876 C 60.315 50.718 60.92 51.766 61.228 52.916 C 61.536 54.065 61.536 55.276 61.228 56.425 C 60.92 57.575 60.315 58.623 59.473 59.465 L 59.466 59.472 C 58.625 60.313 57.576 60.919 56.427 61.227 C 55.277 61.535 54.067 61.535 52.917 61.227 C 51.768 60.919 50.719 60.313 49.878 59.472 L 28.05 37.644 C 27.208 36.802 26.603 35.754 26.295 34.604 C 25.987 33.455 25.987 32.244 26.295 31.095 C 26.603 29.945 27.208 28.897 28.05 28.055\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/sun_7.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"35.96dp\"\n    android:height=\"35.96dp\"\n    android:viewportWidth=\"205\"\n    android:viewportHeight=\"205\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 103.3 69.97 C 94.551 69.97 86.152 73.449 79.965 79.635 C 73.779 85.822 70.3 94.221 70.3 102.97 C 70.3 111.719 73.779 120.118 79.965 126.305 C 86.152 132.491 94.551 135.97 103.3 135.97 C 112.049 135.97 120.448 132.491 126.635 126.305 C 132.821 120.118 136.3 111.719 136.3 102.97 C 136.3 94.221 132.821 85.822 126.635 79.635 C 120.448 73.449 112.049 69.97 103.3 69.97 Z\"\n        android:fillColor=\"#ffffff\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 102.97 0.5 L 102.98 0.5 C 104.777 0.5 106.503 1.215 107.774 2.486 C 109.045 3.757 109.76 5.483 109.76 7.28 L 109.76 46.56 C 109.76 48.357 109.045 50.083 107.774 51.354 C 106.503 52.625 104.777 53.34 102.98 53.34 L 102.97 53.34 C 101.173 53.34 99.447 52.625 98.176 51.354 C 96.905 50.083 96.19 48.357 96.19 46.56 L 96.19 7.28 C 96.19 5.483 96.905 3.757 98.176 2.486 C 99.447 1.215 101.173 0.5 102.97 0.5\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 102.97 0.5 L 102.98 0.5 C 104.777 0.5 106.503 1.215 107.774 2.486 C 109.045 3.757 109.76 5.483 109.76 7.28 L 109.76 46.56 C 109.76 48.357 109.045 50.083 107.774 51.354 C 106.503 52.625 104.777 53.34 102.98 53.34 L 102.97 53.34 C 101.173 53.34 99.447 52.625 98.176 51.354 C 96.905 50.083 96.19 48.357 96.19 46.56 L 96.19 7.28 C 96.19 5.483 96.905 3.757 98.176 2.486 C 99.447 1.215 101.173 0.5 102.97 0.5\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_3\"\n        android:pathData=\"M 102.97 152.6 L 102.98 152.6 C 104.777 152.6 106.503 153.315 107.774 154.586 C 109.045 155.857 109.76 157.583 109.76 159.38 L 109.76 198.66 C 109.76 200.457 109.045 202.183 107.774 203.454 C 106.503 204.725 104.777 205.44 102.98 205.44 L 102.97 205.44 C 101.173 205.44 99.447 204.725 98.176 203.454 C 96.905 202.183 96.19 200.457 96.19 198.66 L 96.19 159.38 C 96.19 157.583 96.905 155.857 98.176 154.586 C 99.447 153.315 101.173 152.6 102.97 152.6\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_4\"\n        android:pathData=\"M 102.97 152.6 L 102.98 152.6 C 104.777 152.6 106.503 153.315 107.774 154.586 C 109.045 155.857 109.76 157.583 109.76 159.38 L 109.76 198.66 C 109.76 200.457 109.045 202.183 107.774 203.454 C 106.503 204.725 104.777 205.44 102.98 205.44 L 102.97 205.44 C 101.173 205.44 99.447 204.725 98.176 203.454 C 96.905 202.183 96.19 200.457 96.19 198.66 L 96.19 159.38 C 96.19 157.583 96.905 155.857 98.176 154.586 C 99.447 153.315 101.173 152.6 102.97 152.6\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_5\"\n        android:pathData=\"M 138.065 58.287 L 165.84 30.512 C 166.681 29.67 167.73 29.065 168.879 28.757 C 170.029 28.449 171.239 28.449 172.389 28.757 C 173.538 29.065 174.587 29.67 175.428 30.512 L 175.435 30.519 C 176.706 31.79 177.421 33.516 177.421 35.313 C 177.421 37.111 176.706 38.836 175.435 40.107 L 147.66 67.882 C 146.819 68.724 145.77 69.329 144.621 69.637 C 143.471 69.945 142.261 69.945 141.111 69.637 C 139.962 69.329 138.913 68.724 138.072 67.882 L 138.065 67.875 C 137.223 67.034 136.618 65.985 136.31 64.836 C 136.002 63.686 136.002 62.476 136.31 61.326 C 136.618 60.177 137.223 59.128 138.065 58.287\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_6\"\n        android:pathData=\"M 138.065 58.287 L 165.84 30.512 C 166.681 29.67 167.73 29.065 168.879 28.757 C 170.029 28.449 171.239 28.449 172.389 28.757 C 173.538 29.065 174.587 29.67 175.428 30.512 L 175.435 30.519 C 176.706 31.79 177.421 33.516 177.421 35.313 C 177.421 37.111 176.706 38.836 175.435 40.107 L 147.66 67.882 C 146.819 68.724 145.77 69.329 144.621 69.637 C 143.471 69.945 142.261 69.945 141.111 69.637 C 139.962 69.329 138.913 68.724 138.072 67.882 L 138.065 67.875 C 137.223 67.034 136.618 65.985 136.31 64.836 C 136.002 63.686 136.002 62.476 136.31 61.326 C 136.618 60.177 137.223 59.128 138.065 58.287\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_7\"\n        android:pathData=\"M 30.522 165.843 L 58.297 138.068 C 59.138 137.226 60.187 136.621 61.336 136.313 C 62.486 136.005 63.696 136.005 64.846 136.313 C 65.995 136.621 67.044 137.226 67.885 138.068 L 67.892 138.075 C 68.734 138.916 69.339 139.965 69.647 141.114 C 69.955 142.264 69.955 143.474 69.647 144.624 C 69.339 145.773 68.734 146.822 67.892 147.663 L 40.117 175.438 C 39.276 176.28 38.227 176.885 37.078 177.193 C 35.928 177.501 34.718 177.501 33.568 177.193 C 32.419 176.885 31.37 176.28 30.529 175.438 L 30.522 175.431 C 29.251 174.16 28.536 172.434 28.536 170.637 C 28.536 168.839 29.251 167.114 30.522 165.843\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_8\"\n        android:pathData=\"M 30.522 165.843 L 58.297 138.068 C 59.138 137.226 60.187 136.621 61.336 136.313 C 62.486 136.005 63.696 136.005 64.846 136.313 C 65.995 136.621 67.044 137.226 67.885 138.068 L 67.892 138.075 C 68.734 138.916 69.339 139.965 69.647 141.114 C 69.955 142.264 69.955 143.474 69.647 144.624 C 69.339 145.773 68.734 146.822 67.892 147.663 L 40.117 175.438 C 39.276 176.28 38.227 176.885 37.078 177.193 C 35.928 177.501 34.718 177.501 33.568 177.193 C 32.419 176.885 31.37 176.28 30.529 175.438 L 30.522 175.431 C 29.251 174.16 28.536 172.434 28.536 170.637 C 28.536 168.839 29.251 167.114 30.522 165.843\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <group android:name=\"group\">\n        <path\n            android:name=\"path_9\"\n            android:pathData=\"M 159.38 96.19 L 198.66 96.19 C 200.457 96.19 202.183 96.905 203.454 98.176 C 204.725 99.447 205.44 101.173 205.44 102.97 L 205.44 102.98 C 205.44 104.777 204.725 106.503 203.454 107.774 C 202.183 109.045 200.457 109.76 198.66 109.76 L 159.38 109.76 C 157.583 109.76 155.857 109.045 154.586 107.774 C 153.315 106.503 152.6 104.777 152.6 102.98 L 152.6 102.97 C 152.6 101.173 153.315 99.447 154.586 98.176 C 155.857 96.905 157.583 96.19 159.38 96.19\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_10\"\n            android:pathData=\"M 159.38 96.19 L 198.66 96.19 C 200.457 96.19 202.183 96.905 203.454 98.176 C 204.725 99.447 205.44 101.173 205.44 102.97 L 205.44 102.98 C 205.44 104.777 204.725 106.503 203.454 107.774 C 202.183 109.045 200.457 109.76 198.66 109.76 L 159.38 109.76 C 157.583 109.76 155.857 109.045 154.586 107.774 C 153.315 106.503 152.6 104.777 152.6 102.98 L 152.6 102.97 C 152.6 101.173 153.315 99.447 154.586 98.176 C 155.857 96.905 157.583 96.19 159.38 96.19\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_1\">\n        <path\n            android:name=\"path_11\"\n            android:pathData=\"M 7.28 96.19 L 46.56 96.19 C 48.357 96.19 50.083 96.905 51.354 98.176 C 52.625 99.447 53.34 101.173 53.34 102.97 L 53.34 102.98 C 53.34 104.777 52.625 106.503 51.354 107.774 C 50.083 109.045 48.357 109.76 46.56 109.76 L 7.28 109.76 C 5.483 109.76 3.757 109.045 2.486 107.774 C 1.215 106.503 0.5 104.777 0.5 102.98 L 0.5 102.97 C 0.5 101.173 1.215 99.447 2.486 98.176 C 3.757 96.905 5.483 96.19 7.28 96.19\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_12\"\n            android:pathData=\"M 7.28 96.19 L 46.56 96.19 C 48.357 96.19 50.083 96.905 51.354 98.176 C 52.625 99.447 53.34 101.173 53.34 102.97 L 53.34 102.98 C 53.34 104.777 52.625 106.503 51.354 107.774 C 50.083 109.045 48.357 109.76 46.56 109.76 L 7.28 109.76 C 5.483 109.76 3.757 109.045 2.486 107.774 C 1.215 106.503 0.5 104.777 0.5 102.98 L 0.5 102.97 C 0.5 101.173 1.215 99.447 2.486 98.176 C 3.757 96.905 5.483 96.19 7.28 96.19\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_2\">\n        <path\n            android:name=\"path_13\"\n            android:pathData=\"M 138.071 138.068 L 138.078 138.061 C 138.92 137.22 139.968 136.614 141.118 136.306 C 142.267 135.998 143.478 135.998 144.627 136.306 C 145.777 136.614 146.825 137.22 147.667 138.061 L 175.442 165.836 C 176.283 166.678 176.889 167.726 177.197 168.876 C 177.505 170.025 177.505 171.236 177.197 172.385 C 176.889 173.535 176.283 174.583 175.442 175.425 L 175.435 175.432 C 174.593 176.273 173.545 176.879 172.395 177.187 C 171.246 177.495 170.035 177.495 168.886 177.187 C 167.736 176.879 166.688 176.273 165.846 175.432 L 138.071 147.657 C 137.23 146.815 136.624 145.767 136.316 144.617 C 136.008 143.468 136.008 142.257 136.316 141.108 C 136.624 139.958 137.23 138.91 138.071 138.068\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_14\"\n            android:pathData=\"M 138.071 138.068 L 138.078 138.061 C 138.92 137.22 139.968 136.614 141.118 136.306 C 142.267 135.998 143.478 135.998 144.627 136.306 C 145.777 136.614 146.825 137.22 147.667 138.061 L 175.442 165.836 C 176.283 166.678 176.889 167.726 177.197 168.876 C 177.505 170.025 177.505 171.236 177.197 172.385 C 176.889 173.535 176.283 174.583 175.442 175.425 L 175.435 175.432 C 174.593 176.273 173.545 176.879 172.395 177.187 C 171.246 177.495 170.035 177.495 168.886 177.187 C 167.736 176.879 166.688 176.273 165.846 175.432 L 138.071 147.657 C 137.23 146.815 136.624 145.767 136.316 144.617 C 136.008 143.468 136.008 142.257 136.316 141.108 C 136.624 139.958 137.23 138.91 138.071 138.068\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_3\">\n        <path\n            android:name=\"path_15\"\n            android:pathData=\"M 30.515 30.525 L 30.522 30.518 C 31.364 29.677 32.412 29.071 33.562 28.763 C 34.711 28.455 35.922 28.455 37.071 28.763 C 38.221 29.071 39.269 29.677 40.111 30.518 L 67.886 58.293 C 68.727 59.135 69.333 60.183 69.641 61.333 C 69.949 62.482 69.949 63.693 69.641 64.842 C 69.333 65.992 68.727 67.04 67.886 67.882 L 67.879 67.889 C 67.037 68.73 65.989 69.336 64.84 69.644 C 63.69 69.952 62.479 69.952 61.33 69.644 C 60.18 69.336 59.132 68.73 58.291 67.889 L 30.515 40.114 C 29.674 39.272 29.069 38.224 28.761 37.074 C 28.453 35.925 28.453 34.714 28.761 33.565 C 29.069 32.415 29.674 31.367 30.515 30.525\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_16\"\n            android:pathData=\"M 30.515 30.525 L 30.522 30.518 C 31.364 29.677 32.412 29.071 33.562 28.763 C 34.711 28.455 35.922 28.455 37.071 28.763 C 38.221 29.071 39.269 29.677 40.111 30.518 L 67.886 58.293 C 68.727 59.135 69.333 60.183 69.641 61.333 C 69.949 62.482 69.949 63.693 69.641 64.842 C 69.333 65.992 68.727 67.04 67.886 67.882 L 67.879 67.889 C 67.037 68.73 65.989 69.336 64.84 69.644 C 63.69 69.952 62.479 69.952 61.33 69.644 C 60.18 69.336 59.132 68.73 58.291 67.889 L 30.515 40.114 C 29.674 39.272 29.069 38.224 28.761 37.074 C 28.453 35.925 28.453 34.714 28.761 33.565 C 29.069 32.415 29.674 31.367 30.515 30.525\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/sun_7_24.xml",
    "content": "<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:name=\"vector\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"205\"\n    android:viewportHeight=\"205\">\n    <path\n        android:name=\"path\"\n        android:pathData=\"M 103.3 69.97 C 94.551 69.97 86.152 73.449 79.965 79.635 C 73.779 85.822 70.3 94.221 70.3 102.97 C 70.3 111.719 73.779 120.118 79.965 126.305 C 86.152 132.491 94.551 135.97 103.3 135.97 C 112.049 135.97 120.448 132.491 126.635 126.305 C 132.821 120.118 136.3 111.719 136.3 102.97 C 136.3 94.221 132.821 85.822 126.635 79.635 C 120.448 73.449 112.049 69.97 103.3 69.97 Z\"\n        android:fillColor=\"#ffffff\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_1\"\n        android:pathData=\"M 102.97 0.5 L 102.98 0.5 C 104.777 0.5 106.503 1.215 107.774 2.486 C 109.045 3.757 109.76 5.483 109.76 7.28 L 109.76 46.56 C 109.76 48.357 109.045 50.083 107.774 51.354 C 106.503 52.625 104.777 53.34 102.98 53.34 L 102.97 53.34 C 101.173 53.34 99.447 52.625 98.176 51.354 C 96.905 50.083 96.19 48.357 96.19 46.56 L 96.19 7.28 C 96.19 5.483 96.905 3.757 98.176 2.486 C 99.447 1.215 101.173 0.5 102.97 0.5\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_2\"\n        android:pathData=\"M 102.97 0.5 L 102.98 0.5 C 104.777 0.5 106.503 1.215 107.774 2.486 C 109.045 3.757 109.76 5.483 109.76 7.28 L 109.76 46.56 C 109.76 48.357 109.045 50.083 107.774 51.354 C 106.503 52.625 104.777 53.34 102.98 53.34 L 102.97 53.34 C 101.173 53.34 99.447 52.625 98.176 51.354 C 96.905 50.083 96.19 48.357 96.19 46.56 L 96.19 7.28 C 96.19 5.483 96.905 3.757 98.176 2.486 C 99.447 1.215 101.173 0.5 102.97 0.5\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_3\"\n        android:pathData=\"M 102.97 152.6 L 102.98 152.6 C 104.777 152.6 106.503 153.315 107.774 154.586 C 109.045 155.857 109.76 157.583 109.76 159.38 L 109.76 198.66 C 109.76 200.457 109.045 202.183 107.774 203.454 C 106.503 204.725 104.777 205.44 102.98 205.44 L 102.97 205.44 C 101.173 205.44 99.447 204.725 98.176 203.454 C 96.905 202.183 96.19 200.457 96.19 198.66 L 96.19 159.38 C 96.19 157.583 96.905 155.857 98.176 154.586 C 99.447 153.315 101.173 152.6 102.97 152.6\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_4\"\n        android:pathData=\"M 102.97 152.6 L 102.98 152.6 C 104.777 152.6 106.503 153.315 107.774 154.586 C 109.045 155.857 109.76 157.583 109.76 159.38 L 109.76 198.66 C 109.76 200.457 109.045 202.183 107.774 203.454 C 106.503 204.725 104.777 205.44 102.98 205.44 L 102.97 205.44 C 101.173 205.44 99.447 204.725 98.176 203.454 C 96.905 202.183 96.19 200.457 96.19 198.66 L 96.19 159.38 C 96.19 157.583 96.905 155.857 98.176 154.586 C 99.447 153.315 101.173 152.6 102.97 152.6\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_5\"\n        android:pathData=\"M 138.065 58.287 L 165.84 30.512 C 166.681 29.67 167.73 29.065 168.879 28.757 C 170.029 28.449 171.239 28.449 172.389 28.757 C 173.538 29.065 174.587 29.67 175.428 30.512 L 175.435 30.519 C 176.706 31.79 177.421 33.516 177.421 35.313 C 177.421 37.111 176.706 38.836 175.435 40.107 L 147.66 67.882 C 146.819 68.724 145.77 69.329 144.621 69.637 C 143.471 69.945 142.261 69.945 141.111 69.637 C 139.962 69.329 138.913 68.724 138.072 67.882 L 138.065 67.875 C 137.223 67.034 136.618 65.985 136.31 64.836 C 136.002 63.686 136.002 62.476 136.31 61.326 C 136.618 60.177 137.223 59.128 138.065 58.287\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_6\"\n        android:pathData=\"M 138.065 58.287 L 165.84 30.512 C 166.681 29.67 167.73 29.065 168.879 28.757 C 170.029 28.449 171.239 28.449 172.389 28.757 C 173.538 29.065 174.587 29.67 175.428 30.512 L 175.435 30.519 C 176.706 31.79 177.421 33.516 177.421 35.313 C 177.421 37.111 176.706 38.836 175.435 40.107 L 147.66 67.882 C 146.819 68.724 145.77 69.329 144.621 69.637 C 143.471 69.945 142.261 69.945 141.111 69.637 C 139.962 69.329 138.913 68.724 138.072 67.882 L 138.065 67.875 C 137.223 67.034 136.618 65.985 136.31 64.836 C 136.002 63.686 136.002 62.476 136.31 61.326 C 136.618 60.177 137.223 59.128 138.065 58.287\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <path\n        android:name=\"path_7\"\n        android:pathData=\"M 30.522 165.843 L 58.297 138.068 C 59.138 137.226 60.187 136.621 61.336 136.313 C 62.486 136.005 63.696 136.005 64.846 136.313 C 65.995 136.621 67.044 137.226 67.885 138.068 L 67.892 138.075 C 68.734 138.916 69.339 139.965 69.647 141.114 C 69.955 142.264 69.955 143.474 69.647 144.624 C 69.339 145.773 68.734 146.822 67.892 147.663 L 40.117 175.438 C 39.276 176.28 38.227 176.885 37.078 177.193 C 35.928 177.501 34.718 177.501 33.568 177.193 C 32.419 176.885 31.37 176.28 30.529 175.438 L 30.522 175.431 C 29.251 174.16 28.536 172.434 28.536 170.637 C 28.536 168.839 29.251 167.114 30.522 165.843\"\n        android:fillColor=\"#ffffff\"\n        android:strokeWidth=\"1\"/>\n    <path\n        android:name=\"path_8\"\n        android:pathData=\"M 30.522 165.843 L 58.297 138.068 C 59.138 137.226 60.187 136.621 61.336 136.313 C 62.486 136.005 63.696 136.005 64.846 136.313 C 65.995 136.621 67.044 137.226 67.885 138.068 L 67.892 138.075 C 68.734 138.916 69.339 139.965 69.647 141.114 C 69.955 142.264 69.955 143.474 69.647 144.624 C 69.339 145.773 68.734 146.822 67.892 147.663 L 40.117 175.438 C 39.276 176.28 38.227 176.885 37.078 177.193 C 35.928 177.501 34.718 177.501 33.568 177.193 C 32.419 176.885 31.37 176.28 30.529 175.438 L 30.522 175.431 C 29.251 174.16 28.536 172.434 28.536 170.637 C 28.536 168.839 29.251 167.114 30.522 165.843\"\n        android:strokeColor=\"#ffffff\"\n        android:strokeWidth=\"1\"\n        android:strokeMiterLimit=\"10\"/>\n    <group android:name=\"group\">\n        <path\n            android:name=\"path_9\"\n            android:pathData=\"M 159.38 96.19 L 198.66 96.19 C 200.457 96.19 202.183 96.905 203.454 98.176 C 204.725 99.447 205.44 101.173 205.44 102.97 L 205.44 102.98 C 205.44 104.777 204.725 106.503 203.454 107.774 C 202.183 109.045 200.457 109.76 198.66 109.76 L 159.38 109.76 C 157.583 109.76 155.857 109.045 154.586 107.774 C 153.315 106.503 152.6 104.777 152.6 102.98 L 152.6 102.97 C 152.6 101.173 153.315 99.447 154.586 98.176 C 155.857 96.905 157.583 96.19 159.38 96.19\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_10\"\n            android:pathData=\"M 159.38 96.19 L 198.66 96.19 C 200.457 96.19 202.183 96.905 203.454 98.176 C 204.725 99.447 205.44 101.173 205.44 102.97 L 205.44 102.98 C 205.44 104.777 204.725 106.503 203.454 107.774 C 202.183 109.045 200.457 109.76 198.66 109.76 L 159.38 109.76 C 157.583 109.76 155.857 109.045 154.586 107.774 C 153.315 106.503 152.6 104.777 152.6 102.98 L 152.6 102.97 C 152.6 101.173 153.315 99.447 154.586 98.176 C 155.857 96.905 157.583 96.19 159.38 96.19\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_1\">\n        <path\n            android:name=\"path_11\"\n            android:pathData=\"M 7.28 96.19 L 46.56 96.19 C 48.357 96.19 50.083 96.905 51.354 98.176 C 52.625 99.447 53.34 101.173 53.34 102.97 L 53.34 102.98 C 53.34 104.777 52.625 106.503 51.354 107.774 C 50.083 109.045 48.357 109.76 46.56 109.76 L 7.28 109.76 C 5.483 109.76 3.757 109.045 2.486 107.774 C 1.215 106.503 0.5 104.777 0.5 102.98 L 0.5 102.97 C 0.5 101.173 1.215 99.447 2.486 98.176 C 3.757 96.905 5.483 96.19 7.28 96.19\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_12\"\n            android:pathData=\"M 7.28 96.19 L 46.56 96.19 C 48.357 96.19 50.083 96.905 51.354 98.176 C 52.625 99.447 53.34 101.173 53.34 102.97 L 53.34 102.98 C 53.34 104.777 52.625 106.503 51.354 107.774 C 50.083 109.045 48.357 109.76 46.56 109.76 L 7.28 109.76 C 5.483 109.76 3.757 109.045 2.486 107.774 C 1.215 106.503 0.5 104.777 0.5 102.98 L 0.5 102.97 C 0.5 101.173 1.215 99.447 2.486 98.176 C 3.757 96.905 5.483 96.19 7.28 96.19\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_2\">\n        <path\n            android:name=\"path_13\"\n            android:pathData=\"M 138.071 138.068 L 138.078 138.061 C 138.92 137.22 139.968 136.614 141.118 136.306 C 142.267 135.998 143.478 135.998 144.627 136.306 C 145.777 136.614 146.825 137.22 147.667 138.061 L 175.442 165.836 C 176.283 166.678 176.889 167.726 177.197 168.876 C 177.505 170.025 177.505 171.236 177.197 172.385 C 176.889 173.535 176.283 174.583 175.442 175.425 L 175.435 175.432 C 174.593 176.273 173.545 176.879 172.395 177.187 C 171.246 177.495 170.035 177.495 168.886 177.187 C 167.736 176.879 166.688 176.273 165.846 175.432 L 138.071 147.657 C 137.23 146.815 136.624 145.767 136.316 144.617 C 136.008 143.468 136.008 142.257 136.316 141.108 C 136.624 139.958 137.23 138.91 138.071 138.068\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_14\"\n            android:pathData=\"M 138.071 138.068 L 138.078 138.061 C 138.92 137.22 139.968 136.614 141.118 136.306 C 142.267 135.998 143.478 135.998 144.627 136.306 C 145.777 136.614 146.825 137.22 147.667 138.061 L 175.442 165.836 C 176.283 166.678 176.889 167.726 177.197 168.876 C 177.505 170.025 177.505 171.236 177.197 172.385 C 176.889 173.535 176.283 174.583 175.442 175.425 L 175.435 175.432 C 174.593 176.273 173.545 176.879 172.395 177.187 C 171.246 177.495 170.035 177.495 168.886 177.187 C 167.736 176.879 166.688 176.273 165.846 175.432 L 138.071 147.657 C 137.23 146.815 136.624 145.767 136.316 144.617 C 136.008 143.468 136.008 142.257 136.316 141.108 C 136.624 139.958 137.23 138.91 138.071 138.068\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n    <group android:name=\"group_3\">\n        <path\n            android:name=\"path_15\"\n            android:pathData=\"M 30.515 30.525 L 30.522 30.518 C 31.364 29.677 32.412 29.071 33.562 28.763 C 34.711 28.455 35.922 28.455 37.071 28.763 C 38.221 29.071 39.269 29.677 40.111 30.518 L 67.886 58.293 C 68.727 59.135 69.333 60.183 69.641 61.333 C 69.949 62.482 69.949 63.693 69.641 64.842 C 69.333 65.992 68.727 67.04 67.886 67.882 L 67.879 67.889 C 67.037 68.73 65.989 69.336 64.84 69.644 C 63.69 69.952 62.479 69.952 61.33 69.644 C 60.18 69.336 59.132 68.73 58.291 67.889 L 30.515 40.114 C 29.674 39.272 29.069 38.224 28.761 37.074 C 28.453 35.925 28.453 34.714 28.761 33.565 C 29.069 32.415 29.674 31.367 30.515 30.525\"\n            android:fillColor=\"#ffffff\"\n            android:strokeWidth=\"1\"/>\n        <path\n            android:name=\"path_16\"\n            android:pathData=\"M 30.515 30.525 L 30.522 30.518 C 31.364 29.677 32.412 29.071 33.562 28.763 C 34.711 28.455 35.922 28.455 37.071 28.763 C 38.221 29.071 39.269 29.677 40.111 30.518 L 67.886 58.293 C 68.727 59.135 69.333 60.183 69.641 61.333 C 69.949 62.482 69.949 63.693 69.641 64.842 C 69.333 65.992 68.727 67.04 67.886 67.882 L 67.879 67.889 C 67.037 68.73 65.989 69.336 64.84 69.644 C 63.69 69.952 62.479 69.952 61.33 69.644 C 60.18 69.336 59.132 68.73 58.291 67.889 L 30.515 40.114 C 29.674 39.272 29.069 38.224 28.761 37.074 C 28.453 35.925 28.453 34.714 28.761 33.565 C 29.069 32.415 29.674 31.367 30.515 30.525\"\n            android:strokeColor=\"#ffffff\"\n            android:strokeWidth=\"1\"\n            android:strokeMiterLimit=\"10\"/>\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/tab_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/colorPrimary\"/>\n    <corners android:topLeftRadius=\"5dp\" android:topRightRadius=\"5dp\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/title_24px.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"960\"\n    android:viewportHeight=\"960\"\n    android:tint=\"?attr/white\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M420,800L420,280L200,280L200,160L760,160L760,280L540,280L540,800L420,800Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/title_shadow.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient\n            android:startColor=\"@android:color/transparent\"\n            android:endColor=\"#000\"\n            android:angle=\"-90\">\n    </gradient>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/type_bg_color.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"@color/typeColorBg\"/>\n    <corners android:radius=\"@dimen/rounded_image_radius\"/>\n   <!-- <stroke android:color=\"@color/typeColor\" android:width=\"2dp\"/>-->\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/video_bottom_button.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:color=\"@color/video_ripple\">\n    <item android:id=\"@android:id/mask\">\n        <color android:color=\"@color/video_ripple\"/>\n    </item>\n</ripple>\n"
  },
  {
    "path": "app/src/main/res/drawable/video_frame.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <stroke\n        android:width=\"@dimen/video_frame_width\"\n        android:color=\"@android:color/white\" />\n\n    <solid android:color=\"@android:color/black\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/video_locked.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"850.39\"\n        android:viewportHeight=\"850.39\">\n    <path\n            android:pathData=\"M241.88,422.73h366.79v270h-366.79z\"\n            android:strokeWidth=\"60\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#fff\"/>\n    <path\n            android:fillColor=\"#FF000000\"\n            android:pathData=\"M426.51,532.77h0.01v49.88h-0.01z\"\n            android:strokeWidth=\"60\"\n            android:strokeColor=\"#fff\"/>\n    <path\n            android:pathData=\"M299.75,260a127.5,127.5 0,0 1,255 0\"\n            android:strokeWidth=\"60\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#fff\"/>\n    <path\n            android:fillColor=\"#FF000000\"\n            android:pathData=\"M554.75,253.39L554.75,399.39\"\n            android:strokeWidth=\"60\"\n            android:strokeColor=\"#fff\"/>\n    <path\n            android:fillColor=\"#FF000000\"\n            android:pathData=\"M299.75,250.89L299.75,396.89\"\n            android:strokeWidth=\"60\"\n            android:strokeColor=\"#fff\"/>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable/video_outline.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\r\n    <stroke android:color=\"#C0FFFFFF\" android:width=\"30dp\"/>\r\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/video_pause.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:color=\"@color/video_ripple\">\n    <item android:drawable=\"@drawable/netflix_pause\" android:height=\"70dp\" android:width=\"70dp\" android:gravity=\"center\">\n\n    </item>\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/video_play.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:color=\"@color/video_ripple\">\n    <item android:drawable=\"@drawable/netflix_play\" android:height=\"70dp\" android:width=\"70dp\" android:gravity=\"center\">\n\n    </item>\n</layer-list>"
  },
  {
    "path": "app/src/main/res/drawable/video_tap_button.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:color=\"@color/video_ripple\">\n    <item android:id=\"@android:id/mask\">\n        <shape android:shape=\"oval\">\n            <solid android:color=\"@color/video_ripple\"/>\n        </shape>\n        <color android:color=\"@color/video_ripple\"/>\n    </item>\n</ripple>\n"
  },
  {
    "path": "app/src/main/res/drawable/video_tap_button_always_white.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:color=\"@color/video_ripple\">\n    <item android:id=\"@android:id/mask\"  android:gravity=\"center\">\n        <shape android:shape=\"oval\">\n            <solid android:color=\"@color/video_ripple\"/>\n        </shape>\n        <color android:color=\"@color/video_ripple\"/>\n    </item>\n</ripple>"
  },
  {
    "path": "app/src/main/res/drawable/video_tap_button_skip.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:color=\"@color/video_ripple\">\n    <item android:id=\"@android:id/mask\" android:height=\"35dp\" android:width=\"35dp\" android:gravity=\"center\">\n        <shape android:shape=\"oval\">\n            <solid android:color=\"@color/video_ripple\"/>\n        </shape>\n        <color android:color=\"@color/video_ripple\"/>\n    </item>\n</ripple>"
  },
  {
    "path": "app/src/main/res/drawable/video_unlocked.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:viewportWidth=\"850.39\"\n        android:viewportHeight=\"850.39\">\n    <path\n            android:pathData=\"M241.88,422.73h366.79v270h-366.79z\"\n            android:strokeWidth=\"60\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#fff\"/>\n    <path\n            android:fillColor=\"#FF000000\"\n            android:pathData=\"M426.51,532.77h0.01v49.88h-0.01z\"\n            android:strokeWidth=\"60\"\n            android:strokeColor=\"#fff\"/>\n    <path\n            android:pathData=\"M299.75,260a127.5,127.5 0,0 1,255 0\"\n            android:strokeWidth=\"60\"\n            android:fillColor=\"#00000000\"\n            android:strokeColor=\"#fff\"/>\n    <path\n            android:fillColor=\"#FF000000\"\n            android:pathData=\"M554.75,253.39L554.75,399.39\"\n            android:strokeWidth=\"60\"\n            android:strokeColor=\"#fff\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_banner_background.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"320dp\"\n    android:height=\"180dp\"\n    android:viewportWidth=\"320\"\n    android:viewportHeight=\"180\">\n  <group android:scaleX=\"0.6666667\"\n      android:scaleY=\"0.6666667\"\n      android:translateX=\"53.333332\"\n      android:translateY=\"30\">\n    <group android:scaleX=\"0.35277516\"\n        android:scaleY=\"0.35277516\"\n        android:translateX=\"5.879586E-4\">\n      <path\n          android:strokeWidth=\"1\"\n          android:pathData=\"M-20.09,-10.91h949.79v534.26h-949.79z\"\n          android:fillColor=\"#121212\"\n          android:strokeColor=\"#fff\"/>\n      <path\n              android:pathData=\"M273.68,250.58a18.79,18.79 0,0 0,-5.64 0.86,26.56 26.56,0 0,0 -24.73,-21.51 40.83,40.83 0,0 0,-68.95 -13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H273.68a18.9,18.9 0,0 0,0 -37.8Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"245.72\"\n                  android:startX=\"113.12\"\n                  android:endY=\"245.72\"\n                  android:endX=\"292.58\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#FF5D49EA\"/>\n            <item android:offset=\"0.45\" android:color=\"#FF452FE4\"/>\n            <item android:offset=\"1\" android:color=\"#FF2309DB\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n              android:pathData=\"M248.76,234.41c0,-1.22 0,-2.42 -0.09,-3.63a27,27 0,0 0,-5.36 -0.85,40.83 40.83,0 0,0 -68.95,-13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H228.5A81.75,81.75 0,0 0,248.76 234.41Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"245.72\"\n                  android:startX=\"113.12\"\n                  android:endY=\"245.72\"\n                  android:endX=\"248.76\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#FF4F6DFB\"/>\n            <item android:offset=\"0.6\" android:color=\"#FF3559E7\"/>\n            <item android:offset=\"1\" android:color=\"#FF2149D8\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n              android:pathData=\"M174.36,216.85A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.89,18.89 0,0 0,-1.18 37.74A81.53,81.53 0,0 0,210 206.83c0,-1.15 0,-2.29 -0.09,-3.43a41.33,41.33 0,0 0,-5 -0.33A40.71,40.71 0,0 0,174.36 216.85Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"245.69\"\n                  android:startX=\"113.12\"\n                  android:endY=\"245.69\"\n                  android:endX=\"210.03\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#FF56B6FE\"/>\n            <item android:offset=\"0.61\" android:color=\"#FF599CFA\"/>\n            <item android:offset=\"1\" android:color=\"#FF5C89F7\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n\n      <path\n              android:pathData=\"M358.81,285q-13.53,0 -22.64,-9.1t-9,-22.72q0,-13.62 9,-22.64 9,-9.18 22.64,-9.19 13.79,0 22.38,10l-5.62,5.44a20.82,20.82 0,0 0,-16.76 -7.91,23 23,0 0,0 -16.94,6.81q-6.72,6.72 -6.72,17.53t6.72,17.53a23,23 0,0 0,16.94 6.81q10.63,0 18.46,-8.94l5.7,5.53a29.57,29.57 0,0 1,-10.63 8A32.44,32.44 0,0 1,358.81 285Z\"\n              android:fillColor=\"#2e24ff\"/>\n      <path\n              android:pathData=\"M397.78,222.69v60.93H390V222.69Z\"\n              android:fillColor=\"#2e24ff\"/>\n      <path\n              android:pathData=\"M404.5,262.77q0,-9.61 6,-15.91a20.6,20.6 0,0 1,15.41 -6.3,20.31 20.31,0 0,1 15.31,6.3 21.87,21.87 0,0 1,6.13 15.91q0,9.71 -6.13,15.92A20.3,20.3 0,0 1,426 285a20.6,20.6 0,0 1,-15.41 -6.29Q404.5,272.39 404.5,262.77ZM412.33,262.77a15.31,15.31 0,0 0,3.91 10.9,13.38 13.38,0 0,0 19.41,0 17,17 0,0 0,0 -21.7,13.18 13.18,0 0,0 -19.41,0A15.18,15.18 0,0 0,412.33 262.77Z\"\n              android:fillColor=\"#2e24ff\"/>\n      <path\n              android:pathData=\"M490.7,283.62h-7.48v-5.78h-0.35a13.86,13.86 0,0 1,-5.48 5.1,15.77 15.77,0 0,1 -7.7,2q-7.67,0 -11.79,-4.38t-4.13,-12.47v-26.2h7.83v25.69q0.25,10.22 10.3,10.22a9.81,9.81 0,0 0,7.83 -3.79,13.7 13.7,0 0,0 3.14,-9.06V241.93h7.83Z\"\n              android:fillColor=\"#2e24ff\"/>\n      <path\n              android:pathData=\"M517.25,285a18.34,18.34 0,0 1,-14 -6.46,24.34 24.34,0 0,1 0,-31.49 18.35,18.35 0,0 1,14 -6.47,18.07 18.07,0 0,1 8.39,2 14.84,14.84 0,0 1,5.83 5.19h0.34l-0.34,-5.78L531.47,222.69h7.82v60.93h-7.48v-5.78h-0.34a14.84,14.84 0,0 1,-5.83 5.19A18.07,18.07 0,0 1,517.25 285ZM518.53,277.86a12,12 0,0 0,9.45 -4.17q3.82,-4.17 3.83,-10.9A15.54,15.54 0,0 0,528 252a12.05,12.05 0,0 0,-9.45 -4.26,12.19 12.19,0 0,0 -9.44,4.26 15.5,15.5 0,0 0,-3.83 10.8,15.32 15.32,0 0,0 3.83,10.81A12.19,12.19 0,0 0,518.53 277.84Z\"\n              android:fillColor=\"#2e24ff\"/>\n      <path\n              android:pathData=\"M587.8,267.33a15.91,15.91 0,0 1,-5.87 12.88A22.43,22.43 0,0 1,567.46 285a21.39,21.39 0,0 1,-13.36 -4.42,22.65 22.65,0 0,1 -8,-12.08l7.49,-3.07a19.3,19.3 0,0 0,2.13 4.94,15.72 15.72,0 0,0 3.19,3.78 14.25,14.25 0,0 0,4 2.47,12.26 12.26,0 0,0 4.68,0.9 13.47,13.47 0,0 0,8.76 -2.77,9 9,0 0,0 3.41,-7.36 8.8,8.8 0,0 0,-2.81 -6.55q-2.64,-2.64 -9.87,-5.11 -7.32,-2.64 -9.11,-3.57 -9.69,-4.94 -9.7,-14.55a14.84,14.84 0,0 1,5.37 -11.49A19.53,19.53 0,0 1,567 221.33a20.5,20.5 0,0 1,12.09 3.58,16.67 16.67,0 0,1 6.8,8.76l-7.31,3.06a10.84,10.84 0,0 0,-4 -5.65,13.1 13.1,0 0,0 -15.11,0.28 7.41,7.41 0,0 0,-3.15 6.19,7.14 7.14,0 0,0 2.47,5.42q2.73,2.29 11.83,5.42 9.27,3.17 13.23,7.72A16.53,16.53 0,0 1,587.8 267.33Z\"\n              android:fillColor=\"#5252ff\"/>\n      <path\n              android:pathData=\"M610.26,284.3a11.88,11.88 0,0 1,-8.46 -3.15c-2.25,-2.09 -3.4,-5 -3.45,-8.76V249.07H591v-7.14h7.32V229.16h7.83v12.77h10.21v7.14H606.18v20.77c0,2.78 0.54,4.66 1.61,5.66a5.27,5.27 0,0 0,3.66 1.48,7.9 7.9,0 0,0 1.83,-0.21 9,9 0,0 0,1.66 -0.55l2.47,7A21.23,21.23 0,0 1,610.26 284.3Z\"\n              android:fillColor=\"#5252ff\"/>\n      <path\n              android:pathData=\"M631.71,283.62h-7.83V241.93h7.48v6.8h0.35a11.31,11.31 0,0 1,4.89 -5.66,13.66 13.66,0 0,1 7.27,-2.34 14.7,14.7 0,0 1,5.79 1l-2.38,7.57a12.93,12.93 0,0 0,-4.6 -0.6,10.11 10.11,0 0,0 -7.7,3.58 12,12 0,0 0,-3.27 8.34Z\"\n              android:fillColor=\"#5252ff\"/>\n      <path\n              android:pathData=\"M670.93,285a19.93,19.93 0,0 1,-15.14 -6.29q-6,-6.3 -6,-15.92a22.65,22.65 0,0 1,5.79 -15.87,19.15 19.15,0 0,1 14.8,-6.34q9.29,0 14.77,6t5.49,16.81l-0.09,0.85L657.83,264.24a13.56,13.56 0,0 0,4.08 9.87,13.06 13.06,0 0,0 9.36,3.75q7.49,0 11.75,-7.49l7,3.4a20.69,20.69 0,0 1,-7.78 8.25A21.51,21.51 0,0 1,670.93 285ZM658.42,257.77h23.92a10.43,10.43 0,0 0,-3.53 -7.19,12.38 12.38,0 0,0 -8.56,-2.85 11.34,11.34 0,0 0,-7.61 2.72A13.09,13.09 0,0 0,658.42 257.75Z\"\n              android:fillColor=\"#5252ff\"/>\n      <path\n              android:pathData=\"M714.08,240.56q8.67,0 13.7,4.64c3.34,3.1 5,7.33 5,12.72v25.7h-7.49v-5.78H725Q720.11,285 712,285a16.83,16.83 0,0 1,-11.53 -4.08,13 13,0 0,1 -4.63,-10.21 12.38,12.38 0,0 1,4.89 -10.3q4.89,-3.83 13.06,-3.83a23.16,23.16 0,0 1,11.49 2.55v-1.78a8.9,8.9 0,0 0,-3.24 -6.94,11.08 11.08,0 0,0 -7.57,-2.85 12,12 0,0 0,-10.38 5.53l-6.89,-4.34Q702.93,240.57 714.08,240.56ZM704,270.86a6.24,6.24 0,0 0,2.59 5.1,9.57 9.57,0 0,0 6.09,2.05 12.5,12.5 0,0 0,8.81 -3.66,11.47 11.47,0 0,0 3.87,-8.6q-3.66,-2.88 -10.21,-2.89a13.22,13.22 0,0 0,-8 2.3A6.81,6.81 0,0 0,704 270.86Z\"\n              android:fillColor=\"#5252ff\"/>\n      <path\n              android:pathData=\"M749.47,283.62h-7.82V241.93h7.48v5.78h0.34a14,14 0,0 1,5.49 -5.1,15.06 15.06,0 0,1 7.36,-2.05 15.22,15.22 0,0 1,8.09 2.13,12.56 12.56,0 0,1 5.1,5.87q5.19,-8 14.39,-8 7.23,0 11.14,4.43T805,257.58v26h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.06,9v23.06h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.07,9Z\"\n              android:fillColor=\"#5252ff\"/>\n      <path\n          android:pathData=\"M-13.76,555.76c10.3,-20.89 58.91,-113.94 157.31,-139.7C261.3,385.24 405.9,462.43 469.89,613.28\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"252.3\"\n                  android:startX=\"194.11\"\n                  android:endY=\"252.3\"\n                  android:endX=\"373.57\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#FF5D49EA\"/>\n            <item android:offset=\"0.45\" android:color=\"#FF452FE4\"/>\n            <item android:offset=\"1\" android:color=\"#FF2309DB\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n          android:pathData=\"M318.2,592.15c52.89,-55.46 139,-131.3 263,-187.83 223.69,-102 495.29,-119.94 515.35,-62.21 13,37.39 -73.5,124.43 -496.69,339.65\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startX=\"400.11\"\n                  android:endX=\"900\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#FF5D49EA\"/>\n            <item android:offset=\"0.45\" android:color=\"#FF452FE4\"/>\n            <item android:offset=\"1\" android:color=\"#FF2309DB\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n          android:pathData=\"M-57.58,195c206.91,86.6 494,-219.13 453.91,-347.48C353.52,-289.67 -103.15,-353.41 -203.15,-176 -265.5,-65.35 -189.57,139.73 -57.58,195Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"252.3\"\n                  android:startX=\"-100\"\n                  android:endY=\"252.3\"\n                  android:endX=\"373.57\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#FF5D49EA\"/>\n            <item android:offset=\"0.45\" android:color=\"#FF452FE4\"/>\n            <item android:offset=\"1\" android:color=\"#FF2309DB\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n          android:pathData=\"M698.42,648.89C625.71,546 764,320.79 920.68,218.45c46.61,-30.44 110.17,-72 164.35,-50.08 102.25,41.28 158.19,303.22 28.17,446.08C996.65,742.52 762.64,739.78 698.42,648.89Z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startX=\"700.11\"\n                  android:endX=\"900.57\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#FF5D49EA\"/>\n            <item android:offset=\"0.45\" android:color=\"#FF452FE4\"/>\n            <item android:offset=\"1\" android:color=\"#FF2309DB\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n      <path\n          android:pathData=\"M339.91,-42.46a246.52,141.46 0,1 0,493.04 0a246.52,141.46 0,1 0,-493.04 0z\">\n        <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startX=\"400.11\"\n                  android:endX=\"800.57\"\n                  android:type=\"linear\">\n            <item android:offset=\"0\" android:color=\"#FF5D49EA\"/>\n            <item android:offset=\"0.45\" android:color=\"#FF452FE4\"/>\n            <item android:offset=\"1\" android:color=\"#FF2309DB\"/>\n          </gradient>\n        </aapt:attr>\n      </path>\n    </group>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_banner_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"320dp\"\n    android:height=\"180dp\"\n    android:viewportWidth=\"320\"\n    android:viewportHeight=\"180\"\n    android:name=\"vector\">\n  <group android:scaleX=\"0.6666667\"\n      android:scaleY=\"0.6666667\"\n      android:translateX=\"53.333332\"\n      android:translateY=\"30\">\n    <group android:scaleX=\"0.2671378\"\n        android:scaleY=\"0.2671378\"\n        android:translateX=\"35.8\"\n        android:translateY=\"52.2\">\n        <path android:name=\"path\"\n              android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n              android:strokeWidth=\"1\"\n              tools:ignore=\"VectorPath\">\n            <aapt:attr name=\"android:fillColor\">\n                <gradient\n                        android:startY=\"0\"\n                        android:startX=\"200\"\n                        android:endY=\"0\"\n                        android:endX=\"300\"\n                        android:type=\"linear\">\n                    <item android:offset=\"0\" android:color=\"#2309db\"/>\n                    <item android:offset=\"1\" android:color=\"#1B08A1\"/>\n                </gradient>\n            </aapt:attr>\n        </path>\n\n        <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n              android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"0\"\n                    android:startX=\"200\"\n                    android:endY=\"0\"\n                    android:endX=\"000\"\n                    android:type=\"linear\">\n                <item android:offset=\"0\" android:color=\"#254cdb\"/>\n                <item android:offset=\"1\" android:color=\"#1138DD\"/>\n            </gradient>\n        </aapt:attr>\n        </path>\n\n        <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n               android:strokeWidth=\"1\">\n        <aapt:attr name=\"android:fillColor\">\n            <gradient\n                    android:startY=\"0\"\n                    android:startX=\"150\"\n                    android:endY=\"0\"\n                    android:endX=\"000\"\n                    android:type=\"linear\">\n                <item android:offset=\"0\" android:color=\"#407EF1\"/>\n                <item android:offset=\"1\" android:color=\"#428CC5\"/>\n            </gradient>\n        </aapt:attr>\n    </path>\n    </group>\n\n    <group android:scaleX=\"0.18556112\"\n        android:scaleY=\"0.18556112\"\n        android:translateX=\"128\"\n        android:translateY=\"72.22962\">\n      <group android:translateY=\"155.39062\">\n        <path android:pathData=\"M81.84375,-4.53125Q70.671875,2,54,2Q32.484375,2,19.546875,-11.953125Q6.609375,-25.921875,6.609375,-48.59375Q6.609375,-72.953125,21.15625,-87.96875Q35.71875,-103,58.078125,-103Q72.421875,-103,81.84375,-98.59375L81.84375,-86Q71.015625,-92,57.9375,-92Q40.578125,-92,29.78125,-80.375Q18.984375,-68.765625,18.984375,-49.34375Q18.984375,-30.890625,29.078125,-19.9375Q39.171875,-9,55.546875,-9Q70.734375,-9,81.84375,-16L81.84375,-4.53125Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M112.203125,0L100.671875,0L100.671875,-107L112.203125,-107L112.203125,0Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M165.76562,2Q149.8125,2,140.28125,-8.171875Q130.75,-18.34375,130.75,-35.15625Q130.75,-53.4375,140.65625,-63.71875Q150.57812,-74,167.45312,-74Q183.5625,-74,192.59375,-64Q201.625,-54,201.625,-36.28125Q201.625,-18.921875,191.89062,-8.453125Q182.15625,2,165.76562,2ZM166.60938,-64Q155.5,-64,149.03125,-56.4375Q142.5625,-48.875,142.5625,-35.578125Q142.5625,-22.78125,149.09375,-15.390625Q155.64062,-8,166.60938,-8Q177.79688,-8,183.79688,-15.25Q189.8125,-22.5,189.8125,-35.859375Q189.8125,-49.359375,183.79688,-56.671875Q177.79688,-64,166.60938,-64Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M277.89062,0L266.35938,0L266.35938,-11.375L266.07812,-11.375Q258.90625,2,243.85938,2Q218.125,2,218.125,-28.78125L218.125,-72L229.59375,-72L229.59375,-30.78125Q229.59375,-8,247.03125,-8Q255.46875,-8,260.90625,-14.21875Q266.35938,-20.453125,266.35938,-30.5L266.35938,-72L277.89062,-72L277.89062,0Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M363.125,0L351.59375,0L351.59375,-12.21875L351.3125,-12.21875Q343.29688,2,326.5625,2Q313,2,304.875,-7.75Q296.75,-17.5,296.75,-34.296875Q296.75,-52.3125,305.75,-63.15625Q314.75,-74,329.73438,-74Q344.5625,-74,351.3125,-62.03125L351.59375,-62.03125L351.59375,-107L363.125,-107L363.125,0ZM351.59375,-32.546875L351.59375,-43.171875Q351.59375,-51.90625,345.82812,-57.953125Q340.0625,-64,331.20312,-64Q320.65625,-64,314.60938,-56.25Q308.5625,-48.515625,308.5625,-34.875Q308.5625,-22.421875,314.35938,-15.203125Q320.17188,-8,329.9375,-8Q339.57812,-8,345.57812,-14.953125Q351.59375,-21.921875,351.59375,-32.546875Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M383.51562,-4.078125L383.51562,-18Q385.90625,-15.90625,389.23438,-14.234375Q392.57812,-12.5625,396.26562,-11.40625Q399.96875,-10.25,403.6875,-9.625Q407.42188,-9,410.57812,-9Q421.48438,-9,426.85938,-13Q432.23438,-17,432.23438,-24.5Q432.23438,-28.609375,430.4375,-31.65625Q428.65625,-34.703125,425.48438,-37.21875Q422.32812,-39.734375,418,-42.03125Q413.67188,-44.328125,408.6875,-46.890625Q403.40625,-49.578125,398.82812,-52.34375Q394.26562,-55.109375,390.89062,-58.4375Q387.51562,-61.765625,385.57812,-65.96875Q383.65625,-70.1875,383.65625,-75.859375Q383.65625,-82.796875,386.67188,-87.9375Q389.70312,-93.078125,394.625,-96.40625Q399.54688,-99.734375,405.82812,-101.359375Q412.125,-103,418.67188,-103Q433.57812,-103,440.39062,-99.296875L440.39062,-86Q431.46875,-92,417.46875,-92Q413.60938,-92,409.73438,-91.1875Q405.875,-90.390625,402.84375,-88.578125Q399.82812,-86.765625,397.92188,-83.90625Q396.03125,-81.046875,396.03125,-76.921875Q396.03125,-73.03125,397.46875,-70.1875Q398.90625,-67.359375,401.71875,-65.015625Q404.53125,-62.6875,408.57812,-60.484375Q412.625,-58.28125,417.89062,-55.671875Q423.3125,-52.96875,428.15625,-50Q433.01562,-47.03125,436.67188,-43.40625Q440.32812,-39.796875,442.46875,-35.40625Q444.60938,-31.015625,444.60938,-25.34375Q444.60938,-17.828125,441.6875,-12.625Q438.78125,-7.421875,433.8125,-4.15625Q428.85938,-0.90625,422.39062,0.546875Q415.92188,2,408.75,2Q406.35938,2,402.84375,1.59375Q399.32812,1.1875,395.67188,0.40625Q392.01562,-0.375,388.75,-1.515625Q385.48438,-2.671875,383.51562,-4.078125Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M497.07812,-0.234375Q493,2,486.3125,2Q467.40625,2,467.40625,-19.1875L467.40625,-62L455.03125,-62L455.03125,-72L467.40625,-72L467.40625,-89.328125L478.9375,-93L478.9375,-72L497.07812,-72L497.07812,-62L478.9375,-62L478.9375,-21.4375Q478.9375,-14.1875,481.39062,-11.09375Q483.85938,-8,489.54688,-8Q493.90625,-8,497.07812,-10L497.07812,-0.234375Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M550.21875,-60Q547.2031,-62,541.5,-62Q534.125,-62,529.15625,-55.109375Q524.2031,-48.21875,524.2031,-36.328125L524.2031,0L512.6719,0L512.6719,-72L524.2031,-72L524.2031,-56.515625L524.4844,-56.515625Q526.9531,-64.296875,532.0156,-68.640625Q537.0781,-73,543.3281,-73Q547.8281,-73,550.21875,-72.015625L550.21875,-60Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M620.5469,-33L569.7031,-33Q569.9844,-21.03125,576.1719,-14.515625Q582.3594,-8,593.1875,-8Q605.3594,-8,615.5469,-16L615.5469,-5Q606.0625,2,590.4531,2Q575.1875,2,566.46875,-7.890625Q557.75,-17.78125,557.75,-35.71875Q557.75,-52.65625,567.28125,-63.328125Q576.8125,-74,590.9375,-74Q605.0781,-74,612.8125,-64.765625Q620.5469,-55.53125,620.5469,-39.109375L620.5469,-33ZM608.7344,-43Q608.65625,-52.9375,603.90625,-58.46875Q599.1719,-64,590.7344,-64Q582.5781,-64,576.875,-58.1875Q571.1875,-52.375,569.84375,-43L608.7344,-43Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M689.21875,0L677.6875,0L677.6875,-11.234375L677.40625,-11.234375Q669.875,2,655.25,2Q644.5,2,638.40625,-3.765625Q632.3281,-9.546875,632.3281,-19.109375Q632.3281,-39.578125,656.09375,-42.9375L677.6875,-46Q677.6875,-64,662.84375,-64Q649.84375,-64,639.3594,-55L639.3594,-67.09375Q649.9844,-74,663.8281,-74Q689.21875,-74,689.21875,-47.03125L689.21875,0ZM677.6875,-37L660.3125,-34.5625Q652.2969,-33.40625,648.21875,-30.5Q644.1406,-27.59375,644.1406,-20.203125Q644.1406,-14.8125,647.90625,-11.40625Q651.6719,-8,657.9219,-8Q666.5,-8,672.09375,-14.140625Q677.6875,-20.28125,677.6875,-29.671875L677.6875,-37Z\"\n            android:fillColor=\"#76A6FD\"/>\n        <path android:pathData=\"M812.90625,0L801.375,0L801.375,-41.359375Q801.375,-53.3125,797.6875,-58.65625Q794,-64,785.28125,-64Q777.8906,-64,772.71875,-57.25Q767.5625,-50.5,767.5625,-41.078125L767.5625,0L756.03125,0L756.03125,-42.765625Q756.03125,-64,739.6406,-64Q732.0469,-64,727.125,-57.625Q722.2031,-51.265625,722.2031,-41.078125L722.2031,0L710.6719,0L710.6719,-72L722.2031,-72L722.2031,-60.625L722.4844,-60.625Q730.15625,-74,744.84375,-74Q752.2344,-74,757.71875,-69.796875Q763.2031,-65.609375,765.2344,-58.796875Q773.25,-74,789.1406,-74Q812.90625,-74,812.90625,-44.5625L812.90625,0Z\"\n            android:fillColor=\"#76A6FD\"/>\n      </group>\n    </group>\n  </group>\n</vector>"
  },
  {
    "path": "app/src/main/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\"\n    android:name=\"vector\">\n  <group android:scaleX=\"0.1755477\"\n      android:scaleY=\"0.1755477\"\n      android:translateX=\"29.16\"\n      android:translateY=\"29.16\">\n      <path android:name=\"path\"\n            android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n            android:strokeWidth=\"1\"\n            tools:ignore=\"VectorPath\">\n          <aapt:attr name=\"android:fillColor\">\n              <gradient\n                      android:startY=\"0\"\n                      android:startX=\"200\"\n                      android:endY=\"0\"\n                      android:endX=\"300\"\n                      android:type=\"linear\">\n                  <item android:offset=\"0\" android:color=\"#2309db\"/>\n                  <item android:offset=\"1\" android:color=\"#1B08A1\"/>\n              </gradient>\n          </aapt:attr>\n      </path>\n\n      <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n            android:strokeWidth=\"1\">\n      <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"0\"\n                  android:startX=\"200\"\n                  android:endY=\"0\"\n                  android:endX=\"000\"\n                  android:type=\"linear\">\n              <item android:offset=\"0\" android:color=\"#254cdb\"/>\n              <item android:offset=\"1\" android:color=\"#1138DD\"/>\n          </gradient>\n      </aapt:attr>\n      </path>\n\n      <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n             android:strokeWidth=\"1\">\n      <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"0\"\n                  android:startX=\"150\"\n                  android:endY=\"0\"\n                  android:endX=\"000\"\n                  android:type=\"linear\">\n              <item android:offset=\"0\" android:color=\"#407EF1\"/>\n              <item android:offset=\"1\" android:color=\"#428CC5\"/>\n          </gradient>\n      </aapt:attr>\n  </path>\n  </group>\n</vector>"
  },
  {
    "path": "app/src/main/res/font/google_sans.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<font-family\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <font\n            app:fontStyle=\"normal\"\n            app:fontWeight=\"100\"\n            app:font=\"@font/productsans_thin\" />\n    <font\n            app:fontStyle=\"italic\"\n            app:fontWeight=\"100\"\n            app:font=\"@font/productsans_thinitalic\" />\n\n    <font\n            app:fontStyle=\"normal\"\n            app:fontWeight=\"300\"\n            app:font=\"@font/productsans_light\" />\n\n    <font\n            app:fontStyle=\"italic\"\n            app:fontWeight=\"300\"\n            app:font=\"@font/productsans_lightitalic\" />\n\n    <font\n            app:fontStyle=\"normal\"\n            app:fontWeight=\"400\"\n            app:font=\"@font/productsans_regular\" />\n\n    <font\n            app:fontStyle=\"italic\"\n            app:fontWeight=\"400\"\n            app:font=\"@font/productsans_italic\" />\n\n    <font\n            app:fontStyle=\"normal\"\n            app:fontWeight=\"500\"\n            app:font=\"@font/productsans_medium\" />\n    <font\n            app:fontStyle=\"italic\"\n            app:fontWeight=\"500\"\n            app:font=\"@font/productsans_mediumitalic\" />\n\n    <font\n            app:fontStyle=\"normal\"\n            app:fontWeight=\"700\"\n            app:font=\"@font/productsans_bold\" />\n    <font\n            app:fontStyle=\"italic\"\n            app:fontWeight=\"700\"\n            app:font=\"@font/productsans_bolditalic\" />\n\n    <font\n            app:fontStyle=\"normal\"\n            app:fontWeight=\"900\"\n            app:font=\"@font/productsans_black\" />\n    <font\n            app:fontStyle=\"italic\"\n            app:fontWeight=\"900\"\n            app:font=\"@font/productsans_blackitalic\" />\n</font-family>"
  },
  {
    "path": "app/src/main/res/layout/account_edit_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:id=\"@+id/title\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_rowWeight=\"1\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_weight=\"1\"\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:text=\"@string/create_account\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"10dp\"\n        android:layout_marginBottom=\"60dp\"\n        android:orientation=\"vertical\">\n\n        <androidx.cardview.widget.CardView\n            android:layout_width=\"@dimen/account_select_linear_item_size\"\n            android:layout_height=\"@dimen/account_select_linear_item_size\"\n            android:layout_gravity=\"center\"\n            app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n            <ImageView\n                android:id=\"@+id/account_image\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"center\"\n                android:contentDescription=\"@string/preview_background_img_des\"\n                android:focusable=\"true\"\n                android:foreground=\"@drawable/outline_drawable_forced_round\"\n                android:scaleType=\"centerCrop\"\n                android:src=\"@drawable/profile_bg_blue\" />\n\n            <ImageView\n                android:id=\"@+id/edit_profile_photo_button\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"bottom|end\"\n                android:background=\"@color/skipOpTransparent\"\n                android:padding=\"5dp\"\n                android:src=\"@drawable/ic_baseline_edit_24\" />\n        </androidx.cardview.widget.CardView>\n\n        <EditText\n            android:id=\"@+id/account_name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:autofillHints=\"username\"\n            android:hint=\"@string/default_account\"\n            android:inputType=\"text\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:nextFocusDown=\"@id/site_url_input\"\n            android:requiresFadingEdge=\"vertical\"\n            android:textColorHint=\"?attr/grayTextColor\"\n            tools:ignore=\"LabelFor\" />\n\n        <CheckBox\n            android:id=\"@+id/lockProfileCheckbox\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:buttonTint=\"?attr/textColor\"\n            android:text=\"@string/lock_profile\"\n            android:textColor=\"?attr/grayTextColor\" />\n\n\n    </LinearLayout>\n\n    <RelativeLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:orientation=\"horizontal\"\n        android:padding=\"10dp\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/delete_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_alignParentStart=\"true\"\n            android:layout_gravity=\"center_vertical\"\n            android:nextFocusRight=\"@id/apply_btt\"\n            android:text=\"@string/delete\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:layout_toStartOf=\"@+id/cancel_btt\"\n            android:nextFocusLeft=\"@id/delete_btt\"\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:text=\"@string/sort_apply\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n            android:text=\"@string/sort_cancel\" />\n\n    </RelativeLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/account_list_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/card_view\"\n    android:layout_width=\"110dp\"\n    android:layout_height=\"110dp\"\n    android:layout_margin=\"10dp\"\n    android:animateLayoutChanges=\"true\"\n    android:backgroundTint=\"@color/primaryGrayBackground\"\n    android:focusable=\"true\"\n    android:foreground=\"?attr/selectableItemBackground\"\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintDimensionRatio=\"1\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintHeight_percent=\"0.4\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\">\n\n    <ImageView\n        android:id=\"@+id/account_image\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:alpha=\"0.4\"\n        android:scaleType=\"centerCrop\" />\n\n    <View\n        android:id=\"@+id/outline\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@drawable/outline_card\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\" />\n\n    <ImageView\n        android:id=\"@+id/lock_icon\"\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:layout_gravity=\"top|end\"\n        android:layout_margin=\"4dp\"\n        android:src=\"@drawable/video_locked\"\n        android:visibility=\"gone\"\n        app:tint=\"@color/textColor\"\n        tools:visibility=\"visible\" />\n\n    <TextView\n        android:id=\"@+id/account_name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:gravity=\"center\"\n        android:padding=\"10dp\"\n        android:textColor=\"@color/textColor\"\n        android:textSize=\"16sp\"\n        tools:text=\"Hello World!\" />\n\n</androidx.cardview.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/account_list_item_add.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/card_view\"\n    android:layout_width=\"110dp\"\n    android:layout_height=\"110dp\"\n    android:animateLayoutChanges=\"true\"\n    android:backgroundTint=\"?attr/primaryGrayBackground\"\n    android:foreground=\"?attr/selectableItemBackground\"\n    android:layout_margin=\"10dp\"\n    android:focusable=\"true\"\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintDimensionRatio=\"1\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintHeight_percent=\"0.4\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\">\n\n    <ImageView\n        android:layout_gravity=\"center\"\n        android:src=\"@drawable/ic_baseline_add_24\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"40dp\"\n        android:scaleType=\"centerCrop\"\n        android:contentDescription=\"@string/add_account\" />\n\n</androidx.cardview.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/account_list_item_edit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/card_view\"\n    android:layout_width=\"110dp\"\n    android:layout_height=\"110dp\"\n    android:layout_margin=\"10dp\"\n    android:animateLayoutChanges=\"true\"\n    android:backgroundTint=\"@color/primaryGrayBackground\"\n    android:focusable=\"true\"\n    android:foreground=\"?attr/selectableItemBackground\"\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n    app:layout_constraintBottom_toBottomOf=\"parent\"\n    app:layout_constraintDimensionRatio=\"1\"\n    app:layout_constraintEnd_toEndOf=\"parent\"\n    app:layout_constraintHeight_percent=\"0.4\"\n    app:layout_constraintStart_toStartOf=\"parent\"\n    app:layout_constraintTop_toTopOf=\"parent\">\n\n    <ImageView\n        android:id=\"@+id/account_image\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:alpha=\"0.1\"\n        android:scaleType=\"centerCrop\" />\n\n    <View\n        android:id=\"@+id/outline\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"@drawable/outline_card\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\" />\n\n    <ImageView\n        android:id=\"@+id/lock_icon\"\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:layout_gravity=\"top|end\"\n        android:layout_margin=\"4dp\"\n        android:src=\"@drawable/video_locked\"\n        android:visibility=\"gone\"\n        app:tint=\"@color/textColor\"\n        tools:visibility=\"visible\" />\n\n    <ImageView\n        android:id=\"@+id/pencil_icon\"\n        android:layout_width=\"42dp\"\n        android:layout_height=\"42dp\"\n        android:layout_gravity=\"top|start\"\n        android:src=\"@drawable/ic_baseline_edit_24\"\n        app:tint=\"@color/textColor\" />\n\n    <TextView\n        android:id=\"@+id/account_name\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:gravity=\"center\"\n        android:padding=\"10dp\"\n        android:textColor=\"@color/textColor\"\n        android:textSize=\"16sp\"\n        tools:text=\"Hello World!\" />\n\n</androidx.cardview.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/account_managment.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    <LinearLayout\n            android:paddingStart=\"20dp\"\n            android:paddingEnd=\"20dp\"\n            android:paddingTop=\"20dp\"\n            android:paddingBottom=\"10dp\"\n            android:orientation=\"horizontal\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n        <androidx.cardview.widget.CardView\n                android:id=\"@+id/account_main_profile_picture_holder\"\n                app:cardCornerRadius=\"100dp\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_width=\"35dp\"\n                android:layout_height=\"35dp\">\n\n            <ImageView\n                    android:id=\"@+id/account_main_profile_picture\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    tools:ignore=\"ContentDescription\" />\n        </androidx.cardview.widget.CardView>\n\n        <LinearLayout\n                android:paddingStart=\"20dp\"\n                android:paddingEnd=\"20dp\"\n                android:layout_gravity=\"center_vertical\"\n                android:orientation=\"vertical\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n\n            <TextView\n                    android:id=\"@+id/account_name\"\n\n                    android:textStyle=\"bold\"\n                    tools:text=\"MAL HelloWorld\"\n                    android:textSize=\"20sp\"\n                    android:textColor=\"?attr/textColor\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_rowWeight=\"1\"\n                    android:layout_height=\"wrap_content\" />\n\n            <TextView\n                    android:id=\"@+id/account_site\"\n                    android:layout_gravity=\"center_vertical\"\n                    tools:text=\"MyAnimeList\"\n                    android:textSize=\"15sp\"\n                    android:textColor=\"?attr/grayTextColor\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_rowWeight=\"1\"\n                    android:layout_height=\"wrap_content\" />\n        </LinearLayout>\n\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/account_switch_account\"\n        android:text=\"@string/switch_account\"\n        style=\"@style/SettingsItem\"\n        android:focusable=\"true\"/>\n\n    <TextView\n        android:id=\"@+id/account_logout\"\n        android:text=\"@string/logout\"\n        style=\"@style/SettingsItem\"\n        android:focusable=\"true\">\n\n        <requestFocus />\n    </TextView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/account_select_linear.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:textStyle=\"bold\"\n        android:text=\"@string/switch_account\"\n        android:textSize=\"20sp\"\n        android:textColor=\"?attr/textColor\"\n        android:layout_width=\"match_parent\"\n        android:layout_rowWeight=\"1\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/account_recycler_view\"\n        android:orientation=\"horizontal\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:layout_marginTop=\"10dp\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        tools:itemCount=\"4\"\n        tools:listitem=\"@layout/account_list_item\" />\n\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/manage_accounts_button\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_marginBottom=\"10dp\"\n        android:text=\"@string/manage_accounts\"\n        android:textSize=\"16sp\"\n        app:icon=\"@drawable/ic_baseline_edit_24\"\n        style=\"@style/BlackButton\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/account_single.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n    android:orientation=\"horizontal\"\n    android:layout_height=\"wrap_content\"\n    android:layout_width=\"match_parent\"\n    android:focusable=\"true\">\n\n    <androidx.cardview.widget.CardView\n            android:id=\"@+id/account_profile_picture_holder\"\n            android:layout_marginStart=\"10dp\"\n            app:cardCornerRadius=\"100dp\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_width=\"30dp\"\n            android:layout_height=\"30dp\">\n\n        <ImageView\n            android:id=\"@+id/account_profile_picture\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            tools:ignore=\"ContentDescription\" />\n    </androidx.cardview.widget.CardView>\n\n    <TextView\n        android:foreground=\"@null\"\n        android:id=\"@+id/account_name\"\n        tools:text=\"Account 1\"\n        style=\"@style/SettingsItem\" />\n</LinearLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/account_switch.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/account_list\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        android:background=\"?attr/primaryBlackBackground\"\n        tools:listitem=\"@layout/account_single\"\n        android:layout_width=\"match_parent\"\n        android:layout_rowWeight=\"1\"\n        android:layout_height=\"wrap_content\"\n        android:focusable=\"true\"/>\n\n    <TextView\n        android:id=\"@+id/account_none\"\n        android:text=\"@string/no_account\"\n        style=\"@style/SettingsItem\"\n        android:focusable=\"true\">\n    </TextView>\n\n    <TextView\n        android:id=\"@+id/account_add\"\n        android:text=\"@string/add_account\"\n        style=\"@style/SettingsItem\"\n        android:focusable=\"true\">\n\n        <requestFocus />\n    </TextView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_account_select.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:background=\"?attr/primaryBlackBackground\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.AppCompatImageView\n        android:id=\"@+id/edit_account_button\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"40dp\"\n        android:layout_gravity=\"end|top\"\n        android:layout_marginTop=\"40dp\"\n        android:layout_marginEnd=\"16dp\"\n        android:src=\"@drawable/ic_baseline_edit_24\"\n        android:focusable=\"true\"\n        android:nextFocusDown=\"@id/account_recycler_view\"\n        android:background=\"?attr/selectableItemBackgroundBorderless\"\n        android:contentDescription=\"@string/manage_accounts\"\n        app:tint=\"@color/player_on_button_tv_attr\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:paddingTop=\"36dp\"\n        android:gravity=\"center\">\n\n        <TextView\n            android:id=\"@+id/title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/select_an_account\"\n            android:textSize=\"24sp\"\n            android:textStyle=\"bold\"\n            android:layout_marginTop=\"16dp\"\n            android:layout_marginBottom=\"16dp\" />\n\n        <com.lagradost.cloudstream3.ui.AutofitRecyclerView\n            android:id=\"@+id/account_recycler_view\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:paddingLeft=\"16dp\"\n            android:paddingRight=\"16dp\" />\n\n    </LinearLayout>\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/homeRoot\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:configChanges=\"orientation|screenSize|screenLayout|keyboardHidden|keyboard|navigation\"\n    android:paddingTop=\"0dp\">\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <com.google.android.material.navigationrail.NavigationRailView\n            android:id=\"@+id/nav_rail_view\"\n            android:layout_width=\"@dimen/nav_rail_view_width\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:descendantFocusability=\"afterDescendants\"\n            app:itemIconTint=\"@color/item_select_color\"\n            app:itemTextColor=\"@color/item_select_color\"\n            app:headerLayout=\"@layout/rail_header\"\n            app:labelVisibilityMode=\"unlabeled\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:menu=\"@menu/bottom_nav_menu\"\n            app:menuGravity=\"center\">\n\n            <include layout=\"@layout/rail_footer\"/>\n\n        </com.google.android.material.navigationrail.NavigationRailView>\n        <!-- android:layout_height=\"65dp\"\n                              app:labelVisibilityMode=\"unlabeled\"\n\n                  -->\n        <com.google.android.material.bottomnavigation.BottomNavigationView\n            android:id=\"@+id/nav_view\"\n            android:layout_height=\"@dimen/nav_view_height\"\n            android:layout_width=\"0dp\"\n            app:labelVisibilityMode=\"unlabeled\"\n            android:background=\"?attr/primaryGrayBackground\"\n\n            app:itemIconTint=\"@color/item_select_color\"\n            app:itemTextColor=\"@color/item_select_color\"\n\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintRight_toRightOf=\"parent\"\n            app:menu=\"@menu/bottom_nav_menu\" />\n\n        <androidx.fragment.app.FragmentContainerView\n            android:id=\"@+id/nav_host_fragment\"\n            android:name=\"androidx.navigation.fragment.NavHostFragment\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            app:defaultNavHost=\"true\"\n            app:layout_constraintBottom_toTopOf=\"@+id/cast_mini_controller_holder\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toEndOf=\"@+id/nav_rail_view\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:navGraph=\"@navigation/mobile_navigation\" />\n\n        <LinearLayout\n            android:id=\"@+id/cast_mini_controller_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            app:layout_constraintBottom_toTopOf=\"@+id/nav_view\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toEndOf=\"@+id/nav_rail_view\"\n            tools:layout_height=\"100dp\">\n            <!--com.google.android.gms.cast.framework.media.widget.MiniControllerFragment-->\n            <fragment\n                android:id=\"@+id/cast_mini_controller\"\n                class=\"com.lagradost.cloudstream3.ui.MyMiniControllerFragment\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:visibility=\"gone\"\n\n                app:castControlButtons=\"@array/cast_mini_controller_control_buttons\"\n                app:customCastBackgroundColor=\"?attr/primaryGrayBackground\"\n                tools:ignore=\"FragmentTagUsage\" />\n        </LinearLayout>\n    </androidx.constraintlayout.widget.ConstraintLayout>\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_main_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/homeRoot\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:configChanges=\"orientation|screenSize|screenLayout|keyboardHidden|keyboard|navigation\"\n    android:paddingTop=\"0dp\">\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <androidx.fragment.app.FragmentContainerView\n            android:id=\"@+id/nav_host_fragment\"\n            android:name=\"androidx.navigation.fragment.NavHostFragment\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            app:defaultNavHost=\"true\"\n            app:layout_constraintBottom_toTopOf=\"@+id/cast_mini_controller_holder\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:navGraph=\"@navigation/mobile_navigation\" />\n\n        <com.google.android.material.navigationrail.NavigationRailView\n            android:id=\"@+id/nav_rail_view\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:descendantFocusability=\"afterDescendants\"\n            android:maxWidth=\"@dimen/nav_rail_view_width\"\n            android:minWidth=\"@dimen/nav_rail_view_width\"\n            app:collapsedItemMinHeight=\"0dp\"\n            app:expanded=\"false\"\n            app:expandedItemMinHeight=\"0dp\"\n            app:expandedMaxWidth=\"220dp\"\n\n            app:headerLayout=\"@layout/rail_header\"\n            app:itemActiveIndicatorStyle=\"@style/CustomIndicator\"\n            app:itemIconSize=\"24dp\"\n            app:itemIconTint=\"@color/item_select_color_tv\"\n\n            app:itemMinHeight=\"0dp\"\n            app:itemPaddingBottom=\"0dp\"\n            app:itemPaddingTop=\"0dp\"\n            app:itemSpacing=\"12dp\"\n            app:itemTextColor=\"@color/item_select_color_tv\"\n            app:labelVisibilityMode=\"unlabeled\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:menu=\"@menu/bottom_nav_menu\"\n            app:menuGravity=\"center\">\n\n            <include layout=\"@layout/rail_footer\" />\n\n        </com.google.android.material.navigationrail.NavigationRailView>\n\n        <com.google.android.material.bottomnavigation.BottomNavigationView\n            android:id=\"@+id/nav_view\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"@dimen/nav_view_height\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:visibility=\"gone\"\n            app:itemIconTint=\"@color/item_select_color\"\n            app:itemTextColor=\"@color/item_select_color\"\n            app:labelVisibilityMode=\"unlabeled\"\n\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintRight_toRightOf=\"parent\"\n            app:menu=\"@menu/bottom_nav_menu\" />\n\n        <LinearLayout\n            android:id=\"@+id/cast_mini_controller_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toEndOf=\"@+id/nav_rail_view\"\n            tools:layout_height=\"100dp\">\n            <!--com.google.android.gms.cast.framework.media.widget.MiniControllerFragment-->\n            <fragment\n                android:id=\"@+id/cast_mini_controller\"\n                class=\"com.lagradost.cloudstream3.ui.MyMiniControllerFragment\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:visibility=\"gone\"\n                app:castControlButtons=\"@array/cast_mini_controller_control_buttons\"\n                app:customCastBackgroundColor=\"?attr/primaryGrayBackground\"\n                tools:ignore=\"FragmentTagUsage\" />\n        </LinearLayout>\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <ImageView\n            android:id=\"@+id/focus_outline\"\n            android:layout_width=\"100dp\"\n            android:layout_height=\"100dp\"\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:focusableInTouchMode=\"false\"\n            android:importantForAccessibility=\"no\"\n            android:src=\"@drawable/outline\"\n            android:visibility=\"gone\" />\n    </FrameLayout>\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/add_account_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:id=\"@+id/text1\"\n            android:layout_weight=\"1\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n\n            android:layout_rowWeight=\"1\"\n            android:layout_gravity=\"center_vertical\"\n\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\"\n            tools:text=\"Test\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/create_account\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/create_account\"\n            app:icon=\"@drawable/ic_baseline_add_24\" />\n    </LinearLayout>\n\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"10dp\"\n        android:layout_marginBottom=\"60dp\"\n        android:orientation=\"vertical\">\n\n        <EditText\n            android:id=\"@+id/login_username_input\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:autofillHints=\"username\"\n            android:hint=\"@string/example_username\"\n            android:inputType=\"text\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:nextFocusDown=\"@id/login_email_input\"\n            android:requiresFadingEdge=\"vertical\"\n            android:textColorHint=\"?attr/grayTextColor\"\n            tools:ignore=\"LabelFor\" />\n\n        <EditText\n            android:id=\"@+id/login_email_input\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:autofillHints=\"emailAddress\"\n            android:hint=\"@string/example_email\"\n            android:inputType=\"textEmailAddress\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n            android:nextFocusRight=\"@id/cancel_btt\"\n\n            android:nextFocusUp=\"@id/login_username_input\"\n            android:nextFocusDown=\"@id/login_server_input\"\n            android:requiresFadingEdge=\"vertical\"\n            android:textColorHint=\"?attr/grayTextColor\"\n            tools:ignore=\"LabelFor\" />\n\n        <EditText\n            android:id=\"@+id/login_server_input\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:autofillHints=\"no\"\n            android:hint=\"@string/example_ip\"\n            android:inputType=\"textUri\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:nextFocusUp=\"@id/login_email_input\"\n            android:nextFocusDown=\"@id/login_password_input\"\n            android:requiresFadingEdge=\"vertical\"\n            android:textColorHint=\"?attr/grayTextColor\"\n            tools:ignore=\"LabelFor\" />\n\n        <EditText\n            android:id=\"@+id/login_password_input\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:autofillHints=\"password\"\n            android:hint=\"@string/example_password\"\n            android:inputType=\"textPassword\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:nextFocusUp=\"@id/login_server_input\"\n            android:nextFocusDown=\"@id/apply_btt\"\n            android:requiresFadingEdge=\"vertical\"\n            android:textColorHint=\"?attr/grayTextColor\"\n            tools:ignore=\"LabelFor\" />\n    </LinearLayout>\n\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/login\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_cancel\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/add_remove_sites.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/add_site\"\n        android:text=\"@string/add_site_pref\"\n        android:focusable=\"true\"\n        style=\"@style/SettingsItem\">\n\n        <requestFocus />\n    </TextView>\n\n    <TextView\n        android:id=\"@+id/remove_site\"\n        android:text=\"@string/remove_site_pref\"\n        android:focusable=\"true\"\n        style=\"@style/SettingsItem\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/add_repo_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:id=\"@+id/text1\"\n            android:layout_weight=\"1\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_rowWeight=\"1\"\n            android:layout_gravity=\"center_vertical\"\n\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:text=\"@string/add_repository\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\" />\n\n<!--        <com.google.android.material.button.MaterialButton-->\n<!--            android:nextFocusDown=\"@id/repo_name_input\"-->\n<!--            android:id=\"@+id/list_repositories\"-->\n<!--            android:nextFocusLeft=\"@id/apply_btt\"-->\n<!--            android:nextFocusRight=\"@id/cancel_btt\"-->\n<!--            style=\"@style/WhiteButton\"-->\n<!--            android:layout_width=\"wrap_content\"-->\n<!--            android:layout_gravity=\"center_vertical\"-->\n<!--            android:text=\"@string/view_public_repositories_button_short\" />-->\n    </LinearLayout>\n\n    <TextView\n        android:id=\"@+id/text2\"\n        android:layout_width=\"match_parent\"\n\n        android:layout_height=\"wrap_content\"\n        android:layout_rowWeight=\"1\"\n        android:layout_gravity=\"center_vertical\"\n\n        android:layout_marginBottom=\"10dp\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:textColor=\"?attr/grayTextColor\"\n        android:textSize=\"15sp\"\n        android:visibility=\"gone\"\n        tools:text=\"Gogoanime\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"10dp\"\n        android:layout_marginBottom=\"60dp\"\n        android:orientation=\"vertical\">\n\n        <EditText\n            android:id=\"@+id/repo_name_input\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:autofillHints=\"username\"\n            android:hint=\"@string/repository_name_hint\"\n            android:inputType=\"text\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:nextFocusDown=\"@id/repo_url_input\"\n            android:requiresFadingEdge=\"vertical\"\n            android:textColorHint=\"?attr/grayTextColor\"\n            tools:ignore=\"LabelFor\" />\n\n        <EditText\n            android:id=\"@+id/repo_url_input\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:autofillHints=\"no\"\n            android:hint=\"@string/repository_url_hint\"\n            android:inputType=\"textUri\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:nextFocusUp=\"@id/repo_name_input\"\n            android:nextFocusDown=\"@id/apply_btt\"\n            android:requiresFadingEdge=\"vertical\"\n            android:textColorHint=\"?attr/grayTextColor\"\n            tools:ignore=\"LabelFor\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/add_repository\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_cancel\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/add_site_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    <TextView\n            android:layout_marginTop=\"20dp\"\n            android:layout_marginBottom=\"10dp\"\n            android:id=\"@+id/text1\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n\n            android:layout_gravity=\"center_vertical\"\n            android:layout_rowWeight=\"1\"\n\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\"\n            android:text=\"@string/add_site_pref\" />\n\n    <TextView\n            android:layout_marginBottom=\"10dp\"\n\n            android:id=\"@+id/text2\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n\n            android:layout_gravity=\"center_vertical\"\n            android:layout_rowWeight=\"1\"\n\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:textColor=\"?attr/grayTextColor\"\n            android:textSize=\"15sp\"\n            tools:text=\"Gogoanime\" />\n\n    <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_marginBottom=\"60dp\"\n            android:layout_marginHorizontal=\"10dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n        <EditText\n                android:textColorHint=\"?attr/grayTextColor\"\n                android:hint=\"@string/example_site_name\"\n                android:autofillHints=\"username\"\n                android:id=\"@+id/site_name_input\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusDown=\"@id/site_url_input\"\n                android:requiresFadingEdge=\"vertical\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"text\"\n                tools:ignore=\"LabelFor\" />\n\n        <EditText\n                android:textColorHint=\"?attr/grayTextColor\"\n                android:autofillHints=\"no\"\n                android:hint=\"@string/example_site_url\"\n                android:id=\"@+id/site_url_input\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusUp=\"@id/site_name_input\"\n                android:nextFocusDown=\"@id/site_lang_input\"\n\n                android:requiresFadingEdge=\"vertical\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"textUri\"\n                tools:ignore=\"LabelFor\" />\n\n        <EditText\n                android:textColorHint=\"?attr/grayTextColor\"\n                android:hint=\"@string/example_lang_name\"\n                android:autofillHints=\"username\"\n                android:id=\"@+id/site_lang_input\"\n                android:nextFocusUp=\"@id/site_url_input\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusDown=\"@id/apply_btt\"\n                android:requiresFadingEdge=\"vertical\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"text\"\n                tools:ignore=\"LabelFor\" />\n    </LinearLayout>\n\n    <LinearLayout\n            android:id=\"@+id/apply_btt_holder\"\n            android:orientation=\"horizontal\"\n            android:layout_gravity=\"bottom\"\n            android:gravity=\"bottom|end\"\n            android:layout_marginTop=\"-60dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"60dp\">\n\n        <com.google.android.material.button.MaterialButton\n                style=\"@style/WhiteButton\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/add_site_pref\"\n                android:id=\"@+id/apply_btt\"\n                android:layout_width=\"wrap_content\" />\n\n        <com.google.android.material.button.MaterialButton\n                style=\"@style/BlackButton\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/sort_cancel\"\n                android:id=\"@+id/cancel_btt\"\n                android:layout_width=\"wrap_content\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/bottom_input_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:nextFocusDown=\"@id/nginx_text_input\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_rowWeight=\"1\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:textColor=\"?attr/textColor\"\n        android:textSize=\"20sp\"\n        android:textStyle=\"bold\"\n        tools:text=\"Test\" />\n\n    <EditText\n        android:id=\"@+id/nginx_text_input\"\n        android:nextFocusRight=\"@id/cancel_btt\"\n        android:nextFocusLeft=\"@id/apply_btt\"\n        android:layout_marginBottom=\"60dp\"\n        android:layout_marginHorizontal=\"10dp\"\n        android:paddingTop=\"10dp\"\n        android:requiresFadingEdge=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_rowWeight=\"1\"\n        android:autofillHints=\"no\"\n        android:inputType=\"text\"\n        tools:text=\"nginx.com\"\n        tools:ignore=\"LabelFor\" />\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:orientation=\"horizontal\"\n        android:layout_gravity=\"bottom\"\n        android:gravity=\"bottom|end\"\n        android:layout_marginTop=\"-60dp\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\">\n\n        <com.google.android.material.button.MaterialButton\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_apply\"\n            android:id=\"@+id/apply_btt\"\n            style=\"@style/WhiteButton\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_cancel\"\n            android:id=\"@+id/cancel_btt\"\n            style=\"@style/BlackButton\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/bottom_loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <com.facebook.shimmer.ShimmerFrameLayout\n        android:id=\"@+id/home_loading_shimmer\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_margin=\"10dp\"\n        android:orientation=\"vertical\"\n        app:shimmer_auto_start=\"true\"\n        app:shimmer_base_alpha=\"0.2\"\n        app:shimmer_duration=\"@integer/loading_time\"\n        app:shimmer_highlight_alpha=\"0.3\">\n\n        <LinearLayout\n            android:layout_marginTop=\"5dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <include layout=\"@layout/loading_line_short\" />\n\n            <include layout=\"@layout/loading_line\" />\n\n            <include layout=\"@layout/loading_line\" />\n\n            <include layout=\"@layout/loading_line\" />\n        </LinearLayout>\n\n    </com.facebook.shimmer.ShimmerFrameLayout>\n\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/overlay_loading_skip_button\"\n        style=\"@style/BlackButton\"\n        android:layout_width=\"match_parent\"\n        android:backgroundTint=\"@color/transparent\"\n        android:text=\"@string/skip_loading\"\n        android:visibility=\"invisible\"\n        tools:visibility=\"visible\">\n\n        <requestFocus />\n    </com.google.android.material.button.MaterialButton>\n\n    <androidx.core.widget.ContentLoadingProgressBar\n        android:id=\"@+id/progressBar\"\n        style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"15dp\"\n        android:layout_gravity=\"center\"\n        android:layout_marginBottom=\"-6.5dp\"\n        android:indeterminate=\"true\"\n        android:indeterminateTint=\"?attr/colorPrimary\"\n        android:progressTint=\"?attr/colorPrimary\"\n        android:visibility=\"gone\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/bottom_resultview_preview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n\n    <LinearLayout\n        android:id=\"@+id/resultview_preview_result\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            android:padding=\"12dp\">\n\n            <androidx.cardview.widget.CardView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n                <ImageView\n                    android:id=\"@+id/resultview_preview_poster\"\n                    android:layout_width=\"88dp\"\n                    android:layout_height=\"138dp\"\n                    android:contentDescription=\"@string/poster_image\"\n                    android:scaleType=\"centerCrop\"\n                    tools:src=\"@drawable/example_poster\" />\n            </androidx.cardview.widget.CardView>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"138dp\"\n                android:layout_marginStart=\"10dp\"\n                android:orientation=\"vertical\">\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\">\n\n                    <TextView\n                        android:id=\"@+id/resultview_preview_title\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"start|center_vertical\"\n                        android:layout_weight=\"1\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"16sp\"\n                        android:textStyle=\"bold\"\n                        tools:text=\"The Perfect Run\" />\n\n                    <ImageView\n                        android:id=\"@+id/resultview_preview_subscribe\"\n                        android:layout_width=\"25dp\"\n                        android:layout_height=\"25dp\"\n                        android:layout_gravity=\"end|center_vertical\"\n\n                        android:layout_margin=\"5dp\"\n                        android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                        android:contentDescription=\"@string/subscribe_tooltip\"\n                        android:elevation=\"10dp\"\n                        android:nextFocusDown=\"@id/resultview_preview_bookmark\"\n                        android:src=\"@drawable/baseline_notifications_none_24\"\n                        app:tint=\"?attr/textColor\" />\n\n                    <ImageView\n                        android:id=\"@+id/resultview_preview_favorite\"\n                        android:layout_width=\"25dp\"\n                        android:layout_height=\"25dp\"\n                        android:layout_gravity=\"end|center_vertical\"\n\n                        android:layout_margin=\"5dp\"\n                        android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                        android:contentDescription=\"@string/favorite\"\n                        android:elevation=\"10dp\"\n                        android:nextFocusDown=\"@id/resultview_preview_bookmark\"\n                        android:src=\"@drawable/ic_baseline_favorite_border_24\"\n                        app:tint=\"?attr/textColor\" />\n\n                </LinearLayout>\n\n                <com.lagradost.cloudstream3.widget.FlowLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    app:itemSpacing=\"10dp\">\n\n                    <TextView\n                        android:id=\"@+id/resultview_preview_meta_type\"\n                        style=\"@style/ResultInfoText\"\n                        tools:text=\"Movie\" />\n\n                    <TextView\n                        android:id=\"@+id/resultview_preview_meta_year\"\n                        style=\"@style/ResultInfoText\"\n                        tools:text=\"2022\" />\n\n                    <TextView\n                        android:id=\"@+id/resultview_preview_meta_rating\"\n                        style=\"@style/ResultInfoText\"\n                        tools:text=\"Rated: 8.5/10.0\" />\n\n                    <TextView\n                        android:id=\"@+id/resultview_preview_meta_status\"\n                        style=\"@style/ResultInfoText\"\n                        tools:text=\"Ongoing\" />\n\n                    <TextView\n                        android:id=\"@+id/resultview_preview_meta_duration\"\n                        style=\"@style/ResultInfoText\"\n                        tools:text=\"121min\" />\n                </com.lagradost.cloudstream3.widget.FlowLayout>\n\n                <!-- <TextView\n                     android:id=\"@+id/resultview_preview_year\"\n                     android:layout_width=\"wrap_content\"\n                     android:layout_height=\"wrap_content\"\n\n                     android:textColor=\"?attr/grayTextColor\"\n                     tools:text=\"2023\" />-->\n\n                <FrameLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\">\n\n                    <TextView\n                        android:id=\"@+id/resultview_preview_description\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n\n                        android:ellipsize=\"end\"\n                        android:textColor=\"?attr/textColor\"\n                        tools:text=\"Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. \" />\n\n                    <View\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"20dp\"\n                        android:layout_gravity=\"bottom\"\n                        android:background=\"@drawable/background_shadow\" />\n                </FrameLayout>\n            </LinearLayout>\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            android:padding=\"7dp\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/resultview_preview_bookmark\"\n                style=\"@style/BlackButton\"\n                android:layout_width=\"50dp\"\n                android:layout_weight=\"1\"\n\n                android:nextFocusRight=\"@id/resultview_preview_more_info\"\n\n                android:nextFocusUp=\"@id/resultview_preview_favorite\"\n                app:icon=\"@drawable/ic_baseline_bookmark_24\"\n                tools:text=\"Bookmark\"\n\n                tools:visibility=\"visible\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/resultview_preview_more_info\"\n                style=\"@style/WhiteButton\"\n                android:layout_width=\"50dp\"\n                android:layout_weight=\"1\"\n\n                android:nextFocusLeft=\"@id/resultview_preview_bookmark\"\n\n                android:nextFocusUp=\"@id/resultview_preview_favorite\"\n                android:text=\"@string/home_more_info\"\n                app:icon=\"@drawable/ic_baseline_open_in_new_24\"\n\n                tools:visibility=\"visible\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <FrameLayout\n        android:id=\"@+id/resultview_preview_loading\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <com.facebook.shimmer.ShimmerFrameLayout\n            android:id=\"@+id/resultview_preview_loading_shimmer\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:orientation=\"vertical\"\n            app:shimmer_auto_start=\"true\"\n            app:shimmer_base_alpha=\"0.2\"\n            app:shimmer_duration=\"@integer/loading_time\"\n            app:shimmer_highlight_alpha=\"0.3\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginStart=\"@dimen/result_padding\"\n                    android:layout_marginTop=\"@dimen/result_padding\"\n\n                    android:layout_marginEnd=\"@dimen/result_padding\"\n                    android:orientation=\"horizontal\">\n\n                    <include layout=\"@layout/loading_poster\" />\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:orientation=\"vertical\"\n                        android:paddingStart=\"10dp\"\n                        android:paddingEnd=\"10dp\">\n\n                        <include layout=\"@layout/loading_line\" />\n\n                        <include layout=\"@layout/loading_line_short\" />\n\n                        <include layout=\"@layout/loading_line\" />\n\n                        <include layout=\"@layout/loading_line\" />\n\n                        <include layout=\"@layout/loading_line\" />\n                    </LinearLayout>\n                </LinearLayout>\n\n                <androidx.cardview.widget.CardView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"26dp\"\n                    android:layout_margin=\"@dimen/result_padding\"\n                    android:layout_marginBottom=\"@dimen/loading_margin\"\n                    android:background=\"@color/grayShimmer\"\n                    app:cardCornerRadius=\"@dimen/loading_radius\"\n                    tools:ignore=\"ContentDescription\" />\n            </LinearLayout>\n        </com.facebook.shimmer.ShimmerFrameLayout>\n    </FrameLayout>\n</FrameLayout>\n\n\n\n"
  },
  {
    "path": "app/src/main/res/layout/bottom_resultview_preview_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\r\n    xmlns:tools=\"http://schemas.android.com/tools\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"match_parent\"\r\n    android:layout_gravity=\"end\">\r\n\r\n    <LinearLayout\r\n        android:id=\"@+id/resultview_preview_result\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"match_parent\"\r\n        android:orientation=\"vertical\"\r\n        android:visibility=\"gone\"\r\n        tools:visibility=\"visible\">\r\n\r\n        <androidx.cardview.widget.CardView\r\n            android:layout_margin=\"15dp\"\r\n            android:layout_width=\"match_parent\"\r\n            android:layout_height=\"138dp\"\r\n            android:visibility=\"visible\"\r\n            app:cardCornerRadius=\"@dimen/rounded_image_radius\">\r\n\r\n            <ImageView\r\n                android:id=\"@+id/resultview_preview_poster\"\r\n                android:layout_width=\"match_parent\"\r\n                android:layout_height=\"match_parent\"\r\n                android:layout_gravity=\"center\"\r\n                android:adjustViewBounds=\"true\"\r\n                android:contentDescription=\"@string/poster_image\"\r\n                android:foregroundGravity=\"top\"\r\n                android:scaleType=\"centerCrop\"\r\n                tools:src=\"@drawable/example_poster\" />\r\n        </androidx.cardview.widget.CardView>\r\n\r\n        <LinearLayout\r\n            android:layout_width=\"match_parent\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:orientation=\"horizontal\"\r\n            android:padding=\"10dp\">\r\n\r\n            <LinearLayout\r\n                android:layout_width=\"match_parent\"\r\n                android:layout_height=\"178dp\"\r\n                android:layout_marginStart=\"10dp\"\r\n                android:orientation=\"vertical\">\r\n\r\n                <LinearLayout\r\n                    android:layout_width=\"match_parent\"\r\n                    android:layout_height=\"wrap_content\">\r\n\r\n                    <TextView\r\n                        android:id=\"@+id/resultview_preview_title\"\r\n                        android:layout_width=\"0dp\"\r\n                        android:layout_height=\"wrap_content\"\r\n                        android:layout_gravity=\"start|center_vertical\"\r\n                        android:layout_weight=\"1\"\r\n                        android:textColor=\"?attr/textColor\"\r\n                        android:textSize=\"16sp\"\r\n                        android:textStyle=\"bold\"\r\n                        tools:text=\"The Perfect Run\" />\r\n\r\n                    <ImageView\r\n                        android:id=\"@+id/resultview_preview_subscribe\"\r\n                        android:layout_width=\"25dp\"\r\n                        android:layout_height=\"25dp\"\r\n                        android:layout_gravity=\"end|center_vertical\"\r\n\r\n                        android:layout_margin=\"5dp\"\r\n                        android:background=\"?android:attr/selectableItemBackgroundBorderless\"\r\n                        android:contentDescription=\"@string/subscribe_tooltip\"\r\n                        android:elevation=\"10dp\"\r\n                        android:nextFocusRight=\"@id/resultview_preview_favorite\"\r\n                        android:nextFocusDown=\"@id/resultview_preview_bookmark\"\r\n                        android:src=\"@drawable/baseline_notifications_none_24\"\r\n                        app:tint=\"?attr/textColor\" />\r\n\r\n                    <ImageView\r\n                        android:id=\"@+id/resultview_preview_favorite\"\r\n                        android:layout_width=\"25dp\"\r\n                        android:layout_height=\"25dp\"\r\n                        android:layout_gravity=\"end|center_vertical\"\r\n\r\n                        android:layout_margin=\"5dp\"\r\n                        android:background=\"?android:attr/selectableItemBackgroundBorderless\"\r\n                        android:contentDescription=\"@string/favorite\"\r\n                        android:elevation=\"10dp\"\r\n                        android:nextFocusLeft=\"@id/resultview_preview_subscribe\"\r\n                        android:nextFocusDown=\"@id/resultview_preview_bookmark\"\r\n                        android:src=\"@drawable/ic_baseline_favorite_border_24\"\r\n                        app:tint=\"?attr/textColor\" />\r\n\r\n                </LinearLayout>\r\n\r\n                <com.lagradost.cloudstream3.widget.FlowLayout\r\n                    android:layout_width=\"match_parent\"\r\n                    android:layout_height=\"wrap_content\"\r\n                    app:itemSpacing=\"10dp\">\r\n\r\n                    <TextView\r\n                        android:id=\"@+id/resultview_preview_meta_type\"\r\n                        style=\"@style/ResultInfoText\"\r\n                        tools:text=\"Movie\" />\r\n\r\n                    <TextView\r\n                        android:id=\"@+id/resultview_preview_meta_year\"\r\n                        style=\"@style/ResultInfoText\"\r\n                        tools:text=\"2022\" />\r\n\r\n                    <TextView\r\n                        android:id=\"@+id/resultview_preview_meta_rating\"\r\n                        style=\"@style/ResultInfoText\"\r\n                        tools:text=\"Rated: 8.5/10.0\" />\r\n\r\n                    <TextView\r\n                        android:id=\"@+id/resultview_preview_meta_status\"\r\n                        style=\"@style/ResultInfoText\"\r\n                        tools:text=\"Ongoing\" />\r\n\r\n                    <TextView\r\n                        android:id=\"@+id/resultview_preview_meta_duration\"\r\n                        style=\"@style/ResultInfoText\"\r\n                        tools:text=\"121min\" />\r\n                </com.lagradost.cloudstream3.widget.FlowLayout>\r\n\r\n                <!-- <TextView\r\n                     android:id=\"@+id/resultview_preview_year\"\r\n                     android:layout_width=\"wrap_content\"\r\n                     android:layout_height=\"wrap_content\"\r\n\r\n                     android:textColor=\"?attr/grayTextColor\"\r\n                     tools:text=\"2023\" />-->\r\n\r\n                <FrameLayout\r\n                    android:layout_width=\"match_parent\"\r\n                    android:layout_height=\"match_parent\">\r\n\r\n                    <TextView\r\n                        android:id=\"@+id/resultview_preview_description\"\r\n                        android:layout_width=\"wrap_content\"\r\n                        android:layout_height=\"wrap_content\"\r\n\r\n                        android:ellipsize=\"end\"\r\n                        android:textColor=\"?attr/textColor\"\r\n                        tools:text=\"Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. \" />\r\n\r\n                    <View\r\n                        android:layout_width=\"match_parent\"\r\n                        android:layout_height=\"20dp\"\r\n                        android:layout_gravity=\"bottom\"\r\n                        android:background=\"@drawable/background_shadow\" />\r\n                </FrameLayout>\r\n            </LinearLayout>\r\n        </LinearLayout>\r\n\r\n        <LinearLayout\r\n            android:layout_width=\"match_parent\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:orientation=\"vertical\"\r\n\r\n            android:layout_margin=\"10dp\">\r\n\r\n            <com.google.android.material.button.MaterialButton\r\n                android:id=\"@+id/resultview_preview_bookmark\"\r\n                style=\"@style/BlackButton\"\r\n                android:layout_width=\"match_parent\"\r\n                android:layout_marginBottom=\"10dp\"\r\n                android:layout_weight=\"1\"\r\n                android:nextFocusUp=\"@id/resultview_preview_favorite\"\r\n                android:nextFocusDown=\"@id/resultview_preview_more_info\"\r\n\r\n                app:icon=\"@drawable/ic_baseline_bookmark_24\"\r\n                tools:text=\"Bookmark\">\r\n\r\n                <requestFocus />\r\n            </com.google.android.material.button.MaterialButton>\r\n\r\n            <com.google.android.material.button.MaterialButton\r\n                android:id=\"@+id/resultview_preview_more_info\"\r\n                style=\"@style/WhiteButton\"\r\n                android:layout_width=\"match_parent\"\r\n                android:layout_weight=\"1\"\r\n                android:nextFocusUp=\"@id/resultview_preview_bookmark\"\r\n                android:text=\"@string/home_more_info\"\r\n                app:icon=\"@drawable/ic_baseline_open_in_new_24\" />\r\n        </LinearLayout>\r\n\r\n    </LinearLayout>\r\n\r\n    <FrameLayout\r\n        android:id=\"@+id/resultview_preview_loading\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"match_parent\"\r\n        android:visibility=\"gone\"\r\n        tools:visibility=\"visible\">\r\n\r\n        <com.facebook.shimmer.ShimmerFrameLayout\r\n            android:id=\"@+id/resultview_preview_loading_shimmer\"\r\n            android:layout_width=\"match_parent\"\r\n            android:layout_height=\"match_parent\"\r\n            android:layout_gravity=\"center\"\r\n            android:orientation=\"vertical\"\r\n            app:shimmer_auto_start=\"true\"\r\n            app:shimmer_base_alpha=\"0.2\"\r\n            app:shimmer_duration=\"@integer/loading_time\"\r\n            app:shimmer_highlight_alpha=\"0.3\">\r\n\r\n            <LinearLayout\r\n                android:layout_width=\"match_parent\"\r\n                android:layout_height=\"wrap_content\"\r\n                android:orientation=\"vertical\">\r\n\r\n                <androidx.cardview.widget.CardView\r\n                    android:layout_width=\"match_parent\"\r\n                    android:layout_height=\"138dp\"\r\n\r\n                    android:layout_marginStart=\"@dimen/result_padding\"\r\n                    android:layout_marginTop=\"@dimen/result_padding\"\r\n                    android:layout_marginEnd=\"@dimen/result_padding\"\r\n                    android:background=\"@color/grayShimmer\"\r\n                    app:cardCornerRadius=\"@dimen/loading_radius\"\r\n                    tools:ignore=\"ContentDescription\" />\r\n\r\n                <LinearLayout\r\n                    android:layout_width=\"match_parent\"\r\n                    android:layout_height=\"wrap_content\"\r\n                    android:layout_marginStart=\"@dimen/result_padding\"\r\n                    android:layout_marginTop=\"@dimen/result_padding\"\r\n\r\n                    android:layout_marginEnd=\"@dimen/result_padding\"\r\n                    android:orientation=\"horizontal\">\r\n\r\n\r\n                    <LinearLayout\r\n                        android:layout_width=\"match_parent\"\r\n                        android:layout_height=\"match_parent\"\r\n                        android:orientation=\"vertical\"\r\n                        android:paddingStart=\"10dp\"\r\n                        android:paddingEnd=\"10dp\">\r\n\r\n                        <include layout=\"@layout/loading_line\" />\r\n\r\n                        <include layout=\"@layout/loading_line_short\" />\r\n\r\n                        <include layout=\"@layout/loading_line\" />\r\n\r\n                        <include layout=\"@layout/loading_line\" />\r\n\r\n                        <include layout=\"@layout/loading_line\" />\r\n\r\n                        <include layout=\"@layout/loading_line\" />\r\n                    </LinearLayout>\r\n                </LinearLayout>\r\n\r\n                <androidx.cardview.widget.CardView\r\n                    android:layout_width=\"match_parent\"\r\n                    android:layout_height=\"26dp\"\r\n                    android:layout_margin=\"@dimen/result_padding\"\r\n                    android:layout_marginBottom=\"@dimen/loading_margin\"\r\n                    android:background=\"@color/grayShimmer\"\r\n                    app:cardCornerRadius=\"@dimen/loading_radius\"\r\n                    tools:ignore=\"ContentDescription\" />\r\n\r\n                <androidx.cardview.widget.CardView\r\n                    android:layout_width=\"match_parent\"\r\n                    android:layout_height=\"26dp\"\r\n                    android:layout_margin=\"@dimen/result_padding\"\r\n                    android:layout_marginBottom=\"@dimen/loading_margin\"\r\n                    android:background=\"@color/grayShimmer\"\r\n                    app:cardCornerRadius=\"@dimen/loading_radius\"\r\n                    tools:ignore=\"ContentDescription\" />\r\n            </LinearLayout>\r\n        </com.facebook.shimmer.ShimmerFrameLayout>\r\n    </FrameLayout>\r\n</FrameLayout>\r\n\r\n\r\n\r\n"
  },
  {
    "path": "app/src/main/res/layout/bottom_selection_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"10dp\">\n\n        <com.google.android.material.bottomsheet.BottomSheetDragHandleView\n            android:id=\"@+id/drag_handle\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:visibility=\"gone\" />\n\n        <TextView\n            android:id=\"@+id/text1\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"30dp\"\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:textStyle=\"bold\"\n            android:textSize=\"20sp\"\n            android:textColor=\"?attr/textColor\"\n            tools:text=\"Test\" />\n    </FrameLayout>\n\n    <ListView\n        android:id=\"@+id/listview1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:paddingTop=\"10dp\"\n        android:dividerHeight=\"1dp\"\n        android:requiresFadingEdge=\"vertical\"\n        android:nextFocusRight=\"@id/cancel_btt\"\n        android:nextFocusLeft=\"@id/apply_btt\"\n        tools:listitem=\"@layout/sort_bottom_single_choice\" />\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:gravity=\"center_vertical|end\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_apply\"\n            style=\"@style/WhiteButton\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_cancel\"\n            style=\"@style/BlackButton\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/bottom_selection_dialog_direct.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_rowWeight=\"1\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:textColor=\"?attr/textColor\"\n        android:textSize=\"20sp\"\n        android:textStyle=\"bold\"\n        tools:text=\"Test\" />\n\n    <ListView\n        android:id=\"@+id/listview1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_rowWeight=\"1\"\n        android:layout_marginBottom=\"60dp\"\n        android:nestedScrollingEnabled=\"true\"\n        android:nextFocusLeft=\"@id/apply_btt\"\n        android:nextFocusRight=\"@id/cancel_btt\"\n        android:paddingTop=\"10dp\"\n        android:requiresFadingEdge=\"vertical\"\n        tools:listitem=\"@layout/sort_bottom_single_choice_no_checkmark\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/bottom_text_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/dialog_title\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:layout_marginTop=\"20dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:textStyle=\"bold\"\n        android:textSize=\"20sp\"\n        android:textColor=\"?attr/textColor\"\n        android:layout_width=\"match_parent\"\n        android:layout_rowWeight=\"1\"\n        tools:text=\"Test\"\n        android:layout_height=\"wrap_content\" />\n\n    <TextView\n        android:id=\"@+id/dialog_text\"\n        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:paddingTop=\"10dp\"\n        android:requiresFadingEdge=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_rowWeight=\"1\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/cast_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n\n    android:id=\"@+id/episode_holder\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"5dp\"\n    android:focusable=\"true\"\n    android:foreground=\"@drawable/outline_drawable\"\n    app:cardBackgroundColor=\"@color/transparent\"\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n    app:cardElevation=\"0dp\">\n\n    <LinearLayout\n        android:layout_width=\"100dp\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:padding=\"5dp\">\n        <!--app:cardCornerRadius=\"@dimen/roundedImageRadius\"-->\n        <FrameLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\">\n\n            <androidx.cardview.widget.CardView\n                android:id=\"@+id/voice_actor_image_holder\"\n                android:layout_width=\"70dp\"\n                android:layout_height=\"70dp\"\n                android:layout_gravity=\"end|bottom\"\n                android:layout_marginStart=\"10dp\"\n                android:layout_marginTop=\"5dp\"\n                android:alpha=\"0.2\"\n                android:foreground=\"@drawable/outline_drawable\"\n                app:cardCornerRadius=\"35dp\">\n\n                <ImageView\n                    android:id=\"@+id/voice_actor_image\"\n                    android:layout_width=\"match_parent\"\n\n                    android:layout_height=\"match_parent\"\n                    android:contentDescription=\"@string/episode_poster_img_des\"\n                    android:foreground=\"@drawable/outline_big_35_gray\"\n                    android:scaleType=\"centerCrop\"\n                    tools:src=\"@drawable/profile_bg_blue\" />\n            </androidx.cardview.widget.CardView>\n\n            <androidx.cardview.widget.CardView\n                android:layout_width=\"70dp\"\n                android:layout_height=\"70dp\"\n                android:foreground=\"@drawable/outline_drawable\"\n                app:cardCornerRadius=\"35dp\">\n\n                <ImageView\n                    android:id=\"@+id/actor_image\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:contentDescription=\"@string/episode_poster_img_des\"\n                    android:foreground=\"@drawable/outline_big_35_gray\"\n                    android:scaleType=\"centerCrop\"\n                    tools:src=\"@drawable/example_poster\" />\n\n            </androidx.cardview.widget.CardView>\n        </FrameLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:gravity=\"center_horizontal\"\n            android:orientation=\"vertical\"\n            android:paddingTop=\"3dp\"\n            android:paddingBottom=\"3dp\">\n\n            <TextView\n                android:id=\"@+id/actor_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_horizontal\"\n                android:textColor=\"?attr/textColor\"\n                android:textStyle=\"bold\"\n                tools:text=\"Ackerman, Mikasa\" />\n\n            <TextView\n                android:id=\"@+id/voice_actor_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_horizontal\"\n                android:textColor=\"?attr/grayTextColor\"\n                tools:text=\"voiceactor\" />\n\n            <TextView\n                android:id=\"@+id/actor_extra\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_horizontal\"\n                android:textColor=\"?attr/grayTextColor\"\n                tools:text=\"Main\" />\n\n        </LinearLayout>\n\n    </LinearLayout>\n</androidx.cardview.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/chromecast_subtitle_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/subs_root\"\n    android:background=\"?attr/primaryBlackBackground\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:paddingStart=\"20dp\"\n                android:paddingEnd=\"20dp\"\n                android:layout_marginTop=\"20dp\"\n                android:layout_marginBottom=\"10dp\"\n                android:textStyle=\"bold\"\n                android:text=\"@string/chromecast_subtitles_settings\"\n                android:textSize=\"20sp\"\n                android:textColor=\"?attr/textColor\"\n                android:layout_width=\"match_parent\"\n                android:layout_rowWeight=\"1\"\n                android:layout_height=\"wrap_content\" />\n\n            <FrameLayout\n                android:visibility=\"gone\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"75sp\">\n\n                <ImageView\n                    android:scaleType=\"centerCrop\"\n                    android:src=\"@drawable/subtitles_preview_background\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:contentDescription=\"@string/preview_background_img_des\" />\n\n                <androidx.media3.ui.SubtitleView\n                    android:id=\"@+id/subtitle_text\"\n\n                    android:layout_width=\"match_parent\"\n                    android:layout_gravity=\"center\"\n                    android:foregroundGravity=\"center\"\n                    android:layout_height=\"match_parent\" />\n            </FrameLayout>\n\n            <TextView\n                android:nextFocusDown=\"@id/subs_font_size\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:id=\"@+id/subs_font\"\n                android:text=\"@string/subs_font\"\n                style=\"@style/SettingsItem\" />\n\n            <TextView\n                android:nextFocusUp=\"@id/subs_font\"\n                android:nextFocusDown=\"@id/subs_text_color\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:id=\"@+id/subs_font_size\"\n                android:text=\"@string/subs_font_size\"\n                style=\"@style/SettingsItem\" />\n\n            <TextView\n                android:nextFocusUp=\"@id/subs_font_size\"\n                android:nextFocusDown=\"@id/subs_outline_color\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:id=\"@+id/subs_text_color\"\n                android:text=\"@string/subs_text_color\"\n                style=\"@style/SettingsItem\" />\n\n            <TextView\n                android:nextFocusUp=\"@id/subs_text_color\"\n                android:nextFocusDown=\"@id/subs_background_color\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:id=\"@+id/subs_outline_color\"\n                android:text=\"@string/subs_outline_color\"\n                style=\"@style/SettingsItem\" />\n\n            <TextView\n                android:nextFocusUp=\"@id/subs_outline_color\"\n                android:nextFocusDown=\"@id/subs_window_color\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:id=\"@+id/subs_background_color\"\n                android:text=\"@string/subs_background_color\"\n                style=\"@style/SettingsItem\" />\n\n            <TextView\n                android:visibility=\"gone\"\n                android:nextFocusUp=\"@id/subs_background_color\"\n                android:nextFocusDown=\"@id/subs_edge_type\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:id=\"@+id/subs_window_color\"\n                android:text=\"@string/subs_window_color\"\n                style=\"@style/SettingsItem\" />\n\n            <TextView\n                android:nextFocusUp=\"@id/subs_window_color\"\n                android:nextFocusDown=\"@id/apply_btt\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:id=\"@+id/subs_edge_type\"\n                android:text=\"@string/subs_edge_type\"\n                style=\"@style/SettingsItem\" />\n\n            <TextView\n                android:gravity=\"center\"\n                android:text=\"@string/subs_hold_to_reset_to_default\"\n                android:textSize=\"14sp\"\n\n                android:textColor=\"?attr/textColor\"\n                android:layout_width=\"match_parent\"\n                android:layout_rowWeight=\"1\"\n                android:layout_height=\"wrap_content\" />\n\n            <LinearLayout\n                android:orientation=\"horizontal\"\n                android:layout_gravity=\"bottom\"\n                android:gravity=\"bottom|end\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"60dp\">\n\n                <com.google.android.material.button.MaterialButton\n                    android:nextFocusUp=\"@id/subs_edge_type\"\n                    android:nextFocusRight=\"@id/cancel_btt\"\n                    style=\"@style/WhiteButton\"\n                    android:layout_gravity=\"center_vertical|end\"\n                    android:visibility=\"visible\"\n                    android:text=\"@string/sort_apply\"\n                    android:id=\"@+id/apply_btt\"\n                    android:layout_width=\"wrap_content\">\n\n                    <requestFocus />\n                </com.google.android.material.button.MaterialButton>\n\n                <com.google.android.material.button.MaterialButton\n                    android:nextFocusUp=\"@id/subs_edge_type\"\n                    android:nextFocusLeft=\"@id/apply_btt\"\n                    style=\"@style/BlackButton\"\n                    android:layout_gravity=\"center_vertical|end\"\n                    android:text=\"@string/sort_cancel\"\n                    android:id=\"@+id/cancel_btt\"\n                    android:layout_width=\"wrap_content\" />\n            </LinearLayout>\n        </LinearLayout>\n    </ScrollView>\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/confirm_exit_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:paddingHorizontal=\"16dp\"\n    android:paddingVertical=\"8dp\">\n\n    <CheckBox\n        android:id=\"@+id/checkboxDontShowAgain\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/dont_show_again\"\n        android:textColor=\"?attr/grayTextColor\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/custom_preference_category_material.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2015 The Android Open Source Project\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n    android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n    android:background=\"@drawable/outline_drawable_less\"\n    android:baselineAligned=\"false\"\n    android:layout_marginTop=\"16dp\"\n    android:gravity=\"center_vertical\">\n\n    <include layout=\"@layout/image_frame\"/>\n\n    <RelativeLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:paddingTop=\"8dp\"\n        android:paddingBottom=\"8dp\">\n\n        <TextView\n            android:id=\"@android:id/title\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"start\"\n            android:textAlignment=\"viewStart\"\n            style=\"@style/PreferenceCategoryTitleTextStyle\"/>\n\n        <TextView\n            android:id=\"@android:id/summary\"\n            android:ellipsize=\"end\"\n            android:singleLine=\"true\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@android:id/title\"\n            android:layout_alignStart=\"@android:id/title\"\n            android:layout_gravity=\"start\"\n            android:textAlignment=\"viewStart\"\n            android:textColor=\"?android:attr/textColorSecondary\"\n            android:maxLines=\"10\"\n            style=\"@style/PreferenceSummaryTextStyle\"/>\n\n    </RelativeLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/custom_preference_material.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2015 The Android Open Source Project\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:gravity=\"center_vertical\"\n    android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n    android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n    android:background=\"?attr/focusBackground\"\n    android:clipToPadding=\"false\"\n    android:baselineAligned=\"false\">\n\n    <include layout=\"@layout/image_frame\"/>\n\n    <RelativeLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:paddingTop=\"16dp\"\n        android:paddingBottom=\"16dp\">\n\n        <TextView\n            android:id=\"@android:id/title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:singleLine=\"true\"\n            android:textAppearance=\"?android:attr/textAppearanceListItem\"\n            android:ellipsize=\"marquee\"/>\n\n        <TextView\n            android:id=\"@android:id/summary\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@android:id/title\"\n            android:layout_alignStart=\"@android:id/title\"\n            android:layout_gravity=\"start\"\n            android:textAlignment=\"viewStart\"\n            android:textColor=\"?android:attr/textColorSecondary\"\n            android:maxLines=\"10\"\n            style=\"@style/PreferenceSummaryTextStyle\"/>\n\n    </RelativeLayout>\n\n    <!-- Preference should place its actual preference widget here. -->\n    <LinearLayout\n        android:id=\"@android:id/widget_frame\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"end|center_vertical\"\n        android:paddingStart=\"16dp\"\n        android:paddingEnd=\"0dp\"\n        android:orientation=\"vertical\"/>\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/custom_preference_widget_seekbar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--\n  ~ Copyright (C) 2018 The Android Open Source Project\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~      http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<!-- Layout used by SeekBarPreference for the seekbar widget style. -->\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:gravity=\"center_vertical\"\n    android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n    android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n    android:background=\"?attr/focusBackground\"\n    android:clipChildren=\"false\"\n    android:clipToPadding=\"false\"\n    android:baselineAligned=\"false\">\n\n    <include layout=\"@layout/image_frame\"/>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:layout_marginTop=\"8dp\"\n        android:layout_marginBottom=\"8dp\"\n        android:clipChildren=\"false\"\n        android:clipToPadding=\"false\">\n\n        <RelativeLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\">\n\n            <TextView\n                android:id=\"@android:id/title\"\n                android:labelFor=\"@id/seekbar\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:ellipsize=\"marquee\"\n                tools:ignore=\"LabelFor\" />\n\n            <TextView\n                android:id=\"@android:id/summary\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_below=\"@android:id/title\"\n                android:layout_alignStart=\"@android:id/title\"\n                android:layout_gravity=\"start\"\n                android:textAlignment=\"viewStart\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:maxLines=\"4\"\n                style=\"@style/PreferenceSummaryTextStyle\"/>\n\n        </RelativeLayout>\n\n        <!-- Using UnPressableLinearLayout as a workaround to disable the pressed state propagation\n        to the children of this container layout. Otherwise, the animated pressed state will also\n        play for the thumb in the AbsSeekBar in addition to the preference's ripple background.\n        The background of the SeekBar is also set to null to disable the ripple background -->\n        <androidx.preference.UnPressableLinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:paddingStart=\"0dp\"\n            android:paddingEnd=\"16dp\"\n            android:clipChildren=\"false\"\n            android:clipToPadding=\"false\">\n\n            <!-- The total height of the Seekbar widget's area should be 48dp - this allows for an\n            increased touch area so you do not need to exactly tap the thumb to move it. However,\n            setting the Seekbar height directly causes the thumb and seekbar to be misaligned on\n            API 22 and 23 - so instead we just set 15dp padding above and below, to account for the\n            18dp default height of the Seekbar thumb for a total of 48dp.\n            Note: we set 0dp padding at the start and end of this seekbar to allow it to properly\n            fit into the layout, but this means that there's no leeway on either side for touch\n            input - this might be something we should reconsider down the line. -->\n            <SeekBar\n                android:id=\"@+id/seekbar\"\n                android:layout_width=\"0dp\"\n                android:layout_weight=\"1\"\n                android:layout_height=\"wrap_content\"\n                android:paddingStart=\"@dimen/preference_seekbar_padding_horizontal\"\n                android:paddingEnd=\"@dimen/preference_seekbar_padding_horizontal\"\n                android:paddingTop=\"@dimen/preference_seekbar_padding_vertical\"\n                android:paddingBottom=\"@dimen/preference_seekbar_padding_vertical\"\n                android:background=\"@null\"/>\n\n            <!-- If the value is shown, we reserve a minimum width of 36dp to allow for consistent\n            seekbar width for smaller values. If the value is ~4 or more digits, it will expand\n            into the seekbar width. -->\n            <TextView\n                android:id=\"@+id/seekbar_value\"\n                android:minWidth=\"@dimen/preference_seekbar_value_minWidth\"\n                android:paddingStart=\"8dp\"\n                android:paddingEnd=\"0dp\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"end\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:ellipsize=\"marquee\"\n                android:fadingEdge=\"horizontal\"\n                android:scrollbars=\"none\"/>\n\n        </androidx.preference.UnPressableLinearLayout>\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/device_auth.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/device_pin_code\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:layout_marginTop=\"10dp\"\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:textColor=\"?attr/colorPrimary\"\n            android:textSize=\"30sp\"\n            android:textStyle=\"bold\"\n            tools:text=\"YJTSKL\" />\n\n        <TextView\n            android:id=\"@+id/device_auth_message\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"20dp\"\n            android:layout_gravity=\"center_horizontal\"\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"17sp\"\n            tools:text=\"Visit simkl.com/pin on your smartphone or computer and enter the above code\" />\n\n        <ImageView\n            android:id=\"@+id/device_auth_qrcode\"\n            android:layout_marginTop=\"20dp\"\n            android:layout_width=\"200dp\"\n            android:layout_height=\"200dp\"\n            android:scaleType=\"fitCenter\"\n            android:adjustViewBounds=\"true\"\n            android:layout_gravity=\"center_horizontal\"\n            android:visibility=\"visible\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:contentDescription=\"@string/qr_image\"\n            tools:visibility=\"visible\"\n            tools:src=\"@drawable/example_qr\" />\n\n        <TextView\n            android:id=\"@+id/device_auth_validation_counter\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"20dp\"\n            android:layout_gravity=\"center_horizontal\"\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"17sp\"\n            tools:text=\"Code expires in 13m 2s\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/dialog_loading.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    <!--\n        <TextView android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n                  android:text=\"Loading...\" android:textColor=\"?attr/textColor\" android:textSize=\"20sp\"\n                  android:textStyle=\"bold\" android:layout_margin=\"10dp\"/>-->\n    <!--            style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n-->\n    <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/loading\"\n            android:layout_gravity=\"center\"\n            android:textColor=\"@color/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\"\n            android:layout_margin=\"10dp\" />\n\n    <ProgressBar\n            android:layout_margin=\"20dp\"\n\n            android:layout_gravity=\"center\"\n            android:layout_width=\"60dp\"\n            android:layout_height=\"60dp\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/dialog_online_subtitles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginBottom=\"60dp\"\n        android:baselineAligned=\"false\"\n        android:orientation=\"horizontal\">\n\n        <LinearLayout\n            android:id=\"@+id/sort_subtitles_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_weight=\"50\"\n            android:orientation=\"vertical\">\n\n            <!--   android:id=\"@+id/subs_settings\"                 android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n-->\n<!--\n-->\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                tools:ignore=\"UseCompoundDrawables\"\n                android:padding=\"10dp\">\n\n                    <FrameLayout\n                        android:layout_width=\"0dp\"\n                        android:layout_weight=\"1\"\n                        android:layout_height=\"30dp\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:layout_marginEnd=\"10dp\"\n                        android:background=\"@drawable/search_background\">\n\n                        <androidx.appcompat.widget.SearchView\n                            android:id=\"@+id/subtitles_search\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"match_parent\"\n                            android:layout_gravity=\"center_vertical\"\n\n                            android:imeOptions=\"actionSearch\"\n                            android:inputType=\"text\"\n\n                            android:paddingStart=\"-10dp\"\n                            android:paddingEnd=\"10dp\"\n                            app:iconifiedByDefault=\"false\"\n\n                            app:queryBackground=\"@color/transparent\"\n                            app:queryHint=\"@string/search_hint\"\n                            app:searchIcon=\"@drawable/search_icon\"\n                            tools:ignore=\"RtlSymmetry\">\n\n                            <!--app:queryHint=\"@string/search_hint\"\n                             android:background=\"@color/grayBackground\" @color/itemBackground\n                                        app:searchHintIcon=\"@drawable/search_white\"\n                                        -->\n                        </androidx.appcompat.widget.SearchView>\n                        <androidx.core.widget.ContentLoadingProgressBar\n                            android:id=\"@+id/search_loading_bar\"\n                            style=\"@style/Widget.AppCompat.ProgressBar\"\n                            android:layout_width=\"20dp\"\n                            android:layout_height=\"20dp\"\n                            android:layout_gravity=\"end|center_vertical\"\n                            android:foregroundTint=\"@color/white\"\n                            android:progressTint=\"@color/white\"\n                            android:visibility=\"visible\"\n                            tools:visibility=\"visible\">\n\n                        </androidx.core.widget.ContentLoadingProgressBar>\n                    </FrameLayout>\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/year_btt\"\n                        style=\"@style/WhiteButton\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"30dp\"\n                        android:layout_gravity=\"center_vertical|end\"\n                        android:nextFocusLeft=\"@id/subtitles_search\"\n                        android:nextFocusRight=\"@id/search_filter\"\n                        android:text=\"@string/none\" />\n                    <ImageView\n                        android:id=\"@+id/search_filter\"\n                        android:layout_width=\"25dp\"\n                        android:layout_height=\"25dp\"\n                        android:layout_gravity=\"end|center_vertical\"\n                        android:layout_margin=\"10dp\"\n                        android:background=\"?selectableItemBackgroundBorderless\"\n                        android:contentDescription=\"@string/change_providers_img_des\"\n                        android:focusable=\"true\"\n                        android:nextFocusLeft=\"@id/year_btt\"\n                        android:nextFocusRight=\"@id/main_search\"\n                        android:nextFocusUp=\"@id/nav_rail_view\"\n                        android:nextFocusDown=\"@id/search_autofit_results\"\n                        android:src=\"@drawable/ic_baseline_tune_24\"\n                        app:tint=\"?attr/textColor\" />\n\n            </LinearLayout>\n\n            <ListView\n                android:id=\"@+id/subtitle_adapter\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n\n                android:layout_rowWeight=\"1\"\n                android:background=\"?attr/primaryBlackBackground\"\n                android:nextFocusLeft=\"@id/sort_providers\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:requiresFadingEdge=\"vertical\"\n                tools:listfooter=\"@layout/sort_bottom_footer_add_choice\"\n                tools:listitem=\"@layout/sort_bottom_single_choice\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_apply\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_cancel\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/download_button.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.lagradost.cloudstream3.ui.download.button.DownloadButton\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/result_download_movie\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_gravity=\"center\"\n    app:download_layout=\"@layout/download_button_layout\" />"
  },
  {
    "path": "app/src/main/res/layout/download_button_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_gravity=\"center\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\">\n\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/download_movie_button\"\n        style=\"@style/BlackButton\"\n        android:layout_width=\"match_parent\"\n        android:layout_marginStart=\"0dp\"\n        android:layout_marginEnd=\"0dp\"\n        android:visibility=\"visible\" />\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\">\n\n        <include\n            layout=\"@layout/download_button_view\"\n            android:layout_width=\"30dp\"\n            android:layout_height=\"30dp\" />\n\n        <TextView\n            android:id=\"@+id/result_movie_download_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginStart=\"10dp\"\n            android:gravity=\"center\"\n            android:letterSpacing=\"0.09\"\n            android:textAllCaps=\"false\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"15sp\"\n            android:textStyle=\"bold\"\n            tools:text=\"Downloading\" />\n\n        <TextView\n            android:id=\"@+id/result_movie_download_text_precentage\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:gravity=\"center\"\n            android:letterSpacing=\"0.09\"\n            android:paddingStart=\"5dp\"\n            android:paddingEnd=\"5dp\"\n            android:textAllCaps=\"false\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"15sp\"\n            android:textStyle=\"bold\"\n            android:visibility=\"gone\"\n            tools:text=\"68%\"\n            tools:visibility=\"visible\" />\n    </LinearLayout>\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/download_button_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:background=\"@android:color/holo_blue_light\">\n\n    <androidx.core.widget.ContentLoadingProgressBar\n        android:id=\"@+id/progress_downloaded\"\n        style=\"?android:attr/progressBarStyleHorizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:indeterminate=\"false\"\n        android:max=\"100\"\n        android:progress=\"0\"\n\n        tools:progress=\"60\"\n        android:progressDrawable=\"@drawable/circular_progress_bar_top_to_bottom\"\n        android:visibility=\"visible\" />\n\n    <View\n        android:id=\"@+id/progress_downloaded_background\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@drawable/circle_shape_dotted\" />\n\n    <ImageView\n        android:scaleX=\"?attr/download_icon_scale\"\n        android:scaleY=\"?attr/download_icon_scale\"\n        tools:visibility=\"visible\"\n        android:id=\"@+id/image_download_status\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:src=\"@drawable/ic_baseline_play_arrow_24\"\n        android:visibility=\"visible\"\n        app:tint=\"?attr/download_icon_color\" />\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/download_child_episode.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/download_child_episode_holder\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"50dp\"\n    android:layout_marginBottom=\"5dp\"\n    android:foreground=\"@drawable/outline_drawable\"\n    android:focusable=\"true\"\n    android:nextFocusLeft=\"@id/nav_rail_view\"\n    android:nextFocusRight=\"@id/download_button\"\n    app:cardBackgroundColor=\"@color/transparent\"\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n    app:cardElevation=\"0dp\">\n\n<!--    <androidx.core.widget.ContentLoadingProgressBar-->\n<!--        android:id=\"@+id/download_child_episode_progress\"-->\n<!--        style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"-->\n<!--        android:layout_width=\"match_parent\"-->\n<!--        android:layout_height=\"5dp\"-->\n<!--        android:layout_gravity=\"bottom\"-->\n<!--        android:layout_marginBottom=\"-1.5dp\"-->\n<!--        android:progressBackgroundTint=\"?attr/colorPrimary\"-->\n<!--        android:progressTint=\"?attr/colorPrimary\"-->\n<!--        tools:progress=\"50\" />-->\n\n    <GridLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:foreground=\"?android:attr/selectableItemBackgroundBorderless\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\">\n\n            <FrameLayout\n                android:id=\"@+id/watch_progress_container\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"5dp\">\n\n                <ImageView\n                    android:id=\"@+id/download_child_episode_play\"\n                    style=\"@style/ContinueWatchingPlayUnderlayProgress\"\n                    android:layout_margin=\"4dp\"/>\n\n                <com.google.android.material.progressindicator.CircularProgressIndicator\n                    android:id=\"@+id/download_child_episode_progress\"\n                    style=\"@style/ContinueWatchingCircularProgress\"\n                    android:progress=\"50\"/>\n            </FrameLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginEnd=\"50dp\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/download_child_episode_text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:layout_marginEnd=\"10dp\"\n                android:ellipsize=\"marquee\"\n                android:gravity=\"center_vertical\"\n                android:marqueeRepeatLimit=\"marquee_forever\"\n                android:scrollHorizontally=\"true\"\n                android:singleLine=\"true\"\n                android:textColor=\"?attr/textColor\"\n                tools:text=\"Episode 1 Episode 1 Episode 1 Episode 1 Episode 1 Episode 1 Episode 1\" />\n\n            <TextView\n                android:id=\"@+id/download_child_episode_text_extra\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:layout_marginEnd=\"10dp\"\n                android:gravity=\"center_vertical\"\n                android:textColor=\"?attr/grayTextColor\"\n                tools:text=\"128MB / 237MB\" />\n        </LinearLayout>\n        </LinearLayout>\n        <com.lagradost.cloudstream3.ui.download.button.PieFetchButton\n            android:id=\"@+id/download_button\"\n            android:layout_width=\"@dimen/download_size\"\n            android:layout_height=\"@dimen/download_size\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:layout_marginStart=\"-50dp\"\n            android:foreground=\"@drawable/outline_drawable\"\n            android:focusable=\"true\"\n            android:nextFocusLeft=\"@id/download_child_episode_holder\"\n            android:padding=\"10dp\" />\n\n        <CheckBox\n            android:id=\"@+id/delete_checkbox\"\n            android:layout_width=\"@dimen/download_size\"\n            android:layout_height=\"@dimen/download_size\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:layout_marginStart=\"-50dp\"\n            android:focusable=\"true\"\n            android:nextFocusLeft=\"@id/download_child_episode_holder\"\n            android:padding=\"10dp\"\n            android:visibility=\"gone\" />\n    </GridLayout>\n</androidx.cardview.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/download_header_episode.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/episode_holder\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginStart=\"10dp\"\n    android:layout_marginTop=\"10dp\"\n    android:layout_marginEnd=\"10dp\"\n    android:foreground=\"@drawable/outline_drawable\"\n    android:focusable=\"true\"\n    android:nextFocusRight=\"@id/download_button\"\n    app:cardBackgroundColor=\"?attr/boxItemBackground\"\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n<!--    <androidx.core.widget.ContentLoadingProgressBar-->\n<!--        android:id=\"@+id/download_header_episode_progress\"-->\n<!--        style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"-->\n<!--        android:layout_width=\"match_parent\"-->\n<!--        android:layout_height=\"5dp\"-->\n<!--        android:layout_gravity=\"bottom\"-->\n<!--        android:layout_marginBottom=\"-1.5dp\"-->\n<!--        android:progressBackgroundTint=\"?attr/white\"-->\n<!--        android:progressTint=\"?attr/white\"-->\n<!--        tools:progress=\"50\" />-->\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n        android:orientation=\"horizontal\">\n        <!--app:cardCornerRadius=\"@dimen/roundedImageRadius\"-->\n        <androidx.cardview.widget.CardView\n            android:layout_width=\"70dp\"\n            android:layout_height=\"104dp\">\n\n            <ImageView\n                android:id=\"@+id/download_header_poster\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:contentDescription=\"@string/episode_poster_img_des\"\n                android:scaleType=\"centerCrop\"\n                tools:src=\"@drawable/example_poster\" />\n            <FrameLayout\n                android:id=\"@+id/watch_progress_container\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\">\n\n                <com.google.android.material.imageview.ShapeableImageView\n                    android:id=\"@+id/play_icon\"\n                    style=\"@style/DownloadHeaderPlayUnderlayProgress\"\n                    />\n                <com.google.android.material.progressindicator.CircularProgressIndicator\n                    android:id=\"@+id/download_header_episode_progress\"\n                    style=\"@style/DownloadHeaderCircularProgress\"\n                    tools:progress=\"100\" />\n            </FrameLayout>\n        </androidx.cardview.widget.CardView>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginStart=\"15dp\"\n            android:layout_marginEnd=\"70dp\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/download_header_title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?attr/textColor\"\n                android:textStyle=\"bold\"\n                tools:text=\"Perfect Run\" />\n\n            <TextView\n                android:id=\"@+id/download_header_info\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?attr/grayTextColor\"\n                tools:text=\"1 episode | 285MB\" />\n        </LinearLayout>\n\n        <ImageView\n            android:id=\"@+id/download_header_goto_child\"\n            android:layout_width=\"@dimen/download_size\"\n            android:layout_height=\"@dimen/download_size\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:layout_marginStart=\"-50dp\"\n            android:contentDescription=\"@string/download\"\n            android:padding=\"10dp\"\n            android:src=\"@drawable/ic_baseline_keyboard_arrow_right_24\" />\n\n        <com.lagradost.cloudstream3.ui.download.button.PieFetchButton\n            android:id=\"@+id/download_button\"\n            android:layout_width=\"@dimen/download_size\"\n            android:layout_height=\"@dimen/download_size\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:layout_marginStart=\"-50dp\"\n            android:foreground=\"@drawable/outline_drawable\"\n            android:focusable=\"true\"\n            android:nextFocusLeft=\"@id/episode_holder\"\n            android:padding=\"10dp\" />\n\n        <CheckBox\n            android:id=\"@+id/delete_checkbox\"\n            android:layout_width=\"@dimen/download_size\"\n            android:layout_height=\"@dimen/download_size\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:layout_marginStart=\"-50dp\"\n            android:focusable=\"true\"\n            android:nextFocusLeft=\"@id/episode_holder\"\n            android:padding=\"10dp\"\n            android:visibility=\"gone\" />\n    </LinearLayout>\n</androidx.cardview.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/download_queue_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:id=\"@+id/root_holder\"\n    android:layout_marginVertical=\"2.5dp\"\n    android:orientation=\"vertical\">\n\n    <androidx.cardview.widget.CardView\n        tools:visibility=\"visible\"\n        android:id=\"@+id/download_child_episode_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:focusable=\"true\"\n        android:foreground=\"@drawable/outline_drawable\"\n        android:nextFocusLeft=\"@id/nav_rail_view\"\n        android:nextFocusRight=\"@id/download_button\"\n        app:cardBackgroundColor=\"@color/transparent\"\n        app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n        app:cardElevation=\"0dp\">\n\n        <GridLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\">\n\n            <ImageView\n                android:id=\"@+id/download_child_episode_play\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:layout_marginEnd=\"10dp\"\n                android:contentDescription=\"@string/episode_play_img_des\"\n                android:src=\"@drawable/ic_baseline_play_arrow_24\"\n                android:visibility=\"gone\" />\n\n            <LinearLayout\n                android:gravity=\"center\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginEnd=\"50dp\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:id=\"@+id/download_child_episode_text\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginStart=\"10dp\"\n                    android:layout_marginEnd=\"10dp\"\n                    android:ellipsize=\"end\"\n                    android:gravity=\"center_vertical\"\n                    android:singleLine=\"true\"\n                    android:textColor=\"?attr/textColor\"\n                    tools:text=\"Episode 1 Episode 1 Episode 1 Episode 1 Episode 1 Episode 1 Episode 1\" />\n\n                <TextView\n                    android:id=\"@+id/download_child_episode_text_extra\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginStart=\"10dp\"\n                    android:layout_marginEnd=\"10dp\"\n                    android:gravity=\"center_vertical\"\n                    android:textColor=\"?attr/grayTextColor\"\n                    tools:text=\"One piece\" />\n            </LinearLayout>\n\n            <com.lagradost.cloudstream3.ui.download.button.PieFetchButton\n                android:id=\"@+id/download_button\"\n                android:layout_width=\"@dimen/download_size\"\n                android:layout_height=\"@dimen/download_size\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:layout_marginStart=\"-50dp\"\n                android:focusable=\"true\"\n                app:download_animate_waiting=\"true\"\n                android:foreground=\"@drawable/outline_drawable\"\n                android:nextFocusLeft=\"@id/download_child_episode_holder\"\n                android:padding=\"10dp\" />\n\n            <CheckBox\n                android:id=\"@+id/delete_checkbox\"\n                android:layout_width=\"@dimen/download_size\"\n                android:layout_height=\"@dimen/download_size\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:layout_marginStart=\"-50dp\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/download_child_episode_holder\"\n                android:padding=\"10dp\"\n                android:visibility=\"gone\" />\n        </GridLayout>\n    </androidx.cardview.widget.CardView>\n\n    <LinearLayout\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\"\n        android:id=\"@+id/separator_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:gravity=\"center\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"5dp\"\n            android:text=\"@string/parallel_downloads\">\n\n        </TextView>\n\n        <ImageView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"5dp\"\n            android:src=\"@drawable/dashed_line_horizontal\" />\n    </LinearLayout>\n\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/empty_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout \n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/nav_host_fragment\"\n        android:name=\"androidx.navigation.fragment.NavHostFragment\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        app:defaultNavHost=\"true\"\n        app:navGraph=\"@navigation/mobile_navigation\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintBottom_toBottomOf=\"parent\" />\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/extra_brightness_overlay.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<View xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/extra_brightness_overlay\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/white\"\n    android:alpha=\"0\"\n/>"
  },
  {
    "path": "app/src/main/res/layout/fragment_child_downloads.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/download_child_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:orientation=\"vertical\"\n    tools:context=\".ui.download.DownloadChildFragment\">\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"?attr/primaryGrayBackground\">\n\n        <LinearLayout\n            android:id=\"@+id/download_delete_appbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:padding=\"8dp\"\n            android:visibility=\"gone\">\n\n            <ImageButton\n                android:id=\"@+id/btnCancel\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"?attr/selectableItemBackground\"\n                android:src=\"@drawable/ic_baseline_close_24\"\n                android:contentDescription=\"@string/cancel\"\n                android:padding=\"8dp\"\n                android:layout_gravity=\"center_vertical\"\n                android:nextFocusLeft=\"@id/navigation_downloads\"\n                app:tint=\"?attr/white\" />\n\n            <Button\n                android:id=\"@+id/btnDelete\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"?attr/selectableItemBackground\"\n                android:text=\"@string/delete\"\n                android:textColor=\"?attr/white\"\n                android:layout_gravity=\"center_vertical\" />\n\n            <TextView\n                android:id=\"@+id/selectItemsText\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"?attr/selectableItemBackground\"\n                android:text=\"@string/downloads_delete_select\"\n                android:textColor=\"?attr/white\"\n                android:layout_gravity=\"center_vertical\"\n                android:visibility=\"gone\" />\n\n            <View\n                android:layout_width=\"0dp\"\n                android:layout_height=\"0dp\"\n                android:layout_weight=\"1\" />\n\n            <Button\n                android:id=\"@+id/btnToggleAll\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"?attr/selectableItemBackground\"\n                android:text=\"@string/select_all\"\n                android:textColor=\"?attr/white\"\n                android:layout_marginEnd=\"8dp\"\n                android:nextFocusDown=\"@id/download_child_list\" />\n        </LinearLayout>\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/download_child_toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:paddingTop=\"@dimen/navbar_height\"\n            app:layout_scrollFlags=\"scroll|enterAlways\"\n            app:navigationIconTint=\"?attr/iconColor\"\n            app:titleTextColor=\"?attr/textColor\"\n            tools:title=\"Overlord\" />\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/download_child_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:nextFocusLeft=\"@id/navigation_downloads\"\n        android:nextFocusUp=\"@id/download_child_toolbar\"\n        android:padding=\"10dp\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        tools:listitem=\"@layout/download_child_episode\" />\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_download_queue.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/download_queue_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryBlackBackground\">\n\n    <androidx.coordinatorlayout.widget.CoordinatorLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <com.google.android.material.appbar.AppBarLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@android:color/transparent\">\n\n            <com.google.android.material.appbar.MaterialToolbar\n                android:id=\"@+id/download_queue_toolbar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"?attr/primaryGrayBackground\"\n                android:paddingTop=\"@dimen/navbar_height\"\n                app:layout_scrollFlags=\"scroll|enterAlways\"\n                app:menu=\"@menu/download_queue\"\n                app:navigationIconTint=\"?attr/iconColor\"\n                app:titleTextColor=\"?attr/textColor\"\n                tools:title=\"Overlord\" />\n\n        </com.google.android.material.appbar.AppBarLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\"\n            app:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/download_queue_list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:nextFocusLeft=\"@id/navigation_downloads\"\n                android:nextFocusUp=\"@id/download_queue_toolbar\"\n                android:padding=\"10dp\"\n                app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                tools:listitem=\"@layout/download_queue_item\" />\n\n        </LinearLayout>\n\n    </androidx.coordinatorlayout.widget.CoordinatorLayout>\n\n    <TextView\n        android:id=\"@+id/text_no_queue\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:gravity=\"center\"\n        android:text=\"@string/queue_empty_message\"\n        android:visibility=\"visible\" />\n\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_downloads.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/download_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:orientation=\"vertical\"\n    tools:context=\".ui.download.DownloadFragment\">\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"?attr/primaryGrayBackground\">\n        <!--\n        For Scroll add to LinearLayout\n        app:layout_scrollFlags=\"scroll|enterAlways\"\n        -->\n        <LinearLayout\n            android:id=\"@+id/download_delete_appbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:padding=\"8dp\"\n            android:visibility=\"gone\">\n\n            <ImageButton\n                android:id=\"@+id/btnCancel\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"?attr/selectableItemBackground\"\n                android:src=\"@drawable/ic_baseline_close_24\"\n                android:contentDescription=\"@string/cancel\"\n                android:padding=\"8dp\"\n                android:layout_gravity=\"center_vertical\"\n                android:nextFocusLeft=\"@id/navigation_downloads\"\n                app:tint=\"?attr/white\" />\n\n            <Button\n                android:id=\"@+id/btnDelete\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"?attr/selectableItemBackground\"\n                android:text=\"@string/delete\"\n                android:textColor=\"?attr/white\"\n                android:layout_gravity=\"center_vertical\" />\n\n            <TextView\n                android:id=\"@+id/selectItemsText\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"?attr/selectableItemBackground\"\n                android:text=\"@string/downloads_delete_select\"\n                android:textColor=\"?attr/white\"\n                android:layout_gravity=\"center_vertical\"\n                android:visibility=\"gone\" />\n\n            <View\n                android:layout_width=\"0dp\"\n                android:layout_height=\"0dp\"\n                android:layout_weight=\"1\" />\n\n            <Button\n                android:id=\"@+id/btnToggleAll\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"?attr/selectableItemBackground\"\n                android:text=\"@string/select_all\"\n                android:textColor=\"?attr/white\"\n                android:layout_marginEnd=\"8dp\"\n                android:nextFocusDown=\"@id/download_list\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/download_appbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:baselineAligned=\"false\"\n            android:focusable=\"true\"\n            android:foreground=\"@drawable/outline_drawable\"\n            android:nextFocusLeft=\"@id/navigation_downloads\"\n            android:nextFocusRight=\"@id/download_stream_button_tv\"\n            android:nextFocusDown=\"@id/download_list\"\n            android:orientation=\"horizontal\">\n\n            <LinearLayout\n                android:id=\"@+id/download_storage_appbar\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"10dp\"\n                android:layout_weight=\"1\"\n                android:orientation=\"vertical\"\n                android:visibility=\"visible\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginBottom=\"5dp\"\n                    android:text=\"@string/download_storage_text\"\n                    android:textColor=\"?attr/textColor\" />\n\n                <com.facebook.shimmer.ShimmerFrameLayout\n                    android:id=\"@+id/download_loading_bytes\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"center\"\n                    android:orientation=\"vertical\"\n                    app:shimmer_auto_start=\"true\"\n                    app:shimmer_base_alpha=\"0.2\"\n                    app:shimmer_duration=\"@integer/loading_time\"\n                    app:shimmer_highlight_alpha=\"0.3\"\n                    tools:ignore=\"MissingClass\"\n                    tools:visibility=\"gone\">\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"vertical\">\n\n                        <include layout=\"@layout/loading_line\" />\n\n                        <include layout=\"@layout/loading_line_short\" />\n                    </LinearLayout>\n                </com.facebook.shimmer.ShimmerFrameLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/download_bytes_bar\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"vertical\"\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\">\n\n                    <androidx.cardview.widget.CardView\n                        android:layout_width=\"fill_parent\"\n                        android:layout_height=\"12dp\"\n                        android:layout_marginBottom=\"5dp\"\n                        android:elevation=\"0dp\"\n                        app:cardCornerRadius=\"@dimen/storage_radius\"\n                        app:cardElevation=\"0dp\"\n                        app:cardMaxElevation=\"0dp\">\n\n                        <LinearLayout\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"match_parent\"\n                            android:orientation=\"horizontal\">\n\n                            <View\n                                android:id=\"@+id/download_used\"\n                                android:layout_width=\"0dp\"\n                                android:layout_height=\"match_parent\"\n                                android:layout_weight=\"0.5\"\n                                android:background=\"@drawable/storage_bar_left\" />\n\n                            <View\n                                android:id=\"@+id/download_app\"\n                                android:layout_width=\"0dp\"\n                                android:layout_height=\"match_parent\"\n                                android:layout_weight=\"0.10\"\n                                android:background=\"@drawable/storage_bar_mid\" />\n\n                            <View\n                                android:id=\"@+id/download_free\"\n                                android:layout_width=\"0dp\"\n                                android:layout_height=\"match_parent\"\n                                android:layout_weight=\"0.10\"\n                                android:background=\"@drawable/storage_bar_right\" />\n                        </LinearLayout>\n                    </androidx.cardview.widget.CardView>\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"horizontal\">\n\n                        <View\n                            android:layout_width=\"10dp\"\n                            android:layout_height=\"10dp\"\n                            android:layout_gravity=\"center_vertical\"\n                            android:layout_marginTop=\"5dp\"\n                            android:layout_marginEnd=\"5dp\"\n                            android:layout_marginBottom=\"5dp\"\n                            android:background=\"@drawable/storage_bar_left_box\" />\n\n                        <TextView\n                            android:id=\"@+id/download_used_txt\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_gravity=\"center_vertical\"\n                            android:textColor=\"?attr/textColor\"\n                            android:textSize=\"12sp\"\n                            tools:text=\"Used • 30.58GB\" />\n\n                        <View\n                            android:layout_width=\"10dp\"\n                            android:layout_height=\"10dp\"\n                            android:layout_gravity=\"center_vertical\"\n                            android:layout_margin=\"5dp\"\n                            android:background=\"@drawable/storage_bar_mid_box\" />\n\n                        <TextView\n                            android:id=\"@+id/download_app_txt\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_gravity=\"center_vertical\"\n                            android:textColor=\"?attr/textColor\"\n                            android:textSize=\"12sp\"\n                            tools:text=\"App • 30.58GB\" />\n\n                        <View\n                            android:layout_width=\"10dp\"\n                            android:layout_height=\"10dp\"\n                            android:layout_gravity=\"center_vertical\"\n                            android:layout_margin=\"5dp\"\n                            android:background=\"@drawable/storage_bar_right_box\" />\n\n                        <TextView\n                            android:id=\"@+id/download_free_txt\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_gravity=\"center_vertical\"\n                            android:textColor=\"?attr/textColor\"\n                            android:textSize=\"12sp\"\n                            tools:text=\"Free • 30.58GB\" />\n                    </LinearLayout>\n                </LinearLayout>\n            </LinearLayout>\n\n            <LinearLayout\n\n                android:id=\"@+id/steam_imageview_holder\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:gravity=\"center\"\n                android:orientation=\"vertical\"\n                android:paddingStart=\"10dp\"\n                android:paddingEnd=\"10dp\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n\n                    android:layout_gravity=\"center\"\n                    android:text=\"@string/stream\"\n                    android:textColor=\"?attr/textColor\" />\n\n                <ImageView\n                    android:id=\"@+id/download_stream_button_tv\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"@drawable/outline_drawable\"\n\n                    android:contentDescription=\"@string/stream\"\n                    android:focusable=\"true\"\n                    android:nextFocusLeft=\"@id/download_appbar\"\n                    android:nextFocusDown=\"@id/download_list\"\n                    android:padding=\"8dp\"\n\n                    android:src=\"@drawable/ic_network_stream\"\n                    app:tint=\"?attr/textColor\"></ImageView>\n            </LinearLayout>\n        </LinearLayout>\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"?attr/primaryBlackBackground\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n        <com.facebook.shimmer.ShimmerFrameLayout\n            android:id=\"@+id/download_loading\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:paddingTop=\"20dp\"\n            app:shimmer_auto_start=\"true\"\n            app:shimmer_base_alpha=\"0.2\"\n            app:shimmer_duration=\"@integer/loading_time\"\n            app:shimmer_highlight_alpha=\"0.3\"\n            tools:visibility=\"gone\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"@dimen/loading_margin\"\n                android:layout_marginEnd=\"@dimen/loading_margin\"\n                android:orientation=\"vertical\">\n\n                <include layout=\"@layout/loading_downloads\" />\n                <include layout=\"@layout/loading_downloads\" />\n                <include layout=\"@layout/loading_downloads\" />\n                <include layout=\"@layout/loading_downloads\" />\n                <include layout=\"@layout/loading_downloads\" />\n                <include layout=\"@layout/loading_downloads\" />\n            </LinearLayout>\n        </com.facebook.shimmer.ShimmerFrameLayout>\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/download_list\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:paddingBottom=\"100dp\"\n            android:clipToPadding=\"false\"\n            android:descendantFocusability=\"afterDescendants\"\n            android:nextFocusUp=\"@id/download_appbar\"\n            android:nextFocusLeft=\"@id/navigation_downloads\"\n            android:nextFocusDown=\"@id/download_queue_button\"\n            android:tag=\"@string/tv_no_focus_tag\"\n            tools:listitem=\"@layout/download_header_episode\" />\n\n        <LinearLayout\n            android:focusable=\"true\"\n            android:nextFocusUp=\"@id/download_list\"\n            android:foreground=\"@drawable/outline_drawable\"\n            android:id=\"@+id/download_queue_button\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\"\n            android:layout_gravity=\"bottom\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:orientation=\"vertical\">\n\n            <ImageView\n                android:paddingTop=\"5dp\"\n                android:layout_width=\"20dp\"\n                android:layout_height=\"25dp\"\n                android:layout_gravity=\"center\"\n                android:src=\"@drawable/round_keyboard_arrow_up_24\" />\n\n            <TextView\n                android:id=\"@+id/download_queue_text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center\"\n                android:text=\"@string/download_queue\"\n                android:textColor=\"?attr/textColor\" />\n\n        </LinearLayout>\n\n        <TextView\n            android:id=\"@+id/text_no_downloads\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginBottom=\"30dp\"\n            android:text=\"@string/downloads_empty\"\n            android:gravity=\"center\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\" />\n    </FrameLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:layout_marginBottom=\"50dp\"\n        android:orientation=\"vertical\">\n\n        <com.google.android.material.floatingactionbutton.FloatingActionButton\n            android:id=\"@+id/open_local_video_button\"\n            style=\"?attr/floatingActionButtonSmallStyle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"bottom|end\"\n            android:layout_marginEnd=\"16dp\"\n            android:backgroundTint=\"?attr/primaryGrayBackground\"\n            android:contentDescription=\"@string/open_local_video\"\n            android:src=\"@drawable/netflix_play\"\n            app:tint=\"?attr/textColor\"\n            android:tooltipText=\"@string/open_local_video\" />\n\n        <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n            android:id=\"@+id/download_stream_button\"\n            style=\"@style/ExtendedFloatingActionButton\"\n            android:contentDescription=\"@string/stream\"\n            android:text=\"@string/stream\"\n            android:textColor=\"?attr/textColor\"\n            app:icon=\"@drawable/ic_network_stream\" />\n    </LinearLayout>\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_easter_egg_monke.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/frame\">\n\n    <androidx.appcompat.widget.AppCompatImageView\n        android:id=\"@+id/monke\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\" />\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_extensions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/extensions_root\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/standard_toolbar\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:clipToPadding=\"false\"\n        android:id=\"@+id/repo_recycler_view\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginBottom=\"80dp\"\n        android:nextFocusUp=\"@id/settings_toolbar\"\n        android:nextFocusDown=\"@id/plugin_storage_appbar\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        app:layout_constraintBottom_toTopOf=\"@id/download_storage_appbar\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        tools:listitem=\"@layout/repository_item\"\n        tools:visibility=\"visible\" />\n\n    <LinearLayout\n        android:id=\"@+id/blank_repo_screen\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center\"\n        android:orientation=\"vertical\"\n        tools:visibility=\"gone\">\n\n        <ImageView\n            android:layout_width=\"30dp\"\n            android:layout_height=\"30dp\"\n            android:layout_margin=\"10dp\"\n            android:src=\"@drawable/ic_baseline_extension_24\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"20dp\"\n            android:gravity=\"center\"\n            android:text=\"@string/blank_repo_message\"\n            android:textSize=\"16sp\" />\n\n        <!--        <com.google.android.material.button.MaterialButton-->\n        <!--            android:id=\"@+id/list_repositories\"-->\n        <!--            style=\"@style/WhiteButton\"-->\n        <!--            android:layout_width=\"wrap_content\"-->\n        <!--            android:nextFocusDown=\"@id/add_repo_button\"-->\n        <!--            android:text=\"@string/view_public_repositories_button\" />-->\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/plugin_storage_appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"80dp\"\n        android:layout_gravity=\"bottom\"\n        android:background=\"?attr/primaryGrayBackground\"\n        android:focusable=\"true\"\n        android:foreground=\"@drawable/outline_drawable\"\n        android:nextFocusRight=\"@id/add_repo_button_imageview\"\n        android:nextFocusUp=\"@id/repo_recycler_view\"\n        android:orientation=\"horizontal\"\n        android:padding=\"10dp\"\n        android:visibility=\"visible\"\n        android:baselineAligned=\"false\">\n\n        <LinearLayout\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"5dp\"\n                android:text=\"@string/extensions\"\n                android:textColor=\"?attr/textColor\" />\n\n            <androidx.cardview.widget.CardView\n                android:layout_width=\"fill_parent\"\n                android:layout_height=\"12dp\"\n                android:layout_marginBottom=\"5dp\"\n                android:elevation=\"0dp\"\n                app:cardCornerRadius=\"@dimen/storage_radius\"\n                app:cardElevation=\"0dp\"\n                app:cardMaxElevation=\"0dp\">\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:orientation=\"horizontal\">\n\n                    <View\n                        android:id=\"@+id/plugin_download\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"match_parent\"\n                        android:background=\"@drawable/storage_bar_left\"\n                        tools:layout_weight=\"0.5\" />\n\n                    <View\n                        android:id=\"@+id/plugin_disabled\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"match_parent\"\n                        android:background=\"@drawable/storage_bar_mid\"\n                        tools:layout_weight=\"0.10\" />\n\n                    <View\n                        android:id=\"@+id/plugin_not_downloaded\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"match_parent\"\n                        android:background=\"@drawable/storage_bar_right\"\n                        tools:layout_weight=\"0.10\" />\n                </LinearLayout>\n            </androidx.cardview.widget.CardView>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\">\n\n                <View\n                    android:layout_width=\"10dp\"\n                    android:layout_height=\"10dp\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginTop=\"5dp\"\n                    android:layout_marginEnd=\"5dp\"\n                    android:layout_marginBottom=\"5dp\"\n                    android:background=\"@drawable/storage_bar_left_box\" />\n\n                <TextView\n                    android:id=\"@+id/plugin_download_txt\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"12sp\"\n                    tools:text=\"Downloaded: 7\" />\n\n                <View\n                    android:layout_width=\"10dp\"\n                    android:layout_height=\"10dp\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_margin=\"5dp\"\n                    android:background=\"@drawable/storage_bar_mid_box\" />\n\n                <TextView\n                    android:id=\"@+id/plugin_disabled_txt\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"12sp\"\n                    tools:text=\"Disabled: 3\" />\n\n                <View\n                    android:layout_width=\"10dp\"\n                    android:layout_height=\"10dp\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_margin=\"5dp\"\n                    android:background=\"@drawable/storage_bar_right_box\" />\n\n                <TextView\n                    android:id=\"@+id/plugin_not_downloaded_txt\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"12sp\"\n                    tools:text=\"Not downloaded 3\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/add_repo_button_imageview_holder\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:paddingStart=\"10dp\"\n            android:paddingEnd=\"10dp\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n\n                android:layout_gravity=\"center\"\n                android:text=\"@string/add_repository\"\n                android:textColor=\"?attr/textColor\" />\n\n            <ImageView\n                android:id=\"@+id/add_repo_button_imageview\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"40dp\"\n                android:layout_gravity=\"center\"\n\n                android:background=\"@drawable/outline_drawable\"\n                android:contentDescription=\"@string/add_repository\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/plugin_storage_appbar\"\n                android:nextFocusUp=\"@id/repo_recycler_view\"\n\n                android:src=\"@drawable/ic_baseline_add_24\"\n                app:tint=\"?attr/textColor\" />\n        </LinearLayout>\n\n    </LinearLayout>\n\n    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n        android:id=\"@+id/add_repo_button\"\n        style=\"@style/ExtendedFloatingActionButton\"\n        android:foreground=\"@drawable/outline_drawable\"\n        android:nextFocusDown=\"@id/plugin_storage_appbar\"\n        android:text=\"@string/add_repository\"\n        android:textColor=\"?attr/textColor\"\n        android:translationY=\"-80dp\"\n        app:icon=\"@drawable/ic_baseline_add_24\"\n        tools:ignore=\"ContentDescription\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_home.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/home_root\"\n    android:layout_width=\"match_parent\"\n\n    android:layout_height=\"match_parent\"\n    tools:context=\".ui.home.HomeFragment\">\n\n    <FrameLayout\n        android:id=\"@+id/home_loading\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <ProgressBar\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            android:layout_gravity=\"center\"\n            android:visibility=\"gone\"\n            tools:visibility=\"gone\" />\n\n        <com.facebook.shimmer.ShimmerFrameLayout\n            android:id=\"@+id/home_loading_shimmer\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:layout_marginTop=\"15dp\"\n            android:orientation=\"vertical\"\n            android:paddingTop=\"40dp\"\n            app:shimmer_auto_start=\"true\"\n            app:shimmer_base_alpha=\"0.2\"\n            app:shimmer_duration=\"@integer/loading_time\"\n            app:shimmer_highlight_alpha=\"0.3\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n\n                <FrameLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <androidx.cardview.widget.CardView\n                        android:layout_width=\"125dp\"\n                        android:layout_height=\"200dp\"\n                        android:layout_gravity=\"center\"\n                        android:layout_margin=\"@dimen/loading_margin\"\n                        android:background=\"@color/grayShimmer\"\n                        android:translationX=\"-164dp\"\n                        app:cardCornerRadius=\"@dimen/loading_radius\" />\n\n                    <androidx.cardview.widget.CardView\n                        android:layout_width=\"148dp\"\n                        android:layout_height=\"234dp\"\n                        android:layout_gravity=\"center\"\n                        android:layout_margin=\"@dimen/loading_margin\"\n                        android:background=\"@color/grayShimmer\"\n                        app:cardCornerRadius=\"@dimen/loading_radius\" />\n\n                    <androidx.cardview.widget.CardView\n                        android:layout_width=\"125dp\"\n                        android:layout_height=\"200dp\"\n                        android:layout_gravity=\"center\"\n                        android:layout_margin=\"@dimen/loading_margin\"\n                        android:background=\"@color/grayShimmer\"\n                        android:translationX=\"164dp\"\n                        app:cardCornerRadius=\"@dimen/loading_radius\" />\n                </FrameLayout>\n\n                <include layout=\"@layout/loading_line_short_center\" />\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginStart=\"@dimen/result_padding\"\n                    android:layout_marginTop=\"@dimen/result_padding\"\n\n                    android:layout_marginEnd=\"@dimen/result_padding\"\n                    android:orientation=\"vertical\">\n\n                    <include layout=\"@layout/loading_list\" />\n\n                    <include layout=\"@layout/loading_list\" />\n\n                    <include layout=\"@layout/loading_list\" />\n                </LinearLayout>\n            </LinearLayout>\n        </com.facebook.shimmer.ShimmerFrameLayout>\n\n        <LinearLayout\n            android:id=\"@+id/home_api_holder\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"40dp\"\n            android:layout_gravity=\"end\"\n            android:layout_margin=\"10dp\"\n            android:background=\"@color/transparent\"\n            android:orientation=\"horizontal\"\n            android:visibility=\"gone\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/home_change_api\"\n                style=\"@style/RegularButtonTV\"\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"0dp\"\n                android:layout_marginEnd=\"0dp\"\n                android:background=\"@drawable/player_button_tv_attr_no_bg\"\n                android:gravity=\"center_vertical\"\n                android:nextFocusLeft=\"@id/nav_rail_view\"\n                android:nextFocusRight=\"@id/home_switch_account\" />\n\n            <ImageView\n                android:id=\"@+id/home_preview_reload_provider\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"end\"\n                android:background=\"@drawable/player_button_tv_attr_no_bg\"\n                android:contentDescription=\"@string/reload_provider\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/home_change_api\"\n                android:nextFocusRight=\"@id/home_preview_search_button\"\n                android:nextFocusUp=\"@id/home_preview_reload_provider\"\n                android:nextFocusDown=\"@id/home_preview_info_btt\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/ic_refresh\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                android:visibility=\"gone\"\n                app:tint=\"@color/player_on_button_tv_attr\" />\n\n            <ImageView\n                android:id=\"@+id/home_preview_search_button\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"end\"\n                android:background=\"@drawable/player_button_tv_attr_no_bg\"\n                android:contentDescription=\"@string/search\"\n                android:nextFocusLeft=\"@id/home_change_api\"\n                android:nextFocusRight=\"@id/home_switch_account\"\n                android:nextFocusDown=\"@id/home_preview_info_btt\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/search_icon\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                android:visibility=\"gone\"\n                app:tint=\"@color/player_on_button_tv_attr\" />\n\n            <ImageView\n                android:id=\"@+id/home_switch_account\"\n\n                android:layout_width=\"50dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"end\"\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/account\"\n                android:nextFocusLeft=\"@id/home_search\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/ic_outline_account_circle_24\" />\n        </LinearLayout>\n    </FrameLayout>\n\n    <LinearLayout\n        android:id=\"@+id/home_loading_error\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"gone\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/home_reload_connectionerror\"\n            style=\"@style/WhiteButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/reload_error\"\n            app:icon=\"@drawable/ic_baseline_autorenew_24\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/home_reload_connection_open_in_browser\"\n            style=\"@style/BlackButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/result_open_in_browser\"\n            app:icon=\"@drawable/ic_baseline_public_24\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/home_reload_connection_go_to_downloads\"\n            style=\"@style/BlackButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/go_to_downloads\"\n            app:icon=\"@drawable/netflix_download\" />\n\n        <TextView\n            android:id=\"@+id/result_error_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:gravity=\"center\"\n            android:textColor=\"?attr/textColor\" />\n    </LinearLayout>\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/home_master_recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusLeft=\"@id/nav_rail_view\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        tools:listitem=\"@layout/homepage_parent\"\n        tools:visibility=\"gone\" />\n\n    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n        android:id=\"@+id/home_api_fab\"\n        style=\"@style/ExtendedFloatingActionButton\"\n        android:text=\"@string/home_source\"\n        android:textColor=\"?attr/textColor\"\n        android:visibility=\"gone\"\n        app:icon=\"@drawable/ic_baseline_filter_list_24\"\n        tools:ignore=\"ContentDescription\"\n        tools:visibility=\"visible\" />\n\n    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n        android:id=\"@+id/home_random\"\n        style=\"@style/ExtendedFloatingActionButton\"\n        android:layout_gravity=\"bottom|start\"\n        android:text=\"@string/home_random\"\n        android:textColor=\"?attr/textColor\"\n        android:visibility=\"gone\"\n        app:icon=\"@drawable/ic_baseline_play_arrow_24\"\n        tools:ignore=\"ContentDescription\"\n        tools:visibility=\"visible\" />\n\n    <!-- Placeholder for TV layout random button - always hidden on phone -->\n    <ImageView\n        android:id=\"@+id/home_random_button_tv\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:visibility=\"gone\" />\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_home_head.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/home_header\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"?attr/primaryBlackBackground\"\n    android:orientation=\"vertical\">\n\n    <View\n        android:id=\"@+id/home_none_padding\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\" />\n\n    <FrameLayout\n        android:id=\"@+id/home_preview_viewpager_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"500dp\">\n\n        <androidx.viewpager2.widget.ViewPager2\n            android:id=\"@+id/home_preview_viewpager\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\">\n\n        </androidx.viewpager2.widget.ViewPager2>\n\n        <LinearLayout\n            android:id=\"@+id/home_padding\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\"\n            android:paddingHorizontal=\"0dp\">\n\n\n            <androidx.appcompat.widget.SearchView\n                android:id=\"@+id/home_search\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginEnd=\"8dp\"\n                android:layout_weight=\"1\"\n                android:editTextColor=\"@color/white\"\n                android:gravity=\"center_vertical\"\n                android:iconifiedByDefault=\"true\"\n                android:nextFocusRight=\"@id/home_head_profile_padding\"\n                android:padding=\"0dp\"\n                android:textColor=\"@color/white\"\n                android:textColorHint=\"@color/white\"\n                app:closeIcon=\"@drawable/ic_baseline_close_24\"\n                app:iconifiedByDefault=\"true\"\n                app:queryBackground=\"@color/transparent\"\n                app:queryHint=\"@string/search_hint\"\n                app:searchIcon=\"@drawable/search_icon\"\n                tools:ignore=\"RtlSymmetry\" />\n\n            <LinearLayout\n                android:id=\"@+id/home_head_profile_padding\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"50dp\"\n                android:clickable=\"true\"\n                android:focusable=\"true\"\n                android:foreground=\"@drawable/rounded_select_ripple\"\n                android:gravity=\"center\"\n                android:nextFocusLeft=\"@id/home_search\"\n                android:orientation=\"horizontal\">\n\n                <androidx.cardview.widget.CardView\n                    android:id=\"@+id/home_head_profile_card\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"@color/transparent\"\n                    android:focusable=\"true\"\n                    android:foreground=\"@drawable/outline_big_15_gray\"\n                    app:cardCornerRadius=\"20dp\">\n\n                    <ImageView\n                        android:id=\"@+id/home_head_profile_pic\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:contentDescription=\"@string/account\"\n                        android:scaleType=\"centerCrop\"\n                        tools:src=\"@drawable/profile_bg_orange\" />\n                </androidx.cardview.widget.CardView>\n            </LinearLayout>\n        </LinearLayout>\n\n        <!--\n                        <TextView\n                            android:visibility=\"gone\"\n                            android:id=\"@+id/test_search\"\n                            android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                            android:layout_gravity=\"start\"\n                            android:gravity=\"center\"\n\n                            android:textSize=\"20dp\"\n                            android:layout_margin=\"20dp\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:text=\"@string/search\"\n                            android:textColor=\"@color/white\"\n                            app:drawableLeftCompat=\"@drawable/search_icon\"\n                            app:tint=\"@color/white\" />\n        -->\n\n        <LinearLayout\n            android:id=\"@+id/home_preview_title_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"100dp\"\n            android:layout_gravity=\"bottom\"\n            android:gravity=\"center\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/home_preview_bookmark\"\n                android:layout_width=\"70dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"25dp\"\n                android:layout_marginEnd=\"25dp\"\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:gravity=\"center\"\n                android:text=\"@string/none\"\n                android:textColor=\"?attr/white\"\n                app:drawableTint=\"?attr/white\"\n                app:drawableTopCompat=\"@drawable/ic_baseline_add_24\"\n                app:tint=\"?attr/white\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/home_preview_play\"\n                style=\"@style/WhiteButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:text=\"@string/home_play\"\n                app:icon=\"@drawable/ic_baseline_play_arrow_24\" />\n\n            <TextView\n                android:id=\"@+id/home_preview_info\"\n                android:layout_width=\"70dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"25dp\"\n                android:layout_marginEnd=\"25dp\"\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:gravity=\"center\"\n                android:text=\"@string/home_info\"\n                android:textColor=\"?attr/white\"\n                app:drawableTint=\"?attr/white\"\n                app:drawableTopCompat=\"@drawable/ic_outline_info_24\"\n                app:tint=\"?attr/white\" />\n\n        </LinearLayout>\n\n    </FrameLayout>\n\n    <LinearLayout\n        android:id=\"@+id/alternative_account_padding\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:gravity=\"end\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"0dp\">\n\n        <LinearLayout\n            android:id=\"@+id/alternate_home_head_profile_padding\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            android:clickable=\"true\"\n            android:focusable=\"true\"\n            android:foreground=\"@drawable/rounded_select_ripple\"\n            android:gravity=\"center\"\n            android:nextFocusLeft=\"@id/home_search\"\n            android:orientation=\"horizontal\">\n\n            <androidx.cardview.widget.CardView\n                android:id=\"@+id/alternate_home_head_profile_card\"\n                android:layout_width=\"30dp\"\n                android:layout_height=\"30dp\"\n                android:layout_gravity=\"center\"\n                android:background=\"@color/transparent\"\n                android:focusable=\"true\"\n                android:foreground=\"@drawable/outline_big_15_gray\"\n                app:cardCornerRadius=\"20dp\">\n\n                <ImageView\n                    android:id=\"@+id/alternate_home_head_profile_pic\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:contentDescription=\"@string/account\"\n                    android:scaleType=\"centerCrop\"\n                    tools:src=\"@drawable/profile_bg_orange\" />\n            </androidx.cardview.widget.CardView>\n        </LinearLayout>\n    </LinearLayout>\n\n\n    <LinearLayout\n        android:id=\"@+id/home_watch_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <TextView\n            android:id=\"@+id/home_watch_parent_item_title\"\n            style=\"@style/WatchHeaderText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginEnd=\"0dp\"\n            android:background=\"?android:attr/selectableItemBackground\"\n            android:contentDescription=\"@string/home_more_info\"\n            android:padding=\"12dp\"\n            android:text=\"@string/continue_watching\"\n            app:drawableRightCompat=\"@drawable/ic_baseline_arrow_forward_24\"\n            app:drawableTint=\"?attr/white\" />\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/home_watch_child_recyclerview\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:clipToPadding=\"false\"\n            android:descendantFocusability=\"afterDescendants\"\n            android:orientation=\"horizontal\"\n            android:paddingHorizontal=\"5dp\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            tools:listitem=\"@layout/home_result_grid\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/home_bookmarked_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <FrameLayout\n            android:id=\"@+id/home_bookmark_parent_item_title\"\n\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?android:attr/selectableItemBackground\">\n\n            <HorizontalScrollView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"50dp\"\n                android:fadingEdge=\"horizontal\"\n\n                android:nextFocusLeft=\"@id/nav_rail_view\"\n                android:nextFocusUp=\"@id/home_watch_child_recyclerview\"\n                android:nextFocusForward=\"@id/home_bookmarked_child_recyclerview\"\n                android:paddingStart=\"12dp\"\n                android:paddingTop=\"5dp\"\n                android:paddingEnd=\"12dp\"\n\n                android:paddingBottom=\"5dp\"\n                android:requiresFadingEdge=\"horizontal\">\n\n                <com.google.android.material.chip.ChipGroup\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_type_watching_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n\n                        android:nextFocusLeft=\"@id/nav_rail_view\"\n                        android:nextFocusRight=\"@id/home_plan_to_watch_btt\"\n                        android:text=\"@string/type_watching\" />\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_plan_to_watch_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n\n                        android:nextFocusLeft=\"@id/home_type_watching_btt\"\n                        android:nextFocusRight=\"@id/home_type_on_hold_btt\"\n                        android:text=\"@string/type_plan_to_watch\" />\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_type_on_hold_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n\n                        android:nextFocusLeft=\"@id/home_plan_to_watch_btt\"\n                        android:nextFocusRight=\"@id/home_type_dropped_btt\"\n                        android:text=\"@string/type_on_hold\" />\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_type_dropped_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n\n                        android:nextFocusLeft=\"@id/home_type_on_hold_btt\"\n                        android:nextFocusRight=\"@id/home_type_completed_btt\"\n                        android:text=\"@string/type_dropped\" />\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_type_completed_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n\n                        android:layout_height=\"wrap_content\"\n                        android:nextFocusLeft=\"@id/home_type_dropped_btt\"\n                        android:text=\"@string/type_completed\" />\n                </com.google.android.material.chip.ChipGroup>\n\n            </HorizontalScrollView>\n\n            <ImageView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"end\"\n                android:layout_marginEnd=\"12dp\"\n                android:contentDescription=\"@string/home_more_info\"\n                android:src=\"@drawable/ic_baseline_arrow_forward_24\"\n                app:drawableTint=\"?attr/white\" />\n        </FrameLayout>\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/home_bookmarked_child_recyclerview\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:clipToPadding=\"false\"\n            android:descendantFocusability=\"afterDescendants\"\n            android:orientation=\"horizontal\"\n            android:paddingHorizontal=\"5dp\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            tools:listitem=\"@layout/home_result_grid\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_home_head_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/home_header\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginTop=\"60dp\"\n    android:orientation=\"vertical\">\n\n    <View\n        android:id=\"@+id/home_none_padding\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\" />\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\"\n            tools:ignore=\"UselessParent\">\n\n            <View\n                android:id=\"@+id/home_preview_hidden_prev_focus\"\n                android:layout_width=\"0.1dp\"\n                android:layout_height=\"0.1dp\"\n                android:focusable=\"true\"\n                android:tag=\"@string/tv_no_focus_tag\" />\n\n            <androidx.cardview.widget.CardView\n                android:id=\"@+id/home_preview_info_btt\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"400dp\"\n                android:layout_marginStart=\"10dp\"\n                android:layout_marginTop=\"10dp\"\n                android:layout_marginEnd=\"10dp\"\n\n                android:backgroundTint=\"@color/transparent\"\n                android:focusable=\"true\"\n                android:foreground=\"@drawable/outline_drawable\"\n                android:nextFocusLeft=\"@id/home_preview_hidden_prev_focus\"\n                android:nextFocusRight=\"@id/home_preview_hidden_next_focus\"\n                android:nextFocusUp=\"@id/home_change_api\"\n                android:nextFocusDown=\"@id/home_watch_child_recyclerview\"\n\n                app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n                <androidx.viewpager2.widget.ViewPager2\n                    android:id=\"@+id/home_preview_viewpager\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:descendantFocusability=\"blocksDescendants\"\n                    android:orientation=\"horizontal\">\n\n                </androidx.viewpager2.widget.ViewPager2>\n\n                <LinearLayout\n                    android:id=\"@+id/home_preview_viewpager_text\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:background=\"@drawable/player_gradient_tv\"\n                    android:layout_gravity=\"bottom\"\n                    android:layout_marginStart=\"@dimen/navbar_width\"\n                    android:gravity=\"bottom\"\n                    android:orientation=\"vertical\"\n                    android:padding=\"20dp\">\n\n                    <ImageView\n                        android:id=\"@+id/home_background_poster_watermark_badge_holder\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"72dp\"\n                        android:contentDescription=\"LogoURL\"\n                        android:minHeight=\"72dp\"\n                        android:maxWidth=\"220dp\"\n                        android:scaleType=\"fitStart\"\n                        android:adjustViewBounds=\"true\" />\n\n\n                    <TextView\n                        android:textColor=\"@color/textColor\"\n                        android:id=\"@+id/home_preview_text\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"10dp\"\n                        android:ellipsize=\"end\"\n                        android:maxLines=\"1\"\n                        android:textSize=\"25sp\"\n                        android:textStyle=\"bold\"\n                        android:shadowColor=\"#B0000000\"\n                        android:shadowDx=\"0\"\n                        android:shadowDy=\"2\"\n                        android:shadowRadius=\"4\"\n                        tools:text=\"The Perfect Run\" />\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"horizontal\"\n                        android:layout_marginTop=\"10dp\"\n                        android:layout_marginBottom=\"4dp\"\n                        android:gravity=\"center_vertical\">\n\n                        <TextView\n                            android:id=\"@+id/home_preview_score\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:background=\"@drawable/rating_bg_color\"\n                            android:textColor=\"@color/white\"\n                            android:textStyle=\"bold\"\n                            android:paddingStart=\"6dp\"\n                            android:paddingEnd=\"6dp\"\n                            android:paddingTop=\"2dp\"\n                            android:paddingBottom=\"2dp\"\n                            android:layout_marginEnd=\"12dp\"\n                            tools:text=\"IMDb : 8.5\" />\n\n                        <TextView\n                            android:id=\"@+id/home_preview_year\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:textColor=\"@color/gray_200\"\n                            android:layout_marginEnd=\"12dp\"\n                            tools:text=\"2021\" />\n\n                        <TextView\n                            android:id=\"@+id/home_preview_duration\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:textColor=\"@color/gray_200\"\n                            tools:text=\"120m\" />\n\n                    </LinearLayout>\n\n                    <TextView\n                        android:id=\"@+id/home_preview_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:ellipsize=\"end\"\n                        android:maxLines=\"3\"\n                        android:paddingBottom=\"5dp\"\n                        android:textSize=\"15sp\"\n                        android:textColor=\"@color/textColor\"\n                        android:shadowColor=\"#B0000000\"\n                        android:shadowDx=\"0\"\n                        android:shadowDy=\"2\"\n                        android:shadowRadius=\"4\"\n                        tools:text=\"very nice tv series\" />\n\n                    <TextView\n                        android:id=\"@+id/home_preview_cast\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:ellipsize=\"end\"\n                        android:maxLines=\"1\"\n                        android:textSize=\"13sp\"\n                        android:textColor=\"@color/gray_400\"\n                        android:paddingBottom=\"5dp\"\n                        tools:text=\"Cast: Actor One, Actor Two\" />\n\n                    <com.google.android.material.chip.ChipGroup\n                        android:id=\"@+id/home_preview_tags\"\n                        style=\"@style/ChipParent\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\" />\n                </LinearLayout>\n\n            </androidx.cardview.widget.CardView>\n\n            <View\n                android:id=\"@+id/home_preview_hidden_next_focus\"\n                android:layout_width=\"0.1dp\"\n                android:layout_height=\"0.1dp\"\n                android:focusable=\"true\"\n                android:tag=\"@string/tv_no_focus_tag\" />\n\n        </LinearLayout>\n\n        <!--\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"40dp\"\n            android:layout_gravity=\"end\"\n            android:layout_margin=\"10dp\"\n            android:background=\"@drawable/player_button_tv_attr\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/home_preview_change_api\"\n                style=\"@style/RegularButtonTV\"\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"0dp\"\n                android:layout_marginEnd=\"0dp\"\n                android:background=\"@drawable/player_button_tv_attr_no_bg\"\n                android:gravity=\"center_vertical\"\n                android:nextFocusLeft=\"@id/home_preview_info_btt\"\n                android:nextFocusRight=\"@id/home_preview_reload_provider\"\n                android:nextFocusUp=\"@id/home_preview_change_api\"\n                android:nextFocusDown=\"@id/home_preview_info_btt\">\n\n                <requestFocus />\n            </com.google.android.material.button.MaterialButton>\n\n            <ImageView\n                android:id=\"@+id/home_preview_reload_provider\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"end\"\n                android:background=\"@drawable/player_button_tv_attr_no_bg\"\n                android:contentDescription=\"@string/reload_provider\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/home_preview_change_api\"\n                android:nextFocusRight=\"@id/home_preview_search_button\"\n                android:nextFocusUp=\"@id/home_preview_reload_provider\"\n                android:nextFocusDown=\"@id/home_preview_info_btt\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/ic_refresh\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                android:visibility=\"gone\"\n                app:tint=\"@color/player_on_button_tv_attr\" />\n\n            <ImageView\n                android:id=\"@+id/home_preview_search_button\"\n                android:layout_width=\"50dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"end\"\n                android:background=\"@drawable/player_button_tv_attr_no_bg\"\n                android:contentDescription=\"@string/search\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/home_preview_reload_provider\"\n                android:nextFocusRight=\"@id/home_preview_switch_account\"\n                android:nextFocusUp=\"@id/home_preview_search_button\"\n                android:nextFocusDown=\"@id/home_preview_info_btt\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/search_icon\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                app:tint=\"@color/player_on_button_tv_attr\" />\n\n            <ImageView\n                android:id=\"@+id/home_preview_switch_account\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"end\"\n                android:background=\"@drawable/player_button_tv_attr_no_bg\"\n                android:contentDescription=\"@string/account\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/home_preview_search_button\"\n                android:nextFocusRight=\"@id/home_preview_switch_account\"\n                android:nextFocusDown=\"@id/home_preview_info_btt\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/ic_outline_account_circle_24\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                android:visibility=\"gone\"\n                app:tint=\"@color/player_on_button_tv_attr\" />\n        </LinearLayout>\n        -->\n        <!--<FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_margin=\"10dp\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/home_preview_change_api\"\n                style=\"@style/RegularButtonTV\"\n                android:nextFocusRight=\"@id/home_preview_switch_account\"\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"top|start\"\n                android:layout_marginStart=\"@dimen/navbar_width\"\n                android:minWidth=\"150dp\"\n                android:nextFocusLeft=\"@id/nav_rail_view\"\n                android:nextFocusDown=\"@id/home_preview_play_btt\" />\n\n            <ImageView\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:nextFocusDown=\"@id/home_preview_play_btt\"\n                android:nextFocusLeft=\"@id/home_preview_change_api\"\n                android:id=\"@+id/home_preview_switch_account\"\n                android:layout_width=\"50dp\"\n                android:layout_gravity=\"end\"\n                android:layout_height=\"wrap_content\"\n                android:contentDescription=\"@string/account\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/ic_outline_account_circle_24\" />\n\n        </FrameLayout>-->\n\n\n    </FrameLayout>\n\n\n    <!-- <FrameLayout\n         android:layout_width=\"match_parent\"\n         android:layout_height=\"match_parent\"\n         android:layout_margin=\"10dp\">\n\n         <com.google.android.material.button.MaterialButton\n             android:id=\"@+id/home_preview_change_api2\"\n             style=\"@style/RegularButtonTV\"\n             android:layout_width=\"wrap_content\"\n             android:layout_gravity=\"top|start\"\n             android:layout_marginStart=\"@dimen/navbar_width\"\n             android:backgroundTint=\"@color/white_attr_20\"\n             android:minWidth=\"150dp\"\n             android:nextFocusUp=\"@id/home_preview_play_btt\"\n             android:nextFocusLeft=\"@id/nav_rail_view\"\n             android:nextFocusDown=\"@id/home_watch_child_recyclerview\" />\n     </FrameLayout>-->\n\n    <LinearLayout\n        android:id=\"@+id/home_watch_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <TextView\n            android:id=\"@+id/home_watch_parent_item_title\"\n\n            style=\"@style/WatchHeaderText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"@dimen/navbar_width\"\n            android:layout_marginEnd=\"0dp\"\n            android:background=\"?android:attr/selectableItemBackground\"\n            android:padding=\"12dp\"\n            android:text=\"@string/continue_watching\"\n            app:drawableTint=\"?attr/white\" />\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/home_watch_child_recyclerview\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:clipToPadding=\"false\"\n            android:descendantFocusability=\"afterDescendants\"\n            android:nextFocusUp=\"@id/home_preview_info_btt\"\n            android:nextFocusDown=\"@id/home_type_holder\"\n            android:orientation=\"horizontal\"\n            android:paddingStart=\"8dp\"\n            android:paddingEnd=\"5dp\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            tools:listitem=\"@layout/home_result_grid\" />\n\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/home_bookmarked_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <FrameLayout\n            android:id=\"@+id/home_bookmark_parent_item_title\"\n\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?android:attr/selectableItemBackground\">\n\n            <HorizontalScrollView\n                android:id=\"@+id/horizontal_scroll_chips\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:fadingEdge=\"horizontal\"\n\n                android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:paddingStart=\"12dp\"\n                android:paddingTop=\"5dp\"\n                android:paddingEnd=\"12dp\"\n\n                android:paddingBottom=\"5dp\"\n                android:requiresFadingEdge=\"horizontal\">\n\n                <com.google.android.material.chip.ChipGroup\n                    android:id=\"@+id/home_type_holder\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginStart=\"@dimen/navbar_width\"\n\n                    android:descendantFocusability=\"afterDescendants\"\n                    android:nextFocusLeft=\"@id/navigation_home\"\n                    android:nextFocusUp=\"@id/home_watch_child_recyclerview\"\n                    android:nextFocusDown=\"@id/home_bookmarked_child_recyclerview\"\n                    android:orientation=\"horizontal\">\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_type_watching_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:nextFocusLeft=\"@id/navigation_home\"\n                        android:nextFocusRight=\"@id/home_plan_to_watch_btt\"\n\n                        android:nextFocusUp=\"@id/home_watch_child_recyclerview\"\n                        android:nextFocusDown=\"@id/home_bookmarked_child_recyclerview\"\n                        android:text=\"@string/type_watching\" />\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_plan_to_watch_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:nextFocusLeft=\"@id/home_type_watching_btt\"\n                        android:nextFocusRight=\"@id/home_type_on_hold_btt\"\n\n                        android:nextFocusUp=\"@id/home_watch_child_recyclerview\"\n                        android:nextFocusDown=\"@id/home_bookmarked_child_recyclerview\"\n                        android:text=\"@string/type_plan_to_watch\" />\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_type_on_hold_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:nextFocusLeft=\"@id/home_plan_to_watch_btt\"\n                        android:nextFocusRight=\"@id/home_type_dropped_btt\"\n\n                        android:nextFocusUp=\"@id/home_watch_child_recyclerview\"\n                        android:nextFocusDown=\"@id/home_bookmarked_child_recyclerview\"\n                        android:text=\"@string/type_on_hold\" />\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_type_dropped_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:nextFocusLeft=\"@id/home_type_on_hold_btt\"\n                        android:nextFocusRight=\"@id/home_type_completed_btt\"\n\n                        android:nextFocusUp=\"@id/home_watch_child_recyclerview\"\n                        android:nextFocusDown=\"@id/home_bookmarked_child_recyclerview\"\n                        android:text=\"@string/type_dropped\" />\n\n                    <com.google.android.material.chip.Chip\n                        android:id=\"@+id/home_type_completed_btt\"\n                        style=\"@style/ChipFilled\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:nextFocusLeft=\"@id/home_type_dropped_btt\"\n\n                        android:nextFocusUp=\"@id/home_watch_child_recyclerview\"\n                        android:nextFocusDown=\"@id/home_bookmarked_child_recyclerview\"\n                        android:text=\"@string/type_completed\" />\n                </com.google.android.material.chip.ChipGroup>\n            </HorizontalScrollView>\n\n            <ImageView\n                android:id=\"@+id/home_bookmark_parent_item_more_info\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"end\"\n                android:layout_marginEnd=\"12dp\"\n                android:contentDescription=\"@string/home_more_info\"\n                android:src=\"@drawable/ic_baseline_arrow_forward_24\"\n                android:visibility=\"gone\"\n                app:drawableTint=\"?attr/white\" />\n        </FrameLayout>\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/home_bookmarked_child_recyclerview\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:clipToPadding=\"false\"\n\n            android:descendantFocusability=\"afterDescendants\"\n            android:nextFocusLeft=\"@id/navigation_home\"\n            android:nextFocusUp=\"@id/home_type_holder\"\n\n            android:nextFocusDown=\"@id/home_child_recyclerview\"\n            android:orientation=\"horizontal\"\n            android:paddingStart=\"8dp\"\n            android:paddingEnd=\"5dp\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            tools:listitem=\"@layout/home_result_grid\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_home_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/home_root\"\n    android:layout_width=\"match_parent\"\n\n    android:layout_height=\"match_parent\"\n    tools:context=\".ui.home.HomeFragment\">\n\n\n    <FrameLayout\n        android:id=\"@+id/home_loading\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginStart=\"@dimen/navbar_width\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <ProgressBar\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            android:layout_gravity=\"center\"\n            android:visibility=\"gone\"\n            tools:visibility=\"gone\" />\n\n        <com.facebook.shimmer.ShimmerFrameLayout\n            android:id=\"@+id/home_loading_shimmer\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:layout_marginTop=\"15dp\"\n            android:orientation=\"vertical\"\n            android:paddingTop=\"40dp\"\n            app:shimmer_auto_start=\"true\"\n            app:shimmer_base_alpha=\"0.2\"\n            app:shimmer_duration=\"@integer/loading_time\"\n            app:shimmer_highlight_alpha=\"0.3\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n\n                <FrameLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <androidx.cardview.widget.CardView\n                        android:layout_width=\"125dp\"\n                        android:layout_height=\"200dp\"\n                        android:layout_gravity=\"center\"\n                        android:layout_margin=\"@dimen/loading_margin\"\n                        android:background=\"@color/grayShimmer\"\n                        android:translationX=\"-164dp\"\n                        app:cardCornerRadius=\"@dimen/loading_radius\" />\n\n                    <androidx.cardview.widget.CardView\n                        android:layout_width=\"148dp\"\n                        android:layout_height=\"234dp\"\n                        android:layout_gravity=\"center\"\n                        android:layout_margin=\"@dimen/loading_margin\"\n                        android:background=\"@color/grayShimmer\"\n                        app:cardCornerRadius=\"@dimen/loading_radius\" />\n\n                    <androidx.cardview.widget.CardView\n                        android:layout_width=\"125dp\"\n                        android:layout_height=\"200dp\"\n                        android:layout_gravity=\"center\"\n                        android:layout_margin=\"@dimen/loading_margin\"\n                        android:background=\"@color/grayShimmer\"\n                        android:translationX=\"164dp\"\n                        app:cardCornerRadius=\"@dimen/loading_radius\" />\n                </FrameLayout>\n\n                <include layout=\"@layout/loading_line_short_center\" />\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginStart=\"@dimen/result_padding\"\n                    android:layout_marginTop=\"@dimen/result_padding\"\n\n                    android:layout_marginEnd=\"@dimen/result_padding\"\n                    android:orientation=\"vertical\">\n\n                    <include layout=\"@layout/loading_list\" />\n\n                    <include layout=\"@layout/loading_list\" />\n\n                    <include layout=\"@layout/loading_list\" />\n                </LinearLayout>\n            </LinearLayout>\n        </com.facebook.shimmer.ShimmerFrameLayout>\n    </FrameLayout>\n\n    <LinearLayout\n        android:id=\"@+id/home_loading_error\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_marginStart=\"@dimen/navbar_width\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"gone\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/home_reload_connectionerror\"\n            style=\"@style/WhiteButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/reload_error\"\n            app:icon=\"@drawable/ic_baseline_autorenew_24\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/home_reload_connection_open_in_browser\"\n            style=\"@style/BlackButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/result_open_in_browser\"\n            app:icon=\"@drawable/ic_baseline_public_24\" />\n\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/home_reload_connection_go_to_downloads\"\n            style=\"@style/BlackButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/go_to_downloads\"\n            app:icon=\"@drawable/netflix_download\" />\n\n        <TextView\n            android:id=\"@+id/result_error_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:gravity=\"center\"\n            android:textColor=\"?attr/textColor\" />\n    </LinearLayout>\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/home_master_recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusLeft=\"@id/navigation_home\"\n        android:nextFocusUp=\"@id/home_bookmarked_child_recyclerview\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        tools:listitem=\"@layout/homepage_parent_tv\"\n        tools:visibility=\"gone\" />\n\n    <LinearLayout\n        android:id=\"@+id/home_api_holder\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"40dp\"\n        android:layout_gravity=\"end\"\n        android:layout_margin=\"10dp\"\n        android:background=\"@drawable/player_button_tv_attr\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/home_change_api\"\n            style=\"@style/RegularButtonTV\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginStart=\"0dp\"\n            android:layout_marginEnd=\"0dp\"\n            android:background=\"@drawable/player_button_tv_attr_no_bg\"\n            android:gravity=\"center\"\n            android:nextFocusLeft=\"@id/navigation_home\"\n            tools:text=\"Hello!\"\n            android:nextFocusRight=\"@id/home_preview_reload_provider\"\n            android:nextFocusDown=\"@id/home_preview_info_btt\" >\n            <requestFocus />\n        </com.google.android.material.button.MaterialButton>\n\n        <ImageView\n            android:id=\"@+id/home_preview_reload_provider\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"end\"\n            android:background=\"@drawable/player_button_tv_attr_no_bg\"\n            android:contentDescription=\"@string/reload_provider\"\n            android:focusable=\"true\"\n            android:nextFocusLeft=\"@id/home_change_api\"\n            android:nextFocusRight=\"@id/home_preview_search_button\"\n            android:nextFocusUp=\"@id/home_preview_reload_provider\"\n            android:nextFocusDown=\"@id/home_preview_info_btt\"\n            android:padding=\"10dp\"\n            tools:visibility=\"visible\"\n            android:src=\"@drawable/ic_refresh\"\n            android:tag=\"@string/tv_no_focus_tag\"\n            android:visibility=\"gone\"\n            app:tint=\"@color/player_on_button_tv_attr\" />\n\n        <ImageView\n            android:id=\"@+id/home_preview_search_button\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"end\"\n            android:background=\"@drawable/player_button_tv_attr_no_bg\"\n            android:clickable=\"true\"\n            android:contentDescription=\"@string/search\"\n            android:focusable=\"true\"\n            android:nextFocusLeft=\"@id/home_preview_reload_provider\"\n            android:nextFocusRight=\"@id/home_switch_account\"\n            android:nextFocusDown=\"@id/home_preview_info_btt\"\n            android:padding=\"10dp\"\n            android:src=\"@drawable/search_icon\"\n            android:tag=\"@string/tv_no_focus_tag\"\n            app:tint=\"@color/player_on_button_tv_attr\" />\n\n        <ImageView\n            android:id=\"@+id/home_random_button_tv\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"end\"\n            android:background=\"@drawable/player_button_tv_attr_no_bg\"\n            android:clickable=\"true\"\n            android:contentDescription=\"@string/home_random\"\n            android:focusable=\"true\"\n            android:nextFocusLeft=\"@id/home_preview_search_button\"\n            android:nextFocusRight=\"@id/home_switch_account\"\n            android:nextFocusDown=\"@id/home_preview_info_btt\"\n            android:padding=\"10dp\"\n            android:src=\"@drawable/ic_baseline_play_arrow_24\"\n            android:tag=\"@string/tv_no_focus_tag\"\n            android:visibility=\"gone\"\n            app:tint=\"@color/player_on_button_tv_attr\" />\n\n        <ImageView\n            android:visibility=\"gone\"\n            android:id=\"@+id/home_switch_account\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"end\"\n            android:background=\"@drawable/player_button_tv_attr_no_bg\"\n            android:contentDescription=\"@string/account\"\n            android:focusable=\"true\"\n            android:nextFocusLeft=\"@id/home_preview_search_button\"\n            android:nextFocusRight=\"@id/home_switch_account\"\n            android:nextFocusDown=\"@id/home_change_api\"\n\n            android:padding=\"10dp\"\n            android:src=\"@drawable/ic_outline_account_circle_24\"\n            android:tag=\"@string/tv_no_focus_tag\"\n            app:tint=\"@color/player_on_button_tv_attr\" />\n    </LinearLayout>\n\n    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n        android:id=\"@+id/home_api_fab\"\n        style=\"@style/ExtendedFloatingActionButton\"\n        android:visibility=\"gone\"\n        app:icon=\"@drawable/ic_baseline_filter_list_24\"\n        tools:ignore=\"ContentDescription\"\n        tools:visibility=\"visible\" />\n\n    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n        android:id=\"@+id/home_random\"\n        style=\"@style/ExtendedFloatingActionButton\"\n        android:layout_gravity=\"bottom|start\"\n        android:text=\"@string/home_random\"\n        android:textColor=\"?attr/textColor\"\n        android:visibility=\"gone\"\n        app:icon=\"@drawable/ic_baseline_play_arrow_24\"\n        tools:ignore=\"ContentDescription\"\n        tools:visibility=\"visible\" />\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_library.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/library_root\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/empty_list_textview\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_margin=\"30dp\"\n        android:gravity=\"center\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\" />\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:id=\"@+id/search_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"?attr/primaryGrayBackground\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            app:layout_scrollFlags=\"scroll|enterAlways\">\n\n            <ImageView\n                android:id=\"@+id/provider_selector\"\n                android:layout_width=\"25dp\"\n                android:layout_height=\"25dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:background=\"?selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/change_providers_img_des\"\n                android:src=\"@drawable/ic_baseline_extension_24\"\n                app:tint=\"?attr/textColor\" />\n\n            <ImageView\n                android:id=\"@+id/library_sort\"\n                android:layout_width=\"45dp\"\n                android:layout_height=\"45dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:background=\"?selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/change_providers_img_des\"\n                android:padding=\"5dp\"\n                android:src=\"@drawable/ic_baseline_sort_24\"\n                android:visibility=\"gone\"\n                app:tint=\"?attr/textColor\"\n                tools:visibility=\"visible\" />\n\n            <FrameLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"40dp\"\n                android:layout_margin=\"10dp\"\n                android:background=\"@drawable/search_background\"\n                android:visibility=\"visible\"\n                app:layout_scrollFlags=\"scroll|enterAlways\">\n\n                <androidx.appcompat.widget.SearchView\n                    android:id=\"@+id/main_search\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginEnd=\"25dp\"\n\n                    android:iconifiedByDefault=\"false\"\n                    android:imeOptions=\"actionSearch\"\n\n                    android:inputType=\"text\"\n                    android:nextFocusLeft=\"@id/nav_rail_view\"\n\n                    android:nextFocusRight=\"@id/search_filter\"\n                    android:paddingStart=\"-10dp\"\n                    app:closeIcon=\"@drawable/ic_baseline_close_24\"\n                    app:iconifiedByDefault=\"false\"\n                    app:queryBackground=\"@color/transparent\"\n                    app:queryHint=\"@string/search_hint\"\n                    app:searchIcon=\"@drawable/search_icon\"\n                    tools:ignore=\"RtlSymmetry\">\n\n                </androidx.appcompat.widget.SearchView>\n\n\n                <ImageView\n                    android:id=\"@+id/list_selector\"\n                    android:layout_width=\"45dp\"\n                    android:layout_height=\"45dp\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:background=\"?selectableItemBackgroundBorderless\"\n                    android:contentDescription=\"@string/change_providers_img_des\"\n                    android:nextFocusLeft=\"@id/main_search\"\n                    android:nextFocusRight=\"@id/main_search\"\n                    android:padding=\"10dp\"\n                    android:src=\"@drawable/ic_baseline_filter_list_24\"\n                    app:tint=\"?attr/textColor\" />\n\n            </FrameLayout>\n        </LinearLayout>\n\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:animateLayoutChanges=\"true\"\n        android:background=\"?attr/primaryBlackBackground\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n        <androidx.viewpager2.widget.ViewPager2\n            android:id=\"@+id/viewpager\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:clipToPadding=\"false\"\n            android:paddingBottom=\"40dp\"\n            tools:listitem=\"@layout/library_viewpager_page\" />\n\n        <LinearLayout\n            android:id=\"@+id/library_loading_overlay\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?attr/primaryBlackBackground\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\">\n\n            <com.facebook.shimmer.ShimmerFrameLayout\n                android:id=\"@+id/library_loading_shimmer\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"center\"\n                android:layout_margin=\"2dp\"\n                app:shimmer_auto_start=\"true\"\n                app:shimmer_base_alpha=\"0.2\"\n                app:shimmer_duration=\"@integer/loading_time\"\n                app:shimmer_highlight_alpha=\"0.3\">\n\n                <GridView\n                    android:id=\"@+id/gridview\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:clipToPadding=\"false\"\n                    android:gravity=\"center\"\n                    android:horizontalSpacing=\"10dp\"\n                    android:numColumns=\"3\"\n                    android:paddingBottom=\"120dp\"\n                    android:verticalSpacing=\"10dp\"\n                    tools:listitem=\"@layout/loading_poster_dynamic\" />\n            </com.facebook.shimmer.ShimmerFrameLayout>\n        </LinearLayout>\n\n    </FrameLayout>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginBottom=\"40dp\">\n\n        <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n            android:id=\"@+id/library_random\"\n            style=\"@style/ExtendedFloatingActionButton\"\n            android:layout_gravity=\"bottom|start\"\n            android:text=\"@string/home_random\"\n            android:textColor=\"?attr/textColor\"\n            android:visibility=\"gone\"\n            app:icon=\"@drawable/ic_baseline_play_arrow_24\"\n            tools:ignore=\"ContentDescription\"\n            tools:visibility=\"visible\" />\n\n        <!-- Placeholder for TV layout random button - always hidden on phone -->\n        <ImageView\n            android:id=\"@+id/library_random_button_tv\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            android:visibility=\"gone\" />\n\n        <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n            android:id=\"@+id/sort_fab\"\n            style=\"@style/ExtendedFloatingActionButton\"\n            android:text=\"@string/sort\"\n            android:textColor=\"?attr/textColor\"\n            app:icon=\"@drawable/ic_baseline_sort_24\"\n            tools:ignore=\"ContentDescription\" />\n    </FrameLayout>\n\n    <com.google.android.material.tabs.TabLayout\n        android:id=\"@+id/library_tab_layout\"\n        style=\"@style/Theme.Widget.Tabs\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"40dp\"\n        android:layout_gravity=\"bottom\"\n        android:background=\"?attr/primaryGrayBackground\"\n        android:focusable=\"true\"\n        android:paddingHorizontal=\"5dp\"\n        app:layout_scrollFlags=\"noScroll\"\n        app:tabGravity=\"center\"\n        app:tabIndicator=\"@drawable/indicator_background\"\n        app:tabIndicatorColor=\"?attr/white\"\n        app:tabIndicatorGravity=\"center\"\n        app:tabIndicatorHeight=\"30dp\"\n        app:tabMode=\"scrollable\"\n        app:tabRippleColor=\"?attr/textColor\"\n        app:tabSelectedTextColor=\"?attr/primaryBlackBackground\"\n        app:tabTextAppearance=\"@style/TabNoCaps\"\n        app:tabTextColor=\"?attr/textColor\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_library_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/library_root\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <TextView\n        android:id=\"@+id/empty_list_textview\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:layout_margin=\"30dp\"\n        android:gravity=\"center\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\" />\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:id=\"@+id/search_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"?attr/primaryGrayBackground\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            app:layout_scrollFlags=\"scroll|enterAlways\">\n\n            <ImageView\n                android:id=\"@+id/provider_selector\"\n                android:layout_width=\"25dp\"\n                android:layout_height=\"25dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:background=\"?selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/change_providers_img_des\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/navigation_library\"\n                android:nextFocusRight=\"@id/library_sort\"\n                android:padding=\"2dp\"\n                android:src=\"@drawable/ic_baseline_extension_24\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                app:tint=\"?attr/textColor\" />\n\n            <ImageView\n                android:id=\"@+id/library_sort\"\n                android:layout_width=\"25dp\"\n                android:layout_height=\"25dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:background=\"?selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/change_providers_img_des\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/provider_selector\"\n                android:nextFocusRight=\"@id/list_selector\"\n                android:src=\"@drawable/ic_baseline_sort_24\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                app:tint=\"?attr/textColor\" />\n\n            <ImageView\n                android:id=\"@+id/list_selector\"\n                android:layout_width=\"25dp\"\n                android:layout_height=\"25dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:background=\"?selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/change_providers_img_des\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/library_sort\"\n                android:nextFocusRight=\"@id/main_search\"\n                android:padding=\"1dp\"\n                android:src=\"@drawable/ic_baseline_filter_list_24\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                app:tint=\"?attr/textColor\" />\n\n            <FrameLayout\n                android:layout_width=\"0dp\"\n                android:layout_height=\"40dp\"\n                android:layout_margin=\"10dp\"\n                android:layout_weight=\"1\"\n                android:background=\"@drawable/search_background\"\n                android:visibility=\"visible\"\n                app:layout_scrollFlags=\"scroll|enterAlways\">\n\n                <androidx.appcompat.widget.SearchView\n                    android:id=\"@+id/main_search\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"end\"\n\n                    android:focusable=\"true\"\n                    android:iconifiedByDefault=\"false\"\n                    android:imeOptions=\"actionSearch\"\n                    android:inputType=\"text\"\n                    android:nextFocusLeft=\"@id/list_selector\"\n                    android:nextFocusDown=\"@id/search_result_root\"\n                    android:paddingStart=\"-10dp\"\n                    android:tag=\"tv_no_focus_tag\"\n                    app:closeIcon=\"@drawable/ic_baseline_close_24\"\n                    app:iconifiedByDefault=\"false\"\n                    app:queryBackground=\"@color/transparent\"\n                    app:queryHint=\"@string/search_hint\"\n                    app:searchIcon=\"@drawable/search_icon\"\n                    tools:ignore=\"RtlSymmetry\">\n\n                </androidx.appcompat.widget.SearchView>\n            </FrameLayout>\n\n            <ImageView\n                android:id=\"@+id/library_random_button_tv\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"40dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginEnd=\"10dp\"\n                android:background=\"?selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/home_random\"\n                android:focusable=\"true\"\n                android:nextFocusLeft=\"@id/main_search\"\n                android:nextFocusDown=\"@id/search_result_root\"\n                android:padding=\"8dp\"\n                android:src=\"@drawable/ic_baseline_play_arrow_24\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                android:visibility=\"gone\"\n                app:tint=\"?attr/textColor\" />\n        </LinearLayout>\n\n        <com.google.android.material.tabs.TabLayout\n            android:id=\"@+id/library_tab_layout\"\n            style=\"@style/Theme.Widget.Tabs\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"40dp\"\n            android:layout_gravity=\"top\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:focusable=\"true\"\n            android:nextFocusDown=\"@id/search_result_root\"\n            android:paddingHorizontal=\"5dp\"\n            app:tabGravity=\"center\"\n            app:tabIndicator=\"@drawable/indicator_background\"\n            app:tabIndicatorColor=\"?attr/white\"\n            app:tabIndicatorGravity=\"center\"\n            app:tabIndicatorHeight=\"30dp\"\n            app:tabMode=\"scrollable\"\n            app:tabRippleColor=\"?attr/textColor\"\n            app:tabSelectedTextColor=\"?attr/primaryBlackBackground\"\n            app:tabTextAppearance=\"@style/TabNoCaps\"\n            app:tabTextColor=\"?attr/textColor\" />\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"?attr/primaryBlackBackground\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n        <androidx.viewpager2.widget.ViewPager2\n            android:id=\"@+id/viewpager\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:clipToPadding=\"false\"\n            android:focusable=\"true\"\n            android:paddingBottom=\"40dp\"\n            android:tag=\"@string/tv_no_focus_tag\"\n            tools:listitem=\"@layout/library_viewpager_page\" />\n\n        <LinearLayout\n            android:id=\"@+id/library_loading_overlay\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?attr/primaryBlackBackground\"\n            android:focusable=\"false\"\n            android:tag=\"@string/tv_no_focus_tag\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\">\n\n            <com.facebook.shimmer.ShimmerFrameLayout\n                android:id=\"@+id/library_loading_shimmer\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"center\"\n                android:layout_margin=\"2dp\"\n                android:focusable=\"false\"\n                android:tag=\"@string/tv_no_focus_tag\"\n                app:shimmer_auto_start=\"true\"\n                app:shimmer_base_alpha=\"0.2\"\n                app:shimmer_duration=\"@integer/loading_time\"\n                app:shimmer_highlight_alpha=\"0.3\">\n\n                <GridView\n                    android:id=\"@+id/gridview\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:clipToPadding=\"false\"\n                    android:focusable=\"false\"\n                    android:gravity=\"center\"\n                    android:horizontalSpacing=\"10dp\"\n                    android:numColumns=\"3\"\n                    android:paddingBottom=\"120dp\"\n                    android:tag=\"@string/tv_no_focus_tag\"\n                    android:verticalSpacing=\"10dp\"\n                    tools:listitem=\"@layout/loading_poster_dynamic\" />\n            </com.facebook.shimmer.ShimmerFrameLayout>\n        </LinearLayout>\n    </FrameLayout>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginBottom=\"40dp\">\n\n        <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n            android:id=\"@+id/library_random\"\n            style=\"@style/ExtendedFloatingActionButton\"\n            android:layout_gravity=\"bottom|start\"\n            android:text=\"@string/home_random\"\n            android:textColor=\"?attr/textColor\"\n            android:visibility=\"gone\"\n            app:icon=\"@drawable/ic_baseline_play_arrow_24\"\n            tools:ignore=\"ContentDescription\"\n            tools:visibility=\"visible\" />\n\n        <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n            android:id=\"@+id/sort_fab\"\n            style=\"@style/ExtendedFloatingActionButton\"\n            android:text=\"@string/sort\"\n            android:textColor=\"?attr/textColor\"\n            android:visibility=\"gone\"\n            app:icon=\"@drawable/ic_baseline_sort_24\"\n            tools:ignore=\"ContentDescription\"\n            tools:visibility=\"visible\" />\n    </FrameLayout>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_player.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/player_background\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\"\n    android:orientation=\"horizontal\"\n    app:backgroundTint=\"@android:color/black\"\n    app:surface_type=\"texture_view\">\n    <!--\n          app:fastforward_increment=\"10000\"\n            app:rewind_increment=\"10000\"-->\n    <androidx.media3.ui.PlayerView\n        android:id=\"@+id/player_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@android:color/black\"\n        android:focusable=\"false\"\n        app:auto_show=\"true\"\n        app:backgroundTint=\"@android:color/black\"\n        app:controller_layout_id=\"@layout/player_custom_layout\"\n        app:hide_on_touch=\"false\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:show_timeout=\"0\" />\n\n    <FrameLayout\n        android:id=\"@+id/player_loading_overlay\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@android:color/black\"\n        android:backgroundTint=\"@android:color/black\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/overlay_loading_skip_button\"\n            style=\"@style/Widget.MaterialComponents.Button.OutlinedButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"45dp\"\n            android:layout_gravity=\"center\"\n            android:layout_marginTop=\"70dp\"\n            android:backgroundTint=\"@color/transparent\"\n\n            android:text=\"@string/skip_loading\"\n            android:textAllCaps=\"false\"\n            android:textColor=\"@color/textColor\"\n            android:visibility=\"gone\"\n            app:cornerRadius=\"4dp\"\n            app:icon=\"@drawable/ic_baseline_skip_next_24\"\n            app:iconTint=\"@color/textColor\"\n            app:rippleColor=\"?attr/colorPrimary\"\n            tools:visibility=\"visible\" />\n\n        <ProgressBar\n            android:id=\"@+id/main_load\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            android:layout_gravity=\"center\" />\n\n        <FrameLayout\n            android:id=\"@+id/video_go_back_holder_holder\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"5dp\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\">\n\n            <ImageView\n                android:layout_width=\"30dp\"\n                android:layout_height=\"30dp\"\n                android:layout_gravity=\"center\"\n                android:contentDescription=\"@string/go_back_img_des\"\n                android:src=\"@drawable/ic_baseline_arrow_back_24\"\n                app:tint=\"@android:color/white\" />\n\n            <ImageView\n                android:id=\"@+id/player_loading_go_back\"\n                android:layout_width=\"70dp\"\n                android:layout_height=\"70dp\"\n                android:layout_gravity=\"center\"\n                android:background=\"@drawable/video_tap_button_always_white\"\n                android:clickable=\"true\"\n                android:contentDescription=\"@string/go_back_img_des\"\n                android:focusable=\"true\" />\n        </FrameLayout>\n    </FrameLayout>\n\n   <!-- <FrameLayout\n        android:id=\"@+id/player_torrent_info\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingStart=\"20dp\"\n        android:paddingEnd=\"20dp\"\n        android:visibility=\"gone\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <TextView\n            android:id=\"@+id/video_torrent_progress\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"15dp\"\n            android:gravity=\"start\"\n            android:textColor=\"@color/white\"\n            android:textStyle=\"bold\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            tools:text=\"78% at 18kb/s\" />\n\n        <TextView\n            android:id=\"@+id/video_torrent_seeders\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"0dp\"\n            android:gravity=\"start\"\n            android:textColor=\"@color/white\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintTop_toBottomOf=\"@+id/player_video_title\"\n            tools:text=\"17 seeders\" />\n    </FrameLayout>-->\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_player_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/player_background\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@android:color/black\"\n    android:orientation=\"horizontal\"\n    app:backgroundTint=\"@android:color/black\"\n    app:surface_type=\"texture_view\">\n    <!--\n          app:fastforward_increment=\"10000\"\n            app:rewind_increment=\"10000\"-->\n    <androidx.media3.ui.PlayerView\n        android:id=\"@+id/player_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:focusable=\"false\"\n        app:auto_show=\"true\"\n        app:controller_layout_id=\"@layout/player_custom_layout_tv\"\n        app:hide_on_touch=\"false\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:show_timeout=\"0\" />\n\n    <FrameLayout\n        android:id=\"@+id/player_loading_overlay\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@android:color/black\"\n        android:backgroundTint=\"@android:color/black\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/overlay_loading_skip_button\"\n            style=\"@style/VideoButtonTV\"\n\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginTop=\"70dp\"\n            android:clickable=\"true\"\n            android:focusable=\"true\"\n            android:focusableInTouchMode=\"true\"\n            android:nextFocusLeft=\"@id/player_loading_go_back\"\n            android:nextFocusUp=\"@id/player_loading_go_back\"\n            android:text=\"@string/skip_loading\"\n\n            android:visibility=\"gone\"\n            app:icon=\"@drawable/ic_baseline_skip_next_24\"\n            tools:visibility=\"visible\" />\n\n        <ProgressBar\n            android:id=\"@+id/main_load\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            android:layout_gravity=\"center\" />\n\n        <FrameLayout\n            android:id=\"@+id/video_go_back_holder_holder\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"5dp\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\">\n\n            <ImageView\n                android:layout_width=\"30dp\"\n                android:layout_height=\"30dp\"\n                android:layout_gravity=\"center\"\n                android:src=\"@drawable/ic_baseline_arrow_back_24\"\n                app:tint=\"@android:color/white\" />\n\n            <ImageView\n                android:tag=\"@string/tv_no_focus_tag\"\n                android:id=\"@+id/player_loading_go_back\"\n                android:layout_width=\"70dp\"\n                android:layout_height=\"70dp\"\n                android:layout_gravity=\"center\"\n                android:background=\"@drawable/video_tap_button_always_white\"\n                android:clickable=\"false\"\n                android:focusable=\"false\"\n                android:focusableInTouchMode=\"false\"\n                android:nextFocusRight=\"@id/overlay_loading_skip_button\"\n                android:nextFocusDown=\"@id/overlay_loading_skip_button\" />\n        </FrameLayout>\n    </FrameLayout>\n\n    <!--<FrameLayout\n        android:id=\"@+id/player_torrent_info\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingStart=\"20dp\"\n        android:paddingEnd=\"20dp\"\n        android:visibility=\"gone\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <TextView\n            android:id=\"@+id/video_torrent_progress\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"15dp\"\n            android:gravity=\"start\"\n            android:textColor=\"@color/white\"\n            android:textStyle=\"bold\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            tools:text=\"78% at 18kb/s\" />\n\n        <TextView\n            android:id=\"@+id/video_torrent_seeders\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"0dp\"\n            android:gravity=\"start\"\n            android:textColor=\"@color/white\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintTop_toBottomOf=\"@+id/player_video_title\"\n            tools:text=\"17 seeders\" />\n    </FrameLayout>-->\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_plugin_details.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:backgroundTint=\"?attr/primaryGrayBackground\"\n    android:clipToPadding=\"false\"\n    android:orientation=\"vertical\"\n    tools:context=\".ui.settings.extensions.PluginDetailsFragment\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"horizontal\"\n        android:padding=\"20dp\"\n        android:visibility=\"visible\">\n\n\n        <androidx.cardview.widget.CardView\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\"\n            app:cardCornerRadius=\"25dp\">\n\n            <ImageView\n                android:id=\"@+id/plugin_icon\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                tools:ignore=\"ContentDescription\" />\n        </androidx.cardview.widget.CardView>\n\n        <TextView\n            android:id=\"@+id/plugin_name\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center_vertical\"\n            android:paddingStart=\"10dp\"\n            android:paddingEnd=\"10dp\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"normal\"\n            tools:text=\"Hello world\" />\n\n        <ImageView\n            android:id=\"@+id/action_settings\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginStart=\"16dp\"\n            android:background=\"?attr/selectableItemBackgroundBorderless\"\n            android:contentDescription=\"@string/title_settings\"\n            android:visibility=\"gone\"\n            android:focusable=\"true\"\n            app:srcCompat=\"@drawable/ic_baseline_tune_24\"\n            tools:visibility=\"visible\" />\n\n        <ImageView\n            android:id=\"@+id/github_btn\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:layout_marginStart=\"16dp\"\n            android:focusable=\"true\"\n            android:background=\"?attr/selectableItemBackgroundBorderless\"\n            android:src=\"@drawable/ic_github_logo\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:padding=\"8dp\">\n\n            <!--marquee_forever-->\n            <com.google.android.material.button.MaterialButton\n                style=\"@style/SmallBlackButton\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"10dp\"\n                android:focusable=\"false\"\n                android:text=\"@string/extension_description\" />\n\n            <TextView\n                android:id=\"@+id/plugin_description\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:layout_marginEnd=\"10dp\"\n\n                android:ellipsize=\"none\"\n\n                android:gravity=\"center_vertical\"\n                android:singleLine=\"false\"\n                android:textColor=\"?attr/textColor\"\n                tools:text=\"Lolem ipsum kek Lolem ipsum kek Lolem ipsum kek Lolem ipsum kek \" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:padding=\"8dp\">\n\n            <!--marquee_forever-->\n            <com.google.android.material.button.MaterialButton\n                style=\"@style/SmallBlackButton\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"10dp\"\n                android:focusable=\"false\"\n                android:text=\"@string/extension_authors\" />\n\n            <TextView\n                android:id=\"@+id/plugin_author\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:ellipsize=\"marquee\"\n\n                android:gravity=\"center_vertical\"\n\n                android:singleLine=\"false\"\n\n                android:textColor=\"?attr/textColor\"\n                tools:text=\"Lolem ipsum kek\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:padding=\"8dp\">\n\n            <!--marquee_forever-->\n            <com.google.android.material.button.MaterialButton\n                style=\"@style/SmallBlackButton\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"10dp\"\n                android:focusable=\"false\"\n                android:text=\"@string/extension_version\" />\n\n            <TextView\n                android:id=\"@+id/plugin_version\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:ellipsize=\"marquee\"\n\n                android:gravity=\"center_vertical\"\n\n                android:singleLine=\"true\"\n\n                android:textColor=\"?attr/textColor\"\n                tools:text=\"Lolem ipsum kek\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:padding=\"8dp\">\n\n            <!--marquee_forever-->\n            <com.google.android.material.button.MaterialButton\n                style=\"@style/SmallBlackButton\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"10dp\"\n                android:focusable=\"false\"\n                android:text=\"@string/extension_status\" />\n\n            <TextView\n                android:id=\"@+id/plugin_status\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:ellipsize=\"marquee\"\n\n                android:gravity=\"center_vertical\"\n\n                android:singleLine=\"true\"\n\n                android:textColor=\"?attr/textColor\"\n                tools:text=\"Lolem ipsum kek\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:padding=\"8dp\">\n\n            <!--marquee_forever-->\n            <com.google.android.material.button.MaterialButton\n                style=\"@style/SmallBlackButton\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"10dp\"\n                android:focusable=\"false\"\n                android:text=\"@string/extension_size\" />\n\n            <TextView\n                android:id=\"@+id/plugin_size\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:ellipsize=\"marquee\"\n\n                android:gravity=\"center_vertical\"\n\n                android:singleLine=\"true\"\n\n                android:textColor=\"?attr/textColor\"\n                tools:text=\"Lolem ipsum kek\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:padding=\"8dp\">\n\n            <!--marquee_forever-->\n\n            <com.google.android.material.button.MaterialButton\n                style=\"@style/SmallBlackButton\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"10dp\"\n                android:focusable=\"false\"\n                android:text=\"@string/extension_types\" />\n\n            <TextView\n                android:id=\"@+id/plugin_types\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:ellipsize=\"marquee\"\n\n                android:gravity=\"center_vertical\"\n\n                android:singleLine=\"false\"\n\n                android:textColor=\"?attr/textColor\"\n                tools:text=\"Lolem ipsum kek\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:padding=\"8dp\">\n\n            <!--marquee_forever-->\n\n            <com.google.android.material.button.MaterialButton\n                style=\"@style/SmallBlackButton\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"10dp\"\n                android:focusable=\"false\"\n                android:text=\"@string/extension_language\" />\n\n            <TextView\n                android:id=\"@+id/plugin_lang\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:ellipsize=\"marquee\"\n\n                android:gravity=\"center_vertical\"\n\n                android:singleLine=\"false\"\n\n                android:textColor=\"?attr/textColor\"\n                tools:text=\"Lolem ipsum kek\" />\n        </LinearLayout>\n\n    </LinearLayout>\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:gravity=\"center_horizontal|center_vertical\">\n\n        <TextView\n            android:id=\"@+id/plugin_votes\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"32dp\"\n            android:layout_marginEnd=\"16dp\"\n            android:layout_marginBottom=\"32dp\"\n            android:gravity=\"center_horizontal|center_vertical\"\n            android:text=\"0\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintEnd_toStartOf=\"@+id/upvote\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n\n        <ImageView\n            android:id=\"@+id/upvote\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginEnd=\"32dp\"\n            android:background=\"?attr/selectableItemBackgroundBorderless\"\n            android:src=\"@drawable/ic_baseline_thumb_up_24\"\n            android:focusable=\"true\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toEndOf=\"@+id/plugin_votes\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_plugins.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/extensions_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:orientation=\"vertical\">\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"?attr/primaryGrayBackground\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/settings_toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:paddingTop=\"@dimen/navbar_height\"\n            app:layout_scrollFlags=\"scroll|enterAlways\"\n            app:menu=\"@menu/repository\"\n            app:navigationIconTint=\"?attr/iconColor\"\n            app:titleTextColor=\"?attr/textColor\"\n            tools:title=\"Overlord\" />\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:paddingBottom=\"10dp\"\n            app:layout_scrollFlags=\"scroll|enterAlways\">\n\n            <include\n                android:id=\"@+id/tvtypes_chips_scroll\"\n                layout=\"@layout/tvtypes_chips_scroll\" />\n        </FrameLayout>\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/plugin_recycler_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:clipToPadding=\"false\"\n\n        android:nextFocusLeft=\"@id/nav_rail_view\"\n        android:nextFocusUp=\"@id/tvtypes_chips\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        tools:listitem=\"@layout/repository_item\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_result.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/result_root\"\n    style=\"@style/DarkFragment\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryBlackBackground\"\n    android:clickable=\"true\"\n    android:focusable=\"true\">\n\n    <com.facebook.shimmer.ShimmerFrameLayout\n        android:id=\"@+id/result_loading\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:orientation=\"vertical\"\n        app:shimmer_auto_start=\"true\"\n        app:shimmer_base_alpha=\"0.2\"\n        app:shimmer_duration=\"@integer/loading_time\"\n        app:shimmer_highlight_alpha=\"0.3\"\n        tools:visibility=\"gone\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"@dimen/result_padding\"\n            android:orientation=\"vertical\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginBottom=\"@dimen/loading_margin\"\n                android:orientation=\"horizontal\">\n\n                <include layout=\"@layout/loading_poster\" />\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_marginStart=\"@dimen/loading_margin\"\n                    android:layout_marginEnd=\"@dimen/loading_margin\"\n                    android:orientation=\"vertical\">\n\n                    <include layout=\"@layout/loading_line\" />\n\n                    <include layout=\"@layout/loading_line\" />\n\n                    <include layout=\"@layout/loading_line\" />\n\n                    <include layout=\"@layout/loading_line\" />\n\n                    <include layout=\"@layout/loading_line_short\" />\n                </LinearLayout>\n            </LinearLayout>\n\n            <ImageView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"20dp\"\n                tools:ignore=\"ContentDescription\" />\n\n            <include layout=\"@layout/loading_episode\" />\n\n            <include layout=\"@layout/loading_episode\" />\n\n            <include layout=\"@layout/loading_episode\" />\n        </LinearLayout>\n    </com.facebook.shimmer.ShimmerFrameLayout>\n    <!--<ProgressBar\n            android:visibility=\"visible\"\n            tools:visibility=\"gone\"\n            android:id=\"@+id/result_loading\"\n            android:layout_gravity=\"center\"\n            android:layout_width=\"50dp\" android:layout_height=\"50dp\">\n    </ProgressBar>-->\n    <LinearLayout\n        android:id=\"@+id/result_loading_error\"\n\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"gone\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/result_reload_connectionerror\"\n            style=\"@style/WhiteButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/reload_error\"\n            app:icon=\"@drawable/ic_baseline_autorenew_24\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/result_reload_connection_open_in_browser\"\n            style=\"@style/BlackButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/result_open_in_browser\"\n            app:icon=\"@drawable/ic_baseline_public_24\" />\n\n        <TextView\n            android:id=\"@+id/result_error_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:gravity=\"center\"\n            android:textColor=\"?attr/textColor\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/result_finish_loading\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <androidx.core.widget.NestedScrollView\n            android:id=\"@+id/result_scroll\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:clipToPadding=\"false\"\n            android:paddingBottom=\"100dp\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:background=\"?attr/primaryBlackBackground\"\n                android:orientation=\"vertical\">\n\n                <!--\n                <com.facebook.shimmer.ShimmerFrameLayout\n                    android:id=\"@+id/result_trailer_loading\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center\"\n                    android:orientation=\"vertical\"\n                    android:visibility=\"gone\"\n                    app:shimmer_auto_start=\"true\"\n                    app:shimmer_base_alpha=\"0.2\"\n                    app:shimmer_duration=\"@integer/loading_time\"\n                    app:shimmer_highlight_alpha=\"0.3\"\n                    tools:visibility=\"gone\">\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_margin=\"@dimen/result_padding\"\n                        android:orientation=\"vertical\">\n\n                        <androidx.cardview.widget.CardView\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"150dp\"\n                            android:background=\"@color/grayShimmer\"\n                            android:foreground=\"@drawable/outline_drawable\"\n                            app:cardCornerRadius=\"@dimen/loading_radius\" />\n                    </LinearLayout>\n                </com.facebook.shimmer.ShimmerFrameLayout>\n-->\n\n\n                <!--\n                <FrameLayout\n                        android:background=\"?attr/primaryGrayBackground\"\n                        android:paddingStart=\"@dimen/result_padding\"\n                        android:paddingEnd=\"@dimen/result_padding\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\">\n\n                    <ImageView\n                            android:nextFocusDown=\"@id/result_bookmark_button\"\n                            android:nextFocusRight=\"@id/result_share\"\n                            android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n\n                            android:id=\"@+id/result_back\"\n                            android:clickable=\"true\"\n                            android:focusable=\"true\"\n\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_gravity=\"center_vertical|start\"\n                            android:src=\"@drawable/ic_baseline_arrow_back_24\"\n                            android:contentDescription=\"@string/go_back\"\n                            app:tint=\"?attr/white\" />\n\n                    <LinearLayout\n                            android:gravity=\"end\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"50dp\"\n                            android:id=\"@+id/media_route_button_holder\"\n                            android:layout_gravity=\"center_vertical|end\">\n\n                        <androidx.mediarouter.app.MediaRouteButton\n                                android:layout_gravity=\"end|center_vertical\"\n                                android:id=\"@+id/media_route_button\"\n                                android:layout_width=\"50dp\"\n                                android:layout_height=\"50dp\"\n                                android:mediaRouteTypes=\"user\"\n                                android:visibility=\"gone\"\n                                app:mediaRouteButtonTint=\"?attr/textColor\" />\n\n\n                        <ImageView\n                                android:nextFocusUp=\"@id/result_back\"\n                                android:nextFocusDown=\"@id/result_descript\"\n                                android:nextFocusLeft=\"@id/result_add_sync\"\n                                android:nextFocusRight=\"@id/result_openinbrower\"\n\n                                android:id=\"@+id/result_share\"\n                                android:layout_width=\"25dp\"\n                                android:layout_height=\"25dp\"\n                                android:layout_marginEnd=\"10dp\"\n                                android:elevation=\"10dp\"\n\n                                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                                android:src=\"@drawable/ic_outline_share_24\"\n                                android:layout_gravity=\"end|center_vertical\"\n                                android:contentDescription=\"@string/result_share\"\n                                app:tint=\"?attr/textColor\" />\n\n                        <ImageView\n                                android:nextFocusUp=\"@id/result_back\"\n                                android:nextFocusDown=\"@id/result_descript\"\n                                android:nextFocusLeft=\"@id/result_share\"\n                                android:nextFocusRight=\"@id/result_search\"\n\n                                android:id=\"@+id/result_openinbrower\"\n                                android:layout_width=\"25dp\"\n                                android:layout_height=\"25dp\"\n                                android:layout_margin=\"5dp\"\n                                android:elevation=\"10dp\"\n\n                                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                                android:src=\"@drawable/ic_baseline_public_24\"\n                                android:layout_gravity=\"end|center_vertical\"\n                                android:contentDescription=\"@string/result_open_in_browser\"\n                                app:tint=\"?attr/textColor\" />\n\n                        <ImageView\n                                android:nextFocusUp=\"@id/result_back\"\n                                android:nextFocusDown=\"@id/result_descript\"\n                                android:nextFocusLeft=\"@id/result_openinbrower\"\n                                android:nextFocusRight=\"@id/result_bookmark_button\"\n\n                                android:id=\"@+id/result_search\"\n                                android:layout_width=\"30dp\"\n                                android:layout_height=\"30dp\"\n                                android:layout_margin=\"5dp\"\n                                android:elevation=\"10dp\"\n\n                                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                                android:src=\"@drawable/search_icon\"\n                                android:layout_gravity=\"end|center_vertical\"\n                                android:contentDescription=\"@string/result_open_in_browser\"\n                                app:tint=\"?attr/textColor\" />\n                    </LinearLayout>\n                </FrameLayout>-->\n                <FrameLayout\n                    android:id=\"@+id/result_top_holder\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"200dp\">\n\n                    <FrameLayout\n                        android:id=\"@+id/result_smallscreen_holder\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:descendantFocusability=\"blocksDescendants\">\n\n                        <include\n                            android:id=\"@+id/fragment_trailer\"\n                            layout=\"@layout/fragment_trailer\" />\n                    </FrameLayout>\n\n                    <FrameLayout\n                        android:id=\"@+id/result_poster_background_holder\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\">\n\n                        <ImageView\n                            android:id=\"@+id/result_poster_background\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"match_parent\"\n                            android:scaleType=\"centerCrop\" />\n\n                        <View\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"60dp\"\n                            android:layout_gravity=\"bottom\"\n                            android:background=\"@drawable/background_shadow\" />\n\n                        <ImageView\n                            android:id=\"@+id/background_poster_watermark_badge\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:maxWidth=\"220dp\"\n                            android:maxHeight=\"64dp\"\n                            android:layout_gravity=\"bottom|start\"\n                            android:layout_marginStart=\"@dimen/result_padding\"\n                            android:layout_marginBottom=\"12dp\"\n                            android:paddingBottom=\"4dp\"\n                            android:adjustViewBounds=\"true\"\n                            android:scaleType=\"fitStart\"\n                            android:contentDescription=\"@null\" />\n\n                    </FrameLayout>\n                </FrameLayout>\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:clipToPadding=\"false\"\n                    android:orientation=\"vertical\"\n                    android:paddingStart=\"@dimen/result_padding\"\n                    android:paddingEnd=\"@dimen/result_padding\">\n\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"10dp\"\n                        android:layout_marginBottom=\"15dp\"\n                        android:orientation=\"horizontal\"\n                        android:visibility=\"visible\">\n\n\n                        <androidx.cardview.widget.CardView\n                            android:id=\"@+id/result_poster_holder\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:visibility=\"gone\"\n                            app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n                            <ImageView\n                                android:id=\"@+id/result_poster\"\n                                android:layout_width=\"100dp\"\n                                android:layout_height=\"140dp\"\n                                android:layout_gravity=\"bottom\"\n                                android:contentDescription=\"@string/result_poster_img_des\"\n                                android:foreground=\"@drawable/outline_drawable\"\n                                android:scaleType=\"centerCrop\"\n                                tools:src=\"@drawable/example_poster\" />\n                        </androidx.cardview.widget.CardView>\n\n                        <LinearLayout\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"match_parent\"\n                            android:orientation=\"vertical\">\n\n                            <TextView\n                                android:id=\"@+id/result_title\"\n                                android:layout_width=\"wrap_content\"\n                                android:layout_height=\"wrap_content\"\n                                android:layout_marginBottom=\"5dp\"\n                                android:maxLines=\"2\"\n                                android:textColor=\"?attr/textColor\"\n                                android:textSize=\"20sp\"\n                                android:textStyle=\"bold\"\n                                tools:text=\"The Perfect Run The Perfect Run\" />\n\n                            <com.lagradost.cloudstream3.widget.FlowLayout\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"wrap_content\"\n                                app:itemSpacing=\"10dp\">\n\n                                <com.google.android.material.button.MaterialButton\n                                    android:id=\"@+id/result_meta_site\"\n                                    style=\"@style/SmallBlackButton\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    tools:text=\"Gogoanime\" />\n\n                                <com.google.android.material.button.MaterialButton\n                                    android:id=\"@+id/result_meta_content_rating\"\n                                    style=\"@style/SmallBlackButton\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    tools:text=\"PG-13\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_type\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"Movie\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_year\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"2022\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_rating\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"Rated: 8.5/10.0\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_status\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"Ongoing\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_duration\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"121min\" />\n                            </com.lagradost.cloudstream3.widget.FlowLayout>\n\n                            <!--\n                            This has half margin and half padding to make TV focus on description look better.\n                            The focus outline now settles between the poster and text.\n                            -->\n                            <FrameLayout\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"match_parent\">\n\n                                <TextView\n                                    android:id=\"@+id/result_description\"\n                                    android:layout_width=\"match_parent\"\n                                    android:layout_height=\"wrap_content\"\n                                    android:ellipsize=\"end\"\n                                    android:foreground=\"@drawable/outline_drawable\"\n                                    android:maxLines=\"10\"\n                                    android:nextFocusUp=\"@id/result_back\"\n                                    android:nextFocusDown=\"@id/result_bookmark_Button\"\n                                    android:paddingTop=\"5dp\"\n                                    android:textColor=\"?attr/textColor\"\n                                    android:textSize=\"15sp\"\n                                    tools:text=\"Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. \" />\n\n                                <ImageView\n                                    android:layout_width=\"match_parent\"\n                                    android:layout_height=\"30dp\"\n                                    android:layout_gravity=\"bottom\"\n                                    android:src=\"@drawable/background_shadow\"\n                                    android:visibility=\"gone\"\n                                    tools:ignore=\"ContentDescription\" />\n                            </FrameLayout>\n                        </LinearLayout>\n                    </LinearLayout>\n\n                    <!--\n                                        <com.google.android.material.button.MaterialButton\n                                                android:id=\"@+id/result_bookmark_button\"\n                                                style=\"@style/BlackButton\"\n                                                android:layout_width=\"wrap_content\"\n                                                android:layout_gravity=\"center_vertical\"\n                                                android:layout_marginStart=\"0dp\"\n                                                android:layout_marginTop=\"0dp\"\n\n                                                android:layout_marginBottom=\"10dp\"\n                                                android:backgroundTint=\"?attr/primaryBlackBackground\"\n\n                                                android:minWidth=\"100dp\"\n                                                android:nextFocusLeft=\"@id/result_back\"\n                                                android:nextFocusRight=\"@id/result_search\"\n                                                android:nextFocusUp=\"@id/result_description\"\n\n                                                android:nextFocusDown=\"@id/result_cast_items\"\n                                                android:paddingTop=\"0dp\"\n                                                app:cornerRadius=\"4dp\"\n                                                app:icon=\"@drawable/ic_baseline_bookmark_24\"\n                                                tools:text=\"Bookmark\"\n                                                tools:visibility=\"visible\" />\n                    -->\n\n                    <TextView\n                        android:id=\"@+id/result_cast_text\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginBottom=\"5dp\"\n                        android:ellipsize=\"end\"\n                        android:maxLines=\"2\"\n                        android:textColor=\"?attr/grayTextColor\"\n                        android:textSize=\"15sp\"\n                        tools:text=\"Cast: Joe Ligma\" />\n\n                    <androidx.recyclerview.widget.RecyclerView\n                        android:id=\"@+id/result_cast_items\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n\n                        android:descendantFocusability=\"afterDescendants\"\n                        android:fadingEdge=\"horizontal\"\n                        android:focusable=\"false\"\n                        android:focusableInTouchMode=\"false\"\n                        android:nextFocusUp=\"@id/result_bookmark_Button\"\n                        android:nextFocusDown=\"@id/result_play_movie\"\n                        android:orientation=\"horizontal\"\n                        android:paddingTop=\"5dp\"\n                        android:requiresFadingEdge=\"horizontal\"\n                        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                        tools:itemCount=\"2\"\n                        tools:listitem=\"@layout/cast_item\"\n                        tools:visibility=\"visible\" />\n\n                    <TextView\n                        android:id=\"@+id/result_vpn\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textColor=\"?attr/grayTextColor\"\n                        android:textSize=\"15sp\"\n                        tools:text=\"@string/vpn_torrent\" />\n\n                    <TextView\n                        android:id=\"@+id/result_info\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginBottom=\"5dp\"\n                        android:textColor=\"?attr/grayTextColor\"\n                        android:textSize=\"15sp\"\n                        tools:text=\"@string/provider_info_meta\" />\n\n                    <TextView\n                        android:id=\"@+id/result_no_episodes\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginBottom=\"5dp\"\n                        android:textColor=\"?attr/grayTextColor\"\n                        android:textSize=\"15sp\"\n                        tools:text=\"@string/no_episodes_found\" />\n\n                    <TextView\n                        android:id=\"@+id/result_tag_holder\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"10dp\"\n                        android:layout_marginBottom=\"10dp\"\n                        android:text=\"@string/result_tags\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"17sp\"\n                        android:textStyle=\"normal\"\n                        android:visibility=\"gone\" />\n\n                    <com.google.android.material.chip.ChipGroup\n                        android:id=\"@+id/result_tag\"\n                        style=\"@style/ChipParent\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\" />\n                    <!--<com.lagradost.cloudstream3.widget.FlowLayout\n                            android:id=\"@+id/result_tag\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"wrap_content\" />-->\n\n                    <TextView\n                        android:id=\"@+id/result_coming_soon\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center\"\n                        android:gravity=\"center\"\n                        android:paddingTop=\"50dp\"\n                        android:text=\"@string/coming_soon\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"20sp\"\n                        android:textStyle=\"bold\"\n                        android:visibility=\"gone\" />\n\n                    <LinearLayout\n                        android:id=\"@+id/result_data_holder\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"vertical\">\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/result_add_sync\"\n                            style=\"@style/WhiteButton\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_gravity=\"center_vertical\"\n                            android:layout_marginStart=\"0dp\"\n\n                            android:layout_marginBottom=\"10dp\"\n                            android:text=\"@string/add_sync\"\n                            android:visibility=\"gone\"\n                            app:icon=\"@drawable/ic_baseline_add_24\" />\n\n                        <FrameLayout\n                            android:id=\"@+id/result_resume_progress_holder\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"wrap_content\"\n                            android:orientation=\"horizontal\"\n                            android:paddingVertical=\"5dp\"\n                            android:visibility=\"gone\"\n                            tools:visibility=\"visible\">\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/result_resume_series_button\"\n                                style=\"@style/WhiteButton\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_margin=\"0dp\"\n                                android:visibility=\"visible\" />\n\n                            <LinearLayout\n                                android:id=\"@+id/progress_group\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"match_parent\"\n                                android:gravity=\"center\"\n                                android:orientation=\"horizontal\">\n\n                                <FrameLayout\n                                    android:id=\"@+id/watch_progress_container\"\n                                    android:layout_width=\"wrap_content\"\n                                    android:layout_height=\"wrap_content\"\n                                    android:layout_gravity=\"center\">\n\n                                    <ImageView\n                                        android:id=\"@+id/episode_play_icon\"\n                                        style=\"@style/ContinueWatchingPlayUnderlayProgress\"\n                                        app:tint=\"?attr/black\" />\n\n                                    <com.google.android.material.progressindicator.CircularProgressIndicator\n                                        android:id=\"@+id/result_resume_series_progress\"\n                                        style=\"@style/ContinueWatchingCircularProgress\"\n                                        app:indicatorColor=\"?attr/iconGrayBackground\"\n                                        app:trackColor=\"@color/skipOpTransparent\"\n                                        tools:progress=\"50\" />\n                                </FrameLayout>\n\n                                <TextView\n                                    android:id=\"@+id/result_resume_series_title\"\n                                    style=\"@style/Widget.MaterialComponents.Button.TextButton\"\n                                    android:layout_width=\"wrap_content\"\n                                    android:layout_height=\"match_parent\"\n                                    android:clickable=\"false\"\n                                    android:ellipsize=\"end\"\n                                    android:focusable=\"false\"\n                                    android:gravity=\"center_vertical\"\n                                    android:maxLines=\"1\"\n                                    android:paddingStart=\"5dp\"\n                                    android:textAllCaps=\"false\"\n                                    android:textColor=\"?attr/iconGrayBackground\"\n                                    android:textSize=\"15sp\"\n                                    android:textStyle=\"bold\"\n                                    android:visibility=\"visible\"\n                                    tools:ignore=\"RtlSymmetry\"\n                                    tools:text=\"S1E1 Episode 1\"\n                                    tools:visibility=\"visible\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_resume_series_progress_text\"\n                                    style=\"@style/Widget.MaterialComponents.Button.TextButton\"\n                                    android:layout_width=\"wrap_content\"\n                                    android:layout_height=\"match_parent\"\n                                    android:clickable=\"false\"\n                                    android:focusable=\"false\"\n                                    android:gravity=\"center\"\n                                    android:maxLines=\"1\"\n                                    android:paddingStart=\"5dp\"\n                                    android:textAllCaps=\"false\"\n                                    android:textColor=\"?attr/iconGrayBackground\"\n                                    android:textSize=\"15sp\"\n                                    android:textStyle=\"bold\"\n                                    android:visibility=\"gone\"\n                                    tools:ignore=\"RtlSymmetry\"\n                                    tools:text=\"69m remaining\"\n                                    tools:visibility=\"visible\" />\n                            </LinearLayout>\n                        </FrameLayout>\n\n                        <LinearLayout\n                            android:id=\"@+id/result_resume_parent\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"wrap_content\"\n                            android:orientation=\"vertical\"\n                            android:visibility=\"gone\"\n                            tools:visibility=\"visible\">\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/result_next_series_button\"\n                                style=\"@style/WhiteButton\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_gravity=\"center_vertical\"\n                                android:layout_marginVertical=\"5dp\"\n                                android:layout_marginStart=\"0dp\"\n                                android:layout_marginEnd=\"0dp\"\n                                android:ellipsize=\"end\"\n                                android:maxLines=\"1\"\n                                android:nextFocusUp=\"@id/result_bookmark_Button\"\n                                android:nextFocusDown=\"@id/result_download_movie\"\n                                android:text=\"S1E2 Episode 2\"\n                                android:visibility=\"gone\"\n                                app:icon=\"@drawable/cast_ic_mini_controller_skip_next\"\n                                tools:visibility=\"visible\" />\n                        </LinearLayout>\n\n                        <LinearLayout\n                            android:id=\"@+id/result_movie_parent\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"wrap_content\"\n                            android:orientation=\"vertical\"\n                            tools:visibility=\"visible\">\n\n                            <LinearLayout\n                                android:id=\"@+id/result_play_parent\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"wrap_content\"\n                                android:layout_marginVertical=\"5dp\">\n\n                                <com.google.android.material.button.MaterialButton\n                                    android:id=\"@+id/result_play_movie\"\n                                    style=\"@style/WhiteButton\"\n                                    android:layout_width=\"match_parent\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    android:layout_marginStart=\"0dp\"\n                                    android:layout_marginEnd=\"0dp\"\n                                    android:nextFocusUp=\"@id/result_bookmark_Button\"\n                                    android:nextFocusDown=\"@id/result_download_movie\"\n                                    android:text=\"@string/play_movie_button\"\n                                    android:visibility=\"visible\"\n                                    app:icon=\"@drawable/ic_baseline_play_arrow_24\">\n\n                                    <requestFocus />\n\n                                </com.google.android.material.button.MaterialButton>\n                            </LinearLayout>\n                            <!--<com.google.android.material.button.MaterialButton\n                                    android:nextFocusUp=\"@id/result_play_movie\"\n                                    android:nextFocusDown=\"@id/result_season_button\"\n                                    android:layout_marginBottom=\"10dp\"\n\n                                    android:id=\"@+id/result_download_movie\"\n                                    style=\"@style/BlackButton\"\n                                    android:layout_marginStart=\"0dp\"\n                                    android:layout_marginEnd=\"0dp\"\n                                    android:visibility=\"visible\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    tools:text=\"Downloading\"\n                                    tools:icon=\"@drawable/netflix_download\"\n\n                                    android:clickable=\"true\"\n                                    android:focusable=\"true\"\n                                    android:layout_width=\"match_parent\" />-->\n\n                            <com.lagradost.cloudstream3.ui.download.button.DownloadButton\n                                android:id=\"@+id/download_button\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"wrap_content\"\n                                android:layout_marginTop=\"5dp\"\n                                app:download_layout=\"@layout/download_button_layout\" />\n\n                            <!--<androidx.core.widget.ContentLoadingProgressBar\n                                    android:layout_width=\"match_parent\"\n                                    android:layout_height=\"20dp\"\n                                    tools:progress=\"50\"\n                                    android:id=\"@+id/result_movie_progress_downloaded\"\n                                    android:indeterminate=\"false\"\n                                    style=\"?android:attr/progressBarStyleHorizontal\"\n                                    android:progressBackgroundTint=\"?attr/colorPrimary\"\n                                    android:max=\"100\"\n                                    android:layout_gravity=\"end|center_vertical\"\n                                    android:progress=\"0\"\n                                    android:visibility=\"gone\"\n                                    tools:visibility=\"visible\" />\n    -->\n                            <!--  <TextView\n                                      android:id=\"@+id/result_movie_text_progress\"\n                                      android:layout_gravity=\"center_vertical\"\n                                      android:gravity=\"center_vertical\"\n                                      tools:text=\"128MB / 237MB\"\n                                      android:textColor=\"?attr/grayTextColor\"\n                                      android:layout_width=\"wrap_content\"\n                                      android:layout_height=\"match_parent\" />-->\n                        </LinearLayout>\n\n                        <LinearLayout\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"wrap_content\"\n                            android:orientation=\"vertical\">\n\n                            <com.lagradost.cloudstream3.widget.FlowLayout\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"wrap_content\"\n                                android:layout_marginBottom=\"10dp\"\n                                android:gravity=\"center_vertical\"\n                                android:orientation=\"horizontal\"\n                                app:itemSpacing=\"10dp\">\n\n                                <com.google.android.material.button.MaterialButton\n                                    android:id=\"@+id/result_season_button\"\n                                    style=\"@style/MultiSelectButton\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    android:layout_marginTop=\"10dp\"\n                                    android:layout_marginBottom=\"10dp\"\n                                    android:drawableEnd=\"@drawable/ic_baseline_keyboard_arrow_down_24\"\n                                    android:nextFocusLeft=\"@id/result_episode_select\"\n                                    android:nextFocusRight=\"@id/result_episode_select\"\n                                    android:nextFocusUp=\"@id/result_description\"\n                                    android:nextFocusDown=\"@id/result_episodes\"\n                                    android:paddingStart=\"10dp\"\n                                    android:paddingEnd=\"5dp\"\n                                    android:visibility=\"gone\"\n                                    tools:text=\"Season 1\"\n                                    tools:visibility=\"visible\" />\n\n                                <com.google.android.material.button.MaterialButton\n                                    android:id=\"@+id/result_episode_select\"\n                                    style=\"@style/MultiSelectButton\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    android:layout_marginTop=\"10dp\"\n                                    android:layout_marginBottom=\"10dp\"\n                                    android:drawableEnd=\"@drawable/ic_baseline_keyboard_arrow_down_24\"\n                                    android:nextFocusLeft=\"@id/result_season_button\"\n                                    android:nextFocusRight=\"@id/result_season_button\"\n                                    android:nextFocusUp=\"@id/result_description\"\n                                    android:nextFocusDown=\"@id/result_episodes\"\n                                    android:paddingStart=\"10dp\"\n                                    android:paddingEnd=\"5dp\"\n                                    android:visibility=\"gone\"\n                                    tools:text=\"50-100\"\n                                    tools:visibility=\"visible\" />\n\n                                <com.google.android.material.button.MaterialButton\n                                    android:id=\"@+id/result_dub_select\"\n                                    style=\"@style/MultiSelectButton\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    android:layout_marginTop=\"10dp\"\n                                    android:layout_marginBottom=\"10dp\"\n                                    android:drawableEnd=\"@drawable/ic_baseline_keyboard_arrow_down_24\"\n                                    android:nextFocusLeft=\"@id/result_season_button\"\n                                    android:nextFocusRight=\"@id/result_season_button\"\n                                    android:nextFocusUp=\"@id/result_description\"\n                                    android:nextFocusDown=\"@id/result_episodes\"\n                                    android:paddingStart=\"10dp\"\n                                    android:paddingEnd=\"5dp\"\n                                    android:visibility=\"gone\"\n                                    tools:text=\"Dubbed1\"\n                                    tools:visibility=\"visible\" />\n\n\n                                <com.google.android.material.button.MaterialButton\n                                    android:id=\"@+id/result_sort_button\"\n                                    style=\"@style/MultiSelectButton\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    android:layout_marginTop=\"10dp\"\n                                    android:layout_marginBottom=\"10dp\"\n                                    android:nextFocusLeft=\"@id/result_dub_select\"\n                                    android:nextFocusUp=\"@id/result_description\"\n                                    android:nextFocusDown=\"@id/result_episodes\"\n                                    android:paddingStart=\"10dp\"\n                                    android:paddingEnd=\"5dp\"\n                                    android:text=\"Sort\"\n                                    android:visibility=\"gone\"\n                                    tools:visibility=\"visible\" />\n\n                                <ImageView\n                                    android:background=\"?selectableItemBackgroundBorderless\"\n                                    android:id=\"@+id/result_batch_download_button\"\n                                    android:layout_width=\"36dp\"\n                                    android:layout_height=\"36dp\"\n                                    android:layout_margin=\"2dp\"\n                                    android:contentDescription=\"@string/download_all\"\n                                    android:nextFocusLeft=\"@id/result_dub_select\"\n                                    android:nextFocusUp=\"@id/result_description\"\n                                    android:nextFocusDown=\"@id/result_episodes\"\n                                    android:src=\"@drawable/netflix_download_batch\"\n                                    android:visibility=\"gone\"\n                                    tools:visibility=\"visible\">\n\n                                </ImageView>\n                                <TextView\n                                    android:id=\"@+id/result_episodes_text\"\n                                    android:layout_width=\"wrap_content\"\n                                    android:layout_height=\"wrap_content\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    android:layout_marginTop=\"10dp\"\n                                    android:layout_marginBottom=\"10dp\"\n                                    android:paddingTop=\"10dp\"\n                                    android:paddingBottom=\"10dp\"\n                                    android:textColor=\"?attr/textColor\"\n                                    android:textSize=\"17sp\"\n                                    android:textStyle=\"normal\"\n                                    tools:text=\"8 Episodes\" />\n                            </com.lagradost.cloudstream3.widget.FlowLayout>\n\n\n                            <!--TODO add next airing-->\n                            <LinearLayout\n                                android:id=\"@+id/result_next_airing_holder\"\n                                android:layout_width=\"wrap_content\"\n                                android:layout_height=\"wrap_content\"\n                                android:layout_gravity=\"start\"\n                                android:orientation=\"horizontal\">\n\n                                <TextView\n                                    android:id=\"@+id/result_next_airing\"\n\n                                    android:layout_width=\"match_parent\"\n                                    android:layout_height=\"wrap_content\"\n                                    android:gravity=\"center\"\n                                    android:textColor=\"?attr/grayTextColor\"\n                                    android:textSize=\"17sp\"\n                                    android:textStyle=\"normal\"\n                                    tools:text=\"Episode 1022 will be released in\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_next_airing_time\"\n                                    android:layout_width=\"match_parent\"\n                                    android:layout_height=\"wrap_content\"\n                                    android:gravity=\"center\"\n                                    android:paddingStart=\"5dp\"\n                                    android:paddingEnd=\"5dp\"\n                                    android:textColor=\"?attr/textColor\"\n                                    android:textSize=\"17sp\"\n                                    android:textStyle=\"normal\"\n                                    tools:text=\"5d 3h 30m\" />\n                            </LinearLayout>\n\n                            <com.facebook.shimmer.ShimmerFrameLayout\n                                android:id=\"@+id/result_episode_loading\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"match_parent\"\n                                android:layout_gravity=\"center\"\n                                android:layout_marginTop=\"15dp\"\n                                android:orientation=\"vertical\"\n                                app:shimmer_auto_start=\"true\"\n                                app:shimmer_base_alpha=\"0.2\"\n                                app:shimmer_duration=\"@integer/loading_time\"\n                                app:shimmer_highlight_alpha=\"0.3\"\n                                tools:visibility=\"visible\">\n\n                                <LinearLayout\n                                    android:layout_width=\"match_parent\"\n                                    android:layout_height=\"wrap_content\"\n                                    android:orientation=\"vertical\">\n\n                                    <include layout=\"@layout/loading_episode\" />\n\n                                    <include layout=\"@layout/loading_episode\" />\n\n                                    <include layout=\"@layout/loading_episode\" />\n\n                                    <include layout=\"@layout/loading_episode\" />\n                                </LinearLayout>\n                            </com.facebook.shimmer.ShimmerFrameLayout>\n                            <!--<androidx.core.widget.ContentLoadingProgressBar\n                                    android:id=\"@+id/result_episode_loading\"\n\n                                    style=\"@style/Widget.AppCompat.ProgressBar\"\n                                    android:layout_gravity=\"center\"\n                                    android:layout_width=\"50dp\"\n                                    android:layout_height=\"50dp\" />-->\n\n                            <androidx.recyclerview.widget.RecyclerView\n                                android:id=\"@+id/result_episodes\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"wrap_content\"\n                                android:layout_marginTop=\"0dp\"\n                                android:clipToPadding=\"false\"\n                                android:descendantFocusability=\"afterDescendants\"\n                                android:paddingBottom=\"100dp\"\n                                app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                                tools:listitem=\"@layout/result_episode\" />\n                        </LinearLayout>\n                    </LinearLayout>\n\n                </LinearLayout>\n            </LinearLayout>\n        </androidx.core.widget.NestedScrollView>\n\n    </LinearLayout>\n\n\n    <!--\n    <androidx.cardview.widget.CardView\n            android:layout_width=\"100dp\"\n            android:layout_height=\"150dp\"\n            app:cardCornerRadius=\"@dimen/roundedImageRadius\"\n            android:elevation=\"10dp\"\n    >\n        <ImageView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:scaleType=\"centerCrop\"\n                android:id=\"@+id/result_poster\"\n                android:clickable=\"true\"\n                android:focusable=\"true\"\n                tools:src=\"@drawable/example_poster\"\n                android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/search_poster_descript\"/>\n    </androidx.cardview.widget.CardView>-->\n\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_result_swipe.xml",
    "content": "<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:orientation=\"vertical\"\n        style=\"@style/AlertDialogCustom\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    <FrameLayout\n            android:id=\"@+id/result_top_bar\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:paddingStart=\"@dimen/result_padding\"\n            android:paddingEnd=\"@dimen/result_padding\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n        <LinearLayout\n                android:orientation=\"horizontal\"\n                android:gravity=\"center_vertical\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n            <ImageView\n                    android:nextFocusRight=\"@id/result_mini_sync\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n\n                    android:id=\"@+id/result_back\"\n                    android:clickable=\"true\"\n                    android:focusable=\"true\"\n\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center_vertical|start\"\n                    android:src=\"@drawable/ic_baseline_arrow_back_24\"\n                    android:contentDescription=\"@string/go_back\"\n                    app:tint=\"?attr/white\" />\n\n            <ImageView\n                android:visibility=\"gone\"\n                android:nextFocusRight=\"@id/result_subscribe\"\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n\n                android:id=\"@+id/result_mini_sync\"\n                android:clickable=\"true\"\n                android:focusable=\"true\"\n\n                android:layout_width=\"30dp\"\n                android:layout_height=\"30dp\"\n                android:layout_marginStart=\"5dp\"\n                android:layout_gravity=\"center_vertical|start\"\n                android:src=\"@drawable/bookmark_star_24px\"\n                app:tint=\"?attr/white\" />\n        </LinearLayout>\n\n        <LinearLayout\n                android:gravity=\"end\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"50dp\"\n                android:id=\"@+id/media_route_button_holder\"\n                android:animateLayoutChanges=\"true\"\n                android:layout_gravity=\"center_vertical|end\">\n\n            <androidx.mediarouter.app.MediaRouteButton\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:id=\"@+id/media_route_button\"\n                    android:layout_width=\"50dp\"\n                    android:layout_height=\"50dp\"\n                    android:mediaRouteTypes=\"user\"\n                    android:visibility=\"gone\"\n                    app:mediaRouteButtonTint=\"?attr/textColor\" />\n\n            <ImageView\n                    android:visibility=\"gone\"\n                    android:nextFocusUp=\"@id/result_back\"\n                    android:nextFocusDown=\"@id/result_description\"\n                    android:nextFocusLeft=\"@id/result_add_sync\"\n                    android:nextFocusRight=\"@id/result_favorite\"\n\n                    tools:visibility=\"visible\"\n\n                    android:id=\"@+id/result_subscribe\"\n                    android:layout_width=\"25dp\"\n                    android:layout_height=\"25dp\"\n                    android:layout_margin=\"5dp\"\n                    android:elevation=\"10dp\"\n                    android:tooltipText=\"@string/subscribe_tooltip\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:src=\"@drawable/baseline_notifications_none_24\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    app:tint=\"?attr/textColor\" />\n\n            <ImageView\n                android:nextFocusUp=\"@id/result_back\"\n                android:nextFocusDown=\"@id/result_description\"\n                android:nextFocusLeft=\"@id/result_subscribe\"\n                android:nextFocusRight=\"@id/result_share\"\n\n                android:id=\"@+id/result_favorite\"\n                android:layout_width=\"25dp\"\n                android:layout_height=\"25dp\"\n                android:layout_margin=\"5dp\"\n                android:elevation=\"10dp\"\n                android:tooltipText=\"@string/action_add_to_favorites\"\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:src=\"@drawable/ic_baseline_favorite_border_24\"\n                android:layout_gravity=\"end|center_vertical\"\n                app:tint=\"?attr/textColor\" />\n\n            <ImageView\n                    android:nextFocusUp=\"@id/result_back\"\n                    android:nextFocusDown=\"@id/result_description\"\n                    android:nextFocusLeft=\"@id/result_favorite\"\n                    android:nextFocusRight=\"@id/result_open_in_browser\"\n\n                    android:id=\"@+id/result_share\"\n                    android:layout_width=\"25dp\"\n                    android:layout_height=\"25dp\"\n                    android:layout_margin=\"5dp\"\n                    android:elevation=\"10dp\"\n                    android:tooltipText=\"@string/result_share\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:src=\"@drawable/ic_outline_share_24\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:contentDescription=\"@string/result_share\"\n                    app:tint=\"?attr/textColor\" />\n\n            <ImageView\n                    android:nextFocusUp=\"@id/result_back\"\n                    android:nextFocusDown=\"@id/result_description\"\n                    android:nextFocusLeft=\"@id/result_share\"\n                    android:nextFocusRight=\"@id/result_search\"\n\n                    android:id=\"@+id/result_open_in_browser\"\n                    android:layout_width=\"25dp\"\n                    android:layout_height=\"25dp\"\n                    android:layout_margin=\"5dp\"\n                    android:elevation=\"10dp\"\n                    android:tooltipText=\"@string/result_open_in_browser\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:src=\"@drawable/ic_baseline_public_24\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:contentDescription=\"@string/result_open_in_browser\"\n                    app:tint=\"?attr/textColor\" />\n\n            <ImageView\n                    android:nextFocusUp=\"@id/result_back\"\n                    android:nextFocusDown=\"@id/result_description\"\n                    android:nextFocusLeft=\"@id/result_open_in_browser\"\n                    android:nextFocusRight=\"@id/result_recommendations_btt\"\n\n                    android:id=\"@+id/result_search\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_margin=\"5dp\"\n                    android:elevation=\"10dp\"\n                    android:tooltipText=\"@string/result_search_tooltip\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:src=\"@drawable/search_icon\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:contentDescription=\"@string/result_open_in_browser\"\n                    app:tint=\"?attr/textColor\" />\n            <ImageView\n                    tools:visibility=\"visible\"\n                    android:visibility=\"gone\"\n                    android:nextFocusUp=\"@id/result_back\"\n                    android:nextFocusDown=\"@id/result_description\"\n                    android:nextFocusLeft=\"@id/result_search\"\n\n                    android:id=\"@+id/result_recommendations_btt\"\n                    android:layout_width=\"25dp\"\n                    android:layout_height=\"25dp\"\n                    android:layout_margin=\"5dp\"\n                    android:elevation=\"10dp\"\n                    android:tooltipText=\"@string/recommendations_tooltip\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:src=\"@drawable/baseline_list_alt_24\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:contentDescription=\"@string/result_open_in_browser\"\n                    app:tint=\"?attr/textColor\" />\n        </LinearLayout>\n    </FrameLayout>\n\n    <FrameLayout\n            android:visibility=\"gone\"\n            android:id=\"@+id/result_fullscreen_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n    </FrameLayout>\n\n    <FrameLayout\n            android:id=\"@+id/result_main_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n        <com.discord.panels.OverlappingPanelsLayout\n                android:id=\"@+id/result_overlapping_panels\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\">\n\n            <!-- Set layout_gravity on the start panel to \"start\" -->\n            <FrameLayout\n                    android:visibility=\"gone\"\n                    android:id=\"@+id/start_panel\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"start\">\n\n                <include layout=\"@layout/result_sync\" android:id=\"@+id/result_sync\"/>\n            </FrameLayout>\n\n            <FrameLayout\n                    android:id=\"@+id/center_panel\"\n                    android:layout_gravity=\"center\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\">\n\n                <include layout=\"@layout/fragment_result\" android:id=\"@+id/fragment_result\" />\n\n            </FrameLayout>\n\n            <!-- Set layout_gravity on the end panel to \"end\" -->\n            <FrameLayout\n                    android:id=\"@+id/end_panel\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"end\">\n\n                <include layout=\"@layout/result_recommendations\" android:id=\"@+id/result_recommendations\" />\n            </FrameLayout>\n        </com.discord.panels.OverlappingPanelsLayout>\n\n        <LinearLayout\n                android:layout_gravity=\"bottom\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n\n            <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\"\n                    android:id=\"@+id/result_bookmark_fab\"\n                    app:icon=\"@drawable/ic_baseline_bookmark_24\"\n                    style=\"@style/ExtendedFloatingActionButton\"\n                    tools:ignore=\"ContentDescription\" />\n\n            <fragment\n                    app:customCastBackgroundColor=\"?attr/primaryBlackBackground\"\n                    app:castControlButtons=\"@array/cast_mini_controller_control_buttons\"\n                    android:id=\"@+id/cast_mini_controller\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:visibility=\"gone\"\n                    class=\"com.lagradost.cloudstream3.ui.MyMiniControllerFragment\"\n                    tools:ignore=\"FragmentTagUsage\" />\n        </LinearLayout>\n    </FrameLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_result_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--\nhttps://developer.android.com/design/ui/tv/guides/foundations/navigation-on-tv\n1. Don't display a back button\n\nhttps://developer.android.com/design/ui/tv/guides/styles/layouts\nTwo-pane layout\nor https://developer.android.com/design/ui/tv/guides/styles/layouts#layout-templates\n\ncast:\nhttps://developer.android.com/design/ui/tv/guides/components/cards#1:1\n\nhttps://developer.android.com/design/ui/tv/samples/jet-fit\n-->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/result_root\"\n    style=\"@style/DarkFragment\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryBlackBackground\">\n\n    <FrameLayout\n        android:id=\"@+id/background_poster_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"275dp\"\n        android:visibility=\"visible\">\n\n\n        <com.lagradost.cloudstream3.utils.PercentageCropImageView\n            android:id=\"@+id/background_poster\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"275dp\"\n            android:layout_gravity=\"center\"\n            android:alpha=\"0.8\"\n            android:scaleType=\"matrix\"\n            app:cropYCenterOffsetPct=\"0.20\"\n            tools:src=\"@drawable/profile_bg_dark_blue\" />\n\n        <ImageView\n            android:layout_marginBottom=\"-1dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"120dp\"\n            android:layout_gravity=\"bottom\"\n            android:src=\"@drawable/background_shadow\" />\n\n        <ImageView\n            android:id=\"@+id/background_poster_watermark_badge_holder\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:maxWidth=\"220dp\"\n            android:maxHeight=\"72dp\"\n            android:layout_gravity=\"bottom|start\"\n            android:layout_marginStart=\"@dimen/result_padding\"\n            android:layout_marginBottom=\"56dp\"\n            android:adjustViewBounds=\"true\"\n            android:scaleType=\"fitStart\"\n            android:contentDescription=\"@null\" />\n\n    </FrameLayout>\n\n    <com.facebook.shimmer.ShimmerFrameLayout\n        android:id=\"@+id/result_loading\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:orientation=\"vertical\"\n        app:shimmer_auto_start=\"true\"\n        app:shimmer_base_alpha=\"0.2\"\n        app:shimmer_duration=\"@integer/loading_time\"\n        app:shimmer_highlight_alpha=\"0.3\"\n        tools:visibility=\"gone\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"@dimen/result_padding\"\n            android:orientation=\"vertical\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginBottom=\"@dimen/loading_margin\"\n                android:orientation=\"horizontal\">\n\n                <include layout=\"@layout/loading_poster\" />\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_marginStart=\"@dimen/loading_margin\"\n                    android:layout_marginEnd=\"@dimen/loading_margin\"\n                    android:orientation=\"vertical\">\n\n                    <include layout=\"@layout/loading_line\" />\n\n                    <include layout=\"@layout/loading_line\" />\n\n                    <include layout=\"@layout/loading_line\" />\n\n                    <include layout=\"@layout/loading_line\" />\n\n                    <include layout=\"@layout/loading_line_short\" />\n                </LinearLayout>\n            </LinearLayout>\n\n            <ImageView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"20dp\"\n                tools:ignore=\"ContentDescription\" />\n\n            <include layout=\"@layout/loading_episode\" />\n\n            <include layout=\"@layout/loading_episode\" />\n\n            <include layout=\"@layout/loading_episode\" />\n        </LinearLayout>\n    </com.facebook.shimmer.ShimmerFrameLayout>\n\n    <LinearLayout\n        android:id=\"@+id/result_loading_error\"\n\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"gone\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/result_reload_connectionerror\"\n            style=\"@style/WhiteButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/reload_error\"\n            app:icon=\"@drawable/ic_baseline_autorenew_24\" />\n\n        <!--\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/result_reload_connection_open_in_browser\"\n            style=\"@style/BlackButton\"\n\n            android:layout_width=\"wrap_content\"\n\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:minWidth=\"200dp\"\n            android:text=\"@string/result_open_in_browser\"\n            app:icon=\"@drawable/ic_baseline_public_24\" />\n            -->\n\n        <TextView\n            android:id=\"@+id/result_error_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_margin=\"5dp\"\n            android:gravity=\"center\"\n            android:textColor=\"?attr/textColor\" />\n    </LinearLayout>\n\n    <androidx.core.widget.NestedScrollView\n        android:id=\"@+id/result_finish_loading\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:paddingStart=\"@dimen/result_padding\"\n            android:paddingEnd=\"@dimen/result_padding\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"225dp\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:id=\"@+id/result_title\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:ellipsize=\"marquee\"\n                    android:gravity=\"center_vertical\"\n                    android:singleLine=\"true\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"25sp\"\n                    android:textStyle=\"bold\"\n                    tools:text=\"The Perfect Run The Perfect Run\" />\n\n                <TextView\n                    android:id=\"@+id/result_episodes_text\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"17sp\"\n                    android:textStyle=\"normal\"\n                    android:visibility=\"gone\"\n                    tools:text=\"8 Episodes\"\n                    tools:visibility=\"visible\" />\n\n                <LinearLayout\n                    android:id=\"@+id/result_next_airing_holder\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"start\"\n                    android:orientation=\"horizontal\">\n\n                    <TextView\n                        android:id=\"@+id/result_next_airing\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginEnd=\"5dp\"\n                        android:gravity=\"start\"\n                        android:textColor=\"?attr/grayTextColor\"\n                        android:textSize=\"17sp\"\n                        android:textStyle=\"normal\"\n                        tools:text=\"Season 2 Episode 1022 will be released in\" />\n\n                    <TextView\n                        android:id=\"@+id/result_next_airing_time\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:gravity=\"start\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"17sp\"\n                        android:textStyle=\"normal\"\n                        tools:text=\"5d 3h 30m\" />\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/result_resume_progress_holder\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginBottom=\"10dp\"\n                    android:orientation=\"horizontal\"\n                    android:layout_marginTop=\"10dp\"\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\">\n                    <TextView\n                        android:id=\"@+id/result_resume_series_title\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_weight=\"2\"\n                        android:textColor=\"?attr/textColor\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:textSize=\"17sp\"\n                        android:textStyle=\"bold\"\n                        tools:text=\"S1E1 Episode 1\"\n                        android:visibility=\"visible\"\n                        tools:visibility=\"visible\"\n                        android:paddingEnd=\"10dp\"/>\n                    <!--https://github.com/material-components/material-components-android/blob/master/docs/components/ProgressIndicator.md-->\n<!--                    <com.google.android.material.progressindicator.LinearProgressIndicator-->\n<!--                        android:id=\"@+id/result_resume_series_progress\"-->\n\n<!--                        style=\"@style/RoundProgressbar\"-->\n\n<!--                        android:layout_width=\"100dp\"-->\n<!--                        android:layout_height=\"20dp\"-->\n<!--                        android:layout_gravity=\"end|center_vertical\"-->\n<!--                        android:layout_weight=\"1\"-->\n<!--                        android:indeterminate=\"false\"-->\n<!--                        android:max=\"100\"-->\n<!--                        android:paddingEnd=\"10dp\"-->\n<!--                        android:progress=\"0\"-->\n\n<!--                        android:scrollbarStyle=\"outsideInset\"-->\n<!--                        tools:ignore=\"RtlSymmetry\"-->\n<!--                        tools:progress=\"25\"-->\n<!--                        tools:visibility=\"visible\" />-->\n                    <FrameLayout\n                        android:id=\"@+id/watch_progress_container\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center\">\n\n                        <ImageView\n                            android:id=\"@+id/episode_play_icon\"\n                            style=\"@style/ContinueWatchingPlayUnderlayProgress\"/>\n\n                        <com.google.android.material.progressindicator.CircularProgressIndicator\n                            android:id=\"@+id/result_resume_series_progress\"\n                            style=\"@style/ContinueWatchingCircularProgress\"\n                            tools:progress=\"50\" />\n                    </FrameLayout>\n\n                    <TextView\n                        android:id=\"@+id/result_resume_series_progress_text\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:maxLines=\"2\"\n                        android:textColor=\"?attr/grayTextColor\"\n                        tools:ignore=\"RtlSymmetry\"\n                        android:gravity=\"center\"\n                        android:layout_gravity=\"center_vertical\"\n                        tools:text=\"69m\\nremaining\" />\n                </LinearLayout>\n            </LinearLayout>\n\n            <LinearLayout\n                android:id=\"@+id/result_play_parent\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"20dp\"\n                android:layout_marginBottom=\"5dp\"\n                android:descendantFocusability=\"afterDescendants\"\n                android:orientation=\"horizontal\">\n\n                <LinearLayout\n                    android:id=\"@+id/result_play_movie\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"8dp\"\n                    android:orientation=\"vertical\"\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/result_play_movie_button\"\n                        style=\"@style/ResultSmallButtonTV\"\n                        android:focusable=\"true\"\n                        android:nextFocusUp=\"@id/result_play_movie_button\"\n                        android:nextFocusDown=\"@id/result_description\"\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:icon=\"@drawable/ic_baseline_play_arrow_24\"\n                        app:iconPadding=\"0dp\" />\n\n                    <TextView\n                        android:id=\"@+id/result_play_movie_text\"\n                        style=\"@style/ResultMarqueeButtonText\"\n                        android:text=\"@string/movies_singular\" />\n\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/result_play_series\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"8dp\"\n                    android:orientation=\"vertical\"\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/result_play_series_button\"\n                        style=\"@style/ResultSmallButtonTV\"\n                        android:focusable=\"true\"\n                        android:nextFocusUp=\"@id/result_play_series_button\"\n                        android:nextFocusDown=\"@id/result_description\"\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:icon=\"@drawable/ic_baseline_play_arrow_24\"\n                        app:iconPadding=\"0dp\" />\n\n                    <TextView\n                        android:id=\"@+id/result_play_series_text\"\n                        style=\"@style/ResultMarqueeButtonText\"\n                        android:text=\"@string/episode\" />\n\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/result_resume_series\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"8dp\"\n                    android:orientation=\"vertical\"\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/result_resume_series_button\"\n                        style=\"@style/ResultSmallButtonTV\"\n                        android:focusable=\"true\"\n                        android:nextFocusUp=\"@id/result_resume_series_button\"\n                        android:nextFocusDown=\"@id/result_description\"\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:icon=\"@drawable/ic_baseline_resume_arrow2\"\n                        app:iconPadding=\"0dp\" />\n\n                    <TextView\n                        android:id=\"@+id/result_resume_series_text\"\n                        style=\"@style/ResultMarqueeButtonText\"\n                        android:text=\"@string/resume\" />\n\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/result_play_trailer\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"8dp\"\n                    android:orientation=\"vertical\"\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/result_play_trailer_button\"\n                        style=\"@style/ResultSmallButtonTV\"\n                        android:focusable=\"true\"\n                        android:nextFocusUp=\"@id/result_play_trailer_button\"\n                        android:nextFocusDown=\"@id/result_description\"\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:icon=\"@drawable/ic_baseline_film_roll_24\"\n                        app:iconPadding=\"0dp\" />\n\n                    <TextView\n                        android:id=\"@+id/result_play_trailer_text\"\n                        style=\"@style/ResultMarqueeButtonText\"\n                        android:text=\"@string/play_trailer_button\" />\n\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/result_bookmark\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"8dp\"\n                    android:orientation=\"vertical\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/result_bookmark_Button\"\n                        style=\"@style/ResultSmallButtonTV\"\n                        android:focusable=\"true\"\n                        android:nextFocusUp=\"@id/result_bookmark_Button\"\n                        android:nextFocusDown=\"@id/result_description\"\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:icon=\"@drawable/outline_bookmark_add_24\"\n                        app:iconPadding=\"0dp\" />\n\n                    <TextView\n                        android:id=\"@+id/result_bookmark_text\"\n                        style=\"@style/ResultMarqueeButtonText\"\n                        android:text=\"@string/type_none\" />\n\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/result_favorite\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"8dp\"\n                    android:orientation=\"vertical\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/result_favorite_Button\"\n                        style=\"@style/ResultSmallButtonTV\"\n                        android:focusable=\"true\"\n                        android:nextFocusUp=\"@id/result_favorite_Button\"\n                        android:nextFocusDown=\"@id/result_description\"\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:icon=\"@drawable/ic_baseline_favorite_border_24\"\n                        app:iconPadding=\"0dp\" />\n\n                    <TextView\n                        android:id=\"@+id/result_favorite_Text\"\n                        style=\"@style/ResultMarqueeButtonText\"\n                        android:text=\"@string/favorite\" />\n\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/result_subscribe\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"8dp\"\n                    android:orientation=\"vertical\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/result_subscribe_Button\"\n                        style=\"@style/ResultSmallButtonTV\"\n                        android:focusable=\"true\"\n                        android:nextFocusUp=\"@id/result_subscribe_Button\"\n                        android:nextFocusDown=\"@id/result_description\"\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:icon=\"@drawable/baseline_notifications_none_24\"\n                        app:iconPadding=\"0dp\" />\n\n                    <TextView\n                        android:id=\"@+id/result_subscribe_text\"\n                        style=\"@style/ResultMarqueeButtonText\"\n                        android:text=\"@string/action_subscribe\" />\n\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/result_search\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"8dp\"\n                    android:orientation=\"vertical\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/result_search_Button\"\n                        style=\"@style/ResultSmallButtonTV\"\n                        android:focusable=\"true\"\n                        android:nextFocusUp=\"@id/result_search_Button\"\n                        android:nextFocusDown=\"@id/result_description\"\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:icon=\"@drawable/search_icon\"\n                        app:iconPadding=\"0dp\" />\n\n                    <TextView\n                        android:id=\"@+id/result_search_text\"\n                        style=\"@style/ResultMarqueeButtonText\"\n                        android:text=\"@string/title_search\" />\n\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/result_episodes_show\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"8dp\"\n                    android:orientation=\"vertical\"\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/result_episodes_show_button\"\n                        style=\"@style/ResultSmallButtonTV\"\n                        android:focusable=\"true\"\n                        android:nextFocusRight=\"@id/redirect_to_episodes\"\n                        android:nextFocusUp=\"@id/result_episodes_show_button\"\n                        android:nextFocusDown=\"@id/result_description\"\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:icon=\"@drawable/ic_baseline_sort_24\"\n                        app:iconPadding=\"0dp\" />\n\n                    <TextView\n                        android:id=\"@+id/result_episodes_show_text\"\n                        style=\"@style/ResultMarqueeButtonText\"\n                        android:text=\"@string/episodes\" />\n\n                </LinearLayout>\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:baselineAligned=\"false\"\n                android:orientation=\"horizontal\">\n\n                <LinearLayout\n                    android:id=\"@+id/right_layout\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:orientation=\"vertical\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:layout_constraintEnd_toEndOf=\"parent\"\n                    app:layout_constraintStart_toEndOf=\"@+id/linearLayout2\"\n                    app:layout_constraintTop_toTopOf=\"parent\"\n                    tools:ignore=\"UselessParent\">\n\n                    <com.lagradost.cloudstream3.widget.FlowLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginBottom=\"5dp\"\n                        app:itemSpacing=\"10dp\">\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/result_meta_site\"\n                            style=\"@style/SmallWhiteButton\"\n                            android:layout_gravity=\"center_vertical\"\n                            tools:text=\"Gogoanime\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/result_meta_content_rating\"\n                            style=\"@style/SmallWhiteButton\"\n                            android:layout_gravity=\"center_vertical\"\n                            android:focusable=\"false\"\n                            tools:text=\"PG-13\" />\n\n                        <TextView\n                            android:id=\"@+id/result_meta_type\"\n                            style=\"@style/ResultInfoText\"\n                            tools:text=\"Movie\" />\n\n                        <TextView\n                            android:id=\"@+id/result_meta_year\"\n                            style=\"@style/ResultInfoText\"\n                            tools:text=\"2022\" />\n\n                        <TextView\n                            android:id=\"@+id/result_meta_rating\"\n                            style=\"@style/ResultInfoText\"\n                            tools:text=\"Rated: 8.5/10.0\" />\n\n                        <TextView\n                            android:id=\"@+id/result_meta_status\"\n                            style=\"@style/ResultInfoText\"\n                            tools:text=\"Ongoing\" />\n\n                        <TextView\n                            android:id=\"@+id/result_meta_duration\"\n                            style=\"@style/ResultInfoText\"\n                            tools:text=\"121min\" />\n                    </com.lagradost.cloudstream3.widget.FlowLayout>\n\n\n                    <TextView\n                        android:id=\"@+id/result_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:ellipsize=\"end\"\n                        android:fadingEdgeLength=\"30dp\"\n                        android:focusable=\"true\"\n                        android:foreground=\"@drawable/outline_drawable\"\n                        android:maxLines=\"7\"\n                        android:nextFocusUp=\"@id/result_play_parent\"\n                        android:nextFocusDown=\"@id/result_cast_items\"\n                        android:padding=\"5dp\"\n                        android:requiresFadingEdge=\"vertical\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"16sp\"\n                        tools:text=\"Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. \" />\n\n                    <com.google.android.material.chip.ChipGroup\n                        android:id=\"@+id/result_tag\"\n                        style=\"@style/ChipParent\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\" />\n                </LinearLayout>\n            </LinearLayout>\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/result_cast_items\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:descendantFocusability=\"afterDescendants\"\n\n                android:fadingEdge=\"horizontal\"\n                android:nextFocusUp=\"@id/result_description\"\n                android:nextFocusDown=\"@id/result_recommendations_list\"\n                android:orientation=\"horizontal\"\n                android:paddingTop=\"5dp\"\n                android:requiresFadingEdge=\"horizontal\"\n                app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                tools:itemCount=\"2\"\n                tools:listitem=\"@layout/cast_item\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/result_tv_coming_soon\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:gravity=\"center\"\n                android:paddingTop=\"50dp\"\n                android:text=\"@string/coming_soon\"\n                android:textColor=\"?attr/textColor\"\n                android:textSize=\"20sp\"\n                android:textStyle=\"bold\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n            <LinearLayout\n                android:id=\"@+id/result_recommendations_holder\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:descendantFocusability=\"afterDescendants\"\n                android:orientation=\"horizontal\"\n                android:paddingTop=\"10dp\"\n                android:paddingBottom=\"10dp\">\n\n                <androidx.recyclerview.widget.RecyclerView\n                    android:id=\"@+id/result_recommendations_filter_selection\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginEnd=\"10dp\"\n                    android:descendantFocusability=\"afterDescendants\"\n                    android:nextFocusUp=\"@id/result_cast_items\"\n                    android:nextFocusDown=\"@id/result_recommendations_list\"\n                    android:orientation=\"horizontal\"\n                    app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                    tools:itemCount=\"2\"\n                    tools:listitem=\"@layout/result_selection\" />\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:gravity=\"center_vertical\"\n                    android:text=\"@string/recommended\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"17sp\" />\n            </LinearLayout>\n\n            <com.lagradost.cloudstream3.ui.AutofitRecyclerView\n                android:id=\"@+id/result_recommendations_list\"\n                android:layout_width=\"match_parent\"\n\n                android:layout_height=\"wrap_content\"\n                android:clipToPadding=\"false\"\n                android:descendantFocusability=\"afterDescendants\"\n                android:nextFocusUp=\"@id/result_cast_items\"\n                android:orientation=\"vertical\"\n                app:spanCount=\"8\"\n                tools:listitem=\"@layout/search_result_grid\" />\n        </LinearLayout>\n    </androidx.core.widget.NestedScrollView>\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:id=\"@+id/episodes_shadow\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"end\"\n        android:visibility=\"gone\"\n        tools:visibility=\"invisible\">\n\n\n        <!--\n         These two shadow spaces are used to create a view which always x% bigger\n         than the episode_holder_tv. This is required for creating a consistent shadow.\n        -->\n        <Space\n            android:id=\"@+id/shadow_space_1\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintDimensionRatio=\"1:1\"\n            app:layout_constraintEnd_toEndOf=\"@+id/episode_holder_tv\"\n            app:layout_constraintStart_toStartOf=\"@+id/episode_holder_tv\" />\n\n        <!--\n        The dimension ratio should and episodes_shadow centerX should add up to\n        100% for the best results. For example (100:80 + 0.2) or (100:70 + 0.3).\n        Bigger centerX => Larger fade distance.\n         -->\n        <Space\n            android:id=\"@+id/shadow_space_2\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintDimensionRatio=\"100:80\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"@+id/shadow_space_1\" />\n\n        <ImageView\n            android:id=\"@+id/episodes_shadow_background\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"end\"\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:focusableInTouchMode=\"false\"\n            android:importantForAccessibility=\"no\"\n            android:src=\"@drawable/episodes_shadow\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toStartOf=\"@+id/shadow_space_2\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n\n\n        <LinearLayout\n            android:id=\"@+id/episode_holder_tv\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"end\"\n            android:orientation=\"horizontal\"\n            android:paddingStart=\"@dimen/result_padding\"\n            android:paddingEnd=\"@dimen/result_padding\"\n            android:visibility=\"gone\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            tools:ignore=\"RtlHardcoded\"\n            tools:visibility=\"visible\">\n\n            <com.lagradost.cloudstream3.ui.MaxRecyclerView\n                android:id=\"@+id/result_dub_selection\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:clipToPadding=\"false\"\n                android:descendantFocusability=\"afterDescendants\"\n                android:nextFocusLeft=\"@id/result_episodes_show\"\n                android:nextFocusRight=\"@id/result_season_selection\"\n                android:orientation=\"vertical\"\n                android:paddingVertical=\"@dimen/result_padding\"\n                app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                tools:listitem=\"@layout/result_selection\"\n                tools:visibility=\"gone\" />\n\n            <com.lagradost.cloudstream3.ui.MaxRecyclerView\n                android:id=\"@+id/result_season_selection\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:clipToPadding=\"false\"\n                android:descendantFocusability=\"afterDescendants\"\n                android:nextFocusLeft=\"@id/result_dub_selection\"\n                android:nextFocusRight=\"@id/result_range_selection\"\n                android:orientation=\"vertical\"\n                android:paddingVertical=\"@dimen/result_padding\"\n                app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                tools:listitem=\"@layout/result_selection\"\n                tools:visibility=\"gone\" />\n\n            <com.lagradost.cloudstream3.ui.MaxRecyclerView\n                android:id=\"@+id/result_range_selection\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:clipToPadding=\"false\"\n                android:descendantFocusability=\"afterDescendants\"\n                android:nextFocusLeft=\"@id/result_season_selection\"\n                android:nextFocusRight=\"@id/result_episodes\"\n                android:orientation=\"vertical\"\n                android:paddingVertical=\"@dimen/result_padding\"\n                app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                tools:listitem=\"@layout/result_selection\"\n                tools:visibility=\"visible\" />\n\n\n            <!--<androidx.core.widget.ContentLoadingProgressBar\n                    android:id=\"@+id/result_episode_loading\"\n\n                    style=\"@style/Widget.AppCompat.ProgressBar\"\n                    android:layout_gravity=\"center\"\n                    android:layout_width=\"50dp\"\n                    android:layout_height=\"50dp\" />-->\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/result_episodes\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:clipToPadding=\"false\"\n                android:descendantFocusability=\"afterDescendants\"\n                android:nextFocusLeft=\"@id/result_range_selection\"\n                android:orientation=\"vertical\"\n                android:paddingVertical=\"@dimen/result_padding\"\n                app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                tools:listitem=\"@layout/result_episode\" />\n\n            <View\n                android:id=\"@+id/temporary_no_focus\"\n                android:layout_width=\"1dp\"\n                android:layout_height=\"1dp\"\n                android:focusable=\"false\"\n                android:nextFocusLeft=\"@id/temporary_no_focus\"\n                android:nextFocusRight=\"@id/temporary_no_focus\"\n                android:nextFocusUp=\"@id/temporary_no_focus\"\n                android:nextFocusDown=\"@id/temporary_no_focus\" />\n        </LinearLayout>\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n    <androidx.core.widget.NestedScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:clipToPadding=\"false\"\n            android:orientation=\"vertical\"\n            android:paddingStart=\"@dimen/result_padding\"\n            android:paddingEnd=\"@dimen/result_padding\"\n            android:visibility=\"gone\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:layout_marginBottom=\"15dp\"\n                android:orientation=\"horizontal\"\n                android:visibility=\"visible\">\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:orientation=\"vertical\">\n\n                    <LinearLayout\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"30dp\"\n                        android:layout_marginBottom=\"10dp\"\n                        android:orientation=\"horizontal\">\n\n                        <!--\n                        <ImageView\n                            android:id=\"@+id/result_back\"\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_gravity=\"center_vertical\"\n                            android:layout_marginEnd=\"10dp\"\n                            android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                            android:clickable=\"true\"\n                            android:contentDescription=\"@string/go_back\"\n                            android:focusable=\"true\"\n                            android:gravity=\"center_vertical\"\n                            android:nextFocusDown=\"@id/result_play_movie\"\n                            android:src=\"@drawable/ic_baseline_arrow_back_24\"\n                            app:tint=\"?attr/white\" />-->\n\n                    </LinearLayout>\n\n                    <LinearLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"horizontal\">\n\n                        <androidx.cardview.widget.CardView\n                            android:id=\"@+id/result_poster_holder\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_marginEnd=\"10dp\"\n                            android:visibility=\"gone\"\n                            app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n\n                            <ImageView\n                                android:id=\"@+id/result_poster\"\n                                android:layout_width=\"100dp\"\n                                android:layout_height=\"140dp\"\n                                android:layout_gravity=\"bottom\"\n                                android:contentDescription=\"@string/result_poster_img_des\"\n                                android:foreground=\"@drawable/outline_drawable\"\n                                android:scaleType=\"centerCrop\"\n                                tools:src=\"@drawable/example_poster\" />\n                        </androidx.cardview.widget.CardView>\n\n                        <!--\n                        <LinearLayout\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"wrap_content\"\n                            android:orientation=\"vertical\">\n\n                            <com.lagradost.cloudstream3.widget.FlowLayout\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"wrap_content\"\n                                app:itemSpacing=\"10dp\">\n\n                                <com.google.android.material.button.MaterialButton\n                                    android:id=\"@+id/result_meta_site\"\n                                    style=\"@style/SmallBlackButton\"\n                                    android:layout_gravity=\"center_vertical\"\n                                    tools:text=\"Gogoanime\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_type\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"Movie\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_year\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"2022\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_rating\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"Rated: 8.5/10.0\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_status\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"Ongoing\" />\n\n                                <TextView\n                                    android:id=\"@+id/result_meta_duration\"\n                                    style=\"@style/ResultInfoText\"\n                                    tools:text=\"121min\" />\n                            </com.lagradost.cloudstream3.widget.FlowLayout>\n\n                            <TextView\n                                android:id=\"@+id/result_description\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"wrap_content\"\n                                android:ellipsize=\"end\"\n                                android:fadingEdgeLength=\"30dp\"\n                                android:foreground=\"@drawable/outline_drawable\"\n                                android:maxLines=\"7\"\n                                android:nextFocusUp=\"@id/result_back\"\n                                android:nextFocusDown=\"@id/result_bookmark_button\"\n                                android:padding=\"5dp\"\n                                android:requiresFadingEdge=\"vertical\"\n                                android:textColor=\"?attr/textColor\"\n                                android:textSize=\"15sp\"\n                                tools:text=\"Ryan Quicksave Romano is an eccentric adventurer with a strange power: he can create a save-point in time and redo his life whenever he dies. Arriving in New Rome, the glitzy capital of sin of a rebuilding Europe, he finds the city torn between mega-corporations, sponsored heroes, superpowered criminals, and true monsters. It's a time of chaos, where potions can grant the power to rule the world and dangers lurk everywhere. \" />\n                        </LinearLayout>\n                        -->\n                        <!--\n                                                    This has half margin and half padding to make TV focus on description look better.\n                                                    The focus outline now settles between the poster and text.\n                                                    -->\n                    </LinearLayout>\n                </LinearLayout>\n            </LinearLayout>\n\n            <TextView\n                android:id=\"@+id/result_cast_text\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"5dp\"\n                android:ellipsize=\"end\"\n                android:maxLines=\"2\"\n                android:textColor=\"?attr/grayTextColor\"\n                android:textSize=\"15sp\"\n                tools:text=\"Cast: Joe Ligma\" />\n\n            <TextView\n                android:id=\"@+id/result_vpn\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?attr/grayTextColor\"\n                android:textSize=\"15sp\"\n                tools:text=\"@string/vpn_torrent\" />\n\n            <TextView\n                android:id=\"@+id/result_info\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"5dp\"\n                android:textColor=\"?attr/grayTextColor\"\n                android:textSize=\"15sp\"\n                tools:text=\"@string/provider_info_meta\" />\n\n            <TextView\n                android:id=\"@+id/result_no_episodes\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"5dp\"\n                android:textColor=\"?attr/grayTextColor\"\n                android:textSize=\"15sp\"\n                tools:text=\"@string/no_episodes_found\" />\n\n\n            <TextView\n                android:id=\"@+id/result_coming_soon\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:gravity=\"center\"\n                android:paddingTop=\"50dp\"\n                android:text=\"@string/coming_soon\"\n                android:textColor=\"?attr/textColor\"\n                android:textSize=\"20sp\"\n                android:textStyle=\"bold\"\n                android:visibility=\"gone\" />\n\n            <LinearLayout\n                android:id=\"@+id/result_data_holder\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/result_add_sync\"\n                    style=\"@style/WhiteButton\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginStart=\"0dp\"\n\n                    android:layout_marginBottom=\"10dp\"\n                    android:text=\"@string/add_sync\"\n                    android:visibility=\"gone\"\n                    app:icon=\"@drawable/ic_baseline_add_24\" />\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"250dp\"\n                android:layout_height=\"0dp\"\n                android:layout_marginEnd=\"10dp\"\n                android:layout_weight=\"0\"\n                android:orientation=\"vertical\">\n\n                <LinearLayout\n                    android:id=\"@+id/result_movie_parent\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"start\"\n                    android:animateLayoutChanges=\"true\"\n                    android:orientation=\"vertical\"\n                    tools:visibility=\"visible\">\n\n                    <LinearLayout\n                        android:id=\"@+id/series_holder\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:orientation=\"vertical\">\n\n                        <View\n                            android:id=\"@+id/redirect_to_episodes\"\n                            android:layout_width=\"1dp\"\n                            android:layout_height=\"1dp\"\n                            android:focusable=\"true\"\n                            android:focusableInTouchMode=\"true\" />\n\n                        <View\n                            android:id=\"@+id/redirect_to_play\"\n                            android:layout_width=\"1dp\"\n                            android:layout_height=\"1dp\"\n                            android:focusable=\"true\"\n                            android:focusableInTouchMode=\"true\" />\n                    </LinearLayout>\n                </LinearLayout>\n            </LinearLayout>\n        </LinearLayout>\n\n    </androidx.core.widget.NestedScrollView>\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_search.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/searchRoot\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_marginTop=\"@dimen/navbar_height\"\n    android:background=\"?attr/primaryGrayBackground\"\n    tools:context=\".ui.search.SearchFragment\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingBottom=\"10dp\"\n        android:background=\"?attr/primaryGrayBackground\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            app:layout_scrollFlags=\"scroll|enterAlways\">\n\n            <ImageView\n                android:id=\"@+id/voice_search\"\n                android:layout_width=\"25dp\"\n                android:layout_height=\"25dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:background=\"?selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/change_providers_img_des\"\n                android:src=\"@drawable/ic_mic\"\n                app:tint=\"?attr/textColor\" />\n\n            <FrameLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"40dp\"\n                android:layout_margin=\"10dp\"\n                android:background=\"@drawable/search_background\"\n                android:visibility=\"visible\">\n\n                <FrameLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginEnd=\"30dp\">\n\n                    <androidx.appcompat.widget.SearchView\n                        android:id=\"@+id/main_search\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_gravity=\"center_vertical\"\n\n                        android:iconifiedByDefault=\"false\"\n                        android:imeOptions=\"actionSearch\"\n\n                        android:inputType=\"text\"\n                        android:nextFocusLeft=\"@id/nav_rail_view\"\n\n                        android:nextFocusRight=\"@id/search_filter\"\n                        android:nextFocusUp=\"@id/nav_rail_view\"\n                        android:nextFocusDown=\"@id/search_autofit_results\"\n                        android:paddingStart=\"-10dp\"\n                        app:iconifiedByDefault=\"false\"\n                        app:queryBackground=\"@color/transparent\"\n                        app:queryHint=\"@string/search_hint\"\n                        app:searchIcon=\"@drawable/search_icon\"\n                        app:closeIcon=\"@drawable/ic_baseline_close_24\"\n                        tools:ignore=\"RtlSymmetry\">\n\n                        <requestFocus />\n\n                        <androidx.core.widget.ContentLoadingProgressBar\n                            android:id=\"@+id/search_loading_bar\"\n                            style=\"@style/Widget.AppCompat.ProgressBar\"\n                            android:layout_width=\"20dp\"\n                            android:layout_height=\"20dp\"\n                            android:layout_gravity=\"center\"\n                            android:layout_marginStart=\"-35dp\"\n                            android:foregroundTint=\"@color/white\"\n                            android:progressTint=\"@color/white\">\n\n                        </androidx.core.widget.ContentLoadingProgressBar>\n                        <!--app:queryHint=\"@string/search_hint\"\n                        android:background=\"@color/grayBackground\" @color/itemBackground\n                                    app:searchHintIcon=\"@drawable/search_white\"\n                                    -->\n                    </androidx.appcompat.widget.SearchView>\n                </FrameLayout>\n\n                <ImageView\n                    android:id=\"@+id/search_filter\"\n                    android:layout_width=\"25dp\"\n                    android:layout_height=\"25dp\"\n                    android:layout_gravity=\"end|center_vertical\"\n\n                    android:layout_margin=\"10dp\"\n                    android:background=\"?selectableItemBackgroundBorderless\"\n                    android:contentDescription=\"@string/change_providers_img_des\"\n                    android:nextFocusLeft=\"@id/main_search\"\n                    android:nextFocusRight=\"@id/main_search\"\n                    android:nextFocusUp=\"@id/nav_rail_view\"\n                    android:nextFocusDown=\"@id/search_autofit_results\"\n                    android:src=\"@drawable/ic_baseline_tune_24\"\n                    app:tint=\"?attr/textColor\" />\n            </FrameLayout>\n        </LinearLayout>\n\n        <include\n            android:id=\"@+id/tvtypes_chips_scroll\"\n            layout=\"@layout/tvtypes_chips_scroll\" />\n    </LinearLayout>\n\n\n    <com.lagradost.cloudstream3.ui.AutofitRecyclerView\n        android:id=\"@+id/search_autofit_results\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n\n        android:background=\"?attr/primaryBlackBackground\"\n        android:clipToPadding=\"false\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusLeft=\"@id/nav_rail_view\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"8dp\"\n        android:paddingTop=\"5dp\"\n        android:paddingEnd=\"8dp\"\n        android:visibility=\"gone\"\n        app:spanCount=\"3\"\n        tools:listitem=\"@layout/search_result_grid\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/search_master_recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n\n        android:background=\"?attr/primaryBlackBackground\"\n        android:descendantFocusability=\"afterDescendants\"\n\n        android:nextFocusLeft=\"@id/nav_rail_view\"\n        android:nextFocusUp=\"@id/tvtypes_chips\"\n        android:visibility=\"gone\"\n        tools:listitem=\"@layout/homepage_parent\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/search_history_recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusLeft=\"@id/nav_rail_view\"\n        android:nextFocusUp=\"@id/tvtypes_chips\"\n        android:visibility=\"visible\"\n        tools:listitem=\"@layout/search_history_item\" />\n    </LinearLayout>\n\n    <!-- Suggestions overlay - appears on top of content -->\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/search_suggestions_recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"100dp\"\n        android:background=\"?attr/primaryGrayBackground\"\n        android:elevation=\"8dp\"\n        android:visibility=\"gone\"\n        tools:listitem=\"@layout/search_suggestion_item\" />\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_search_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/searchRoot\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_marginTop=\"@dimen/navbar_height\"\n    android:background=\"?attr/primaryGrayBackground\"\n    tools:context=\".ui.search.SearchFragment\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"@dimen/navbar_width\"\n        android:orientation=\"vertical\"\n        android:paddingBottom=\"10dp\"\n        android:background=\"?attr/primaryGrayBackground\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            app:layout_scrollFlags=\"scroll|enterAlways\">\n\n            <ImageView\n                android:id=\"@+id/voice_search\"\n                android:layout_width=\"25dp\"\n                android:layout_height=\"25dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginStart=\"10dp\"\n                android:background=\"?selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/change_providers_img_des\"\n                android:src=\"@drawable/ic_mic\"\n                app:tint=\"?attr/textColor\" />\n\n            <FrameLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"40dp\"\n                android:layout_margin=\"10dp\"\n                android:background=\"@drawable/search_background\"\n                android:visibility=\"visible\">\n\n                <FrameLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginEnd=\"30dp\">\n\n                    <androidx.appcompat.widget.SearchView\n                        android:id=\"@+id/main_search\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_gravity=\"center_vertical\"\n\n                        android:iconifiedByDefault=\"false\"\n                        android:imeOptions=\"actionSearch\"\n\n                        android:inputType=\"text\"\n                        android:nextFocusLeft=\"@id/navigation_search\"\n\n                        android:nextFocusRight=\"@id/search_filter\"\n                        android:nextFocusUp=\"@id/navigation_search\"\n                        android:nextFocusDown=\"@id/search_autofit_results\"\n                        android:paddingStart=\"-10dp\"\n                        app:iconifiedByDefault=\"false\"\n                        app:queryBackground=\"@color/transparent\"\n                        app:queryHint=\"@string/search_hint\"\n                        app:searchIcon=\"@drawable/search_icon\"\n                        app:closeIcon=\"@drawable/ic_baseline_close_24\"\n                        tools:ignore=\"RtlSymmetry\">\n\n                        <requestFocus />\n\n                        <androidx.core.widget.ContentLoadingProgressBar\n                            android:id=\"@+id/search_loading_bar\"\n                            style=\"@style/Widget.AppCompat.ProgressBar\"\n                            android:layout_width=\"20dp\"\n                            android:layout_height=\"20dp\"\n                            android:layout_gravity=\"center\"\n                            android:layout_marginStart=\"-35dp\"\n                            android:foregroundTint=\"@color/white\"\n                            android:progressTint=\"@color/white\">\n\n                        </androidx.core.widget.ContentLoadingProgressBar>\n                        <!--app:queryHint=\"@string/search_hint\"\n                        android:background=\"@color/grayBackground\" @color/itemBackground\n                                    app:searchHintIcon=\"@drawable/search_white\"\n                                    -->\n                    </androidx.appcompat.widget.SearchView>\n                </FrameLayout>\n\n                <ImageView\n                    android:id=\"@+id/search_filter\"\n                    android:layout_width=\"25dp\"\n                    android:layout_height=\"25dp\"\n                    android:layout_gravity=\"end|center_vertical\"\n\n                    android:layout_margin=\"10dp\"\n                    android:background=\"?selectableItemBackgroundBorderless\"\n                    android:contentDescription=\"@string/change_providers_img_des\"\n                    android:nextFocusLeft=\"@id/main_search\"\n                    android:nextFocusRight=\"@id/main_search\"\n                    android:nextFocusUp=\"@id/navigation_search\"\n                    android:nextFocusDown=\"@id/tvtypes_chips_scroll\"\n                    android:tag = \"@string/tv_no_focus_tag\"\n                    android:src=\"@drawable/ic_baseline_tune_24\"\n                    app:tint=\"?attr/textColor\" />\n            </FrameLayout>\n        </LinearLayout>\n\n        <include\n            android:id=\"@+id/tvtypes_chips_scroll\"\n            layout=\"@layout/tvtypes_chips_scroll\" />\n    </LinearLayout>\n\n\n    <com.lagradost.cloudstream3.ui.AutofitRecyclerView\n        android:id=\"@+id/search_autofit_results\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginStart=\"@dimen/navbar_width\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:clipToPadding=\"false\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusLeft=\"@id/navigation_search\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"8dp\"\n        android:paddingTop=\"5dp\"\n        android:paddingEnd=\"8dp\"\n        android:visibility=\"gone\"\n        app:spanCount=\"3\"\n        tools:listitem=\"@layout/search_result_grid\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/search_master_recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n\n        android:background=\"?attr/primaryBlackBackground\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusLeft=\"@id/navigation_search\"\n        android:nextFocusUp=\"@id/tvtypes_chips\"\n        android:visibility=\"gone\"\n        tools:listitem=\"@layout/homepage_parent\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/search_history_recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginStart=\"@dimen/navbar_width\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusLeft=\"@id/navigation_search\"\n        android:nextFocusUp=\"@id/tvtypes_chips\"\n        android:tag = \"@string/tv_no_focus_tag\"\n        android:visibility=\"visible\"\n        tools:listitem=\"@layout/search_history_item\" />\n    </LinearLayout>\n\n    <!-- Suggestions overlay - appears on top of content -->\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/search_suggestions_recycler\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"100dp\"\n        android:layout_marginStart=\"@dimen/navbar_width\"\n        android:background=\"?attr/primaryGrayBackground\"\n        android:elevation=\"8dp\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusLeft=\"@id/navigation_search\"\n        android:nextFocusUp=\"@id/tvtypes_chips\"\n        android:visibility=\"gone\"\n        tools:listitem=\"@layout/search_suggestion_item\" />\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_setup_extensions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/setup_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:gravity=\"center\"\n        android:text=\"@string/extensions\"\n        android:textSize=\"18sp\" />\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:text=\"@string/setup_extensions_subtext\" />\n\n    <LinearLayout\n        android:id=\"@+id/blank_repo_screen\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_margin=\"20dp\"\n        android:gravity=\"center\"\n        android:orientation=\"vertical\"\n        tools:visibility=\"gone\">\n\n        <ImageView\n            android:layout_width=\"30dp\"\n            android:layout_height=\"30dp\"\n            android:layout_margin=\"10dp\"\n            android:src=\"@drawable/ic_baseline_extension_24\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"20dp\"\n            android:gravity=\"center\"\n            android:text=\"@string/blank_repo_message\"\n            android:textSize=\"16sp\" />\n\n<!--        <com.google.android.material.button.MaterialButton-->\n<!--            android:id=\"@+id/list_repositories\"-->\n<!--            style=\"@style/WhiteButton\"-->\n<!--            android:layout_width=\"wrap_content\"-->\n<!--            android:text=\"@string/view_public_repositories_button\" />-->\n    </LinearLayout>\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/repo_recycler_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        tools:listitem=\"@layout/repository_item\"\n        tools:visibility=\"visible\" />\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n<!--        <com.google.android.material.button.MaterialButton-->\n<!--            android:id=\"@+id/view_public_repositories_button\"-->\n<!--            style=\"@style/WhiteButton\"-->\n<!--            android:layout_width=\"wrap_content\"-->\n<!--            android:layout_gravity=\"center_vertical|end\"-->\n<!--            android:text=\"@string/add_repository\" />-->\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/next_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/next\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/prev_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/previous\" />\n    </LinearLayout>\n\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_setup_language.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:id=\"@+id/setup_root\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\">\n\n        <ImageView\n            android:id=\"@+id/app_icon_image\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"50dp\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"20dp\"\n            android:gravity=\"center\"\n            android:text=\"@string/app_language\"\n            android:textSize=\"18sp\" />\n    </LinearLayout>\n\n    <ListView\n        android:id=\"@+id/listview1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_rowWeight=\"1\"\n        android:layout_marginBottom=\"60dp\"\n        android:paddingTop=\"10dp\"\n        android:requiresFadingEdge=\"vertical\"\n        tools:listitem=\"@layout/sort_bottom_single_choice\" />\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/next_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/next\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/skip_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/skip_setup\">\n\n            <requestFocus />\n        </com.google.android.material.button.MaterialButton>\n    </LinearLayout>\n\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_setup_layout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/setup_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:gravity=\"center\"\n        android:text=\"@string/app_layout\"\n        android:textSize=\"18sp\" />\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:text=\"@string/app_layout_subtext\">\n\n    </TextView>\n\n    <ListView\n        android:id=\"@+id/listview1\"\n        android:layout_width=\"match_parent\"\n\n        android:layout_height=\"match_parent\"\n        android:layout_rowWeight=\"1\"\n        android:layout_marginBottom=\"60dp\"\n        android:nextFocusLeft=\"@id/apply_btt\"\n        android:nextFocusRight=\"@id/cancel_btt\"\n        android:paddingTop=\"10dp\"\n        android:requiresFadingEdge=\"vertical\"\n        tools:listitem=\"@layout/sort_bottom_single_choice\" />\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/next_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/setup_done\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/prev_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/previous\" />\n    </LinearLayout>\n\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_setup_media.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/setup_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:gravity=\"center\"\n        android:text=\"@string/preferred_media_settings\"\n        android:textSize=\"18sp\" />\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:text=\"@string/preferred_media_subtext\" />\n\n    <ListView\n        android:id=\"@+id/listview1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_rowWeight=\"1\"\n        android:layout_marginBottom=\"60dp\"\n        android:nextFocusLeft=\"@id/apply_btt\"\n        android:nextFocusRight=\"@id/cancel_btt\"\n        android:paddingTop=\"10dp\"\n        android:requiresFadingEdge=\"vertical\"\n        tools:listitem=\"@layout/sort_bottom_single_choice\" />\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/next_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/next\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/prev_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/previous\" />\n    </LinearLayout>\n\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_setup_provider_languages.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/setup_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"20dp\"\n        android:gravity=\"center\"\n        android:text=\"@string/provider_lang_settings\"\n        android:textSize=\"18sp\" />\n\n    <TextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center\"\n        android:text=\"@string/provider_languages_tip\">\n\n    </TextView>\n\n    <ListView\n        android:id=\"@+id/listview1\"\n        android:layout_width=\"match_parent\"\n\n        android:layout_height=\"match_parent\"\n        android:layout_rowWeight=\"1\"\n        android:layout_marginBottom=\"60dp\"\n        android:nextFocusLeft=\"@id/apply_btt\"\n        android:nextFocusRight=\"@id/cancel_btt\"\n        android:paddingTop=\"10dp\"\n        android:requiresFadingEdge=\"vertical\"\n        tools:listitem=\"@layout/sort_bottom_single_choice\" />\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/next_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/next\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/prev_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/previous\" />\n    </LinearLayout>\n\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_testing.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:orientation=\"vertical\">\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:id=\"@+id/provider_test_appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/settings_toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:paddingTop=\"@dimen/navbar_height\"\n            app:layout_scrollFlags=\"scroll|enterAlways\"\n            app:navigationIconTint=\"?attr/iconColor\"\n            app:titleTextColor=\"?attr/textColor\"\n            tools:title=\"@string/category_provider_test\">\n\n        </com.google.android.material.appbar.MaterialToolbar>\n\n        <com.lagradost.cloudstream3.ui.settings.testing.TestView\n            android:id=\"@+id/provider_test\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:nextFocusDown=\"@id/provider_test_recycler_view\"\n            app:header_text=\"@string/category_provider_test\"\n            app:layout_scrollFlags=\"scroll|enterAlways\" />\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:background=\"?attr/primaryBlackBackground\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\">\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/provider_test_recycler_view\"\n            android:clipToPadding=\"false\"\n            android:paddingBottom=\"60dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            tools:listitem=\"@layout/provider_test_item\" />\n\n    </LinearLayout>\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_trailer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:visibility=\"visible\"\n        android:orientation=\"horizontal\"\n        android:id=\"@+id/player_background\"\n        app:backgroundTint=\"@android:color/black\"\n        android:background=\"@android:color/black\"\n        app:surface_type=\"texture_view\">\n    <!--\n          app:fastforward_increment=\"10000\"\n            app:rewind_increment=\"10000\"-->\n    <androidx.media3.ui.PlayerView\n            android:id=\"@+id/player_view\"\n            app:show_timeout=\"0\"\n            app:hide_on_touch=\"false\"\n            app:auto_show=\"true\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            app:backgroundTint=\"@android:color/black\"\n            android:background=\"@android:color/black\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:controller_layout_id=\"@layout/trailer_custom_layout\" />\n\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_webview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<WebView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/web_view\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".ui.WebviewFragment\">\n\n</WebView>"
  },
  {
    "path": "app/src/main/res/layout/home_episodes_expanded.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:background=\"?attr/primaryGrayBackground\"\n        android:layout_height=\"wrap_content\">\n\n    <FrameLayout\n            android:nextFocusDown=\"@id/home_expanded_recycler\"\n\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:id=\"@+id/home_expanded_drag_down\"\n            android:padding=\"12dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n        <requestFocus />\n\n        <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n\n            <ImageView\n                    app:tint=\"?attr/textColor\"\n                    android:id=\"@+id/home_expanded_delete\"\n                    android:layout_marginEnd=\"10dp\"\n                    android:layout_gravity=\"start|center_vertical\"\n                    android:src=\"@drawable/ic_baseline_delete_outline_24\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"match_parent\"\n                    android:contentDescription=\"@string/delete\" />\n\n            <TextView\n                    android:id=\"@+id/home_expanded_text\"\n                    style=\"@style/WatchHeaderText\"\n                    tools:text=\"Trending\" />\n        </LinearLayout>\n\n        <ImageView\n                android:layout_marginEnd=\"5dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:src=\"@drawable/ic_baseline_keyboard_arrow_down_24\"\n                android:layout_width=\"30dp\"\n                android:layout_height=\"match_parent\"\n                android:contentDescription=\"@string/home_expanded_hide\" />\n    </FrameLayout>\n\n    <com.lagradost.cloudstream3.ui.AutofitRecyclerView\n            android:descendantFocusability=\"afterDescendants\"\n\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:id=\"@+id/home_expanded_recycler\"\n            tools:listitem=\"@layout/search_result_grid\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/home_remove_grid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n\r\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\r\n    xmlns:tools=\"http://schemas.android.com/tools\"\r\n    android:id=\"@+id/background_card\"\r\n    android:layout_width=\"114dp\"\r\n    android:layout_height=\"180dp\"\r\n    android:layout_margin=\"2dp\"\r\n    android:layout_marginBottom=\"2dp\"\r\n    android:elevation=\"10dp\"\r\n    android:foreground=\"@drawable/outline_drawable\"\r\n    app:cardBackgroundColor=\"?attr/primaryGrayBackground\"\r\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\">\r\n\r\n    <ImageView\r\n        android:id=\"@+id/title_shadow\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"50dp\"\r\n        android:layout_gravity=\"bottom\"\r\n        android:clickable=\"false\"\r\n        android:focusable=\"false\"\r\n        android:src=\"@drawable/title_shadow\"\r\n        tools:ignore=\"ContentDescription\" />\r\n\r\n    <TextView\r\n        android:id=\"@+id/imageText\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:layout_gravity=\"bottom\"\r\n        android:ellipsize=\"end\"\r\n        android:gravity=\"center\"\r\n        android:maxLines=\"2\"\r\n        android:paddingStart=\"5dp\"\r\n        android:paddingTop=\"5dp\"\r\n        android:paddingEnd=\"5dp\"\r\n        android:paddingBottom=\"5dp\"\r\n        android:text=\"@string/clear_history\"\r\n        android:textColor=\"@color/textColor\"\r\n        android:textStyle=\"bold\" />\r\n\r\n    <ImageView\r\n        android:layout_width=\"60dp\"\r\n        android:layout_height=\"60dp\"\r\n        android:layout_gravity=\"center\"\r\n        android:src=\"@drawable/delete_all\" />\r\n\r\n</androidx.cardview.widget.CardView>\r\n"
  },
  {
    "path": "app/src/main/res/layout/home_remove_grid_expanded.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n\r\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\r\n    xmlns:tools=\"http://schemas.android.com/tools\"\r\n\r\n    android:layout_width=\"wrap_content\"\r\n    android:layout_height=\"wrap_content\"\r\n    android:layout_margin=\"2dp\"\r\n    android:backgroundTint=\"@color/transparent\"\r\n    android:foreground=\"@drawable/outline_drawable\"\r\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\"\r\n    app:cardElevation=\"0dp\">\r\n\r\n    <LinearLayout\r\n        android:layout_width=\"wrap_content\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:orientation=\"vertical\">\r\n\r\n        <androidx.cardview.widget.CardView\r\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\r\n            android:id=\"@+id/background_card\"\r\n            android:layout_width=\"114dp\"\r\n            android:layout_height=\"180dp\"\r\n            android:elevation=\"10dp\"\r\n            app:cardBackgroundColor=\"?attr/primaryGrayBackground\"\r\n            app:cardCornerRadius=\"@dimen/rounded_image_radius\">\r\n\r\n            <ImageView\r\n                android:layout_width=\"60dp\"\r\n                android:layout_height=\"60dp\"\r\n                android:layout_gravity=\"center\"\r\n                android:src=\"@drawable/delete_all\" />\r\n\r\n        </androidx.cardview.widget.CardView>\r\n\r\n        <TextView\r\n            android:id=\"@+id/imageText\"\r\n            android:layout_width=\"match_parent\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:layout_gravity=\"bottom\"\r\n            android:ellipsize=\"end\"\r\n            android:gravity=\"center\"\r\n            android:maxLines=\"2\"\r\n            android:minLines=\"2\"\r\n            android:paddingStart=\"5dp\"\r\n            android:paddingTop=\"5dp\"\r\n            android:paddingEnd=\"5dp\"\r\n            android:paddingBottom=\"5dp\"\r\n            android:text=\"@string/clear_history\"\r\n            android:textColor=\"?attr/textColor\"\r\n            android:textSize=\"13sp\" />\r\n    </LinearLayout>\r\n</androidx.cardview.widget.CardView>\r\n"
  },
  {
    "path": "app/src/main/res/layout/home_result_big_grid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--  android:layout_width=\"114dp\"\n        android:layout_height=\"180dp\"-->\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:foreground=\"@drawable/outline_drawable\"\n        android:layout_margin=\"2dp\"\n        android:layout_width=\"148dp\"\n        android:layout_height=\"234dp\"\n        android:layout_marginBottom=\"2dp\"\n        android:elevation=\"10dp\"\n        app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n        android:id=\"@+id/background_card\"\n        app:cardBackgroundColor=\"?attr/primaryGrayBackground\">\n\n    <ImageView\n            android:duplicateParentState=\"true\"\n            android:id=\"@+id/imageView\"\n            tools:src=\"@drawable/example_poster\"\n            android:scaleType=\"centerCrop\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:contentDescription=\"@string/search_poster_img_des\" />\n\n    <TextView\n            style=\"@style/TypeButton\" />\n    <!--\n    <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_gravity=\"end\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n        <TextView\n                android:text=\"@string/app_dubbed_text\"\n                android:id=\"@+id/text_is_dub\"\n                android:textColor=\"?attr/textColor\"\n                android:paddingRight=\"10dp\"\n                android:paddingLeft=\"10dp\"\n                android:paddingTop=\"4dp\"\n                android:layout_marginBottom=\"5dp\"\n                android:layout_gravity=\"end\"\n                android:paddingBottom=\"4dp\"\n                android:minWidth=\"50dp\"\n                android:gravity=\"center\"\n                android:background=\"@drawable/dub_bg_color\"\n                android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\">\n        </TextView>\n        <TextView\n                android:id=\"@+id/text_is_sub\"\n                android:text=\"@string/app_subbed_text\"\n                android:layout_gravity=\"end\"\n                android:textColor=\"?attr/textColor\"\n                android:paddingRight=\"10dp\"\n                android:paddingLeft=\"10dp\"\n                android:paddingTop=\"4dp\"\n                android:paddingBottom=\"4dp\"\n                android:minWidth=\"50dp\"\n                android:gravity=\"center\"\n                android:background=\"@drawable/sub_bg_color\"\n                android:layout_width=\"wrap_content\" android:layout_height=\"wrap_content\"\n        />\n\n    </LinearLayout>\n     -->\n</androidx.cardview.widget.CardView>\n"
  },
  {
    "path": "app/src/main/res/layout/home_result_grid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--  android:layout_width=\"114dp\"\n        android:layout_height=\"180dp\"-->\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/background_card\"\n    android:layout_width=\"114dp\"\n    android:layout_height=\"180dp\"\n    android:layout_margin=\"2dp\"\n    android:layout_marginBottom=\"2dp\"\n    android:elevation=\"10dp\"\n    android:foreground=\"@drawable/outline_drawable\"\n    app:cardBackgroundColor=\"?attr/primaryGrayBackground\"\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n    <ImageView\n        android:id=\"@+id/imageView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:contentDescription=\"@string/search_poster_img_des\"\n        android:duplicateParentState=\"true\"\n        android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n        android:scaleType=\"centerCrop\"\n        tools:src=\"@drawable/example_poster\" />\n\n    <ImageView\n        android:id=\"@+id/title_shadow\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:layout_gravity=\"bottom\"\n        android:clickable=\"false\"\n        android:focusable=\"false\"\n        android:src=\"@drawable/title_shadow\"\n        tools:ignore=\"ContentDescription\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom\"\n        android:orientation=\"vertical\"\n        android:paddingBottom=\"5dp\">\n        <TextView\n            android:id=\"@+id/episode_text\"\n            android:layout_width=\"wrap_content\"\n            style=\"@style/EpisodeTextButton\"\n            android:layout_gravity=\"center\"/>\n        <TextView\n            android:id=\"@+id/imageText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"bottom\"\n            android:ellipsize=\"end\"\n            android:gravity=\"center\"\n            android:maxLines=\"1\"\n            android:paddingStart=\"5dp\"\n            android:paddingEnd=\"5dp\"\n            android:textColor=\"@color/textColor\"\n            android:textStyle=\"bold\"\n            tools:text=\"The Perfect Run\" />\n    </LinearLayout>\n\n\n\n\n\n    <!--<View\n            android:id=\"@+id/search_result_lang\"\n            android:layout_gravity=\"bottom\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"4dp\"\n            android:alpha=\"0.9\">\n\n    </View>-->\n    <!--<ImageView\n            android:src=\"@drawable/ic_baseline_bookmark_24\"\n            android:id=\"@+id/search_result_lang\"\n            android:layout_gravity=\"right\"\n            android:layout_marginTop=\"-5dp\"\n            android:layout_marginRight=\"-6.5dp\"\n            android:layout_width=\"30dp\"\n            android:layout_height=\"30dp\">\n    </ImageView>-->\n    <TextView android:id=\"@+id/text_quality\" style=\"@style/TypeButton\" />\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"end\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/text_is_dub\"\n            style=\"@style/DubButton\"\n            android:layout_gravity=\"end\" />\n\n        <TextView\n            android:id=\"@+id/text_is_sub\"\n            style=\"@style/SubButton\"\n            android:layout_gravity=\"end\" />\n\n        <TextView\n            android:id=\"@+id/text_rating\"\n            style=\"@style/RatingButton\"\n            android:layout_gravity=\"end\"\n            tools:text=\"7.7\" />\n\n        <TextView\n            android:id=\"@+id/text_flag\"\n            style=\"@style/SearchBox\"\n            android:layout_gravity=\"end\"\n            android:background=\"@color/transparent\"\n            android:textSize=\"20sp\"\n            android:visibility=\"gone\"\n            tools:text=\"🇸🇪\"\n            tools:visibility=\"visible\" />\n    </LinearLayout>\n\n    <FrameLayout\n        android:id=\"@+id/watch_progress_container\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\">\n\n        <com.google.android.material.imageview.ShapeableImageView\n            android:id=\"@+id/search_item_download_play\"\n            style=\"@style/HomePlayUnderlayProgress\"\n            />\n        <com.google.android.material.progressindicator.CircularProgressIndicator\n            android:id=\"@+id/watchProgress\"\n            style=\"@style/HomeCircularProgress\"\n            tools:progress=\"50\" />\n\n    </FrameLayout>\n</androidx.cardview.widget.CardView>\n"
  },
  {
    "path": "app/src/main/res/layout/home_result_grid_expanded.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<!--  android:layout_width=\"114dp\"\n        android:layout_height=\"180dp\"-->\n\n\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_margin=\"2dp\"\n    android:backgroundTint=\"@color/transparent\"\n    android:foreground=\"@drawable/outline_drawable\"\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n    app:cardElevation=\"0dp\">\n\n    <!-- Needed for layout tests -->\n    <ImageView\n        android:id=\"@+id/title_shadow\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:visibility=\"gone\"\n        tools:ignore=\"ContentDescription\" />\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <androidx.cardview.widget.CardView\n            android:id=\"@+id/background_card\"\n            android:layout_width=\"114dp\"\n            android:layout_height=\"180dp\"\n            android:elevation=\"10dp\"\n            app:cardBackgroundColor=\"?attr/primaryGrayBackground\"\n            app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n            <ImageView\n                android:id=\"@+id/imageView\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:contentDescription=\"@string/search_poster_img_des\"\n                android:duplicateParentState=\"true\"\n                android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:scaleType=\"centerCrop\"\n                tools:src=\"@drawable/example_poster\" />\n\n\n            <FrameLayout\n                android:id=\"@+id/watch_progress_container\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\">\n\n                <com.google.android.material.imageview.ShapeableImageView\n                    android:id=\"@+id/search_item_download_play\"\n                    style=\"@style/HomePlayUnderlayProgress\"\n                    />\n                <com.google.android.material.progressindicator.CircularProgressIndicator\n                    android:id=\"@+id/watchProgress\"\n                    style=\"@style/HomeCircularProgress\"\n                    tools:progress=\"50\" />\n\n            </FrameLayout>\n<!--            <FrameLayout-->\n<!--                android:id=\"@+id/small_watch_progress_container\"-->\n<!--                android:layout_width=\"wrap_content\"-->\n<!--                android:layout_height=\"wrap_content\"-->\n<!--                android:layout_gravity=\"bottom|end\"-->\n<!--                android:visibility=\"gone\"-->\n<!--                tools:visibility=\"visible\"-->\n<!--                >-->\n\n<!--                <ImageView-->\n<!--                    android:id=\"@+id/small_episode_play_icon\"-->\n<!--                    android:layout_width=\"30dp\"-->\n<!--                    android:layout_height=\"30dp\"-->\n<!--                    android:src=\"@drawable/play_button\"-->\n<!--                    android:layout_gravity=\"center\" />-->\n\n<!--                <com.google.android.material.progressindicator.CircularProgressIndicator-->\n<!--                    android:id=\"@+id/small_episode_progress\"-->\n<!--                    android:layout_width=\"30dp\"-->\n<!--                    android:layout_height=\"30dp\"-->\n<!--                    app:indicatorSize=\"28.75dp\"-->\n<!--                    app:trackThickness=\"2.5dp\"-->\n<!--                    android:progressBackgroundTint=\"?attr/colorPrimary\"-->\n<!--                    android:progressTint=\"?attr/colorPrimary\"-->\n<!--                    tools:progress=\"50\" />-->\n<!--            </FrameLayout>-->\n<!--            <FrameLayout-->\n<!--                android:id=\"@+id/playProgressContainer\"-->\n<!--                android:layout_width=\"wrap_content\"-->\n<!--                android:layout_height=\"wrap_content\"-->\n<!--                android:layout_gravity=\"bottom|end\">-->\n\n<!--                <ImageView-->\n<!--                    android:id=\"@+id/search_item_download_play\"-->\n<!--                    android:layout_width=\"50dp\"-->\n<!--                    android:layout_height=\"50dp\"-->\n<!--                    android:src=\"@drawable/play_button\"-->\n<!--                    android:layout_gravity=\"center\" />-->\n\n<!--                <com.google.android.material.progressindicator.CircularProgressIndicator-->\n<!--                    android:id=\"@+id/watchProgress\"-->\n<!--                    android:layout_width=\"25dp\"-->\n<!--                    android:layout_height=\"25dp\"-->\n<!--                    app:indicatorSize=\"23.75dp\"-->\n<!--                    app:trackThickness=\"2.5dp\"-->\n<!--                    android:progressBackgroundTint=\"?attr/colorPrimary\"-->\n<!--                    android:progressTint=\"?attr/colorPrimary\"-->\n<!--                    tools:progress=\"50\" />-->\n<!--            </FrameLayout>-->\n\n            <!--<View\n                    android:id=\"@+id/search_result_lang\"\n                    android:layout_gravity=\"bottom\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"4dp\"\n                    android:alpha=\"0.9\">\n\n            </View>-->\n            <!--<ImageView\n                    android:src=\"@drawable/ic_baseline_bookmark_24\"\n                    android:id=\"@+id/search_result_lang\"\n                    android:layout_gravity=\"right\"\n                    android:layout_marginTop=\"-5dp\"\n                    android:layout_marginRight=\"-6.5dp\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\">\n            </ImageView>-->\n            <TextView\n                android:id=\"@+id/text_quality\"\n                style=\"@style/TypeButton\" />\n\n            <LinearLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"end\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:id=\"@+id/text_is_dub\"\n                    style=\"@style/DubButton\"\n                    android:layout_gravity=\"end\" />\n\n                <TextView\n                    android:id=\"@+id/text_is_sub\"\n                    style=\"@style/SubButton\"\n                    android:layout_gravity=\"end\" />\n\n                <TextView\n                    android:id=\"@+id/text_rating\"\n                    style=\"@style/RatingButton\"\n                    android:layout_gravity=\"end\"\n                    tools:text=\"7.7\" />\n\n                <TextView\n                    android:id=\"@+id/text_flag\"\n                    style=\"@style/SearchBox\"\n                    android:layout_gravity=\"end\"\n                    android:background=\"@color/transparent\"\n                    android:textSize=\"20sp\"\n                    android:visibility=\"gone\"\n                    tools:text=\"🇸🇪\"\n                    tools:visibility=\"visible\" />\n            </LinearLayout>\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"bottom\"\n                android:orientation=\"vertical\"\n                android:paddingBottom=\"3dp\">\n                <TextView\n                    android:id=\"@+id/episode_text\"\n                    android:layout_width=\"wrap_content\"\n                    style=\"@style/EpisodeTextButton\"\n                    android:layout_gravity=\"center\"/>\n            </LinearLayout>\n        </androidx.cardview.widget.CardView>\n\n        <TextView\n            android:id=\"@+id/imageText\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"bottom\"\n            android:ellipsize=\"end\"\n            android:gravity=\"center\"\n            android:maxLines=\"2\"\n            android:minLines=\"2\"\n            android:paddingStart=\"5dp\"\n            android:paddingTop=\"5dp\"\n            android:paddingEnd=\"5dp\"\n            android:paddingBottom=\"5dp\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"13sp\"\n            tools:text=\"The Perfect Run\\nThe Perfect Run\\nhello\" />\n    </LinearLayout>\n</androidx.cardview.widget.CardView>\n"
  },
  {
    "path": "app/src/main/res/layout/home_scroll_view.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/home_scroll_preview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"centerCrop\"\n        tools:src=\"@drawable/example_poster\" />\n\n    <View\n        android:id=\"@+id/title_shadow_top\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"150dp\"\n        android:layout_gravity=\"top\"\n        android:alpha=\"1\"\n        android:background=\"@drawable/background_shadow\"\n        android:rotation=\"180\"\n        android:visibility=\"visible\" />\n\n    <View\n        android:id=\"@+id/title_shadow\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"300dp\"\n        android:layout_gravity=\"bottom\"\n        android:background=\"@drawable/background_shadow\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal|bottom\"\n        android:layout_marginBottom=\"100dp\"\n        android:orientation=\"vertical\">\n\n        <ImageView\n            android:id=\"@+id/home_preview_logo\"\n            android:layout_width=\"260dp\"\n            android:layout_height=\"80dp\"\n            android:layout_gravity=\"center_horizontal|bottom\"\n            android:scaleType=\"fitCenter\"\n            android:paddingBottom=\"10dp\"\n            android:contentDescription=\"@null\" />\n\n        <TextView\n            android:id=\"@+id/home_scroll_preview_title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:gravity=\"center\"\n            android:paddingHorizontal=\"30dp\"\n            android:paddingBottom=\"10dp\"\n            android:textColor=\"?attr/white\"\n            android:textSize=\"17sp\"\n            android:textStyle=\"bold\"\n            tools:text=\"The Perfect Run\" />\n        <!--<TextView\n            android:paddingStart=\"30dp\"\n            android:paddingEnd=\"30dp\"\n            android:id=\"@+id/home_season_tags\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center\"\n            android:textColor=\"@color/white\"\n            android:textSize=\"14sp\"\n            tools:text=\"5 seasons 50 episodes\" />-->\n        <TextView\n            android:id=\"@+id/home_scroll_preview_tags\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:gravity=\"center\"\n            android:paddingStart=\"30dp\"\n            android:paddingEnd=\"30dp\"\n            android:textColor=\"?attr/white\"\n            android:textSize=\"14sp\"\n            tools:text=\"Hello • World • Tags\" />\n    </LinearLayout>\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/home_scroll_view_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:layout_height=\"match_parent\">\n\n    <com.lagradost.cloudstream3.utils.PercentageCropImageView\n        android:id=\"@+id/home_scroll_preview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scaleType=\"matrix\"\n        app:cropYCenterOffsetPct=\"0.20\"\n        tools:src=\"@drawable/example_poster\" />\n\n    <View\n        android:id=\"@+id/title_shadow\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"250dp\"\n        android:layout_gravity=\"bottom\"\n        android:background=\"@drawable/background_shadow\" />\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/home_select_mainpage.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <ListView\n        android:id=\"@+id/listview1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_rowWeight=\"1\"\n        android:layout_marginTop=\"10dp\"\n        android:layout_marginBottom=\"60dp\"\n        android:clipToPadding=\"false\"\n        android:minHeight=\"0dp\"\n        android:nestedScrollingEnabled=\"true\"\n        android:nextFocusLeft=\"@id/apply_btt\"\n        android:nextFocusRight=\"@id/cancel_btt\"\n        android:requiresFadingEdge=\"vertical\"\n        tools:listitem=\"@layout/sort_bottom_single_provider_choice\" />\n\n    <LinearLayout\n        android:orientation=\"vertical\"\n        android:layout_gravity=\"bottom\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\">\n        <include layout=\"@layout/tvtypes_chips_scroll\" android:id=\"@+id/tvtypes_chips_scroll\" />\n        <LinearLayout\n            android:id=\"@+id/apply_btt_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"60dp\"\n            android:layout_marginTop=\"-60dp\"\n            android:layout_gravity=\"bottom\"\n            android:gravity=\"bottom|end\"\n            android:orientation=\"horizontal\"\n            android:visibility=\"gone\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/apply_btt\"\n                style=\"@style/WhiteButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/sort_apply\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/cancel_btt\"\n                style=\"@style/BlackButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/sort_cancel\" />\n        </LinearLayout>\n    </LinearLayout>\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/homepage_parent.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n    <TextView\n        android:id=\"@+id/home_child_more_info\"\n        style=\"@style/WatchHeaderText\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginEnd=\"0dp\"\n        android:padding=\"12dp\"\n        tools:text=\"@string/continue_watching\"\n        app:drawableRightCompat=\"@drawable/ic_baseline_arrow_forward_24\"\n        app:drawableTint=\"?attr/white\"\n        android:background=\"?android:attr/selectableItemBackground\"\n        android:contentDescription=\"@string/home_more_info\"/>\n\n    <androidx.recyclerview.widget.RecyclerView\n            android:nextFocusUp=\"@id/home_child_more_info\"\n            android:paddingHorizontal=\"5dp\"\n            android:clipToPadding=\"false\"\n            android:descendantFocusability=\"afterDescendants\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            android:id=\"@+id/home_child_recyclerview\"\n            android:orientation=\"horizontal\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            tools:listitem=\"@layout/home_result_grid\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/homepage_parent_emulator.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/home_child_more_info\"\n        style=\"@style/WatchHeaderText\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"@dimen/navbar_width\"\n        android:layout_marginEnd=\"0dp\"\n        android:padding=\"12dp\"\n        tools:text=\"@string/continue_watching\"\n        app:drawableRightCompat=\"@drawable/ic_baseline_arrow_forward_24\"\n        app:drawableTint=\"?attr/white\"\n        android:background=\"?android:attr/selectableItemBackground\"\n        android:contentDescription=\"@string/home_more_info\"/>\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/home_child_recyclerview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:clipToPadding=\"false\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusUp=\"@id/home_child_more_info\"\n        android:orientation=\"horizontal\"\n        android:paddingStart=\"8dp\"\n        android:paddingEnd=\"5dp\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        tools:listitem=\"@layout/home_result_grid\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/homepage_parent_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/home_child_more_info\"\n        style=\"@style/WatchHeaderText\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"@dimen/navbar_width\"\n        android:layout_marginEnd=\"0dp\"\n        android:padding=\"12dp\"\n        tools:text=\"Trending\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/home_child_recyclerview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:clipToPadding=\"false\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusUp=\"@id/home_child_more_info\"\n        android:orientation=\"horizontal\"\n        android:paddingStart=\"8dp\"\n        android:paddingEnd=\"5dp\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        tools:listitem=\"@layout/home_result_grid\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/item_logcat.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    xmlns:tools=\"http://schemas.android.com/tools\"\r\n    android:layout_width=\"match_parent\"\r\n    android:layout_height=\"wrap_content\"\r\n    android:padding=\"8dp\">\r\n\r\n    <TextView\r\n        android:id=\"@+id/log_text\"\r\n        android:textSize=\"14sp\"\r\n        android:textColor=\"?attr/textColor\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:focusable=\"true\"\r\n        android:nextFocusRight=\"@id/save_btt\"\r\n        tools:text=\"Test\" />\r\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/library_viewpager_page.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.lagradost.cloudstream3.ui.AutofitRecyclerView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/page_recyclerview\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:clipToPadding=\"false\"\n    android:focusable=\"false\"\n    android:tag=\"tv_no_focus_tag\"\n    tools:listitem=\"@layout/home_result_grid_expanded\" />\n\n"
  },
  {
    "path": "app/src/main/res/layout/loading_downloads.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:paddingBottom=\"@dimen/loading_margin\"\n        android:orientation=\"horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n    <include layout=\"@layout/loading_poster\" />\n\n    <LinearLayout\n            android:layout_marginStart=\"15dp\"\n            android:orientation=\"vertical\"\n            android:layout_gravity=\"center\"\n            android:layout_width=\"match_parent\"\n            android:layout_marginEnd=\"50dp\"\n            android:layout_height=\"wrap_content\">\n\n        <include layout=\"@layout/loading_line\" />\n\n        <include layout=\"@layout/loading_line_short\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/loading_episode.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        android:paddingTop=\"@dimen/loading_margin\"\n        android:paddingBottom=\"@dimen/loading_margin\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n    <LinearLayout\n            android:layout_marginBottom=\"@dimen/loading_margin\"\n            android:layout_width=\"match_parent\"\n            android:orientation=\"horizontal\"\n            android:layout_height=\"wrap_content\">\n        <!--app:cardCornerRadius=\"@dimen/roundedImageRadius\"-->\n        <androidx.cardview.widget.CardView\n                android:background=\"@color/grayShimmer\"\n                app:cardCornerRadius=\"@dimen/loading_radius\"\n                android:layout_width=\"126dp\"\n                android:layout_height=\"72dp\"\n                android:foreground=\"@drawable/outline_drawable\" />\n\n        <LinearLayout\n                android:layout_marginStart=\"15dp\"\n                android:orientation=\"vertical\"\n                android:layout_gravity=\"center\"\n                android:layout_width=\"match_parent\"\n                android:layout_marginEnd=\"50dp\"\n                android:layout_height=\"wrap_content\">\n\n            <include layout=\"@layout/loading_line\" />\n\n            <include layout=\"@layout/loading_line_short\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <include layout=\"@layout/loading_line\" />\n\n    <include layout=\"@layout/loading_line\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/loading_line.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        app:cardCornerRadius=\"@dimen/loading_radius\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"@dimen/loading_line_height\"\n        android:layout_marginBottom=\"@dimen/loading_margin\"\n        android:background=\"@color/grayShimmer\"\n        tools:ignore=\"ContentDescription\" />"
  },
  {
    "path": "app/src/main/res/layout/loading_line_short.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        app:cardCornerRadius=\"@dimen/loading_radius\"\n        android:layout_width=\"120dp\"\n        android:layout_height=\"@dimen/loading_line_height\"\n        android:layout_marginBottom=\"@dimen/loading_margin\"\n        android:background=\"@color/grayShimmer\"\n        tools:ignore=\"ContentDescription\" />"
  },
  {
    "path": "app/src/main/res/layout/loading_line_short_center.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        app:cardCornerRadius=\"@dimen/loading_radius\"\n        android:layout_width=\"200dp\"\n        android:layout_gravity=\"center\"\n        android:layout_height=\"@dimen/loading_line_height\"\n        android:layout_marginBottom=\"@dimen/loading_margin\"\n        android:background=\"@color/grayShimmer\"\n        tools:ignore=\"ContentDescription\" />"
  },
  {
    "path": "app/src/main/res/layout/loading_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"200dp\"\n    android:orientation=\"vertical\"\n    android:paddingTop=\"@dimen/loading_margin\"\n    android:paddingBottom=\"@dimen/loading_margin\">\n\n    <include layout=\"@layout/loading_line_short\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <include layout=\"@layout/loading_poster\" />\n\n        <View\n            android:layout_width=\"@dimen/loading_margin\"\n            android:layout_height=\"wrap_content\" />\n\n        <include layout=\"@layout/loading_poster\" />\n\n        <View\n            android:layout_width=\"@dimen/loading_margin\"\n            android:layout_height=\"wrap_content\" />\n\n        <include layout=\"@layout/loading_poster\" />\n\n        <View\n            android:layout_width=\"@dimen/loading_margin\"\n            android:layout_height=\"wrap_content\" />\n\n        <include layout=\"@layout/loading_poster\" />\n\n        <View\n            android:layout_width=\"@dimen/loading_margin\"\n            android:layout_height=\"wrap_content\" />\n\n        <include layout=\"@layout/loading_poster\" />\n\n        <View\n            android:layout_width=\"@dimen/loading_margin\"\n            android:layout_height=\"wrap_content\" />\n\n        <include layout=\"@layout/loading_poster\" />\n\n        <View\n            android:layout_width=\"@dimen/loading_margin\"\n            android:layout_height=\"match_parent\" />\n\n        <include layout=\"@layout/loading_poster\" />\n\n        <View\n            android:layout_width=\"@dimen/loading_margin\"\n            android:layout_height=\"wrap_content\" />\n\n        <include layout=\"@layout/loading_poster\" />\n    </LinearLayout>\n\n</LinearLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/loading_poster.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        app:cardCornerRadius=\"@dimen/loading_radius\"\n        android:layout_width=\"100dp\"\n        android:layout_height=\"140dp\"\n        android:background=\"@color/grayShimmer\"\n        tools:ignore=\"ContentDescription\" />"
  },
  {
    "path": "app/src/main/res/layout/loading_poster_dynamic.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:clipToPadding=\"false\"\n        android:orientation=\"vertical\">\n\n        <androidx.cardview.widget.CardView\n            android:id=\"@+id/card_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_marginBottom=\"10dp\"\n            android:background=\"@color/grayShimmer\"\n            app:cardCornerRadius=\"@dimen/loading_radius\"\n            app:layout_constraintDimensionRatio=\"1:1.414\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            tools:ignore=\"ContentDescription\" />\n\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n    <include\n        layout=\"@layout/loading_line_short_center\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"15dp\"\n        android:layout_marginHorizontal=\"20dp\"\n        android:layout_marginVertical=\"10dp\" />\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/lock_pin_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:padding=\"16dp\">\n\n    <EditText\n        android:id=\"@+id/pinEditText\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"16dp\"\n        android:autofillHints=\"no\"\n        android:hint=\"@string/pin\"\n        android:inputType=\"numberPassword\"\n        android:maxLength=\"4\" />\n\n    <TextView\n        android:id=\"@+id/pinEditTextError\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginTop=\"8dp\"\n        android:visibility=\"gone\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/logcat.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/logcat_recycler_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:layout_marginBottom=\"60dp\"\n        tools:listitem=\"@layout/item_logcat\" />\n\n    <HorizontalScrollView\n        android:id=\"@+id/apply_btt_holder\"\n        android:scrollbars=\"none\"\n        android:gravity=\"bottom|end\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\">\n\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/save_btt\"\n                android:text=\"@string/sort_save\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:layout_width=\"wrap_content\"\n                android:nextFocusRight=\"@id/copy_btt\"\n                style=\"@style/WhiteButton\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/copy_btt\"\n                android:text=\"@string/sort_copy\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:layout_width=\"wrap_content\"\n                android:nextFocusLeft=\"@id/save_btt\"\n                android:nextFocusRight=\"@id/clear_btt\"\n                style=\"@style/BlackButton\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/clear_btt\"\n                android:text=\"@string/sort_clear\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:layout_width=\"wrap_content\"\n                android:nextFocusRight=\"@id/close_btt\"\n                android:nextFocusLeft=\"@id/copy_btt\"\n                style=\"@style/BlackButton\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/close_btt\"\n                android:text=\"@string/sort_close\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:layout_width=\"wrap_content\"\n                android:nextFocusLeft=\"@id/clear_btt\"\n                style=\"@style/BlackButton\" />\n        </LinearLayout>\n    </HorizontalScrollView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/main_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryBlackBackground\">\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"vertical\">\n\n            <LinearLayout\n                android:id=\"@+id/settings_profile\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                android:padding=\"20dp\"\n                tools:visibility=\"visible\">\n\n                <androidx.cardview.widget.CardView\n                    android:layout_width=\"50dp\"\n                    android:layout_height=\"50dp\"\n                    android:foreground=\"@drawable/outline_big_25_gray\"\n                    app:cardCornerRadius=\"25dp\">\n\n                    <ImageView\n                        android:id=\"@+id/settings_profile_pic\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:contentDescription=\"@string/account\"\n                        android:scaleType=\"centerCrop\"\n                        tools:src=\"@drawable/profile_bg_orange\" />\n\n                </androidx.cardview.widget.CardView>\n\n                <TextView\n                    android:id=\"@+id/settings_profile_text\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:gravity=\"center_vertical\"\n                    android:paddingStart=\"10dp\"\n                    android:paddingEnd=\"10dp\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"18sp\"\n                    android:textStyle=\"normal\"\n                    tools:text=\"Quick Brown Fox\" />\n            </LinearLayout>\n\n            <TextView\n                android:id=\"@+id/settings_general\"\n\n                style=\"@style/SettingsItem\"\n                android:nextFocusDown=\"@id/settings_player\"\n                android:text=\"@string/category_general\" />\n\n            <TextView\n                android:id=\"@+id/settings_player\"\n                style=\"@style/SettingsItem\"\n\n                android:nextFocusUp=\"@id/settings_general\"\n                android:nextFocusDown=\"@id/settings_providers\"\n                android:text=\"@string/category_player\" />\n\n            <TextView\n                android:id=\"@+id/settings_providers\"\n                style=\"@style/SettingsItem\"\n\n                android:nextFocusUp=\"@id/settings_player\"\n                android:nextFocusDown=\"@id/settings_ui\"\n                android:text=\"@string/category_providers\" />\n\n            <TextView\n                android:id=\"@+id/settings_ui\"\n                style=\"@style/SettingsItem\"\n\n                android:nextFocusUp=\"@id/settings_providers\"\n                android:nextFocusDown=\"@id/settings_updates\"\n                android:text=\"@string/category_ui\" />\n\n            <TextView\n                android:id=\"@+id/settings_updates\"\n                style=\"@style/SettingsItem\"\n\n                android:nextFocusUp=\"@id/settings_ui\"\n                android:nextFocusDown=\"@id/settings_credits\"\n                android:text=\"@string/category_updates\" />\n\n            <TextView\n                android:id=\"@+id/settings_credits\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusUp=\"@id/settings_updates\"\n                android:text=\"@string/category_account\" />\n\n            <TextView\n                android:id=\"@+id/settings_extensions\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusUp=\"@id/settings_credits\"\n                android:text=\"@string/extensions\" />\n\n            <LinearLayout\n                android:id=\"@+id/app_version_info\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"center\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:id=\"@+id/app_version\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"10dp\"\n                    android:textColor=\"?attr/textColor\"\n                    tools:text=\"0.0.0\" />\n\n                <TextView\n                    android:id=\"@+id/delimiter0\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"•\"\n                    android:textColor=\"?attr/textColor\" />\n\n                <TextView\n                    android:id=\"@+id/commit_hash\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"10dp\"\n                    android:text=\"@string/commit_hash\"\n                    android:textColor=\"?attr/textColor\" />\n\n                <TextView\n                    android:id=\"@+id/delimiter1\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"•\"\n                    android:textColor=\"?attr/textColor\" />\n\n                <TextView\n                    android:id=\"@+id/build_date\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"10dp\"\n                    android:textColor=\"?attr/textColor\"\n                    tools:text=\"21/03/2024 09:02 pm\" />\n            </LinearLayout>\n\n        </LinearLayout>\n    </ScrollView>\n</androidx.constraintlayout.widget.ConstraintLayout>"
  },
  {
    "path": "app/src/main/res/layout/options_popup_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"horizontal\">\n\n    <androidx.cardview.widget.CardView\n            android:foreground=\"@drawable/outline_drawable\"\n            android:layout_margin=\"2dp\"\n            android:layout_width=\"114dp\"\n            android:layout_height=\"180dp\"\n            android:layout_marginBottom=\"2dp\"\n            android:elevation=\"10dp\"\n            app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n            android:id=\"@+id/background_card\"\n            app:cardBackgroundColor=\"?attr/primaryGrayBackground\">\n\n        <ImageView\n                android:duplicateParentState=\"true\"\n                android:id=\"@+id/imageView\"\n                tools:src=\"@drawable/example_poster\"\n                android:scaleType=\"centerCrop\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:contentDescription=\"@string/search_poster_img_des\" />\n    </androidx.cardview.widget.CardView>\n\n    <ListView\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n\n            android:nextFocusUp=\"@id/toggle1\"\n            android:nextFocusDown=\"@id/apply_btt\"\n\n            android:id=\"@+id/listview1\"\n            android:requiresFadingEdge=\"vertical\"\n            tools:listitem=\"@layout/sort_bottom_single_choice_color\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_rowWeight=\"1\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/player_custom_layout.xml",
    "content": "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/player_holder\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:orientation=\"vertical\">\n\n    <ImageView\n        android:visibility=\"gone\"\n        android:id=\"@+id/video_outline\"\n        android:src=\"@drawable/video_outline\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </ImageView>\n\n\n    <!--\n        <LinearLayout android:layout_width=\"match_parent\"\n                      android:layout_height=\"wrap_content\"\n                      android:gravity=\"end\"\n                      android:id=\"@+id/video_lock_holder\"\n        >\n\n            <FrameLayout\n                    android:layout_margin=\"5dp\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    tools:ignore=\"UselessParent\">\n                <ImageView\n                        android:layout_width=\"30dp\"\n                        android:layout_height=\"30dp\"\n                        android:layout_margin=\"20dp\"\n                        android:id=\"@+id/video_locked_img\"\n                        android:layout_gravity=\"end|center_vertical\"\n                        android:src=\"@drawable/video_locked\">\n                </ImageView>\n                <ImageView\n                        android:id=\"@+id/video_lock\"\n                        android:layout_width=\"70dp\"\n                        android:layout_height=\"70dp\"\n                        android:layout_gravity=\"end|center_vertical\"\n                        android:focusable=\"true\"\n                        android:clickable=\"true\"\n                        android:background=\"@drawable/video_tap_button_always_white\">\n                </ImageView>\n\n            </FrameLayout>\n\n    </LinearLayout>\n-->\n    <FrameLayout\n        android:id=\"@+id/piphide\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n\n        <View\n            android:id=\"@+id/shadow_overlay\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/black_overlay\" />\n\n        <RelativeLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"200dp\"\n            android:orientation=\"horizontal\"\n            app:layout_constraintBottom_toTopOf=\"@+id/player_center_menu\"\n            app:layout_constraintTop_toBottomOf=\"@+id/topMenuRight\">\n\n            <TextView\n                android:id=\"@+id/player_time_text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:gravity=\"center\"\n                android:shadowColor=\"@android:color/black\"\n                android:shadowRadius=\"10.0\"\n                android:textColor=\"@android:color/white\"\n                android:textSize=\"30sp\"\n                tools:text=\"+100\" />\n        </RelativeLayout>\n\n        <FrameLayout\n            android:id=\"@+id/player_episode_filler_holder\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"end\"\n            android:layout_margin=\"20dp\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/player_episode_filler\"\n                style=\"@style/SmallBlackButton\"\n                android:text=\"@string/filler\" />\n        </FrameLayout>\n\n\n        <!-- atm this is useless, however it might be used for PIP one day? -->\n        <ImageView\n            android:id=\"@+id/player_fullscreen\"\n            android:layout_width=\"30dp\"\n            android:layout_height=\"30dp\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginEnd=\"20dp\"\n            android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:src=\"@drawable/baseline_fullscreen_24\"\n            android:visibility=\"gone\"\n            app:tint=\"@color/white\" />\n\n        <FrameLayout\n            android:id=\"@+id/player_intro_play\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            android:visibility=\"gone\" />\n\n        <ImageView\n            android:id=\"@+id/player_open_source\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:focusableInTouchMode=\"false\"\n            android:importantForAccessibility=\"no\"\n            android:visibility=\"gone\" />\n\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:id=\"@+id/player_video_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n\n            <FrameLayout\n                android:id=\"@+id/player_top_holder\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\">\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginStart=\"80dp\"\n                    android:layout_marginEnd=\"80dp\"\n                    android:clipToPadding=\"false\"\n                    android:orientation=\"vertical\"\n                    android:paddingTop=\"20dp\"\n                    app:layout_constraintLeft_toLeftOf=\"parent\"\n                    app:layout_constraintTop_toTopOf=\"parent\">\n\n                    <TextView\n                        android:id=\"@+id/player_video_title_rez\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginBottom=\"2.5dp\"\n                        android:gravity=\"center\"\n                        android:textColor=\"@color/white\"\n                        tools:text=\"1920x1080\" />\n\n\n                    <TextView\n                        android:id=\"@+id/player_video_info\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:gravity=\"center\"\n                        android:layout_marginBottom=\"2.5dp\"\n                        android:textColor=\"@color/white\"\n                        android:visibility=\"gone\"\n                        tools:text=\"HEVC\" />\n\n                    <LinearLayout\n                        android:id=\"@+id/player_video_title_holder\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:gravity=\"center\">\n                        <TextView\n                            android:maxLines=\"2\"\n                            android:id=\"@+id/player_video_title\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:gravity=\"center\"\n                            android:textColor=\"@color/white\"\n                            android:textStyle=\"bold\"\n                            android:visibility=\"visible\"\n                            tools:text=\"Hello world \" />\n                        <ImageView\n                            android:id=\"@+id/offline_pin\"\n                            android:layout_width=\"16dp\"\n                            android:layout_height=\"16dp\"\n                            android:layout_marginStart=\"2dp\"\n                            android:src=\"@drawable/ic_offline_pin_24\"\n                            android:visibility=\"gone\"\n                            tools:visibility=\"visible\"\n                            android:layout_gravity=\"center\"/>\n                    </LinearLayout>\n                </LinearLayout>\n\n                <!-- Removed as it has no use anymore-->\n                <!--<androidx.mediarouter.app.MediaRouteButton\n                        android:id=\"@+id/player_media_route_button\"\n                        android:layout_width=\"70dp\"\n                        android:layout_height=\"70dp\"\n                        android:layout_gravity=\"end\"\n                        android:layout_margin=\"5dp\"\n                        android:mediaRouteTypes=\"user\"\n                        android:visibility=\"visible\"\n                        app:layout_constraintRight_toRightOf=\"parent\"\n                        app:layout_constraintTop_toTopOf=\"parent\" />-->\n\n\n\n                <LinearLayout\n                    android:id=\"@+id/player_go_back_holder\"\n                    android:layout_width=\"70dp\"\n                    android:layout_height=\"70dp\"\n                    android:layout_margin=\"5dp\"\n                    android:orientation=\"horizontal\"\n                    app:layout_constraintStart_toStartOf=\"parent\"\n                    app:layout_constraintTop_toTopOf=\"parent\">\n\n                    <LinearLayout\n                        android:id=\"@+id/player_go_back_root\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:orientation=\"vertical\">\n\n                        <ImageView\n                            android:id=\"@+id/player_go_back\"\n                            android:layout_width=\"70dp\"\n                            android:layout_height=\"70dp\"\n                            android:layout_gravity=\"center\"\n                            android:background=\"@drawable/video_tap_button_always_white\"\n                            android:clickable=\"true\"\n                            android:contentDescription=\"@string/go_back_img_des\"\n                            android:focusable=\"true\"\n                            android:nextFocusLeft=\"@id/player_go_back\"\n                            android:nextFocusRight=\"@id/player_restart\"\n                            android:nextFocusUp=\"@id/player_go_back\"\n                            android:nextFocusDown=\"@id/player_pause_play\"\n                            android:padding=\"20dp\"\n                            android:src=\"@drawable/ic_baseline_arrow_back_24\"\n                            android:tag=\"@string/tv_no_focus_tag\"\n                            app:tint=\"@android:color/white\" />\n\n                        <TextView\n                            android:id=\"@+id/player_go_back_text\"\n                            style=\"@style/ResultMarqueeButtonText\"\n                            android:text=\"@string/go_back_img_des\"\n                            android:visibility=\"gone\" />\n\n                    </LinearLayout>\n\n                    <LinearLayout\n                        android:id=\"@+id/player_restart_root\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginStart=\"40dp\"\n                        android:layout_marginEnd=\"10dp\"\n                        android:orientation=\"vertical\"\n                        android:visibility=\"gone\">\n\n                        <ImageView\n                            android:id=\"@+id/player_restart\"\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_gravity=\"center\"\n                            android:background=\"@drawable/video_tap_button_always_white\"\n                            android:clickable=\"true\"\n                            android:contentDescription=\"@string/restart\"\n                            android:focusable=\"true\"\n                            android:nextFocusLeft=\"@id/player_go_back\"\n                            android:nextFocusRight=\"@id/player_go_forward\"\n                            android:nextFocusUp=\"@id/player_restart\"\n                            android:nextFocusDown=\"@id/player_pause_play\"\n                            android:src=\"@drawable/ic_baseline_replay_24\"\n                            android:tag=\"@string/tv_no_focus_tag\"\n                            app:tint=\"@android:color/white\" />\n\n                        <TextView\n                            android:id=\"@+id/player_restart_text\"\n                            style=\"@style/ResultMarqueeButtonText\"\n                            android:text=\"@string/restart\" />\n\n                    </LinearLayout>\n\n                    <LinearLayout\n                        android:id=\"@+id/player_go_forward_root\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginStart=\"80dp\"\n                        android:layout_marginEnd=\"10dp\"\n                        android:orientation=\"vertical\"\n                        android:visibility=\"gone\">\n\n                        <ImageView\n                            android:id=\"@+id/player_go_forward\"\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_gravity=\"center\"\n                            android:background=\"@drawable/video_tap_button_always_white\"\n                            android:clickable=\"true\"\n                            android:contentDescription=\"@string/next_episode\"\n                            android:focusable=\"true\"\n                            android:nextFocusLeft=\"@id/player_restart\"\n                            android:nextFocusRight=\"@id/player_go_forward\"\n                            android:nextFocusUp=\"@id/player_go_forward\"\n                            android:nextFocusDown=\"@id/player_pause_play\"\n                            android:src=\"@drawable/ic_baseline_skip_next_rounded_24\"\n                            android:tag=\"@string/tv_no_focus_tag\"\n                            app:tint=\"@android:color/white\" />\n\n                        <TextView\n                            android:id=\"@+id/player_go_forward_text\"\n                            style=\"@style/ResultMarqueeButtonText\"\n                            android:text=\"@string/next_episode\" />\n\n                    </LinearLayout>\n\n                </LinearLayout>\n\n\n            </FrameLayout>\n\n            <!--use for thinner app:trackThickness=\"3dp\" com.google.android.material.progressindicator.CircularProgressIndicator-->\n            <ProgressBar\n                android:id=\"@+id/player_buffering\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n\n                android:clickable=\"false\"\n                android:focusable=\"false\"\n                android:focusableInTouchMode=\"false\"\n\n                android:indeterminate=\"true\"\n                android:visibility=\"gone\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toLeftOf=\"parent\"\n                app:layout_constraintRight_toRightOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                tools:visibility=\"visible\" />\n\n\n\n            <!-- This nested layout is necessary because of buffering and clicking-->\n\n            <androidx.constraintlayout.widget.ConstraintLayout\n                android:id=\"@+id/player_center_menu\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"100dp\"\n                android:layout_gravity=\"center\"\n                android:gravity=\"center\"\n                android:layoutDirection=\"ltr\"\n                android:orientation=\"horizontal\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toLeftOf=\"parent\"\n                app:layout_constraintRight_toRightOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\">\n\n                <FrameLayout\n                    android:id=\"@+id/player_rew_holder\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical|start\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:layout_constraintLeft_toLeftOf=\"parent\"\n                    app:layout_constraintRight_toLeftOf=\"@id/player_ffwd_holder\"\n                    app:layout_constraintTop_toTopOf=\"parent\"\n                    app:layout_constraintWidth_percent=\"0.5\">\n\n                    <TextView\n                        android:id=\"@+id/exo_rew_text\"\n                        android:layout_width=\"200dp\"\n                        android:layout_height=\"40dp\"\n                        android:layout_gravity=\"center\"\n\n                        android:gravity=\"center\"\n                        android:textColor=\"@color/white\"\n                        android:textSize=\"19sp\"\n\n                        android:textStyle=\"bold\"\n                        tools:text=\"10\" />\n\n                    <ImageButton\n                        android:id=\"@+id/player_rew\"\n                        android:layout_width=\"70dp\"\n                        android:layout_height=\"70dp\"\n                        android:layout_gravity=\"center\"\n\n                        android:background=\"@drawable/video_tap_button_skip\"\n                        android:nextFocusLeft=\"@id/player_rew\"\n                        android:nextFocusUp=\"@id/player_go_back\"\n                        android:nextFocusDown=\"@id/player_lock\"\n                        android:padding=\"10dp\"\n                        android:scaleType=\"fitCenter\"\n                        android:scaleX=\"-1\"\n                        android:src=\"@drawable/netflix_skip_forward\"\n                        android:tintMode=\"src_in\"\n                        app:tint=\"@color/white\"\n                        tools:ignore=\"ContentDescription\" />\n                </FrameLayout>\n\n                <FrameLayout\n                    android:id=\"@+id/player_pause_play_holder_holder\"\n                    android:layout_width=\"100dp\"\n                    android:layout_height=\"100dp\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:layout_constraintLeft_toLeftOf=\"parent\"\n                    app:layout_constraintRight_toRightOf=\"parent\"\n                    app:layout_constraintTop_toTopOf=\"parent\">\n\n                    <ImageView\n                        android:id=\"@+id/player_pause_play\"\n                        android:layout_width=\"70dp\"\n                        android:layout_height=\"70dp\"\n                        android:layout_gravity=\"center\"\n                        android:background=\"@drawable/video_tap_button\"\n                        android:nextFocusLeft=\"@id/player_rew\"\n\n                        android:nextFocusRight=\"@id/player_ffwd\"\n\n                        android:nextFocusUp=\"@id/player_go_back\"\n                        android:nextFocusDown=\"@id/player_lock\"\n\n                        android:src=\"@drawable/netflix_pause\"\n                        app:tint=\"@color/white\"\n                        tools:ignore=\"ContentDescription\" />\n                </FrameLayout>\n\n                <FrameLayout\n                    android:id=\"@+id/player_ffwd_holder\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical|end\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:layout_constraintLeft_toRightOf=\"@id/player_rew_holder\"\n                    app:layout_constraintRight_toRightOf=\"parent\"\n                    app:layout_constraintTop_toTopOf=\"parent\"\n                    app:layout_constraintWidth_percent=\"0.5\">\n\n                    <TextView\n                        android:id=\"@+id/exo_ffwd_text\"\n                        android:layout_width=\"200dp\"\n                        android:layout_height=\"40dp\"\n                        android:layout_gravity=\"center\"\n                        android:gravity=\"center\"\n                        android:textColor=\"@color/white\"\n                        android:textSize=\"19sp\"\n                        android:textStyle=\"bold\"\n                        tools:text=\"10\" />\n\n                    <ImageButton\n                        android:id=\"@+id/player_ffwd\"\n                        android:layout_width=\"70dp\"\n                        android:layout_height=\"70dp\"\n                        android:layout_gravity=\"center\"\n\n                        android:background=\"@drawable/video_tap_button_skip\"\n                        android:nextFocusRight=\"@id/player_rew\"\n                        android:nextFocusUp=\"@id/player_go_back\"\n                        android:nextFocusDown=\"@id/player_lock\"\n                        android:padding=\"10dp\"\n                        android:scaleType=\"fitCenter\"\n                        android:src=\"@drawable/netflix_skip_forward\"\n                        android:tintMode=\"src_in\"\n                        app:tint=\"@color/white\"\n                        tools:ignore=\"ContentDescription\" />\n                </FrameLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/download_both_header\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\">\n\n                    <FrameLayout\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\">\n\n                        <ImageView\n                            android:id=\"@+id/download_header_toggle\"\n                            android:layout_width=\"40dp\"\n                            android:layout_height=\"40dp\"\n                            android:layout_gravity=\"center_vertical|start\"\n                            android:layout_marginStart=\"60dp\"\n                            android:background=\"@drawable/video_tap_button_always_white\"\n                            android:padding=\"10dp\"\n                            android:src=\"@drawable/baseline_downloading_24\"\n                            app:tint=\"@color/white\">\n\n                        </ImageView>\n\n                        <androidx.cardview.widget.CardView\n                            android:id=\"@+id/download_header\"\n                            android:layout_width=\"200dp\"\n                            android:layout_height=\"80dp\"\n                            android:layout_gravity=\"start|center_vertical\"\n                            android:layout_margin=\"10dp\"\n                            android:elevation=\"10dp\"\n                            app:cardBackgroundColor=\"@color/darkBar\"\n                            app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n                            <LinearLayout\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"match_parent\"\n                                android:layout_margin=\"10dp\"\n                                android:gravity=\"end|center_vertical\"\n                                android:orientation=\"vertical\">\n\n                                <TextView\n                                    android:id=\"@+id/download_header_toggle_text\"\n                                    style=\"@style/ResultMarqueeButtonText\"\n                                    android:layout_marginTop=\"5dp\"\n                                    android:text=\"@string/torrent_singular\"\n                                    android:visibility=\"gone\" />\n\n                                <TextView\n                                    android:id=\"@+id/downloaded_progress_text\"\n                                    android:layout_width=\"wrap_content\"\n                                    android:layout_height=\"wrap_content\"\n                                    android:textColor=\"@color/white\"\n                                    tools:text=\"10MB / 20MB\" />\n\n                                <TextView\n                                    android:id=\"@+id/downloaded_progress_speed_text\"\n                                    android:layout_width=\"wrap_content\"\n                                    android:layout_height=\"wrap_content\"\n                                    android:textColor=\"@color/white\"\n                                    tools:text=\"10MB/s - 12 seeders\" />\n\n                                <com.google.android.material.progressindicator.LinearProgressIndicator\n                                    android:id=\"@+id/downloaded_progress\"\n                                    style=\"@style/RoundProgressbar\"\n                                    android:layout_width=\"match_parent\"\n                                    android:layout_height=\"wrap_content\"\n                                    android:layout_marginTop=\"5dp\"\n                                    android:indeterminate=\"false\"\n                                    android:indeterminateTint=\"?attr/colorPrimary\"\n                                    android:progressBackgroundTint=\"?attr/colorPrimary\"\n                                    android:progressTint=\"?attr/colorPrimary\"\n                                    tools:progress=\"20\" />\n\n                            </LinearLayout>\n                        </androidx.cardview.widget.CardView>\n                    </FrameLayout>\n\n                </LinearLayout>\n            </androidx.constraintlayout.widget.ConstraintLayout>\n\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/skip_chapter_button\"\n                style=\"@style/NiceButton\"\n                android:layout_width=\"150dp\"\n                android:layout_height=\"40dp\"\n                android:layout_marginTop=\"60dp\"\n                android:layout_marginEnd=\"100dp\"\n                android:backgroundTint=\"@color/skipOpTransparent\"\n                android:maxLines=\"1\"\n                android:padding=\"10dp\"\n                android:textColor=\"@color/white\"\n                android:visibility=\"gone\"\n                app:cornerRadius=\"@dimen/rounded_button_radius\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"@+id/player_top_holder\"\n                app:strokeColor=\"@color/white\"\n                app:strokeWidth=\"1dp\"\n                tools:text=\"Skip Opening\"\n                tools:visibility=\"visible\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"bottom\"\n                android:layout_marginBottom=\"20dp\"\n                android:gravity=\"center\"\n                android:orientation=\"horizontal\"\n                android:paddingTop=\"4dp\"\n                android:visibility=\"gone\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\">\n\n                <ImageButton\n                    android:id=\"@id/exo_prev\"\n                    style=\"@style/ExoMediaButton.Previous\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n\n                <ImageButton\n                    android:id=\"@id/exo_repeat_toggle\"\n                    style=\"@style/ExoMediaButton\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n\n                <ImageButton\n                    android:id=\"@id/exo_next\"\n                    style=\"@style/ExoMediaButton.Next\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <ImageButton\n                    android:id=\"@id/exo_vr\"\n                    style=\"@style/ExoMediaButton.VR\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <ImageButton\n                    android:id=\"@id/exo_play\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"0dp\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <ImageButton\n                    android:id=\"@id/exo_pause\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"0dp\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:id=\"@+id/bottom_player_bar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"10dp\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"vertical\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\">\n\n                <androidx.constraintlayout.widget.ConstraintLayout\n                    android:id=\"@+id/player_video_bar\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layoutDirection=\"ltr\"\n                    android:orientation=\"horizontal\"\n                    tools:visibility=\"visible\">\n\n                    <TextView\n                        android:id=\"@id/exo_position\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"30dp\"\n                        android:layout_gravity=\"center\"\n                        android:layout_marginStart=\"20dp\"\n                        android:gravity=\"end|center_vertical\"\n                        android:includeFontPadding=\"false\"\n                        android:minWidth=\"50dp\"\n                        android:paddingLeft=\"4dp\"\n                        android:paddingRight=\"4dp\"\n                        android:textColor=\"@android:color/white\"\n                        android:textSize=\"14sp\"\n                        android:textStyle=\"normal\"\n                        app:layout_constraintBottom_toBottomOf=\"parent\"\n                        app:layout_constraintStart_toStartOf=\"parent\"\n                        tools:text=\"15:30\" />\n\n                    <FrameLayout\n                        android:id=\"@+id/previewFrameLayout\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"0dp\"\n                        android:layout_marginStart=\"16dp\"\n                        android:layout_marginEnd=\"16dp\"\n                        android:layout_marginBottom=\"16dp\"\n                        android:background=\"@drawable/video_frame\"\n                        android:visibility=\"invisible\"\n                        app:layout_constraintBottom_toTopOf=\"@+id/exo_progress\"\n                        app:layout_constraintDimensionRatio=\"16:9\"\n                        app:layout_constraintEnd_toEndOf=\"parent\"\n                        app:layout_constraintHorizontal_bias=\"0.0\"\n                        app:layout_constraintStart_toStartOf=\"parent\"\n                        app:layout_constraintWidth_default=\"percent\"\n                        app:layout_constraintWidth_percent=\"0.25\"\n                        tools:visibility=\"visible\">\n\n                        <ImageView\n                            android:id=\"@+id/previewImageView\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"match_parent\"\n                            android:layout_margin=\"@dimen/video_frame_width\"\n                            android:importantForAccessibility=\"no\"\n                            android:scaleType=\"centerCrop\" />\n                    </FrameLayout>\n\n                    <com.github.rubensousa.previewseekbar.media3.PreviewTimeBar\n                        android:id=\"@id/exo_progress\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"30dp\"\n                        android:layout_weight=\"1\"\n                        app:bar_height=\"2dp\"\n                        app:layout_constraintBottom_toBottomOf=\"@id/exo_position\"\n                        app:layout_constraintEnd_toStartOf=\"@id/exo_duration\"\n                        app:layout_constraintStart_toEndOf=\"@+id/exo_position\"\n                        app:played_color=\"?attr/colorPrimary\"\n\n                        app:scrubber_color=\"?attr/colorPrimary\"\n                        app:scrubber_dragged_size=\"26dp\"\n                        app:scrubber_enabled_size=\"24dp\"\n                        app:unplayed_color=\"@color/videoProgress\" />\n\n                    <TextView\n                        android:id=\"@id/exo_duration\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"30dp\"\n                        android:layout_gravity=\"center|center_vertical\"\n\n                        android:layout_marginEnd=\"20dp\"\n                        android:includeFontPadding=\"false\"\n                        android:minWidth=\"50dp\"\n                        android:paddingLeft=\"4dp\"\n                        android:paddingRight=\"4dp\"\n                        android:textColor=\"@android:color/white\"\n                        android:textSize=\"14sp\"\n                        android:textStyle=\"normal\"\n                        app:layout_constraintBaseline_toBaselineOf=\"@id/exo_position\"\n                        app:layout_constraintEnd_toEndOf=\"parent\"\n                        tools:text=\"23:20\" />\n\n                    <TextView\n                        android:id=\"@+id/time_left\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"30dp\"\n                        android:layout_gravity=\"center|center_vertical\"\n\n                        android:layout_marginEnd=\"20dp\"\n                        android:includeFontPadding=\"false\"\n                        android:minWidth=\"50dp\"\n                        android:paddingLeft=\"4dp\"\n                        android:paddingRight=\"4dp\"\n                        android:textColor=\"@android:color/white\"\n                        android:textSize=\"14sp\"\n                        android:textStyle=\"normal\"\n                        android:visibility=\"gone\"\n                        app:layout_constraintBaseline_toBaselineOf=\"@id/exo_position\"\n                        app:layout_constraintEnd_toEndOf=\"parent\"\n                        tools:text=\"-23:20\" />\n\n                </androidx.constraintlayout.widget.ConstraintLayout>\n\n                <HorizontalScrollView\n                    android:id=\"@+id/player_controls_scroll\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center\">\n\n                    <LinearLayout\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"60dp\"\n                        android:gravity=\"center\"\n                        android:orientation=\"horizontal\"\n                        android:paddingTop=\"10dp\"\n                        android:paddingBottom=\"10dp\">\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_lock\"\n                            style=\"@style/VideoButton\"\n                            android:nextFocusLeft=\"@id/player_skip_episode\"\n                            android:nextFocusRight=\"@id/player_resize_btt\"\n                            android:text=\"@string/video_lock\"\n                            app:icon=\"@drawable/video_locked\"\n\n                            app:iconSize=\"30dp\" />\n\n                        <LinearLayout\n                            android:id=\"@+id/player_lock_holder\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"match_parent\"\n                            android:orientation=\"horizontal\">\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/player_rotate_btt\"\n                                style=\"@style/VideoButton\"\n                                android:nextFocusLeft=\"@id/player_lock\"\n\n                                android:nextFocusRight=\"@id/player_resize_btt\"\n                                android:text=\"@string/rotate_video\"\n                                app:icon=\"@drawable/screen_rotation\" />\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/player_resize_btt\"\n                                style=\"@style/VideoButton\"\n                                android:nextFocusLeft=\"@id/player_rotate_btt\"\n\n                                android:nextFocusRight=\"@id/player_speed_btt\"\n                                android:text=\"@string/video_aspect_ratio_resize\"\n                                app:icon=\"@drawable/ic_baseline_aspect_ratio_24\" />\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/player_speed_btt\"\n                                style=\"@style/VideoButton\"\n                                android:nextFocusLeft=\"@id/player_resize_btt\"\n\n                                android:nextFocusRight=\"@id/player_subtitle_offset_btt\"\n                                app:icon=\"@drawable/ic_baseline_speed_24\"\n                                tools:text=\"Speed\" />\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/player_subtitle_offset_btt\"\n                                style=\"@style/VideoButton\"\n                                android:nextFocusLeft=\"@id/player_speed_btt\"\n                                android:nextFocusRight=\"@id/player_sources_btt\"\n                                android:text=\"@string/subtitle_offset\"\n\n                                android:visibility=\"gone\"\n                                app:icon=\"@drawable/ic_outline_subtitles_24\"\n                                tools:visibility=\"visible\" />\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/player_sources_btt\"\n                                style=\"@style/VideoButton\"\n                                android:layout_height=\"40dp\"\n\n                                android:nextFocusLeft=\"@id/player_subtitle_offset_btt\"\n                                android:nextFocusRight=\"@id/player_tracks_btt\"\n                                android:text=\"@string/video_source\"\n                                app:icon=\"@drawable/ic_baseline_playlist_play_24\" />\n\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/player_tracks_btt\"\n                                style=\"@style/VideoButton\"\n                                android:layout_height=\"40dp\"\n\n                                android:nextFocusLeft=\"@id/player_sources_btt\"\n                                android:nextFocusRight=\"@id/player_skip_op\"\n                                android:text=\"@string/tracks\"\n                                app:icon=\"@drawable/ic_baseline_equalizer_24\" />\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/player_skip_op\"\n                                style=\"@style/VideoButton\"\n                                android:nextFocusLeft=\"@id/player_sources_btt\"\n\n                                android:nextFocusRight=\"@id/player_skip_episode\"\n                                android:text=\"@string/video_skip_op\"\n                                app:icon=\"@drawable/ic_baseline_fast_forward_24\" />\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/player_skip_episode\"\n                                style=\"@style/VideoButton\"\n                                android:nextFocusLeft=\"@id/player_skip_op\"\n                                android:nextFocusRight=\"@id/player_lock\"\n                                android:text=\"@string/next_episode\"\n                                app:icon=\"@drawable/ic_baseline_skip_next_24\" />\n\n                        </LinearLayout>\n                    </LinearLayout>\n                </HorizontalScrollView>\n            </LinearLayout>\n        </androidx.constraintlayout.widget.ConstraintLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layoutDirection=\"ltr\"\n            android:orientation=\"horizontal\">\n\n            <RelativeLayout\n                android:id=\"@+id/player_progressbar_left_holder\"\n                android:layout_width=\"100dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:gravity=\"start\"\n                android:visibility=\"gone\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toLeftOf=\"parent\"\n                app:layout_constraintRight_toLeftOf=\"@+id/centerMenuView\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                tools:alpha=\"1\"\n                tools:visibility=\"visible\">\n\n                <!-- VERY hacky layout -->\n                <ImageView\n                    android:id=\"@+id/player_progressbar_left_icon\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_centerHorizontal=\"true\"\n                    android:layout_marginBottom=\"220dp\"\n                    android:src=\"@drawable/ic_baseline_volume_up_24\"\n                    app:tint=\"@android:color/white\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <ProgressBar\n                    android:id=\"@+id/player_progressbar_left_level1\"\n                    android:layout_width=\"5dp\"\n                    android:layout_height=\"150dp\"\n                    android:layout_centerInParent=\"true\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginStart=\"40dp\"\n                    android:indeterminate=\"false\"\n                    android:max=\"100\"\n                    android:progress=\"100\"\n                    android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                    android:progressTint=\"@color/white\"\n                    android:progressTintMode=\"src_in\"\n                    tools:progress=\"30\"\n                    style=\"@android:style/Widget.Material.ProgressBar.Horizontal\" />\n\n                <ProgressBar\n                    android:id=\"@+id/player_progressbar_left_level2\"\n                    android:layout_width=\"5dp\"\n                    android:layout_height=\"150dp\"\n                    android:layout_centerInParent=\"true\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginStart=\"40dp\"\n                    android:indeterminate=\"false\"\n                    android:max=\"100\"\n                    android:progress=\"0\"\n                    android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                    android:progressTint=\"@color/colorPrimaryOrange\"\n                    android:progressTintMode=\"src_in\"\n                    tools:progress=\"0\"\n                    style=\"@android:style/Widget.Material.ProgressBar.Horizontal\" />\n            </RelativeLayout>\n\n\n            <RelativeLayout\n                android:id=\"@+id/player_progressbar_right_holder\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:gravity=\"right\"\n                android:visibility=\"gone\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toRightOf=\"@+id/centerMenuView\"\n                app:layout_constraintRight_toRightOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                tools:alpha=\"1\"\n                tools:ignore=\"RtlHardcoded\"\n                tools:visibility=\"visible\">\n\n                <ImageView\n                    android:id=\"@+id/player_progressbar_right_icon\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_centerHorizontal=\"true\"\n                    android:layout_marginBottom=\"220dp\"\n                    android:src=\"@drawable/ic_baseline_brightness_7_24\"\n                    app:tint=\"@android:color/white\"\n                    tools:ignore=\"ContentDescription\">\n\n                </ImageView>\n\n                <ProgressBar\n                    android:id=\"@+id/player_progressbar_right_level1\"\n                    style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n                    android:layout_width=\"5dp\"\n                    android:layout_height=\"150dp\"\n                    android:layout_centerInParent=\"true\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginEnd=\"40dp\"\n                    android:indeterminate=\"false\"\n                    android:max=\"100\"\n                    android:progress=\"100\"\n                    android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                    android:progressTint=\"@color/white\"\n                    android:progressTintMode=\"src_in\" />\n\n                <ProgressBar\n                    android:id=\"@+id/player_progressbar_right_level2\"\n                    style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n                    android:layout_width=\"5dp\"\n                    android:layout_height=\"150dp\"\n                    android:layout_centerInParent=\"true\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginEnd=\"40dp\"\n                    android:indeterminate=\"false\"\n                    android:max=\"100\"\n                    android:progress=\"0\"\n                    android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                    android:progressTint=\"@color/colorPrimaryOrange\"\n                    android:progressTintMode=\"src_in\" />\n            </RelativeLayout>\n        </LinearLayout>\n\n\n\n\n    </FrameLayout>\n\n    <FrameLayout\n        android:id=\"@+id/subtitle_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    </FrameLayout>\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/player_speedup_button\"\n        style=\"@style/Widget.MaterialComponents.Button.OutlinedButton\"\n        android:layout_width=\"45dp\"\n        android:layout_height=\"45dp\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginTop=\"30dp\"\n        app:iconPadding=\"0dp\"\n        app:iconGravity=\"textStart\"\n        android:clickable=\"false\"\n        android:focusable=\"false\"\n        android:textAllCaps=\"false\"\n        android:visibility=\"gone\"\n        app:icon=\"@drawable/speedup\"\n        app:iconTint=\"@color/textColor\"\n        android:foreground=\"@null\"\n        android:backgroundTint=\"@color/skipOpTransparent\"\n        tools:visibility=\"visible\" />\n    <LinearLayout\n        android:id=\"@+id/player_episodes_button_root\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:layout_gravity=\"end|center_vertical\"\n        >\n        <ImageView\n            android:padding=\"15dp\"\n            android:id=\"@+id/player_episodes_button\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:foregroundGravity=\"center\"\n            android:src=\"@drawable/ic_baseline_arrow_back_ios_24\"\n            android:background=\"@drawable/video_tap_button_always_white\"\n            app:tint=\"@android:color/white\"\n            tools:ignore=\"ContentDescription\" />\n        <TextView\n            android:id=\"@+id/player_episodes_button_text\"\n            style=\"@style/ResultMarqueeButtonText\"\n            android:layout_marginTop=\"5dp\"\n            android:text=\"@string/episodes\"\n            android:visibility=\"gone\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/player_episode_overlay\"\n        android:visibility=\"gone\"\n        android:padding=\"5dp\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:orientation=\"vertical\"\n        android:layout_gravity=\"end\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\">\n\n        <TextView\n            android:id=\"@+id/player_episode_overlay_title\"\n            android:padding=\"10dp\"\n            style=\"@style/WatchHeaderText\"\n            android:textSize=\"15sp\"\n            android:layout_marginEnd=\"0dp\"\n            android:text=\"@string/episodes\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"/>\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:requiresFadingEdge=\"vertical\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            android:id=\"@+id/player_episode_list\"\n            tools:listitem=\"@layout/player_episodes\"\n            android:nextFocusLeft=\"@id/player_episodes_button\"\n            android:layout_width=\"350dp\"\n            android:layout_height=\"match_parent\"\n            android:clipToPadding=\"false\"\n            android:descendantFocusability=\"afterDescendants\">\n\n        </androidx.recyclerview.widget.RecyclerView>\n    </LinearLayout>\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/player_custom_layout_tv.xml",
    "content": "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/player_holder\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:tag=\"television\"\n    tools:orientation=\"vertical\">\n\n    <ImageView\n        android:visibility=\"gone\"\n        android:id=\"@+id/video_outline\"\n        android:src=\"@drawable/video_outline\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </ImageView>\n\n\n    <FrameLayout\n        android:id=\"@+id/piphide\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <View\n            android:id=\"@+id/shadow_overlay\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@drawable/player_gradient_tv\" />\n        <!--\n            <LinearLayout android:layout_width=\"match_parent\"\n                          android:layout_height=\"wrap_content\"\n                          android:gravity=\"end\"\n                          android:id=\"@+id/video_lock_holder\"\n            >\n\n                <FrameLayout\n                        android:layout_margin=\"5dp\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        tools:ignore=\"UselessParent\">\n                    <ImageView\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_margin=\"20dp\"\n                            android:id=\"@+id/video_locked_img\"\n                            android:layout_gravity=\"end|center_vertical\"\n                            android:src=\"@drawable/video_locked\">\n                    </ImageView>\n                    <ImageView\n                            android:id=\"@+id/video_lock\"\n                            android:layout_width=\"70dp\"\n                            android:layout_height=\"70dp\"\n                            android:layout_gravity=\"end|center_vertical\"\n                            android:focusable=\"true\"\n                            android:clickable=\"true\"\n                            android:background=\"@drawable/video_tap_button_always_white\">\n                    </ImageView>\n\n                </FrameLayout>\n\n        </LinearLayout>\n    -->\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layoutDirection=\"ltr\"\n            android:orientation=\"horizontal\">\n\n            <RelativeLayout\n                android:id=\"@+id/player_progressbar_left_holder\"\n                android:layout_width=\"100dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:gravity=\"start\"\n                android:visibility=\"gone\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toLeftOf=\"parent\"\n                app:layout_constraintRight_toLeftOf=\"@+id/centerMenuView\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                tools:alpha=\"1\"\n                tools:visibility=\"visible\">\n                <!--VERY hacky layout -->\n                <ImageView\n                    android:id=\"@+id/player_progressbar_left_icon\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_centerHorizontal=\"true\"\n                    android:layout_marginBottom=\"220dp\"\n                    android:src=\"@drawable/ic_baseline_volume_up_24\"\n                    app:tint=\"@android:color/white\"\n                    tools:ignore=\"ContentDescription\">\n\n                </ImageView>\n\n                <ProgressBar\n                    android:id=\"@+id/player_progressbar_left_level1\"\n                    android:layout_width=\"5dp\"\n                    android:layout_height=\"150dp\"\n                    android:layout_centerInParent=\"true\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginStart=\"40dp\"\n                    android:indeterminate=\"false\"\n                    android:max=\"100\"\n                    android:progress=\"100\"\n                    android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                    android:progressTint=\"@color/white\"\n                    android:progressTintMode=\"src_in\"\n                    tools:progress=\"30\"\n                    style=\"@android:style/Widget.Material.ProgressBar.Horizontal\" />\n\n                <ProgressBar\n                    android:id=\"@+id/player_progressbar_left_level2\"\n                    android:layout_width=\"5dp\"\n                    android:layout_height=\"150dp\"\n                    android:layout_centerInParent=\"true\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginStart=\"40dp\"\n                    android:indeterminate=\"false\"\n                    android:max=\"100\"\n                    android:progress=\"0\"\n                    android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                    android:progressTint=\"@color/colorPrimaryOrange\"\n                    android:progressTintMode=\"src_in\"\n                    tools:progress=\"0\"\n                    style=\"@android:style/Widget.Material.ProgressBar.Horizontal\" />\n            </RelativeLayout>\n\n            <RelativeLayout\n                android:id=\"@+id/player_progressbar_right_holder\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:gravity=\"right\"\n                android:visibility=\"gone\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toRightOf=\"@+id/centerMenuView\"\n                app:layout_constraintRight_toRightOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                tools:alpha=\"1\"\n                tools:ignore=\"RtlHardcoded\"\n                tools:visibility=\"visible\">\n\n                <ImageView\n                    android:id=\"@+id/player_progressbar_right_icon\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_centerHorizontal=\"true\"\n                    android:layout_marginBottom=\"220dp\"\n                    android:src=\"@drawable/ic_baseline_brightness_7_24\"\n                    app:tint=\"@android:color/white\"\n                    tools:ignore=\"ContentDescription\">\n\n                </ImageView>\n\n                <ProgressBar\n                    android:id=\"@+id/player_progressbar_right_level1\"\n                    style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n                    android:layout_width=\"5dp\"\n                    android:layout_height=\"150dp\"\n                    android:layout_centerInParent=\"true\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginEnd=\"40dp\"\n                    android:indeterminate=\"false\"\n                    android:max=\"100\"\n                    android:progress=\"100\"\n                    android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                    android:progressTint=\"@color/white\"\n                    android:progressTintMode=\"src_in\" />\n\n                <ProgressBar\n                    android:id=\"@+id/player_progressbar_right_level2\"\n                    style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n                    android:layout_width=\"5dp\"\n                    android:layout_height=\"150dp\"\n                    android:layout_centerInParent=\"true\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginEnd=\"40dp\"\n                    android:indeterminate=\"false\"\n                    android:max=\"100\"\n                    android:progress=\"0\"\n                    android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                    android:progressTint=\"@color/colorPrimaryOrange\"\n                    android:progressTintMode=\"src_in\" />\n            </RelativeLayout>\n        </LinearLayout>\n\n\n        <TextView\n            android:id=\"@+id/player_time_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"200dp\"\n            android:gravity=\"center\"\n            android:shadowColor=\"@android:color/black\"\n            android:shadowRadius=\"10.0\"\n            android:textColor=\"@android:color/white\"\n            android:textSize=\"30sp\"\n            android:visibility=\"gone\"\n            tools:text=\"+100\"\n            tools:visibility=\"visible\" />\n\n        <FrameLayout\n            android:id=\"@+id/player_pause_play_holder_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            android:visibility=\"gone\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintRight_toRightOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\" />\n\n        <FrameLayout\n            android:id=\"@+id/player_intro_play\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            android:visibility=\"gone\" />\n\n        <ImageView\n            android:id=\"@+id/player_open_source\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"0dp\"\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:focusableInTouchMode=\"false\"\n            android:importantForAccessibility=\"no\"\n            android:visibility=\"gone\" />\n\n        <!-- atm this is useless, however it might be used for PIP one day? -->\n        <ImageView\n            android:id=\"@+id/player_fullscreen\"\n            android:layout_width=\"30dp\"\n            android:layout_height=\"30dp\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginEnd=\"20dp\"\n            android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:src=\"@drawable/baseline_fullscreen_24\"\n            android:visibility=\"gone\"\n            app:tint=\"@color/white\" />\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:id=\"@+id/player_video_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:padding=\"16dp\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/skip_chapter_button\"\n                style=\"@style/NiceButton\"\n                android:layout_width=\"150dp\"\n                android:layout_height=\"40dp\"\n                android:layout_marginEnd=\"100dp\"\n                android:backgroundTint=\"@color/skipOpTransparent\"\n                android:maxLines=\"1\"\n                android:nextFocusLeft=\"@id/player_pause_play\"\n                android:nextFocusUp=\"@id/player_restart\"\n                android:nextFocusDown=\"@id/player_pause_play\"\n                android:padding=\"10dp\"\n                android:textColor=\"@color/white\"\n                android:visibility=\"gone\"\n                app:cornerRadius=\"@dimen/rounded_button_radius\"\n                app:layout_constraintBottom_toTopOf=\"@+id/bottom_player_bar\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:strokeColor=\"@color/white\"\n                app:strokeWidth=\"1dp\"\n                tools:text=\"Skip Opening\"\n                tools:visibility=\"visible\" />\n\n            <FrameLayout\n                android:id=\"@+id/player_top_holder\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\">\n\n                <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginStart=\"32dp\"\n                    android:layout_marginTop=\"20dp\"\n                    android:layout_marginEnd=\"32dp\"\n                    android:orientation=\"vertical\">\n\n                    <LinearLayout\n                        android:id=\"@+id/player_video_title_holder\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"end\">\n                        <TextView\n                            android:maxLines=\"2\"\n                            android:id=\"@+id/player_video_title\"\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_gravity=\"end\"\n                            android:gravity=\"end\"\n                            android:maxWidth=\"600dp\"\n                            android:textAlignment=\"viewEnd\"\n                            android:textColor=\"@color/white\"\n                            android:textSize=\"16sp\"\n                            android:textStyle=\"bold\"\n                            tools:text=\"Hello world\" />\n                        <ImageView\n                            android:id=\"@+id/offline_pin\"\n                            android:layout_width=\"18dp\"\n                            android:layout_height=\"18dp\"\n                            android:layout_marginStart=\"2dp\"\n                            android:src=\"@drawable/ic_offline_pin_24\"\n                            android:visibility=\"gone\"\n                            tools:visibility=\"visible\"\n                            android:layout_gravity=\"start\"/>\n                    </LinearLayout>\n\n                    <TextView\n                        android:id=\"@+id/player_video_title_rez\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"end\"\n                        android:gravity=\"end\"\n                        android:maxWidth=\"600dp\"\n                        android:textAlignment=\"viewEnd\"\n                        android:textColor=\"@color/white\"\n                        android:textSize=\"16sp\"\n                        tools:text=\"1920x1080\" />\n\n                    <TextView\n                        android:id=\"@+id/player_video_info\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginStart=\"6dp\"\n                        android:layout_marginBottom=\"2.5dp\"\n                        android:layout_gravity=\"end\"\n                        android:textColor=\"#B3FFFFFF\"\n                        android:textSize=\"16sp\"\n                        android:visibility=\"gone\"\n                        tools:text=\"HEVC • English • 5.1 • E-AC3\" />\n\n\n                    <FrameLayout\n                        android:id=\"@+id/player_episode_filler_holder\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"end\"\n                        android:layout_marginTop=\"2dp\">\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_episode_filler\"\n                            style=\"@style/SmallBlackButton\"\n                            android:text=\"@string/filler\" />\n                    </FrameLayout>\n                </LinearLayout>\n\n                <!-- Removed as it has no use anymore-->\n                <!--<androidx.mediarouter.app.MediaRouteButton\n                        android:id=\"@+id/player_media_route_button\"\n                        android:layout_width=\"70dp\"\n                        android:layout_height=\"70dp\"\n                        android:layout_gravity=\"end\"\n                        android:layout_margin=\"5dp\"\n                        android:mediaRouteTypes=\"user\"\n                        android:visibility=\"visible\"\n                        app:layout_constraintRight_toRightOf=\"parent\"\n                        app:layout_constraintTop_toTopOf=\"parent\" />-->\n\n                <LinearLayout\n                    android:id=\"@+id/player_go_back_holder\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginStart=\"17dp\"\n                    android:layout_marginEnd=\"17dp\"\n                    android:orientation=\"horizontal\"\n                    app:layout_constraintStart_toStartOf=\"parent\"\n                    app:layout_constraintTop_toTopOf=\"parent\">\n\n                    <LinearLayout\n                        android:id=\"@+id/player_go_back_root\"\n                        android:layout_width=\"60dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"20dp\"\n                        android:orientation=\"vertical\">\n\n                        <ImageView\n                            android:id=\"@+id/player_go_back\"\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_gravity=\"center\"\n                            android:background=\"@drawable/video_tap_button_always_white\"\n                            android:clickable=\"true\"\n                            android:contentDescription=\"@string/go_back_img_des\"\n                            android:focusable=\"true\"\n                            android:nextFocusLeft=\"@id/player_go_back\"\n                            android:nextFocusRight=\"@id/player_restart\"\n                            android:nextFocusUp=\"@id/player_go_back\"\n                            android:nextFocusDown=\"@id/player_pause_play\"\n                            android:src=\"@drawable/ic_baseline_arrow_back_24\"\n                            android:tag=\"@string/tv_no_focus_tag\"\n                            app:tint=\"@android:color/white\" />\n\n                        <TextView\n                            android:id=\"@+id/player_go_back_text\"\n                            style=\"@style/ResultMarqueeButtonText\"\n                            android:layout_marginTop=\"5dp\"\n                            android:text=\"@string/go_back_img_des\"\n                            android:visibility=\"invisible\"\n                            tools:visibility=\"visible\" />\n\n                    </LinearLayout>\n\n                    <LinearLayout\n                        android:id=\"@+id/player_restart_root\"\n                        android:layout_width=\"60dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"20dp\"\n                        android:orientation=\"vertical\">\n\n                        <ImageView\n                            android:id=\"@+id/player_restart\"\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_gravity=\"center\"\n                            android:background=\"@drawable/video_tap_button_always_white\"\n                            android:clickable=\"true\"\n                            android:contentDescription=\"@string/restart\"\n                            android:focusable=\"true\"\n                            android:nextFocusLeft=\"@id/player_go_back\"\n                            android:nextFocusRight=\"@id/player_go_forward\"\n                            android:nextFocusUp=\"@id/player_restart\"\n                            android:nextFocusDown=\"@id/player_pause_play\"\n                            android:src=\"@drawable/ic_baseline_replay_24\"\n                            android:tag=\"@string/tv_no_focus_tag\"\n                            app:tint=\"@android:color/white\" />\n\n                        <TextView\n                            android:id=\"@+id/player_restart_text\"\n                            style=\"@style/ResultMarqueeButtonText\"\n                            android:layout_marginTop=\"5dp\"\n                            android:text=\"@string/restart\"\n                            android:visibility=\"invisible\"\n                            tools:visibility=\"visible\" />\n\n                    </LinearLayout>\n\n                    <LinearLayout\n                        android:id=\"@+id/player_go_forward_root\"\n                        android:layout_width=\"60dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"20dp\"\n                        android:orientation=\"vertical\">\n\n                        <ImageView\n                            android:id=\"@+id/player_go_forward\"\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_gravity=\"center\"\n                            android:background=\"@drawable/video_tap_button_always_white\"\n                            android:clickable=\"true\"\n                            android:contentDescription=\"@string/next_episode\"\n                            android:focusable=\"true\"\n                            android:nextFocusLeft=\"@id/player_restart\"\n                            android:nextFocusRight=\"@id/download_header_toggle\"\n                            android:nextFocusUp=\"@id/player_go_forward\"\n                            android:nextFocusDown=\"@id/player_pause_play\"\n                            android:src=\"@drawable/ic_baseline_skip_next_rounded_24\"\n                            android:tag=\"@string/tv_no_focus_tag\"\n                            app:tint=\"@android:color/white\" />\n\n                        <TextView\n                            android:id=\"@+id/player_go_forward_text\"\n                            style=\"@style/ResultMarqueeButtonText\"\n                            android:layout_marginTop=\"5dp\"\n                            android:text=\"@string/next_episode\"\n                            android:visibility=\"invisible\"\n                            tools:visibility=\"visible\" />\n\n                    </LinearLayout>\n\n                    <LinearLayout\n                        android:id=\"@+id/download_both_header\"\n                        android:layout_width=\"60dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"20dp\"\n                        android:layout_marginEnd=\"10dp\"\n                        android:orientation=\"vertical\">\n\n                        <ImageView\n                            android:id=\"@+id/download_header_toggle\"\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_gravity=\"center\"\n                            android:background=\"@drawable/video_tap_button_always_white\"\n                            android:clickable=\"true\"\n                            android:contentDescription=\"@string/torrent_singular\"\n                            android:focusable=\"true\"\n                            android:nextFocusLeft=\"@id/player_go_forward\"\n                            android:nextFocusRight=\"@id/player_episodes_button\"\n                            android:nextFocusUp=\"@id/download_header_toggle\"\n                            android:nextFocusDown=\"@id/player_pause_play\"\n                            android:src=\"@drawable/baseline_downloading_24\"\n                            android:tag=\"@string/tv_no_focus_tag\"\n                            app:tint=\"@android:color/white\" />\n\n                        <TextView\n                            android:id=\"@+id/download_header_toggle_text\"\n                            style=\"@style/ResultMarqueeButtonText\"\n                            android:layout_marginTop=\"5dp\"\n                            android:text=\"@string/torrent_singular\"\n                            android:visibility=\"invisible\"\n                            tools:visibility=\"visible\" />\n\n                    </LinearLayout>\n                    <LinearLayout\n                        android:id=\"@+id/player_episodes_button_root\"\n                        android:layout_width=\"60dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginTop=\"20dp\"\n                        android:orientation=\"vertical\">\n\n                        <ImageView\n                            android:id=\"@+id/player_episodes_button\"\n                            android:layout_width=\"30dp\"\n                            android:layout_height=\"30dp\"\n                            android:layout_gravity=\"center\"\n                            android:background=\"@drawable/video_tap_button_always_white\"\n                            android:clickable=\"true\"\n                            android:contentDescription=\"@string/episodes\"\n                            android:focusable=\"true\"\n                            android:nextFocusLeft=\"@id/download_header_toggle\"\n                            android:nextFocusRight=\"@id/player_episode_overlay\"\n                            android:nextFocusUp=\"@id/player_episodes_button\"\n                            android:nextFocusDown=\"@id/player_pause_play\"\n                            android:src=\"@drawable/ic_baseline_sort_24\"\n                            android:tag=\"@string/tv_no_focus_tag\"\n                            app:tint=\"@android:color/white\" />\n\n                        <TextView\n                            android:id=\"@+id/player_episodes_button_text\"\n                            style=\"@style/ResultMarqueeButtonText\"\n                            android:layout_marginTop=\"5dp\"\n                            android:text=\"@string/episodes\"\n                            android:visibility=\"invisible\"\n                            tools:visibility=\"visible\" />\n\n                    </LinearLayout>\n\n                    <androidx.cardview.widget.CardView\n                        android:id=\"@+id/download_header\"\n                        android:layout_width=\"200dp\"\n                        android:layout_height=\"70dp\"\n                        android:layout_gravity=\"end|center_vertical\"\n                        android:layout_marginTop=\"5dp\"\n                        android:elevation=\"10dp\"\n                        app:cardBackgroundColor=\"@color/darkBar\"\n                        app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n                        <LinearLayout\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"match_parent\"\n                            android:layout_margin=\"10dp\"\n                            android:gravity=\"end|center_vertical\"\n                            android:orientation=\"vertical\">\n\n                            <TextView\n                                android:id=\"@+id/downloaded_progress_text\"\n                                android:layout_width=\"wrap_content\"\n                                android:layout_height=\"wrap_content\"\n                                android:textColor=\"@color/white\"\n                                tools:text=\"10MB / 20MB\" />\n\n                            <TextView\n                                android:id=\"@+id/downloaded_progress_speed_text\"\n                                android:layout_width=\"wrap_content\"\n                                android:layout_height=\"wrap_content\"\n                                android:textColor=\"@color/white\"\n                                tools:text=\"10MB/s - 12 seeders\" />\n\n                            <com.google.android.material.progressindicator.LinearProgressIndicator\n                                android:id=\"@+id/downloaded_progress\"\n                                style=\"@style/RoundProgressbar\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"wrap_content\"\n                                android:layout_marginTop=\"5dp\"\n                                android:indeterminate=\"false\"\n                                android:indeterminateTint=\"?attr/colorPrimary\"\n                                android:progressBackgroundTint=\"?attr/colorPrimary\"\n                                android:progressTint=\"?attr/colorPrimary\"\n                                tools:progress=\"20\" />\n\n                        </LinearLayout>\n                    </androidx.cardview.widget.CardView>\n\n                </LinearLayout>\n            </FrameLayout>\n\n\n            <androidx.constraintlayout.widget.ConstraintLayout\n                android:id=\"@+id/player_center_menu\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"100dp\"\n                android:layout_gravity=\"center\"\n                android:gravity=\"center\"\n                android:layoutDirection=\"ltr\"\n                android:orientation=\"horizontal\"\n                android:visibility=\"gone\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toLeftOf=\"parent\"\n                app:layout_constraintRight_toRightOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                tools:visibility=\"visible\">\n\n                <FrameLayout\n                    android:id=\"@+id/player_rew_holder\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical|start\"\n                    android:visibility=\"gone\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:layout_constraintLeft_toLeftOf=\"parent\"\n                    app:layout_constraintRight_toLeftOf=\"@id/player_ffwd_holder\"\n                    app:layout_constraintTop_toTopOf=\"parent\"\n                    app:layout_constraintWidth_percent=\"0.5\">\n\n                    <TextView\n                        android:id=\"@+id/exo_rew_text\"\n                        android:layout_width=\"200dp\"\n                        android:layout_height=\"40dp\"\n                        android:layout_gravity=\"center\"\n\n                        android:gravity=\"center\"\n                        android:textColor=\"@color/white\"\n                        android:textSize=\"19sp\"\n\n                        android:textStyle=\"bold\"\n                        tools:text=\"10\" />\n\n                    <ImageButton\n                        android:id=\"@id/player_rew\"\n                        android:layout_width=\"70dp\"\n                        android:layout_height=\"70dp\"\n                        android:layout_gravity=\"center\"\n\n                        android:background=\"@drawable/video_tap_button_skip\"\n                        android:nextFocusLeft=\"@id/player_rew\"\n                        android:nextFocusUp=\"@id/player_go_back\"\n                        android:nextFocusDown=\"@id/player_pause_play\"\n                        android:padding=\"10dp\"\n                        android:scaleType=\"fitCenter\"\n                        android:scaleX=\"-1\"\n                        android:src=\"@drawable/netflix_skip_forward\"\n                        android:tintMode=\"src_in\"\n                        app:tint=\"@color/white\"\n                        tools:ignore=\"ContentDescription\" />\n                </FrameLayout>\n\n                <FrameLayout\n                    android:id=\"@+id/player_ffwd_holder\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical|end\"\n                    android:visibility=\"gone\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:layout_constraintLeft_toRightOf=\"@id/player_rew_holder\"\n                    app:layout_constraintRight_toRightOf=\"parent\"\n                    app:layout_constraintTop_toTopOf=\"parent\"\n                    app:layout_constraintWidth_percent=\"0.5\">\n\n                    <TextView\n                        android:id=\"@+id/exo_ffwd_text\"\n                        android:layout_width=\"200dp\"\n                        android:layout_height=\"40dp\"\n                        android:layout_gravity=\"center\"\n                        android:gravity=\"center\"\n                        android:textColor=\"@color/white\"\n                        android:textSize=\"19sp\"\n                        android:textStyle=\"bold\"\n                        tools:text=\"10\" />\n\n                    <ImageButton\n                        android:id=\"@id/player_ffwd\"\n                        android:layout_width=\"70dp\"\n                        android:layout_height=\"70dp\"\n                        android:layout_gravity=\"center\"\n\n                        android:background=\"@drawable/video_tap_button_skip\"\n                        android:nextFocusRight=\"@id/player_rew\"\n                        android:nextFocusUp=\"@id/player_go_back\"\n                        android:nextFocusDown=\"@id/player_pause_play\"\n                        android:padding=\"10dp\"\n                        android:scaleType=\"fitCenter\"\n                        android:src=\"@drawable/netflix_skip_forward\"\n                        android:tintMode=\"src_in\"\n                        app:tint=\"@color/white\"\n                        tools:ignore=\"ContentDescription\" />\n                </FrameLayout>\n            </androidx.constraintlayout.widget.ConstraintLayout>\n\n            <!--use for thinner app:trackThickness=\"3dp\" com.google.android.material.progressindicator.CircularProgressIndicator-->\n            <ProgressBar\n                android:id=\"@+id/player_buffering\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n\n                android:clickable=\"false\"\n                android:focusable=\"false\"\n                android:focusableInTouchMode=\"false\"\n\n                android:indeterminate=\"true\"\n                android:visibility=\"gone\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toLeftOf=\"parent\"\n                app:layout_constraintRight_toRightOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                tools:visibility=\"visible\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"bottom\"\n                android:layout_marginBottom=\"20dp\"\n                android:gravity=\"center\"\n                android:orientation=\"horizontal\"\n                android:paddingTop=\"4dp\"\n                android:visibility=\"gone\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\">\n\n                <ImageButton\n                    android:id=\"@id/exo_prev\"\n                    style=\"@style/ExoMediaButton.Previous\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n\n                <ImageButton\n                    android:id=\"@id/exo_repeat_toggle\"\n                    style=\"@style/ExoMediaButton\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n\n                <ImageButton\n                    android:id=\"@id/exo_next\"\n                    style=\"@style/ExoMediaButton.Next\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <ImageButton\n                    android:id=\"@id/exo_vr\"\n                    style=\"@style/ExoMediaButton.VR\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <ImageButton\n                    android:id=\"@id/exo_play\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"0dp\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <ImageButton\n                    android:id=\"@id/exo_pause\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"0dp\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"?attr/colorPrimaryDark\"\n                    tools:ignore=\"ContentDescription\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:id=\"@+id/bottom_player_bar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"64dp\"\n                android:layout_marginEnd=\"64dp\"\n                android:layout_marginBottom=\"10dp\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"vertical\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintStart_toStartOf=\"parent\">\n\n                <androidx.constraintlayout.widget.ConstraintLayout\n                    android:id=\"@+id/player_video_bar\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layoutDirection=\"ltr\"\n                    android:orientation=\"horizontal\">\n\n                    <ImageView\n                        android:id=\"@+id/player_pause_play\"\n\n                        android:layout_width=\"30dp\"\n                        android:layout_height=\"30dp\"\n                        android:layout_gravity=\"center\"\n                        android:layout_marginStart=\"20dp\"\n                        android:background=\"@drawable/video_tap_button\"\n                        android:focusable=\"true\"\n                        android:focusableInTouchMode=\"true\"\n                        android:nextFocusUp=\"@id/skip_chapter_button\"\n                        android:nextFocusDown=\"@id/player_lock_holder\"\n                        android:src=\"@drawable/netflix_pause\"\n\n                        android:tag=\"@string/tv_no_focus_tag\"\n                        app:layout_constraintBottom_toBottomOf=\"parent\"\n                        app:layout_constraintStart_toStartOf=\"parent\"\n                        app:tint=\"@color/player_button_tv\"\n                        tools:ignore=\"ContentDescription\" />\n\n                    <TextView\n                        android:id=\"@id/exo_position\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"30dp\"\n                        android:gravity=\"center\"\n                        android:includeFontPadding=\"false\"\n                        android:minWidth=\"50dp\"\n                        android:textColor=\"@android:color/white\"\n                        android:textSize=\"14sp\"\n                        android:textStyle=\"normal\"\n                        app:layout_constraintBottom_toBottomOf=\"parent\"\n                        app:layout_constraintStart_toEndOf=\"@id/player_pause_play\"\n                        tools:text=\"15:30\" />\n\n                    <FrameLayout\n                        android:id=\"@+id/previewFrameLayout\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"0dp\"\n                        android:layout_marginStart=\"16dp\"\n                        android:layout_marginEnd=\"16dp\"\n                        android:layout_marginBottom=\"16dp\"\n                        android:background=\"@drawable/video_frame\"\n                        android:visibility=\"invisible\"\n                        app:layout_constraintBottom_toTopOf=\"@+id/exo_progress\"\n                        app:layout_constraintDimensionRatio=\"16:9\"\n                        app:layout_constraintEnd_toEndOf=\"parent\"\n                        app:layout_constraintHorizontal_bias=\"0.0\"\n                        app:layout_constraintStart_toStartOf=\"parent\"\n                        app:layout_constraintWidth_default=\"percent\"\n                        app:layout_constraintWidth_percent=\"0.25\"\n                        tools:visibility=\"visible\">\n\n                        <ImageView\n                            android:id=\"@+id/previewImageView\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"match_parent\"\n                            android:layout_margin=\"@dimen/video_frame_width\"\n                            android:importantForAccessibility=\"no\"\n                            android:scaleType=\"centerCrop\" />\n                    </FrameLayout>\n\n                    <com.github.rubensousa.previewseekbar.media3.PreviewTimeBar\n                        android:id=\"@id/exo_progress\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"30dp\"\n                        android:layout_weight=\"1\"\n                        app:bar_height=\"2dp\"\n                        app:layout_constraintBottom_toBottomOf=\"@id/exo_position\"\n                        app:layout_constraintEnd_toStartOf=\"@id/exo_duration\"\n                        app:layout_constraintStart_toEndOf=\"@+id/exo_position\"\n                        app:played_color=\"?attr/colorPrimary\"\n\n                        app:scrubber_color=\"?attr/colorPrimary\"\n                        app:scrubber_dragged_size=\"26dp\"\n                        app:scrubber_enabled_size=\"24dp\"\n                        app:unplayed_color=\"@color/videoProgress\" />\n\n                    <TextView\n                        android:id=\"@id/exo_duration\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"30dp\"\n                        android:layout_gravity=\"center|center_vertical\"\n\n                        android:layout_marginEnd=\"20dp\"\n                        android:includeFontPadding=\"false\"\n                        android:minWidth=\"50dp\"\n                        android:paddingLeft=\"4dp\"\n                        android:paddingRight=\"4dp\"\n                        android:textColor=\"@android:color/white\"\n                        android:textSize=\"14sp\"\n                        android:textStyle=\"normal\"\n                        app:layout_constraintBaseline_toBaselineOf=\"@id/exo_position\"\n                        app:layout_constraintEnd_toEndOf=\"parent\"\n                        tools:text=\"23:20\" />\n\n                    <TextView\n                        android:id=\"@+id/time_left\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"30dp\"\n                        android:layout_gravity=\"center|center_vertical\"\n\n                        android:layout_marginEnd=\"20dp\"\n                        android:includeFontPadding=\"false\"\n                        android:minWidth=\"50dp\"\n                        android:paddingLeft=\"4dp\"\n                        android:paddingRight=\"4dp\"\n                        android:textColor=\"@android:color/white\"\n                        android:textSize=\"14sp\"\n                        android:textStyle=\"normal\"\n                        android:visibility=\"gone\"\n                        app:layout_constraintBaseline_toBaselineOf=\"@id/exo_position\"\n                        app:layout_constraintEnd_toEndOf=\"parent\"\n                        tools:text=\"-23:20\" />\n                </androidx.constraintlayout.widget.ConstraintLayout>\n\n\n                <HorizontalScrollView\n                    android:id=\"@+id/player_controls_scroll\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center\">\n\n                    <LinearLayout\n                        android:id=\"@+id/player_lock_holder\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\"\n                        android:orientation=\"horizontal\">\n\n                        <FrameLayout\n                            android:layout_width=\"0dp\"\n                            android:layout_height=\"0dp\"\n                            android:visibility=\"gone\">\n\n                            <com.google.android.material.button.MaterialButton\n                                android:id=\"@+id/player_lock\"\n                                style=\"@style/VideoButtonTV\"\n                                android:nextFocusLeft=\"@id/player_skip_episode\"\n\n                                android:nextFocusRight=\"@id/player_resize_btt\"\n                                android:nextFocusUp=\"@id/player_pause_play\"\n                                android:text=\"@string/video_lock\"\n                                android:visibility=\"gone\"\n                                app:icon=\"@drawable/video_locked\" />\n                        </FrameLayout>\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_rotate_btt\"\n                            style=\"@style/VideoButton\"\n                            android:visibility=\"gone\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_skip_op\"\n                            style=\"@style/VideoButtonTV\"\n                            android:nextFocusLeft=\"@id/player_pause_play\"\n                            android:nextFocusRight=\"@id/player_skip_episode\"\n                            android:nextFocusUp=\"@id/player_pause_play\"\n                            android:nextFocusDown=\"@id/player_skip_episode\"\n                            android:text=\"@string/video_skip_op\"\n                            app:icon=\"@drawable/ic_baseline_fast_forward_24\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_skip_episode\"\n                            style=\"@style/VideoButtonTV\"\n                            android:nextFocusLeft=\"@id/player_skip_op\"\n                            android:nextFocusRight=\"@id/player_resize_btt\"\n                            android:nextFocusUp=\"@id/player_pause_play\"\n                            android:nextFocusDown=\"@id/player_resize_btt\"\n                            android:text=\"@string/next_episode\"\n                            android:visibility=\"gone\"\n                            app:icon=\"@drawable/ic_baseline_skip_next_24\"\n                            tools:visibility=\"visible\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_resize_btt\"\n                            style=\"@style/VideoButtonTV\"\n                            android:nextFocusLeft=\"@id/player_skip_episode\"\n\n                            android:nextFocusRight=\"@id/player_speed_btt\"\n                            android:nextFocusUp=\"@id/player_pause_play\"\n                            android:nextFocusDown=\"@id/player_speed_btt\"\n                            android:text=\"@string/video_aspect_ratio_resize\"\n                            app:icon=\"@drawable/ic_baseline_aspect_ratio_24\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_speed_btt\"\n                            style=\"@style/VideoButtonTV\"\n                            android:nextFocusLeft=\"@id/player_resize_btt\"\n\n                            android:nextFocusRight=\"@id/player_subtitle_offset_btt\"\n                            android:nextFocusUp=\"@id/player_pause_play\"\n                            android:nextFocusDown=\"@id/player_subtitle_offset_btt\"\n                            app:icon=\"@drawable/ic_baseline_speed_24\"\n                            tools:text=\"Speed\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_subtitle_offset_btt\"\n                            style=\"@style/VideoButtonTV\"\n                            android:nextFocusLeft=\"@id/player_speed_btt\"\n                            android:nextFocusRight=\"@id/player_sources_btt\"\n                            android:nextFocusUp=\"@id/player_pause_play\"\n                            android:nextFocusDown=\"@id/player_sources_btt\"\n                            android:text=\"@string/subtitle_offset\"\n\n                            android:visibility=\"gone\"\n                            app:icon=\"@drawable/ic_outline_subtitles_24\"\n                            tools:visibility=\"visible\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_sources_btt\"\n                            style=\"@style/VideoButtonTV\"\n                            android:nextFocusLeft=\"@id/player_subtitle_offset_btt\"\n                            android:nextFocusRight=\"@id/player_tracks_btt\"\n                            android:nextFocusUp=\"@id/player_pause_play\"\n                            android:nextFocusDown=\"@id/player_tracks_btt\"\n\n                            android:text=\"@string/video_source\"\n                            app:icon=\"@drawable/ic_baseline_playlist_play_24\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_tracks_btt\"\n                            style=\"@style/VideoButtonTV\"\n                            android:nextFocusLeft=\"@id/player_sources_btt\"\n                            android:nextFocusRight=\"@id/player_skip_op\"\n                            android:nextFocusUp=\"@id/player_pause_play\"\n                            android:text=\"@string/tracks\"\n                            app:icon=\"@drawable/ic_baseline_equalizer_24\" />\n                    </LinearLayout>\n                </HorizontalScrollView>\n            </LinearLayout>\n        </androidx.constraintlayout.widget.ConstraintLayout>\n    </FrameLayout>\n\n    <FrameLayout\n        android:id=\"@+id/subtitle_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    </FrameLayout>\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/player_speedup_button\"\n        style=\"@style/Widget.MaterialComponents.Button.OutlinedButton\"\n        android:layout_width=\"45dp\"\n        android:layout_height=\"45dp\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginTop=\"70dp\"\n        app:iconGravity=\"top\"\n        android:clickable=\"false\"\n        android:textAllCaps=\"false\"\n        android:visibility=\"gone\"\n        app:icon=\"@drawable/speedup\"\n        app:iconTint=\"@color/textColor\"\n        app:rippleColor=\"?attr/colorPrimary\"\n        tools:visibility=\"visible\" />\n\n\n    <LinearLayout\n        android:id=\"@+id/player_episode_overlay\"\n        android:visibility=\"gone\"\n        android:padding=\"5dp\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:orientation=\"vertical\"\n        android:layout_gravity=\"end\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\">\n\n        <TextView\n            android:id=\"@+id/player_episode_overlay_title\"\n            android:padding=\"10dp\"\n            style=\"@style/WatchHeaderText\"\n            android:textSize=\"15sp\"\n            android:layout_marginEnd=\"0dp\"\n            android:text=\"@string/episodes\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"/>\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:requiresFadingEdge=\"vertical\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            android:id=\"@+id/player_episode_list\"\n            tools:listitem=\"@layout/player_episodes\"\n            android:nextFocusLeft=\"@id/player_episodes_button\"\n            android:layout_width=\"400dp\"\n            android:layout_height=\"match_parent\"\n            android:clipToPadding=\"false\"\n            android:descendantFocusability=\"afterDescendants\">\n\n        </androidx.recyclerview.widget.RecyclerView>\n    </LinearLayout>\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/player_prioritize_item.xml",
    "content": "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingHorizontal=\"15dp\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\">\n\n    <TextView\n        android:id=\"@+id/priority_text\"\n        style=\"@style/NoCheckLabel\"\n        android:layout_width=\"wrap_content\"\n        android:layout_alignParentStart=\"true\"\n        android:layout_toStartOf=\"@+id/subtract_button\"\n        tools:text=\"hello\" />\n\n    <ImageView\n        android:id=\"@+id/subtract_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:layout_toStartOf=\"@id/priority_number\"\n        android:background=\"?attr/selectableItemBackgroundBorderless\"\n        android:padding=\"10dp\"\n        android:focusable=\"true\"\n        android:src=\"@drawable/baseline_remove_24\" />\n\n    <TextView\n        android:id=\"@+id/priority_number\"\n        style=\"@style/NoCheckLabel\"\n        android:layout_width=\"wrap_content\"\n        android:layout_centerVertical=\"true\"\n        android:layout_toStartOf=\"@id/add_button\"\n        android:gravity=\"center\"\n        android:minWidth=\"50dp\"\n        android:textColor=\"?attr/textColor\"\n        tools:text=\"1\" />\n\n    <ImageView\n        android:id=\"@+id/add_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentEnd=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:background=\"?attr/selectableItemBackgroundBorderless\"\n        android:padding=\"10dp\"\n        android:focusable=\"true\"\n        android:src=\"@drawable/ic_baseline_add_24\" />\n\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/player_quality_profile_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:id=\"@+id/profile_text_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentTop=\"true\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_rowWeight=\"1\"\n            android:layout_marginTop=\"10dp\"\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingTop=\"10dp\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:paddingBottom=\"10dp\"\n            android:text=\"@string/source_priority\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\" />\n\n        <TextView\n            android:id=\"@+id/currently_selected_profile_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_rowWeight=\"1\"\n            android:layout_marginTop=\"10dp\"\n            android:paddingTop=\"10dp\"\n            android:paddingBottom=\"10dp\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"15sp\"\n            tools:text=\"Profile 1\" />\n    </LinearLayout>\n\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/profiles_recyclerview\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_above=\"@+id/profile_button_bar\"\n        android:layout_below=\"@+id/profile_text_bar\"\n        android:orientation=\"horizontal\"\n        app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n        tools:itemCount=\"4\"\n        tools:listitem=\"@layout/player_quality_profile_item\" />\n\n    <LinearLayout\n        android:id=\"@+id/profile_button_bar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_alignParentBottom=\"true\"\n        android:layout_margin=\"10dp\"\n        android:animateLayoutChanges=\"true\"\n        android:gravity=\"end|bottom\"\n        android:orientation=\"horizontal\">\n\n        <LinearLayout\n            android:id=\"@+id/selected_item_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:alpha=\"0.5\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/edit_btt\"\n                style=\"@style/WhiteButton\"\n                android:layout_width=\"wrap_content\"\n                android:text=\"@string/edit\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/set_default_btt\"\n                style=\"@style/WhiteButton\"\n                android:layout_width=\"wrap_content\"\n                android:text=\"@string/set_default\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"end\">\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/use_btt\"\n                    style=\"@style/WhiteButton\"\n                    android:layout_width=\"wrap_content\"\n                    android:text=\"@string/use\" />\n            </LinearLayout>\n        </LinearLayout>\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:text=\"@string/sort_apply\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:text=\"@string/sort_cancel\" />\n    </LinearLayout>\n\n\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/layout/player_quality_profile_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"match_parent\"\n    android:focusable=\"false\">\n\n    <androidx.cardview.widget.CardView\n        android:id=\"@+id/card_view\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"0dp\"\n        android:layout_marginStart=\"5dp\"\n        android:layout_marginEnd=\"5dp\"\n        android:animateLayoutChanges=\"true\"\n        android:backgroundTint=\"@color/primaryGrayBackground\"\n        android:focusable=\"true\"\n        android:foreground=\"?attr/selectableItemBackgroundBorderless\"\n        android:maxWidth=\"220dp\"\n        android:maxHeight=\"220dp\"\n        app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintDimensionRatio=\"1\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintHeight_percent=\"0.4\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\">\n\n        <ImageView\n            android:id=\"@+id/profile_image_background\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:alpha=\"0.4\"\n            android:contentDescription=\"@string/profile_background_des\"\n            android:scaleType=\"centerCrop\"\n            tools:src=\"@drawable/profile_bg_teal\" />\n\n        <View\n            android:id=\"@+id/outline\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@drawable/outline_card\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\" />\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/text_is_wifi\"\n                style=\"@style/DubButton\"\n                android:layout_height=\"0dp\"\n                android:layout_gravity=\"end\"\n                android:layout_margin=\"2dp\"\n                android:autoSizeMaxTextSize=\"20sp\"\n                android:autoSizeTextType=\"uniform\"\n                android:minHeight=\"30dp\"\n                android:text=\"@string/wifi\"\n                android:textColor=\"@color/textColor\"\n                android:textStyle=\"normal\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintHeight_percent=\"0.2\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\" />\n\n            <TextView\n                android:id=\"@+id/text_is_mobile_data\"\n                style=\"@style/DubButton\"\n                android:layout_height=\"0dp\"\n                android:layout_gravity=\"end\"\n                android:layout_margin=\"2dp\"\n                android:autoSizeMaxTextSize=\"20sp\"\n                android:autoSizeTextType=\"uniform\"\n                android:minHeight=\"30dp\"\n                android:text=\"@string/mobile_data\"\n                android:textColor=\"@color/textColor\"\n                android:textStyle=\"normal\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintHeight_percent=\"0.2\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                app:layout_constraintTop_toBottomOf=\"@id/text_is_wifi\" />\n\n            <TextView\n                android:id=\"@+id/text_is_download_data\"\n                style=\"@style/DubButton\"\n                android:layout_height=\"0dp\"\n                android:layout_gravity=\"end\"\n                android:layout_margin=\"2dp\"\n                android:autoSizeMaxTextSize=\"20sp\"\n                android:autoSizeTextType=\"uniform\"\n                android:minHeight=\"30dp\"\n                android:text=\"@string/download\"\n                android:textColor=\"@color/textColor\"\n                android:textStyle=\"normal\"\n                app:layout_constraintEnd_toEndOf=\"parent\"\n                app:layout_constraintHeight_percent=\"0.2\"\n                app:layout_constraintStart_toStartOf=\"parent\"\n                app:layout_constraintTop_toBottomOf=\"@id/text_is_mobile_data\" />\n        </androidx.constraintlayout.widget.ConstraintLayout>\n\n\n    </androidx.cardview.widget.CardView>\n\n    <TextView\n        android:id=\"@+id/profile_text\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center\"\n        android:ellipsize=\"end\"\n        android:gravity=\"center\"\n        android:lines=\"2\"\n        android:padding=\"10dp\"\n        android:textColor=\"@color/textColor\"\n        android:textSize=\"16sp\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toBottomOf=\"@+id/card_view\"\n        tools:text=\"@string/mobile_data\" />\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/player_select_source_and_subs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginBottom=\"60dp\"\n        android:baselineAligned=\"false\"\n        android:orientation=\"horizontal\">\n\n        <LinearLayout\n            android:id=\"@+id/sort_sources_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"50\"\n            android:orientation=\"vertical\">\n\n            <LinearLayout\n                android:id=\"@+id/profiles_click_settings\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_rowWeight=\"1\"\n                android:layout_marginTop=\"10dp\"\n                android:focusable=\"true\"\n                android:foreground=\"@drawable/outline_drawable_forced\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n                    android:paddingTop=\"10dp\"\n                    android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                    android:paddingBottom=\"10dp\"\n                    android:text=\"@string/pick_source\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"20sp\"\n                    android:textStyle=\"bold\" />\n\n                <TextView\n                    android:id=\"@+id/source_settings_btt\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"center\"\n                    android:drawablePadding=\"10dp\"\n                    android:gravity=\"center\"\n                    android:minWidth=\"140dp\"\n                    android:paddingHorizontal=\"10dp\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"15sp\"\n                    app:drawableEndCompat=\"@drawable/ic_outline_settings_24\"\n                    tools:text=\"@string/profile_number\" />\n            </LinearLayout>\n\n            <ListView\n                android:id=\"@+id/sort_providers\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_rowWeight=\"1\"\n                android:background=\"?attr/primaryBlackBackground\"\n                android:listSelector=\"@drawable/outline_drawable_forced\"\n                android:nextFocusRight=\"@id/sort_subtitles\"\n                android:nextFocusUp=\"@id/profiles_click_settings\"\n                android:nextFocusDown=\"@id/apply_btt\"\n                android:requiresFadingEdge=\"vertical\"\n                tools:layout_height=\"100dp\"\n                tools:listitem=\"@layout/sort_bottom_single_choice\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/sort_subtitles_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"50\"\n            android:orientation=\"vertical\">\n\n            <!--   android:id=\"@+id/subs_settings\"                 android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n-->\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                tools:ignore=\"UseCompoundDrawables\">\n\n                <RelativeLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_marginTop=\"10dp\"\n                    android:orientation=\"horizontal\">\n\n                    <TextView\n                        android:id=\"@+id/subtitles_text\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_alignParentStart=\"true\"\n                        android:paddingVertical=\"10dp\"\n                        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n                        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                        android:text=\"@string/pick_subtitle\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"20sp\"\n                        android:textStyle=\"bold\" />\n\n                    <TextView\n                        android:id=\"@+id/subtitles_encoding_format\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_gravity=\"center\"\n                        android:layout_toStartOf=\"@+id/subtitle_settings_btt\"\n                        android:layout_toEndOf=\"@id/subtitles_text\"\n                        android:focusable=\"true\"\n                        android:foreground=\"@drawable/outline_drawable_forced\"\n                        android:gravity=\"start\"\n                        android:maxLines=\"1\"\n                        android:paddingHorizontal=\"10dp\"\n                        android:paddingVertical=\"10dp\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"15sp\"\n                        tools:text=\"Thai (TIS 620-2533/ISO 8859-11)\" />\n\n                    <ImageView\n                        android:id=\"@+id/subtitle_settings_btt\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"44dp\"\n                        android:layout_alignParentEnd=\"true\"\n                        android:layout_centerVertical=\"true\"\n                        android:layout_gravity=\"center\"\n                        android:contentDescription=\"@string/subtitles_settings\"\n                        android:foreground=\"@drawable/outline_drawable_forced\"\n                        android:paddingHorizontal=\"10dp\"\n                        android:paddingVertical=\"10dp\"\n                        android:src=\"@drawable/ic_outline_settings_24\" />\n                </RelativeLayout>\n\n                <ImageView\n                    android:layout_width=\"25dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginTop=\"0dp\"\n                    android:layout_marginEnd=\"10dp\"\n                    android:contentDescription=\"@string/home_change_provider_img_des\"\n                    android:src=\"@drawable/ic_outline_settings_24\"\n                    android:visibility=\"gone\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:baselineAligned=\"false\"\n                android:orientation=\"horizontal\">\n\n                <ListView\n                    android:id=\"@+id/sort_subtitles\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_rowWeight=\"1\"\n                    android:layout_weight=\"1\"\n                    android:background=\"?attr/primaryBlackBackground\"\n                    android:listSelector=\"@drawable/outline_drawable_forced\"\n                    android:nextFocusLeft=\"@id/sort_providers\"\n                    android:nextFocusRight=\"@id/sort_subtitles_options\"\n                    android:nextFocusUp=\"@id/subtitles_click_settings\"\n                    android:nextFocusDown=\"@id/apply_btt\"\n                    android:requiresFadingEdge=\"vertical\"\n                    tools:layout_height=\"200dp\"\n                    tools:listfooter=\"@layout/sort_bottom_footer_add_choice\"\n                    tools:listitem=\"@layout/sort_bottom_single_choice\" />\n\n                <ListView\n                    android:id=\"@+id/sort_subtitles_options\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_rowWeight=\"1\"\n                    android:layout_weight=\"1\"\n                    android:background=\"?attr/primaryBlackBackground\"\n                    android:listSelector=\"@drawable/outline_drawable_forced\"\n                    android:nextFocusLeft=\"@id/sort_subtitles\"\n                    android:nextFocusRight=\"@id/apply_btt\"\n                    android:nextFocusUp=\"@id/subtitle_settings_btt\"\n                    android:nextFocusDown=\"@id/apply_btt\"\n                    android:requiresFadingEdge=\"vertical\"\n                    tools:layout_height=\"200dp\"\n                    tools:listfooter=\"@layout/sort_bottom_footer_add_choice\"\n                    tools:listitem=\"@layout/sort_bottom_single_choice\" />\n            </LinearLayout>\n\n\n        </LinearLayout>\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_apply\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_cancel\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/player_select_source_priority.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@null\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginBottom=\"60dp\"\n        android:baselineAligned=\"false\"\n        android:orientation=\"horizontal\">\n\n        <LinearLayout\n            android:id=\"@+id/sort_sources_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"50\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_rowWeight=\"1\"\n                android:layout_marginTop=\"10dp\"\n                android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n                android:paddingTop=\"10dp\"\n                android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                android:paddingBottom=\"10dp\"\n                android:text=\"@string/pick_source\"\n                android:textColor=\"?attr/textColor\"\n                android:textSize=\"20sp\"\n                android:textStyle=\"bold\" />\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/sort_sources\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_rowWeight=\"1\"\n                android:background=\"?attr/primaryBlackBackground\"\n                android:listSelector=\"@drawable/outline_drawable_less\"\n                android:nextFocusRight=\"@id/sort_subtitles\"\n                android:nextFocusDown=\"@id/profile_text_editable\"\n                android:requiresFadingEdge=\"vertical\"\n                app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                tools:layout_height=\"100dp\"\n                tools:listitem=\"@layout/player_prioritize_item\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/sort_subtitles_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"50\"\n            android:orientation=\"vertical\">\n\n            <!--   android:id=\"@+id/subs_settings\"                 android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n-->\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                tools:ignore=\"UseCompoundDrawables\">\n\n                <LinearLayout\n                    android:id=\"@+id/subtitles_click_settings\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_rowWeight=\"1\"\n                    android:layout_marginTop=\"10dp\"\n                    android:orientation=\"horizontal\">\n\n                    <TextView\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_weight=\"1\"\n                        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n                        android:paddingTop=\"10dp\"\n                        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                        android:paddingBottom=\"10dp\"\n                        android:text=\"@string/qualities\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"20sp\"\n                        android:textStyle=\"bold\" />\n\n                    <ImageView\n                        android:id=\"@+id/help_btt\"\n                        android:layout_width=\"50dp\"\n                        android:layout_height=\"50dp\"\n                        android:background=\"?attr/selectableItemBackgroundBorderless\"\n                        android:contentDescription=\"@string/help\"\n                        android:focusable=\"true\"\n                        android:nextFocusLeft=\"@id/sort_sources\"\n                        android:padding=\"12dp\"\n                        android:src=\"@drawable/baseline_help_outline_24\" />\n\n                </LinearLayout>\n\n                <ImageView\n                    android:layout_width=\"25dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginTop=\"0dp\"\n                    android:layout_marginEnd=\"10dp\"\n                    android:contentDescription=\"@string/home_change_provider_img_des\"\n                    android:src=\"@drawable/ic_outline_settings_24\"\n                    android:visibility=\"gone\" />\n            </LinearLayout>\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/sort_qualities\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_rowWeight=\"1\"\n                android:background=\"?attr/primaryBlackBackground\"\n                android:listSelector=\"@drawable/outline_drawable_less\"\n                android:nextFocusLeft=\"@id/sort_sources\"\n                android:nextFocusRight=\"@id/apply_btt\"\n                android:nextFocusUp=\"@id/help_btt\"\n                android:nextFocusDown=\"@id/apply_btt\"\n                android:requiresFadingEdge=\"vertical\"\n                app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n                tools:layout_height=\"200dp\"\n                tools:listfooter=\"@layout/sort_bottom_footer_add_choice\"\n                tools:listitem=\"@layout/player_prioritize_item\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginTop=\"-60dp\"\n        android:orientation=\"horizontal\">\n\n        <EditText\n            android:id=\"@+id/profile_text_editable\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_marginHorizontal=\"?android:attr/listPreferredItemPaddingStart\"\n            android:autofillHints=\"username\"\n            android:inputType=\"text\"\n            android:maxLength=\"32\"\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\"\n            tools:ignore=\"LabelFor\"\n            tools:text=\"@string/profile_number\" />\n        <!--        <ImageView-->\n        <!--            android:layout_width=\"50dp\"-->\n        <!--            android:layout_height=\"50dp\"-->\n        <!--            android:padding=\"10dp\"-->\n        <!--            android:layout_gravity=\"center\"-->\n        <!--            android:src=\"@drawable/outline_edit_24\" />-->\n\n        <Space\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\">\n\n        </Space>\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/save_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_save\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/close_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_close\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/player_select_tracks.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@null\"\n        android:orientation=\"vertical\">\n\n    <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginBottom=\"60dp\"\n            android:baselineAligned=\"false\"\n            android:orientation=\"horizontal\">\n\n        <LinearLayout\n                android:id=\"@+id/video_tracks_holder\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"50\"\n                android:orientation=\"vertical\">\n\n            <TextView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_rowWeight=\"1\"\n                    android:layout_marginTop=\"10dp\"\n                    android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n                    android:paddingTop=\"10dp\"\n                    android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                    android:paddingBottom=\"10dp\"\n                    android:text=\"@string/video_tracks\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"20sp\"\n                    android:textStyle=\"bold\" />\n\n            <ListView\n                    android:requiresFadingEdge=\"vertical\"\n                    android:id=\"@+id/video_tracks_list\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_rowWeight=\"1\"\n                    android:background=\"?attr/primaryBlackBackground\"\n                    android:nextFocusRight=\"@id/audio_tracks_holder\"\n\n                    tools:listitem=\"@layout/sort_bottom_single_choice\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/audio_tracks_holder\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"50\"\n            android:orientation=\"vertical\">\n\n            <!--   android:id=\"@+id/subs_settings\"                 android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n-->\n            <LinearLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\"\n                    tools:ignore=\"UseCompoundDrawables\">\n\n                <LinearLayout\n                        android:foreground=\"?attr/selectableItemBackgroundBorderless\"\n                        android:id=\"@+id/subtitles_click_settings\"\n                        android:layout_rowWeight=\"1\"\n                        android:paddingTop=\"10dp\"\n                        android:paddingBottom=\"10dp\"\n                        android:layout_marginTop=\"10dp\"\n                        android:orientation=\"horizontal\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\">\n\n                    <TextView\n                            android:layout_width=\"wrap_content\"\n                            android:layout_height=\"wrap_content\"\n                            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n                            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                            android:text=\"@string/audio_tracks\"\n                            android:textColor=\"?attr/textColor\"\n                            android:textSize=\"20sp\"\n                            android:textStyle=\"bold\" />\n\n<!--                    <TextView-->\n<!--                            android:textSize=\"15sp\"-->\n<!--                            android:id=\"@+id/subtitles_encoding_format\"-->\n<!--                            android:textColor=\"?attr/textColor\"-->\n<!--                            android:layout_gravity=\"center\"-->\n<!--                            android:gravity=\"center\"-->\n<!--                            tools:text=\"Thai (TIS 620-2533/ISO 8859-11)\"-->\n<!--                            android:layout_width=\"wrap_content\"-->\n<!--                            android:layout_height=\"wrap_content\" />-->\n                </LinearLayout>\n\n                <ImageView\n                        android:layout_width=\"25dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"end|center_vertical\"\n                        android:layout_marginTop=\"0dp\"\n                        android:layout_marginEnd=\"10dp\"\n\n                        android:contentDescription=\"@string/home_change_provider_img_des\"\n                        android:src=\"@drawable/ic_outline_settings_24\"\n                        android:visibility=\"gone\" />\n            </LinearLayout>\n\n            <ListView\n                android:requiresFadingEdge=\"vertical\"\n                android:id=\"@+id/auto_tracks_list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_rowWeight=\"1\"\n                android:background=\"?attr/primaryBlackBackground\"\n                android:nextFocusRight=\"@id/apply_btt\"\n                android:nextFocusLeft=\"@id/video_tracks_list\"\n                tools:listfooter=\"@layout/sort_bottom_footer_add_choice\"\n                tools:listitem=\"@layout/sort_bottom_single_choice\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <LinearLayout\n            android:id=\"@+id/apply_btt_holder\"\n            android:orientation=\"horizontal\"\n            android:layout_gravity=\"bottom\"\n            android:gravity=\"bottom|end\"\n            android:layout_marginTop=\"-60dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"60dp\">\n\n\n        <com.google.android.material.button.MaterialButton\n            style=\"@style/WhiteButton\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_apply\"\n            android:id=\"@+id/apply_btt\"\n            android:nextFocusLeft=\"@id/auto_tracks_list\"\n            android:layout_width=\"wrap_content\" />\n\n        <com.google.android.material.button.MaterialButton\n                style=\"@style/BlackButton\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/sort_cancel\"\n                android:id=\"@+id/cancel_btt\"\n                android:layout_width=\"wrap_content\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/provider_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:layout_height=\"match_parent\">\n\n    <!--\n       app:thumbTint=\"@color/toggle_selector\"\n       app:trackTint=\"@color/toggle_selector\"-->\n    <com.google.android.material.switchmaterial.SwitchMaterial\n            android:id=\"@+id/toggle1\"\n\n            android:nextFocusLeft=\"@id/apply_btt\"\n            android:nextFocusRight=\"@id/cancel_btt\"\n\n            android:layout_marginTop=\"10dp\"\n            android:paddingStart=\"20dp\"\n            android:paddingEnd=\"20dp\"\n            android:textStyle=\"bold\"\n            android:textSize=\"20sp\"\n            app:useMaterialThemeColors=\"false\"\n\n            android:textColor=\"?attr/textColor\"\n            tools:text=\"Search\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n        <requestFocus />\n    </com.google.android.material.switchmaterial.SwitchMaterial>\n\n    <ListView\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n\n            android:nextFocusUp=\"@id/toggle1\"\n            android:nextFocusDown=\"@id/apply_btt\"\n\n            android:id=\"@+id/listview1\"\n            android:layout_marginTop=\"-10dp\"\n            android:layout_marginBottom=\"60dp\"\n            android:paddingTop=\"10dp\"\n            android:requiresFadingEdge=\"vertical\"\n            tools:listitem=\"@layout/sort_bottom_single_choice\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_rowWeight=\"1\" />\n\n    <ListView\n            android:nextFocusRight=\"@id/cancel_btt\"\n            android:nextFocusLeft=\"@id/apply_btt\"\n\n            android:nextFocusUp=\"@id/toggle1\"\n            android:nextFocusDown=\"@id/apply_btt\"\n\n            android:id=\"@+id/listview2\"\n            android:layout_marginTop=\"-10dp\"\n            android:layout_marginBottom=\"60dp\"\n            android:paddingTop=\"10dp\"\n            android:requiresFadingEdge=\"vertical\"\n            tools:listitem=\"@layout/sort_bottom_single_choice\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_rowWeight=\"1\" />\n\n    <LinearLayout\n            android:id=\"@+id/apply_btt_holder\"\n            android:orientation=\"horizontal\"\n            android:layout_gravity=\"bottom\"\n            android:gravity=\"bottom|end\"\n            android:layout_marginTop=\"-60dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"60dp\">\n\n        <com.google.android.material.button.MaterialButton\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusLeft=\"@id/cancel_btt\"\n\n                android:id=\"@+id/apply_btt\"\n                style=\"@style/WhiteButton\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/sort_apply\"\n                android:layout_width=\"wrap_content\" />\n\n        <com.google.android.material.button.MaterialButton\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/apply_btt\"\n\n                android:id=\"@+id/cancel_btt\"\n                style=\"@style/BlackButton\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/sort_cancel\"\n                android:layout_width=\"wrap_content\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/provider_test_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"?attr/selectableItemBackground\"\n    android:nextFocusRight=\"@id/action_button\"\n    android:orientation=\"horizontal\"\n    android:padding=\"12dp\">\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/main_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"16sp\"\n            tools:text=\"Test repository\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center_vertical\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/lang_icon\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginEnd=\"5dp\"\n                tools:text=\"🇷🇼\"\n                android:textColor=\"?attr/grayTextColor\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/passed_failed_marker\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                tools:text=\"Failed\"\n                tools:visibility=\"visible\" />\n        </LinearLayout>\n\n        <TextView\n            android:id=\"@+id/fail_description\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textColor=\"?attr/grayTextColor\"\n            tools:text=\"Unable to load videos\"\n            tools:visibility=\"visible\" />\n    </LinearLayout>\n\n    <ImageView\n        android:id=\"@+id/action_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical|end\"\n        android:layout_marginStart=\"10dp\"\n        android:background=\"?attr/selectableItemBackgroundBorderless\"\n        android:clickable=\"true\"\n        android:focusable=\"true\"\n        android:padding=\"12dp\"\n        android:src=\"@drawable/baseline_text_snippet_24\"\n        app:tint=\"?attr/white\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/quick_search.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n\n    android:id=\"@+id/quick_search_root\"\n    style=\"@style/DarkFragment\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"10dp\"\n        android:visibility=\"visible\">\n\n        <ImageView\n            android:id=\"@+id/quick_search_back\"\n            android:layout_width=\"25dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:foregroundGravity=\"center\"\n            android:src=\"@drawable/ic_baseline_arrow_back_24\"\n            android:visibility=\"gone\"\n            app:tint=\"?attr/white\"\n            tools:visibility=\"visible\" />\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"40dp\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginStart=\"10dp\"\n            android:background=\"@drawable/search_background\">\n\n            <androidx.appcompat.widget.SearchView\n                android:id=\"@+id/quick_search\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n\n                android:layout_gravity=\"center_vertical\"\n                android:iconifiedByDefault=\"false\"\n\n                android:imeOptions=\"actionSearch\"\n                android:inputType=\"text\"\n\n                android:nextFocusLeft=\"@id/search_filter\"\n                android:nextFocusRight=\"@id/search_filter\"\n\n                android:nextFocusDown=\"@id/search_autofit_results\"\n                android:paddingStart=\"-10dp\"\n                app:closeIcon=\"@drawable/ic_baseline_close_24\"\n                app:iconifiedByDefault=\"false\"\n                app:queryBackground=\"@color/transparent\"\n                app:queryHint=\"@string/search_hint\"\n                app:searchIcon=\"@drawable/search_icon\"\n                tools:ignore=\"RtlSymmetry\">\n\n                <androidx.core.widget.ContentLoadingProgressBar\n                    android:id=\"@+id/quick_search_loading_bar\"\n                    style=\"@style/Widget.AppCompat.ProgressBar\"\n                    android:layout_width=\"20dp\"\n                    android:layout_height=\"20dp\"\n                    android:layout_gravity=\"center\"\n                    android:layout_marginStart=\"-35dp\"\n                    android:foregroundTint=\"@color/white\"\n                    android:progressTint=\"@color/white\">\n\n                </androidx.core.widget.ContentLoadingProgressBar>\n                <!--app:queryHint=\"@string/search_hint\"\n                 android:background=\"@color/grayBackground\" @color/itemBackground\n                            app:searchHintIcon=\"@drawable/search_white\"\n                            -->\n            </androidx.appcompat.widget.SearchView>\n        </FrameLayout>\n    </LinearLayout>\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/quick_search_master_recycler\"\n\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:descendantFocusability=\"afterDescendants\"\n        tools:listitem=\"@layout/homepage_parent\" />\n\n    <com.lagradost.cloudstream3.ui.AutofitRecyclerView\n        android:id=\"@+id/quick_search_autofit_results\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n\n        android:background=\"?attr/primaryBlackBackground\"\n        android:clipToPadding=\"false\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:nextFocusLeft=\"@id/nav_rail_view\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"8dp\"\n        android:paddingTop=\"5dp\"\n        android:paddingEnd=\"8dp\"\n        android:visibility=\"gone\"\n        app:spanCount=\"3\"\n        tools:listitem=\"@layout/search_result_grid\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/rail_footer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/nav_footer_root\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_gravity=\"bottom|center_horizontal\"\n    android:layout_marginBottom=\"10dp\"\n    android:padding=\"1dp\"\n    android:visibility=\"gone\"\n    tools:visibility=\"visible\">\n\n    <androidx.cardview.widget.CardView\n        android:id=\"@+id/nav_footer_profile_card\"\n        android:layout_width=\"36dp\"\n        android:layout_height=\"36dp\"\n        android:background=\"@color/transparent\"\n        android:focusable=\"true\"\n        android:foreground=\"@drawable/outline_drawable_round_20\"\n        android:nextFocusUp=\"@id/navigation_settings\"\n        android:nextFocusDown=\"@id/nav_footer_profile_card\"\n        app:cardCornerRadius=\"18dp\">\n\n        <ImageView\n            android:foreground=\"@drawable/outline_big_20_gray\"\n            android:id=\"@+id/nav_footer_profile_pic\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:contentDescription=\"@string/account\"\n            android:scaleType=\"centerCrop\"\n            tools:src=\"@drawable/profile_bg_orange\" />\n\n    </androidx.cardview.widget.CardView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/rail_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:padding=\"1dp\"\n    android:visibility=\"gone\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n        <ImageView\n            android:id=\"@+id/nav_header_notification\"\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            app:itemIconTint=\"@color/item_select_color\"\n            android:focusable=\"true\"\n            android:nextFocusRight=\"@id/home_preview_info_btt\"\n            android:src=\"@drawable/notifications_icon_selector\"\n            android:contentDescription=\"@string/account\"\n            app:tint=\"@color/item_select_color\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/repository_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/repository_item_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"?attr/selectableItemBackground\"\n    android:nextFocusRight=\"@id/action_button\"\n    android:orientation=\"horizontal\"\n    android:padding=\"12dp\">\n\n    <ImageView\n        android:id=\"@+id/entry_icon\"\n        android:layout_width=\"32dp\"\n        android:layout_height=\"32dp\"\n        android:layout_gravity=\"start|center_vertical\"\n        android:layout_marginEnd=\"16dp\"\n        android:scaleType=\"fitCenter\"\n        app:srcCompat=\"@drawable/ic_github_logo\" />\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/main_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"16sp\"\n            tools:text=\"Test repository\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center_vertical\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/lang_icon\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginEnd=\"5dp\"\n                android:text=\"🇷🇼\"\n\n                android:textColor=\"?attr/grayTextColor\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/ext_version\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginEnd=\"5dp\"\n                android:text=\"v1\"\n                android:textColor=\"?attr/grayTextColor\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/ext_filesize\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginEnd=\"5dp\"\n                android:text=\"100MB\"\n                android:textColor=\"?attr/grayTextColor\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/ext_votes\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginEnd=\"5dp\"\n                android:textColor=\"?attr/grayTextColor\"\n                tools:text=\"Votes: 10K\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/nsfw_marker\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/is_adult\"\n                android:textColor=\"@color/adultColor\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n        </LinearLayout>\n\n        <TextView\n            android:id=\"@+id/sub_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:singleLine=\"true\"\n            android:textColor=\"?attr/grayTextColor\"\n            android:textSize=\"12sp\"\n            tools:text=\"https://github.com/...\" />\n    </LinearLayout>\n\n    <ImageView\n        android:id=\"@+id/action_settings\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_marginStart=\"10dp\"\n        android:background=\"?attr/selectableItemBackgroundBorderless\"\n        android:contentDescription=\"@string/title_settings\"\n        android:visibility=\"gone\"\n        app:srcCompat=\"@drawable/ic_baseline_tune_24\"\n        tools:visibility=\"visible\" />\n\n    <ImageView\n        android:id=\"@+id/action_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical|end\"\n        android:layout_marginStart=\"10dp\"\n        android:background=\"?attr/selectableItemBackgroundBorderless\"\n        android:clickable=\"true\"\n        android:contentDescription=\"@string/download\"\n        android:focusable=\"true\"\n        android:nextFocusLeft=\"@id/repository_item_root\"\n        android:padding=\"12dp\"\n        tools:src=\"@drawable/ic_baseline_add_24\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/repository_item_tv.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/repository_item_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@drawable/outline_drawable\"\n    android:nextFocusRight=\"@id/action_settings\"\n    android:orientation=\"horizontal\"\n    android:clickable=\"true\"\n    android:focusable=\"true\"\n    android:padding=\"12dp\">\n\n    <ImageView\n        android:id=\"@+id/entry_icon\"\n        android:layout_width=\"32dp\"\n        android:layout_height=\"32dp\"\n        android:layout_gravity=\"start|center_vertical\"\n        android:layout_marginEnd=\"16dp\"\n        android:scaleType=\"fitCenter\"\n        app:srcCompat=\"@drawable/ic_github_logo\" />\n\n    <LinearLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/main_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"16sp\"\n            tools:text=\"Test repository\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center_vertical\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/lang_icon\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_marginEnd=\"5dp\"\n                android:text=\"🇷🇼\"\n\n                android:textColor=\"?attr/grayTextColor\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/ext_version\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginEnd=\"5dp\"\n                android:text=\"v1\"\n                android:textColor=\"?attr/grayTextColor\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/ext_filesize\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginEnd=\"5dp\"\n                android:text=\"100MB\"\n                android:textColor=\"?attr/grayTextColor\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/ext_votes\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginEnd=\"5dp\"\n                tools:text=\"Rating: 0\"\n                android:textColor=\"?attr/grayTextColor\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n            <TextView\n                android:id=\"@+id/nsfw_marker\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/is_adult\"\n                android:textColor=\"@color/adultColor\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\" />\n\n        </LinearLayout>\n\n        <TextView\n            android:id=\"@+id/sub_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:singleLine=\"true\"\n            android:textColor=\"?attr/grayTextColor\"\n            android:textSize=\"12sp\"\n            tools:text=\"https://github.com/...\" />\n\n    </LinearLayout>\n\n    <ImageView\n        android:id=\"@+id/action_settings\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:padding=\"12dp\"\n        android:background=\"@drawable/outline_drawable\"\n        android:contentDescription=\"@string/title_settings\"\n        android:visibility=\"gone\"\n        android:focusable=\"true\"\n        android:nextFocusLeft=\"@id/repository_item_root\"\n        android:nextFocusRight=\"@id/action_button\"\n        app:srcCompat=\"@drawable/ic_baseline_tune_24\"\n        tools:visibility=\"visible\" />\n\n    <ImageView\n        android:id=\"@+id/action_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical|end\"\n        android:layout_marginStart=\"10dp\"\n        android:background=\"@drawable/outline_drawable\"\n        android:clickable=\"true\"\n        android:contentDescription=\"@string/download\"\n        android:focusable=\"true\"\n        android:nextFocusLeft=\"@id/action_settings\"\n        android:padding=\"12dp\"\n        tools:src=\"@drawable/ic_baseline_add_24\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/result_episode.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/episode_holder\"\n\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"50dp\"\n    android:layout_marginBottom=\"5dp\"\n\n    android:nextFocusRight=\"@id/download_button\"\n    app:cardBackgroundColor=\"@color/transparent\"\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n    app:cardElevation=\"0dp\"\n    android:foreground=\"@drawable/outline_drawable\"\n    >\n    <!--\n        android:nextFocusLeft=\"@id/result_episode_download\"\n        -->\n\n    <!-- IDK BUT THIS DOES NOT SEAM LIKE A GOOD WAY OF DOING IT -->\n    <!--<LinearLayout\n            android:layout_width=\"fill_parent\"\n            android:layout_height=\"fill_parent\"\n            android:orientation=\"horizontal\">\n        <View\n                android:layout_weight=\"0.5\"\n                android:id=\"@+id/episode_view_procentage\"\n                android:alpha=\"0.2\"\n                android:background=\"?attr/colorPrimary\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\">\n        </View>\n        <View\n                android:id=\"@+id/episode_view_procentage_off\"\n                android:layout_weight=\"0.10\"\n                android:alpha=\"0\"\n                android:background=\"@color/transparent\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\">\n        </View>\n    </LinearLayout>-->\n<!--    <androidx.core.widget.ContentLoadingProgressBar-->\n<!--        android:id=\"@+id/episode_progress\"-->\n<!--        style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"-->\n<!--        android:layout_width=\"match_parent\"-->\n<!--        android:layout_height=\"5dp\"-->\n<!--        android:layout_gravity=\"bottom\"-->\n<!--        android:layout_marginBottom=\"-1.5dp\"-->\n<!--        android:progressBackgroundTint=\"?attr/colorPrimary\"-->\n<!--        android:progressTint=\"?attr/colorPrimary\"-->\n<!--        tools:progress=\"50\" />-->\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n        android:orientation=\"horizontal\">\n\n        <FrameLayout\n            android:id=\"@+id/watch_progress_container\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"5dp\"\n            android:layout_gravity=\"center\">\n\n            <ImageView\n                android:id=\"@+id/episode_play_icon\"\n                style=\"@style/ContinueWatchingPlayUnderlayProgress\"\n                android:layout_margin=\"4dp\"/>\n\n            <com.google.android.material.progressindicator.CircularProgressIndicator\n                android:id=\"@+id/episode_progress\"\n                style=\"@style/ContinueWatchingCircularProgress\" />\n        </FrameLayout>\n        <!--marquee_forever-->\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/episode_filler\"\n            style=\"@style/SmallWhiteButton\"\n            android:layout_gravity=\"center\"\n            android:text=\"@string/filler\" />\n\n        <TextView\n            android:id=\"@+id/episode_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginStart=\"10dp\"\n            android:layout_marginEnd=\"50dp\"\n            android:ellipsize=\"marquee\"\n\n            android:gravity=\"center_vertical\"\n            android:marqueeRepeatLimit=\"0\"\n\n            android:scrollHorizontally=\"true\"\n            android:singleLine=\"true\"\n\n            android:textColor=\"?attr/textColor\"\n            tools:text=\"Episode 1\" />\n\n        <com.lagradost.cloudstream3.ui.download.button.PieFetchButton\n            android:id=\"@+id/download_button\"\n            android:layout_width=\"@dimen/download_size\"\n            android:layout_height=\"@dimen/download_size\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:layout_marginStart=\"-60dp\"\n            android:background=\"?selectableItemBackgroundBorderless\"\n            android:padding=\"10dp\" />\n\n    </LinearLayout>\n</androidx.cardview.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/result_episode_large.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n\n    android:id=\"@+id/episode_holder_large\"\n    android:layout_width=\"wrap_content\"\n\n    android:layout_height=\"wrap_content\"\n    android:layout_marginBottom=\"10dp\"\n    android:foreground=\"@drawable/outline_drawable\"\n    android:nextFocusRight=\"@id/download_button\"\n    app:cardBackgroundColor=\"?attr/boxItemBackground\"\n\n    app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n    <LinearLayout\n        android:id=\"@+id/episode_holder\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n        android:orientation=\"vertical\"\n        android:padding=\"10dp\">\n\n        <LinearLayout\n            android:id=\"@+id/episode_lin_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n            <!--app:cardCornerRadius=\"@dimen/roundedImageRadius\"-->\n            <androidx.cardview.widget.CardView\n                android:layout_width=\"126dp\"\n                android:layout_height=\"72dp\"\n                android:foreground=\"@drawable/outline_drawable\">\n\n                <ImageView\n                    android:id=\"@+id/episode_poster\"\n\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:contentDescription=\"@string/episode_poster_img_des\"\n\n                    android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:nextFocusRight=\"@id/download_button\"\n                    android:scaleType=\"centerCrop\"\n                    tools:src=\"@drawable/example_poster\"\n                    tools:visibility=\"invisible\" />\n\n<!--                <ImageView-->\n<!--                    android:id=\"@+id/episode_play_icon\"-->\n<!--                    android:layout_width=\"36dp\"-->\n<!--                    android:layout_height=\"36dp\"-->\n<!--                    android:layout_gravity=\"center\"-->\n<!--                    android:contentDescription=\"@string/play_episode\"-->\n<!--                    android:src=\"@drawable/play_button\"-->\n<!--                    tools:visibility=\"invisible\" />-->\n\n                <ImageView\n                    android:id=\"@+id/episode_upcoming_icon\"\n                    android:layout_width=\"36dp\"\n                    android:layout_height=\"36dp\"\n                    android:layout_gravity=\"center\"\n                    android:src=\"@drawable/hourglass_24\"\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\" />\n\n                <FrameLayout\n                    android:id=\"@+id/watch_progress_container\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center\">\n\n                    <com.google.android.material.imageview.ShapeableImageView\n                        android:id=\"@+id/episode_play_icon\"\n                        style=\"@style/EpisodePlayUnderlayProgress\"\n                        />\n                    <com.google.android.material.progressindicator.CircularProgressIndicator\n                        android:id=\"@+id/episode_progress\"\n                        style=\"@style/EpisodeCircularProgress\"\n                        tools:progress=\"100\" />\n                </FrameLayout>\n            </androidx.cardview.widget.CardView>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"15dp\"\n                android:layout_marginEnd=\"50dp\"\n                android:orientation=\"vertical\">\n\n                <LinearLayout\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/episode_filler\"\n                        style=\"@style/SmallWhiteButton\"\n                        android:layout_gravity=\"start\"\n                        android:layout_marginEnd=\"10dp\"\n                        android:text=\"@string/filler\" />\n\n                    <TextView\n                        android:id=\"@+id/episode_text\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textStyle=\"bold\"\n                        tools:text=\"1. Jobless\" />\n                </LinearLayout>\n\n                <LinearLayout\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"start\"\n                    android:orientation=\"horizontal\">\n\n                    <TextView\n                        android:id=\"@+id/episode_rating\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginEnd=\"10dp\"\n                        android:textColor=\"?attr/grayTextColor\"\n                        tools:text=\"Rated: 8.8\" />\n\n                    <TextView\n                        android:id=\"@+id/episode_runtime\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginEnd=\"10dp\"\n                        android:textColor=\"?attr/grayTextColor\"\n                        tools:text=\"80min\" />\n\n                </LinearLayout>\n\n                <TextView\n                    android:id=\"@+id/episode_date\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textColor=\"?attr/grayTextColor\"\n                    tools:text=\"15 Apr 2024\" />\n\n            </LinearLayout>\n\n            <com.lagradost.cloudstream3.ui.download.button.PieFetchButton\n                android:id=\"@+id/download_button\"\n                android:layout_width=\"@dimen/download_size\"\n                android:layout_height=\"@dimen/download_size\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:layout_marginStart=\"-50dp\"\n                android:background=\"?selectableItemBackgroundBorderless\"\n                android:padding=\"10dp\" />\n        </LinearLayout>\n\n        <TextView\n            android:id=\"@+id/episode_descript\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:ellipsize=\"end\"\n            android:maxLines=\"4\"\n            android:paddingTop=\"10dp\"\n            android:paddingBottom=\"10dp\"\n            android:textColor=\"?attr/grayTextColor\"\n            tools:text=\"Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart. Jon and Daenerys arrive in Winterfell and are met with skepticism. Sam learns about the fate of his family. Cersei gives Euron the reward he aims for. Theon follows his heart.\" />\n    </LinearLayout>\n</androidx.cardview.widget.CardView>"
  },
  {
    "path": "app/src/main/res/layout/result_mini_image.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ImageView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:layout_width=\"25dp\"\n        android:layout_height=\"25dp\"\n        android:layout_gravity=\"center\"\n        android:gravity=\"center\"\n        tools:src=\"@drawable/ic_anilist_icon\"\n        android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n        app:tint=\"?attr/white\">\n</ImageView>"
  },
  {
    "path": "app/src/main/res/layout/result_poster.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"?attr/primaryBlackBackground\">\n\n    <ImageView\n            android:id=\"@+id/imgPoster\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:scaleType=\"fitCenter\"\n            android:adjustViewBounds=\"true\"\n            android:src=\"@drawable/default_cover\"\n            android:background=\"?attr/primaryGrayBackground\"\n            android:contentDescription=\"@string/poster_image\" />\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/result_recommendations.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.core.widget.NestedScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n    <LinearLayout\n            android:orientation=\"vertical\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n        <com.google.android.material.button.MaterialButton\n                style=\"@style/BlackButton\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"GogoAnime\"\n                android:id=\"@+id/result_recommendations_filter_button\"\n                android:layout_width=\"match_parent\"\n                android:layout_marginTop=\"10dp\"\n                android:layout_marginBottom=\"10dp\"\n                android:layout_marginStart=\"0dp\"\n                android:layout_marginEnd=\"0dp\"\n                app:layout_constraintBottom_toTopOf=\"@id/result_recommendations_list\" />\n\n        <com.lagradost.cloudstream3.ui.AutofitRecyclerView\n                android:descendantFocusability=\"afterDescendants\"\n\n                android:background=\"?attr/primaryBlackBackground\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:clipToPadding=\"false\"\n                app:spanCount=\"3\"\n                android:id=\"@+id/result_recommendations_list\"\n                tools:listitem=\"@layout/search_result_grid\"\n                android:orientation=\"vertical\" />\n    </LinearLayout>\n</androidx.core.widget.NestedScrollView>"
  },
  {
    "path": "app/src/main/res/layout/result_selection.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!--style=\"@style/SelectableButton\"-->\n\n<com.google.android.material.button.MaterialButton xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/SelectableButtonTV\"\n    android:layout_gravity=\"start\"\n    android:layout_margin=\"2dp\"\n    android:minWidth=\"115dp\"\n    android:singleLine=\"true\"\n    tools:text=\"1000-1000\" />"
  },
  {
    "path": "app/src/main/res/layout/result_sync.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <ScrollView\n        android:id=\"@+id/result_sync_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"16dp\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/result_sync_names\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"10dp\"\n                android:text=\"MyAnimeList, AniList\"\n                android:textSize=\"16sp\"\n                android:textStyle=\"bold\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                android:visibility=\"visible\">\n\n                <ImageView\n                    android:id=\"@+id/result_sync_sub_episode\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:padding=\"10dp\"\n                    android:src=\"@drawable/baseline_remove_24\"\n                    app:tint=\"?attr/textColor\" />\n\n                <EditText\n                    android:id=\"@+id/result_sync_current_episodes\"\n                    style=\"@style/AppEditStyle\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:autofillHints=\"no\"\n                    android:inputType=\"number\"\n                    android:textColorHint=\"?attr/grayTextColor\"\n                    android:textSize=\"20sp\"\n                    tools:hint=\"20\"\n                    tools:ignore=\"LabelFor\" />\n\n                <TextView\n                    android:id=\"@+id/result_sync_max_episodes\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:paddingBottom=\"1dp\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"20sp\"\n                    tools:text=\"30\" />\n\n                <ImageView\n                    android:id=\"@+id/result_sync_add_episode\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:padding=\"10dp\"\n                    android:src=\"@drawable/ic_baseline_add_24\"\n                    app:tint=\"?attr/textColor\" />\n            </LinearLayout>\n\n            <androidx.core.widget.ContentLoadingProgressBar\n                android:id=\"@+id/result_sync_episodes\"\n                style=\"?android:attr/progressBarStyleHorizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"20dp\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:indeterminate=\"false\"\n                android:max=\"100\"\n                android:padding=\"10dp\"\n                android:progress=\"0\"\n                android:progressBackgroundTint=\"?attr/colorPrimary\"\n                tools:visibility=\"visible\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:padding=\"10dp\"\n                    android:text=\"@string/sync_score\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"17sp\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/result_sync_score_text\"\n\n                    style=\"@style/BlackButton\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginStart=\"0dp\"\n                    android:minWidth=\"0dp\"\n                    android:text=\"7/10\" />\n            </LinearLayout>\n\n            <com.google.android.material.slider.Slider\n                android:id=\"@+id/result_sync_rating\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"-5dp\"\n                android:layout_marginEnd=\"-5dp\"\n                app:thumbHeight=\"20dp\"\n                android:stepSize=\"1\"\n                android:value=\"4\"\n                android:valueFrom=\"0\"\n                android:valueTo=\"10\"\n                app:labelStyle=\"@style/BlackLabel\"\n                app:thumbRadius=\"10dp\"\n                app:tickVisible=\"false\" />\n\n            <FrameLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                android:paddingTop=\"12dp\"\n                android:paddingBottom=\"12dp\"\n                android:visibility=\"gone\">\n\n                <TextView\n                    android:id=\"@+id/home_parent_item_title\"\n                    style=\"@style/WatchHeaderText\"\n                    tools:text=\"Recommended\" />\n\n                <ImageView\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:layout_marginEnd=\"5dp\"\n                    android:contentDescription=\"@string/home_more_info\"\n                    android:src=\"@drawable/ic_baseline_arrow_forward_24\"\n                    app:tint=\"?attr/textColor\" />\n            </FrameLayout>\n\n            <ListView\n                android:id=\"@+id/result_sync_check\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_rowWeight=\"1\"\n                tools:listitem=\"@layout/sort_bottom_single_choice\" />\n\n            <com.google.android.material.button.MaterialButton\n                style=\"@style/WhiteButton\"\n                android:layout_width=\"match_parent\"\n                android:layout_marginTop=\"10dp\"\n                android:text=\"@string/type_watching\"\n                android:visibility=\"gone\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/result_sync_set_score\"\n                style=\"@style/BlackButton\"\n                android:layout_width=\"match_parent\"\n                android:layout_marginTop=\"10dp\"\n                android:text=\"@string/upload_sync\"\n                app:icon=\"@drawable/baseline_sync_24\" />\n        </LinearLayout>\n\n    </ScrollView>\n\n    <com.facebook.shimmer.ShimmerFrameLayout\n        android:id=\"@+id/result_sync_loading_shimmer\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:orientation=\"vertical\"\n        android:padding=\"15dp\"\n        app:shimmer_auto_start=\"true\"\n        app:shimmer_base_alpha=\"0.2\"\n        app:shimmer_duration=\"@integer/loading_time\"\n        app:shimmer_highlight_alpha=\"0.3\"\n        tools:visibility=\"gone\"\n        tools:ignore=\"MissingClass\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <Space\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"30dp\" />\n\n            <include layout=\"@layout/loading_line_short\" />\n\n            <include layout=\"@layout/loading_line\" />\n\n            <Space\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"30dp\" />\n\n            <include layout=\"@layout/loading_line_short\" />\n\n            <include layout=\"@layout/loading_line\" />\n\n            <Space\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"30dp\" />\n\n            <include layout=\"@layout/loading_line_short\" />\n\n            <include layout=\"@layout/loading_line_short\" />\n\n            <include layout=\"@layout/loading_line_short\" />\n\n            <include layout=\"@layout/loading_line_short\" />\n\n            <include layout=\"@layout/loading_line_short\" />\n\n            <Space\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"30dp\" />\n\n            <include layout=\"@layout/loading_line\" />\n\n            <include layout=\"@layout/loading_line\" />\n\n        </LinearLayout>\n    </com.facebook.shimmer.ShimmerFrameLayout>\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/result_tag.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginTop=\"-4dp\"\n    android:layout_marginBottom=\"-4dp\"\n    android:paddingLeft=\"2dp\"\n    android:paddingTop=\"-10dp\"\n    android:paddingRight=\"2dp\">\n    <!--app:strokeColor=\"@color/colorAccent\"-->\n\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/result_tag_card\"\n        style=\"@style/Tag\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"37dp\"\n        android:minWidth=\"0dp\"\n        android:minHeight=\"0dp\"\n        android:textAllCaps=\"false\"\n        android:textColor=\"?attr/textColor\"\n        android:textSize=\"12sp\"\n        app:cornerRadius=\"100dp\"\n        tools:text=\"Test\">\n\n    </com.google.android.material.button.MaterialButton>\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/search_history_footer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.google.android.material.button.MaterialButton \n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/search_clear_call_history\"\n    style=\"@style/BlackButton\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"50dp\"\n    android:layout_gravity=\"bottom\"\n    android:layout_margin=\"0dp\"\n    android:padding=\"0dp\"\n    android:text=\"@string/clear_history\"\n    app:cornerRadius=\"0dp\"\n    app:icon=\"@drawable/delete_all\" />\n"
  },
  {
    "path": "app/src/main/res/layout/search_history_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.constraintlayout.widget.ConstraintLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/home_history_tab\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@drawable/outline_drawable_less\"\n    android:focusable=\"true\"\n    android:nextFocusRight=\"@id/home_history_remove\"\n    android:orientation=\"horizontal\">\n    <!-- android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n      -->\n    <TextView\n        android:id=\"@+id/home_history_title\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:padding=\"10dp\"\n        android:textColor=\"?attr/textColor\"\n        android:textSize=\"18sp\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintStart_toStartOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:layout_constraintEnd_toStartOf=\"@id/home_history_remove\"\n        tools:text=\"Hello World\" />\n\n    <ImageView\n        android:id=\"@+id/home_history_remove\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center_vertical|end\"\n\n        android:background=\"@drawable/outline_drawable_less\"\n        android:focusable=\"true\"\n        android:nextFocusLeft=\"@id/home_history_tab\"\n        android:padding=\"10dp\"\n        android:src=\"@drawable/ic_baseline_close_24\"\n        app:layout_constraintBottom_toBottomOf=\"parent\"\n        app:layout_constraintEnd_toEndOf=\"parent\"\n        app:layout_constraintTop_toTopOf=\"parent\"\n        app:tint=\"?attr/white\"\n        tools:ignore=\"ContentDescription\" />\n</androidx.constraintlayout.widget.ConstraintLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/search_result_compact.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"80dp\"\n        android:layout_marginBottom=\"0dp\"\n        android:layoutDirection=\"ltr\">\n\n    <androidx.cardview.widget.CardView\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n\n            android:id=\"@+id/background_card\"\n            android:layout_margin=\"2dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginBottom=\"2dp\"\n            android:elevation=\"0dp\"\n\n            app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n            app:cardBackgroundColor=\"?attr/boxItemBackground\"\n            android:clickable=\"true\"\n            android:focusable=\"true\">\n\n        <androidx.cardview.widget.CardView\n                android:elevation=\"0dp\"\n                app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n                android:layout_width=\"54dp\"\n                android:layout_height=\"match_parent\">\n\n            <ImageView\n                    android:layout_gravity=\"left\"\n                    android:id=\"@+id/imageView\"\n                    android:scaleType=\"centerCrop\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_width=\"match_parent\"\n                    android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n                    tools:ignore=\"RtlHardcoded\" />\n        </androidx.cardview.widget.CardView>\n\n        <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"64dp\">\n\n            <TextView\n                    tools:text=\"@string/no_data\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textSize=\"17sp\"\n                    android:textColor=\"?attr/textColor\"\n                    android:id=\"@+id/imageText\"\n                    android:textStyle=\"bold\"\n                    android:maxLines=\"3\" />\n\n            <TextView\n                    tools:text=\"@string/no_data\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textColor=\"?attr/grayTextColor\"\n                    android:id=\"@+id/imageTextExtra\"\n                    android:textSize=\"13sp\"\n                    android:textStyle=\"bold\"\n                    android:maxLines=\"3\" />\n\n            <TextView\n                    tools:text=\"Rated 4.13\"\n                    android:visibility=\"gone\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textColor=\"?attr/colorPrimary\"\n                    android:id=\"@+id/imageTextProvider\"\n                    android:maxLines=\"1\" />\n        </LinearLayout>\n\n    </androidx.cardview.widget.CardView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/search_result_grid.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/search_result_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n\n    android:clickable=\"true\"\n    android:focusable=\"true\"\n    android:foreground=\"@drawable/outline_drawable\"\n    android:orientation=\"vertical\">\n\n    <androidx.cardview.widget.CardView\n        android:id=\"@+id/background_card\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_margin=\"2dp\"\n        android:layout_marginBottom=\"2dp\"\n        android:elevation=\"10dp\"\n        app:cardBackgroundColor=\"?attr/primaryGrayBackground\"\n        app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n        <ImageView\n            android:id=\"@+id/imageView\"\n\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:contentDescription=\"@string/search_poster_img_des\"\n            android:duplicateParentState=\"true\"\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:scaleType=\"centerCrop\" />\n\n        <ImageView\n            android:id=\"@+id/title_shadow\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"50dp\"\n            android:layout_gravity=\"bottom\"\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:src=\"@drawable/title_shadow\"\n            tools:ignore=\"ContentDescription\" />\n\n        <TextView android:id=\"@+id/text_quality\" style=\"@style/TypeButton\" />\n\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"end\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:id=\"@+id/text_is_dub\"\n                style=\"@style/DubButton\"\n                android:layout_gravity=\"end\" />\n\n            <TextView\n                android:id=\"@+id/text_is_sub\"\n                style=\"@style/SubButton\"\n                android:layout_gravity=\"end\" />\n\n            <TextView\n                android:id=\"@+id/text_rating\"\n                style=\"@style/RatingButton\"\n                android:layout_gravity=\"end\"\n\n                tools:text=\"7.7\" />\n            <TextView\n                android:id=\"@+id/text_flag\"\n                style=\"@style/SearchBox\"\n                android:layout_gravity=\"end\"\n                android:background=\"@color/transparent\"\n                android:textSize=\"20sp\"\n                android:visibility=\"gone\"\n                tools:text=\"🇸🇪\"\n                tools:visibility=\"visible\" />\n        </LinearLayout>\n        <androidx.core.widget.ContentLoadingProgressBar\n            android:id=\"@+id/watchProgress\"\n            style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"5dp\"\n            android:layout_gravity=\"bottom\"\n            android:layout_marginBottom=\"-1.5dp\"\n            android:progressBackgroundTint=\"?attr/white\"\n            android:progressTint=\"?attr/white\"\n            android:visibility=\"gone\"\n            tools:progress=\"50\"\n            tools:visibility=\"visible\" />\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"bottom\"\n            android:orientation=\"vertical\"\n            android:paddingBottom=\"5dp\">\n            <TextView\n                android:id=\"@+id/episode_text\"\n                android:layout_width=\"wrap_content\"\n                style=\"@style/EpisodeTextButton\"\n                android:layout_gravity=\"center\"/>\n            <TextView\n                android:id=\"@+id/imageText\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"bottom\"\n                android:ellipsize=\"end\"\n                android:gravity=\"center\"\n                android:maxLines=\"1\"\n                android:paddingStart=\"5dp\"\n                android:paddingEnd=\"5dp\"\n                android:textColor=\"@color/textColor\"\n                android:textStyle=\"bold\"\n                tools:text=\"The Perfect Run\" />\n        </LinearLayout>\n    </androidx.cardview.widget.CardView>\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/search_result_grid_expanded.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/search_result_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:clickable=\"true\"\n    android:focusable=\"true\"\n    android:foreground=\"@drawable/outline_drawable\"\n    android:orientation=\"vertical\">\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <androidx.cardview.widget.CardView\n            android:id=\"@+id/background_card\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"2dp\"\n            android:layout_marginBottom=\"2dp\"\n            android:elevation=\"10dp\"\n            app:cardBackgroundColor=\"?attr/primaryGrayBackground\"\n            app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n            app:layout_constraintDimensionRatio=\"1:1.5\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\">\n\n            <ImageView\n                android:id=\"@+id/imageView\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:contentDescription=\"@string/search_poster_img_des\"\n                android:duplicateParentState=\"true\"\n                android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:scaleType=\"centerCrop\"\n                tools:src=\"@drawable/example_poster\" />\n\n            <TextView\n                android:id=\"@+id/text_quality\"\n                style=\"@style/TypeButton\" />\n\n            <LinearLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:layout_gravity=\"end\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:id=\"@+id/text_is_dub\"\n                    style=\"@style/DubButton\"\n                    android:layout_gravity=\"end\" />\n\n                <TextView\n                    android:id=\"@+id/text_is_sub\"\n                    style=\"@style/SubButton\"\n                    android:layout_gravity=\"end\" />\n\n\n                <TextView\n                    android:id=\"@+id/text_rating\"\n                    style=\"@style/RatingButton\"\n                    android:layout_gravity=\"end\"\n                    tools:text=\"7.7\" />\n\n                <TextView\n                    android:id=\"@+id/text_flag\"\n                    style=\"@style/SearchBox\"\n                    android:layout_gravity=\"end\"\n                    android:background=\"@color/transparent\"\n                    android:textSize=\"20sp\"\n                    android:visibility=\"gone\"\n                    tools:text=\"🇸🇪\"\n                    tools:visibility=\"visible\" />\n            </LinearLayout>\n\n            <ImageView\n                android:focusable=\"false\"\n                android:visibility=\"gone\"\n                android:clickable=\"false\"\n                android:focusableInTouchMode=\"false\"\n                android:id=\"@+id/title_shadow\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"0dp\"\n                tools:ignore=\"ContentDescription\" />\n\n            <androidx.core.widget.ContentLoadingProgressBar\n                android:id=\"@+id/watchProgress\"\n                style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"5dp\"\n                android:layout_gravity=\"bottom\"\n                android:layout_marginBottom=\"-1.5dp\"\n                android:progressBackgroundTint=\"?attr/white\"\n                android:progressTint=\"?attr/white\"\n                android:visibility=\"gone\"\n                tools:progress=\"50\"\n                tools:visibility=\"visible\" />\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"bottom\"\n                android:orientation=\"vertical\"\n                android:paddingBottom=\"7dp\">\n                <TextView\n                    android:id=\"@+id/episode_text\"\n                    android:layout_width=\"wrap_content\"\n                    style=\"@style/EpisodeTextButton\"\n                    android:layout_gravity=\"center\"/>\n            </LinearLayout>\n        </androidx.cardview.widget.CardView>\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n    <TextView\n        android:id=\"@+id/imageText\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom\"\n        android:ellipsize=\"end\"\n        android:gravity=\"center\"\n        android:maxLines=\"2\"\n        android:minLines=\"2\"\n        android:paddingStart=\"5dp\"\n        android:paddingTop=\"5dp\"\n        android:paddingEnd=\"5dp\"\n        android:paddingBottom=\"5dp\"\n        android:textColor=\"?attr/textColor\"\n        android:textSize=\"13sp\"\n        tools:text=\"The Perfect Run\\nThe Perfect Run\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/search_result_super_compact.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:layout_marginBottom=\"3dp\">\n\n    <androidx.cardview.widget.CardView\n            android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:id=\"@+id/background_card\"\n            android:layout_margin=\"2dp\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginBottom=\"10dp\"\n            android:elevation=\"0dp\"\n            app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n            app:cardBackgroundColor=\"?attr/boxItemBackground\"\n            android:clickable=\"true\"\n            android:focusable=\"true\">\n        <!-- USING CROP RATIO (182/268), centerCrop for fill -->\n        <androidx.cardview.widget.CardView\n                app:cardCornerRadius=\"@dimen/rounded_image_radius\"\n                android:layout_width=\"35dp\"\n                android:elevation=\"0dp\"\n                android:layout_height=\"match_parent\">\n\n            <ImageView\n                    android:layout_gravity=\"left\"\n                    android:id=\"@+id/imageView\"\n                    android:scaleType=\"centerCrop\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:foreground=\"?android:attr/selectableItemBackgroundBorderless\"\n                    tools:ignore=\"RtlHardcoded\"\n                    android:contentDescription=\"@string/search_poster_img_des\" />\n        </androidx.cardview.widget.CardView>\n\n        <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginStart=\"45dp\">\n\n            <TextView\n                    tools:text=\"@string/no_data\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textSize=\"17sp\"\n                    android:textColor=\"?attr/textColor\"\n                    android:id=\"@+id/imageText\"\n                    android:textStyle=\"normal\"\n                    android:maxLines=\"3\" />\n\n            <TextView\n                    tools:text=\"@string/no_data\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:visibility=\"gone\"\n                    android:textColor=\"?attr/grayTextColor\"\n                    android:id=\"@+id/imageTextExtra\"\n                    android:textSize=\"13sp\"\n                    android:textStyle=\"bold\"\n                    android:maxLines=\"3\" />\n\n            <TextView\n                    tools:text=\"Rated 4.13\"\n                    android:visibility=\"gone\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textColor=\"?attr/colorPrimary\"\n                    android:id=\"@+id/imageTextProvider\"\n                    android:maxLines=\"1\" />\n        </LinearLayout>\n    </androidx.cardview.widget.CardView>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/search_suggestion_footer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.google.android.material.button.MaterialButton \n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/clear_suggestions_button\"\n    style=\"@style/BlackButton\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"50dp\"\n    android:layout_gravity=\"bottom\"\n    android:layout_margin=\"0dp\"\n    android:padding=\"0dp\"\n    android:text=\"@string/clear_suggestions\"\n    app:cornerRadius=\"0dp\"\n    app:icon=\"@drawable/ic_baseline_close_24\" />\n"
  },
  {
    "path": "app/src/main/res/layout/search_suggestion_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/suggestion_item\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"48dp\"\n    android:background=\"?attr/selectableItemBackground\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\"\n    android:paddingStart=\"16dp\"\n    android:paddingEnd=\"8dp\">\n\n    <ImageView\n        android:layout_width=\"24dp\"\n        android:layout_height=\"24dp\"\n        android:contentDescription=\"@string/search_hint\"\n        android:src=\"@drawable/search_icon\"\n        app:tint=\"?attr/textColor\" />\n\n    <TextView\n        android:id=\"@+id/suggestion_text\"\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginStart=\"16dp\"\n        android:layout_weight=\"1\"\n        android:ellipsize=\"end\"\n        android:maxLines=\"1\"\n        android:textColor=\"?attr/textColor\"\n        android:textSize=\"18sp\"\n        tools:text=\"Search suggestion\" />\n\n    <ImageView\n        android:id=\"@+id/suggestion_fill\"\n        android:layout_width=\"40dp\"\n        android:layout_height=\"40dp\"\n        android:background=\"?attr/selectableItemBackgroundBorderless\"\n        android:contentDescription=\"@string/search_hint\"\n        android:padding=\"8dp\"\n        android:src=\"@drawable/ic_baseline_north_west_24\"\n        app:tint=\"?attr/textColor\" />\n\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/settings_title_top.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/settings_top_root\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"?attr/primaryGrayBackground\"\n    android:orientation=\"vertical\">\n\n    <include layout=\"@layout/standard_toolbar\" />\n\n    <!-- Required ViewGroup for PreferenceFragmentCompat -->\n    <FrameLayout\n        android:id=\"@android:id/list_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"?attr/primaryBlackBackground\"\n        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n        tools:targetApi=\"n\" />\n        <!-- list_container is actually defined by the support library, but lint doesn't know that it exists before API 24. -->\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/sort_bottom_footer_add_choice.xml",
    "content": "<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        style=\"@style/CheckLabel\"\n        android:id=\"@android:id/text1\"\n        tools:text=\"hello\"\n        android:foreground=\"@drawable/outline_drawable_forced\"\n        app:drawableStartCompat=\"@drawable/ic_baseline_add_24\"\n        app:drawableTint=\"?attr/textColor\" />"
  },
  {
    "path": "app/src/main/res/layout/sort_bottom_sheet.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        android:orientation=\"vertical\"\n        android:layout_width=\"match_parent\"\n        android:background=\"@null\"\n        android:layout_height=\"match_parent\">\n\n    <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:orientation=\"vertical\"\n            android:layout_weight=\"50\">\n\n        <TextView\n                android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n                android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                android:layout_marginTop=\"20dp\"\n                android:layout_marginBottom=\"10dp\"\n                android:textStyle=\"bold\"\n                android:text=\"@string/pick_source\"\n                android:textSize=\"20sp\"\n                android:textColor=\"?attr/textColor\"\n                android:layout_width=\"match_parent\"\n                android:layout_rowWeight=\"1\"\n                android:layout_height=\"wrap_content\" />\n\n        <ListView\n                android:layout_marginTop=\"-10dp\"\n                android:paddingTop=\"10dp\"\n                android:id=\"@+id/sort_providers\"\n                android:background=\"?attr/primaryBlackBackground\"\n                android:requiresFadingEdge=\"vertical\"\n                tools:listitem=\"@layout/sort_bottom_single_choice\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:layout_rowWeight=\"1\" />\n    </LinearLayout>\n\n    <LinearLayout\n            android:id=\"@+id/sort_subtitles_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:orientation=\"vertical\"\n            android:layout_weight=\"50\">\n\n        <TextView\n                android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n                android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n                android:layout_marginTop=\"20dp\"\n                android:layout_marginBottom=\"10dp\"\n                android:textStyle=\"bold\"\n                android:text=\"@string/pick_subtitle\"\n                android:textSize=\"20sp\"\n                android:textColor=\"?attr/textColor\"\n                android:layout_rowWeight=\"1\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\" />\n\n        <ListView\n                android:layout_marginTop=\"-10dp\"\n                android:paddingTop=\"10dp\"\n                android:id=\"@+id/sort_subtitles\"\n                android:background=\"?attr/primaryBlackBackground\"\n                android:requiresFadingEdge=\"vertical\"\n                tools:listitem=\"@layout/sort_bottom_single_choice\"\n                android:layout_width=\"match_parent\"\n                android:layout_rowWeight=\"1\"\n                android:layout_height=\"match_parent\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/sort_bottom_single_choice.xml",
    "content": "<!--<CheckedTextView\n        xmlns:android=\"http://schemas.android.com/apk/res/android\" xmlns:tools=\"http://schemas.android.com/tools\"\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?android:attr/listPreferredItemHeightSmall\"\n        android:textAppearance=\"?android:attr/textAppearanceListItemSmall\"\n        android:gravity=\"center_vertical\"\n        android:textColor=\"?attr/textColor\"\n        tools:text=\"Example Text\"\n        android:background=\"?attr/bitDarkerGrayBackground\"\n        android:checkMark=\"?android:attr/listChoiceIndicatorSingle\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"/>\n-->\n\n<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@android:id/text1\"\n    style=\"@style/CheckLabel\"\n    tools:text=\"hello\" />"
  },
  {
    "path": "app/src/main/res/layout/sort_bottom_single_choice_color.xml",
    "content": "<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:tools=\"http://schemas.android.com/tools\"\n        style=\"@style/AppTextViewStyle\"\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n        android:textAppearance=\"?android:attr/textAppearanceSmall\"\n        android:textColor=\"@color/text_selection_color\"\n        android:textSize=\"16sp\"\n        android:textStyle=\"bold\"\n        android:gravity=\"center_vertical\"\n        android:paddingStart=\"12dp\"\n        android:paddingEnd=\"7dip\"\n        tools:text=\"TEST\"\n        android:checkMark=\"?android:attr/listChoiceIndicatorSingle\"\n        android:ellipsize=\"marquee\"\n        android:foreground=\"?attr/selectableItemBackgroundBorderless\" />\n"
  },
  {
    "path": "app/src/main/res/layout/sort_bottom_single_choice_double_text.xml",
    "content": "<!--<CheckedTextView\n        xmlns:android=\"http://schemas.android.com/apk/res/android\" xmlns:tools=\"http://schemas.android.com/tools\"\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?android:attr/listPreferredItemHeightSmall\"\n        android:textAppearance=\"?android:attr/textAppearanceListItemSmall\"\n        android:gravity=\"center_vertical\"\n        android:textColor=\"?attr/textColor\"\n        tools:text=\"Example Text\"\n        android:background=\"?attr/bitDarkerGrayBackground\"\n        android:checkMark=\"?android:attr/listChoiceIndicatorSingle\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"/>\n-->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:paddingVertical=\"10dp\"\n    android:orientation=\"horizontal\">\n\n    <ImageView\n        android:id=\"@+id/drawable_start\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:paddingHorizontal=\"10dp\"\n        android:src=\"@drawable/ic_baseline_check_24_listview\"\n        tools:ignore=\"ContentDescription\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center\"\n        android:orientation=\"vertical\">\n\n        <TextView\n            android:id=\"@+id/main_text\"\n            style=\"@style/CheckLabel\"\n            android:foreground=\"@null\"\n            android:minHeight=\"@null\"\n            app:drawableStartCompat=\"@null\"\n            tools:text=\"The Boys - S01E02 Cherry\" />\n\n        <TextView\n            android:id=\"@+id/secondary_text\"\n            style=\"@style/CheckLabel\"\n            android:foreground=\"@null\"\n            android:minHeight=\"@null\"\n            android:padding=\"0dp\"\n            android:textSize=\"12sp\"\n            app:drawableStartCompat=\"@null\"\n            tools:text=\"English · OpenSubtitles\" />\n    </LinearLayout>\n\n    <ImageView\n        tools:src=\"@drawable/ic_baseline_hearing_24\"\n        android:id=\"@+id/drawable_end\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"center\"\n        android:layout_weight=\"0\"\n        android:paddingHorizontal=\"10dp\"\n        tools:ignore=\"ContentDescription\" />\n</LinearLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/sort_bottom_single_choice_no_checkmark.xml",
    "content": "<!--<CheckedTextView\n        xmlns:android=\"http://schemas.android.com/apk/res/android\" xmlns:tools=\"http://schemas.android.com/tools\"\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?android:attr/listPreferredItemHeightSmall\"\n        android:textAppearance=\"?android:attr/textAppearanceListItemSmall\"\n        android:gravity=\"center_vertical\"\n        android:textColor=\"?attr/textColor\"\n        tools:text=\"Example Text\"\n        android:background=\"?attr/bitDarkerGrayBackground\"\n        android:checkMark=\"?android:attr/listChoiceIndicatorSingle\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"/>\n-->\n\n<TextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@android:id/text1\"\n    style=\"@style/NoCheckLabel\"\n    android:textColor=\"?attr/textColor\"\n    android:textStyle=\"normal\"\n    tools:text=\"hello\" />\n"
  },
  {
    "path": "app/src/main/res/layout/sort_bottom_single_provider_choice.xml",
    "content": "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n     >\n    <TextView\n        android:id=\"@+id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        style=\"@style/CheckLabel\"\n        android:layout_gravity=\"center\"\n        tools:text=\"hello\" />\n    <ImageView\n        android:id=\"@+id/pinicon\"\n        android:layout_width=\"50dp\"\n        android:layout_height=\"24dp\"\n        android:layout_gravity=\"end|center_vertical\"\n        android:src=\"@drawable/pin_ic\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\"\n        tools:ignore=\"RtlHardcoded\" />\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/speed_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\r\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\r\n    xmlns:tools=\"http://schemas.android.com/tools\"\r\n    android:layout_width=\"500dp\"\r\n    android:layout_height=\"match_parent\"\r\n    android:orientation=\"vertical\">\r\n\r\n    <TextView\r\n        android:id=\"@+id/speed_text\"\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:layout_gravity=\"center_vertical\"\r\n        android:layout_margin=\"20dp\"\r\n        android:gravity=\"center_horizontal\"\r\n        android:text=\"1.00x\"\r\n        android:textSize=\"20sp\"\r\n        tools:ignore=\"HardcodedText\" />\r\n\r\n    <LinearLayout\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\">\r\n\r\n        <com.google.android.material.floatingactionbutton.FloatingActionButton\r\n            android:id=\"@+id/speed_minus\"\r\n            style=\"@style/ExtendedFloatingActionButton\"\r\n            android:layout_gravity=\"center_vertical\"\r\n\r\n            android:foreground=\"@drawable/outline_drawable\"\r\n            android:nextFocusLeft=\"@id/speed_plus\"\r\n            android:nextFocusRight=\"@id/speed_bar\"\r\n            android:nextFocusUp=\"@id/speed_minus\"\r\n            android:nextFocusDown=\"@id/speed_25\"\r\n            android:src=\"@drawable/media3_icon_minus\"\r\n            app:tint=\"?attr/textColor\" />\r\n\r\n        <com.google.android.material.slider.Slider\r\n            android:id=\"@+id/speed_bar\"\r\n            android:layout_width=\"0dp\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:layout_gravity=\"center\"\r\n            android:layout_weight=\"1\"\r\n            android:nextFocusLeft=\"@id/speed_minus\"\r\n            android:nextFocusRight=\"@id/speed_plus\"\r\n            android:nextFocusUp=\"@id/speed_bar\"\r\n            android:nextFocusDown=\"@id/speed_125\"\r\n            android:progressTint=\"?attr/white\"\r\n            android:stepSize=\"0.05\"\r\n            android:thumbTint=\"?attr/white\"\r\n            android:value=\"1.0\"\r\n            android:valueFrom=\"0.1\"\r\n            android:valueTo=\"2.0\"\r\n            app:labelStyle=\"@style/BlackLabel\"\r\n            app:thumbColor=\"?attr/white\"\r\n            app:tickVisible=\"false\"\r\n            app:trackColorActive=\"?attr/white\"\r\n            app:trackColorInactive=\"?attr/primaryGrayBackground\">\r\n\r\n            <requestFocus />\r\n        </com.google.android.material.slider.Slider>\r\n\r\n        <com.google.android.material.floatingactionbutton.FloatingActionButton\r\n            android:id=\"@+id/speed_plus\"\r\n            style=\"@style/ExtendedFloatingActionButton\"\r\n            android:layout_gravity=\"center_vertical\"\r\n            android:foreground=\"@drawable/outline_drawable\"\r\n            android:nextFocusLeft=\"@id/speed_bar\"\r\n            android:nextFocusRight=\"@id/speed_minus\"\r\n            android:nextFocusDown=\"@id/speed_200\"\r\n            android:src=\"@drawable/media3_icon_plus\"\r\n            app:tint=\"?attr/textColor\" />\r\n    </LinearLayout>\r\n\r\n    <LinearLayout\r\n        android:layout_width=\"match_parent\"\r\n        android:layout_height=\"wrap_content\"\r\n        android:layout_margin=\"14dp\">\r\n\r\n        <com.google.android.material.button.MaterialButton\r\n            android:id=\"@+id/speed_25\"\r\n            style=\"@style/BlackButton\"\r\n            android:layout_width=\"0dp\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:layout_weight=\"1\"\r\n            android:nextFocusLeft=\"@id/speed_200\"\r\n            android:nextFocusRight=\"@id/speed_100\"\r\n            android:nextFocusUp=\"@id/speed_minus\"\r\n            android:nextFocusDown=\"@id/speed_25\"\r\n            android:text=\"0.25x\"\r\n            tools:ignore=\"HardcodedText\" />\r\n\r\n        <com.google.android.material.button.MaterialButton\r\n            android:id=\"@+id/speed_100\"\r\n            style=\"@style/BlackButton\"\r\n            android:layout_width=\"0dp\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:layout_weight=\"1\"\r\n            android:nextFocusLeft=\"@id/speed_25\"\r\n            android:nextFocusRight=\"@id/speed_125\"\r\n            android:nextFocusUp=\"@id/speed_bar\"\r\n            android:nextFocusDown=\"@id/speed_100\"\r\n            android:text=\"1.0x\"\r\n            tools:ignore=\"HardcodedText\" />\r\n\r\n        <com.google.android.material.button.MaterialButton\r\n            android:id=\"@+id/speed_125\"\r\n            style=\"@style/BlackButton\"\r\n            android:layout_width=\"0dp\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:layout_weight=\"1\"\r\n            android:nextFocusLeft=\"@id/speed_100\"\r\n            android:nextFocusRight=\"@id/speed_150\"\r\n            android:nextFocusUp=\"@id/speed_bar\"\r\n            android:nextFocusDown=\"@id/speed_125\"\r\n            android:text=\"1.25x\"\r\n            tools:ignore=\"HardcodedText\" />\r\n\r\n        <com.google.android.material.button.MaterialButton\r\n            android:id=\"@+id/speed_150\"\r\n            style=\"@style/BlackButton\"\r\n            android:layout_width=\"0dp\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:layout_weight=\"1\"\r\n            android:nextFocusLeft=\"@id/speed_125\"\r\n            android:nextFocusRight=\"@id/speed_200\"\r\n            android:nextFocusUp=\"@id/speed_bar\"\r\n            android:nextFocusDown=\"@id/speed_150\"\r\n            android:text=\"1.5x\"\r\n            tools:ignore=\"HardcodedText\" />\r\n\r\n        <com.google.android.material.button.MaterialButton\r\n            android:id=\"@+id/speed_200\"\r\n            style=\"@style/BlackButton\"\r\n            android:layout_width=\"0dp\"\r\n            android:layout_height=\"wrap_content\"\r\n            android:layout_weight=\"1\"\r\n            android:nextFocusLeft=\"@id/speed_150\"\r\n            android:nextFocusRight=\"@id/speed_25\"\r\n            android:nextFocusUp=\"@id/speed_plus\"\r\n            android:nextFocusDown=\"@id/speed_200\"\r\n            android:text=\"2.0x\"\r\n            tools:ignore=\"HardcodedText\" />\r\n    </LinearLayout>\r\n\r\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/standard_toolbar.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.google.android.material.appbar.AppBarLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@android:color/transparent\">\n\n    <com.google.android.material.appbar.MaterialToolbar\n        android:id=\"@+id/settings_toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:background=\"?attr/primaryGrayBackground\"\n        android:descendantFocusability=\"afterDescendants\"\n        android:paddingTop=\"@dimen/navbar_height\"\n        app:layout_scrollFlags=\"scroll|enterAlways\"\n        app:navigationIconTint=\"?attr/iconColor\"\n        app:titleTextColor=\"?attr/textColor\"\n        tools:title=\"Overlord\" />\n</com.google.android.material.appbar.AppBarLayout>"
  },
  {
    "path": "app/src/main/res/layout/stream_input.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\">\n\n        <TextView\n            android:id=\"@+id/text1\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_rowWeight=\"1\"\n            android:layout_marginTop=\"20dp\"\n            android:layout_marginBottom=\"10dp\"\n            android:text=\"@string/stream\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\" />\n\n        <EditText\n            android:id=\"@+id/stream_url\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"20\"\n            android:autofillHints=\"no\"\n            android:hint=\"@string/network_adress_example\"\n            android:inputType=\"textUri\"\n            tools:ignore=\"LabelFor\" />\n\n        <EditText\n            android:id=\"@+id/stream_referer\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"20\"\n            android:autofillHints=\"no\"\n            android:hint=\"@string/referer\"\n            android:inputType=\"textUri\"\n            tools:ignore=\"LabelFor\" />\n\n        <com.google.android.material.switchmaterial.SwitchMaterial\n            android:id=\"@+id/hls_switch\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginTop=\"10dp\"\n            android:text=\"@string/hls_playlist\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"16sp\"\n            android:visibility=\"invisible\" />\n    </LinearLayout>\n\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:layout_gravity=\"bottom\"\n        android:gravity=\"bottom|end\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/home_play\"\n            android:visibility=\"visible\">\n\n            <requestFocus />\n        </com.google.android.material.button.MaterialButton>\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            style=\"@style/BlackButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:text=\"@string/sort_cancel\" />\n    </LinearLayout>\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/subtitle_offset.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:baselineAligned=\"false\"\n    android:orientation=\"horizontal\">\n\n    <FrameLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:id=\"@+id/no_subtitles_loaded_notice\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:textSize=\"18sp\"\n            android:textStyle=\"italic\"\n            android:alpha=\"0.7\"\n            android:text=\"@string/no_subtitles_loaded\">\n        </TextView>\n\n        <androidx.recyclerview.widget.RecyclerView\n            tools:visibility=\"gone\"\n            android:id=\"@+id/subtitle_offset_recyclerview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:paddingVertical=\"10dp\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            tools:listitem=\"@layout/subtitle_offset_item\">\n\n        </androidx.recyclerview.widget.RecyclerView>\n    </FrameLayout>\n\n    <LinearLayout\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\">\n\n        <LinearLayout\n            android:layout_width=\"410dp\"\n            android:layout_height=\"0dp\"\n            android:layout_gravity=\"center\"\n            android:layout_weight=\"1\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                style=\"@style/WatchHeaderText\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_margin=\"0dp\"\n                android:paddingTop=\"10dp\"\n                android:text=\"@string/subtitle_offset_title\" />\n\n            <TextView\n                android:id=\"@+id/subtitle_offset_sub_title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:textColor=\"?attr/grayTextColor\"\n                tools:text=\"@string/subtitle_offset_extra_hint_none_format\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\">\n\n                <ImageView\n                    android:id=\"@+id/subtitle_offset_subtract_more\"\n                    android:layout_width=\"44dp\"\n                    android:layout_height=\"44dp\"\n                    android:layout_gravity=\"center\"\n                    android:layout_marginStart=\"10dp\"\n                    android:layout_marginEnd=\"10dp\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:focusable=\"true\"\n                    android:nextFocusRight=\"@id/subtitle_offset_subtract\"\n                    android:padding=\"10dp\"\n                    android:src=\"@drawable/ic_baseline_keyboard_arrow_left_24\"\n                    app:tint=\"?attr/white\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <ImageView\n                    android:id=\"@+id/subtitle_offset_subtract\"\n                    android:layout_width=\"44dp\"\n                    android:layout_height=\"44dp\"\n                    android:layout_gravity=\"center\"\n                    android:layout_marginEnd=\"10dp\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:focusable=\"true\"\n                    android:nextFocusLeft=\"@id/subtitle_offset_subtract_more\"\n                    android:padding=\"10dp\"\n                    android:src=\"@drawable/baseline_remove_24\"\n                    app:tint=\"?attr/white\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <EditText\n                    android:id=\"@+id/subtitle_offset_input\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:autofillHints=\"no\"\n                    android:gravity=\"center\"\n                    android:hint=\"@string/subtitle_offset_hint\"\n                    android:inputType=\"numberSigned\"\n                    tools:ignore=\"LabelFor\" />\n\n                <ImageView\n                    android:id=\"@+id/subtitle_offset_add\"\n                    android:layout_width=\"44dp\"\n                    android:layout_height=\"44dp\"\n                    android:layout_gravity=\"center\"\n                    android:layout_marginStart=\"10dp\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:focusable=\"true\"\n                    android:nextFocusRight=\"@id/subtitle_offset_add_more\"\n                    android:padding=\"10dp\"\n                    android:src=\"@drawable/ic_baseline_add_24\"\n                    app:tint=\"?attr/white\"\n                    tools:ignore=\"ContentDescription\" />\n\n                <ImageView\n                    android:id=\"@+id/subtitle_offset_add_more\"\n                    android:layout_width=\"44dp\"\n                    android:layout_height=\"44dp\"\n                    android:layout_gravity=\"center\"\n                    android:layout_marginStart=\"10dp\"\n                    android:layout_marginEnd=\"10dp\"\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:focusable=\"true\"\n                    android:nextFocusLeft=\"@id/subtitle_offset_add\"\n                    android:nextFocusDown=\"@id/apply_btt\"\n                    android:padding=\"10dp\"\n\n                    android:src=\"@drawable/ic_baseline_keyboard_arrow_right_24\"\n                    app:tint=\"?attr/white\"\n                    tools:ignore=\"ContentDescription\" />\n            </LinearLayout>\n\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"60dp\"\n            android:layout_gravity=\"bottom\"\n            android:gravity=\"bottom|end\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/apply_btt\"\n                style=\"@style/WhiteButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/sort_apply\"\n                android:visibility=\"visible\">\n\n                <requestFocus />\n            </com.google.android.material.button.MaterialButton>\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/reset_btt\"\n                style=\"@style/BlackButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/reset_btn\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/cancel_btt\"\n                style=\"@style/BlackButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:text=\"@string/sort_cancel\" />\n        </LinearLayout>\n\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/subtitle_offset_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    android:background=\"?attr/selectableItemBackground\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <TextView\n        android:id=\"@+id/subtitle_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"2dp\"\n        android:ellipsize=\"end\"\n        android:lineSpacingMultiplier=\"1.1\"\n        android:paddingHorizontal=\"10dp\"\n        android:paddingVertical=\"6dp\"\n        android:textSize=\"18sp\"\n        android:textStyle=\"bold\"\n        tools:text=\"Long testing subtitle line 1\\nSubtitle line 2\" />\n\n\n    <androidx.core.widget.ContentLoadingProgressBar\n        android:id=\"@+id/subtitle_progress\"\n        style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"5dp\"\n        android:layout_gravity=\"bottom\"\n        android:max=\"1000\"\n        android:progressBackgroundTint=\"?attr/white\"\n        android:progressTint=\"?attr/white\"\n        android:visibility=\"gone\"\n        tools:progress=\"50\"\n        tools:visibility=\"visible\" />\n\n</LinearLayout>\n\n"
  },
  {
    "path": "app/src/main/res/layout/subtitle_settings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/subs_root\"\n    android:background=\"?attr/primaryBlackBackground\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <ScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_rowWeight=\"1\"\n                android:layout_marginTop=\"20dp\"\n                android:layout_marginBottom=\"10dp\"\n                android:paddingStart=\"20dp\"\n                android:paddingEnd=\"20dp\"\n                android:text=\"@string/subtitles_settings\"\n                android:textColor=\"?attr/textColor\"\n                android:textSize=\"20sp\"\n                android:textStyle=\"bold\" />\n\n            <FrameLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"75sp\">\n\n                <ImageView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:contentDescription=\"@string/preview_background_img_des\"\n                    android:scaleType=\"centerCrop\"\n                    android:src=\"@drawable/subtitles_preview_background\" />\n\n                <androidx.media3.ui.SubtitleView\n                    android:id=\"@+id/subtitle_text\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_gravity=\"center\"\n                    android:foregroundGravity=\"center\" />\n            </FrameLayout>\n\n            <TextView\n                android:id=\"@+id/subs_font\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusDown=\"@id/subs_font_size\"\n                android:text=\"@string/subs_font\" />\n\n            <TextView\n                android:id=\"@+id/subs_font_size\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_font\"\n                android:nextFocusDown=\"@id/subs_text_color\"\n                android:text=\"@string/subs_font_size\" />\n\n            <TextView\n                android:id=\"@+id/subs_text_color\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_font_size\"\n                android:nextFocusDown=\"@id/subs_outline_color\"\n                android:text=\"@string/subs_text_color\" />\n\n            <TextView\n                android:id=\"@+id/subs_outline_color\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_text_color\"\n                android:nextFocusDown=\"@id/subs_background_color\"\n                android:text=\"@string/subs_outline_color\" />\n\n            <TextView\n                android:id=\"@+id/subs_background_color\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_outline_color\"\n                android:nextFocusDown=\"@id/subs_background_radius\"\n                android:text=\"@string/subs_background_color\" />\n\n            <TextView\n                android:id=\"@+id/subs_background_radius\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_background_color\"\n                android:nextFocusDown=\"@id/subs_window_color\"\n                android:text=\"@string/background_radius\" />\n\n            <TextView\n                android:id=\"@+id/subs_window_color\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_background_radius\"\n                android:nextFocusDown=\"@id/subs_edge_type\"\n                android:text=\"@string/subs_window_color\" />\n\n            <TextView\n                android:id=\"@+id/subs_edge_type\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_window_color\"\n                android:nextFocusDown=\"@id/subs_edge_size\"\n                android:text=\"@string/subs_edge_type\" />\n\n            <TextView\n                android:id=\"@+id/subs_edge_size\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_edge_type\"\n                android:nextFocusDown=\"@id/subs_subtitle_alignment\"\n                android:text=\"@string/subs_edge_size\" />\n\n            <TextView\n                android:id=\"@+id/subs_subtitle_alignment\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_edge_size\"\n                android:nextFocusDown=\"@id/subs_subtitle_elevation\"\n                android:text=\"@string/subs_subtitle_alignment\" />\n\n            <TextView\n                android:id=\"@+id/subs_subtitle_elevation\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_subtitle_alignment\"\n                android:nextFocusDown=\"@id/subs_auto_select_language\"\n                android:text=\"@string/subs_subtitle_elevation\" />\n\n            <TextView\n                android:id=\"@+id/subs_auto_select_language\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_subtitle_elevation\"\n                android:nextFocusDown=\"@id/subs_download_languages\"\n                android:text=\"@string/subs_auto_select_language\" />\n\n            <TextView\n                android:id=\"@+id/subs_download_languages\"\n                style=\"@style/SettingsItem\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n\n                android:nextFocusUp=\"@id/subs_auto_select_language\"\n                android:nextFocusDown=\"@id/subtitles_remove_bloat\"\n                android:text=\"@string/subs_download_languages\" />\n\n            <com.google.android.material.switchmaterial.SwitchMaterial\n                android:id=\"@+id/subtitles_remove_bloat\"\n                style=\"@style/SettingsItem\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:fontFamily=\"@font/google_sans\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusUp=\"@id/subs_download_languages\"\n                android:nextFocusDown=\"@id/subtitles_remove_captions\"\n                android:text=\"@string/subtitles_remove_bloat\"\n                app:trackTint=\"@color/toggle_selector\"\n                app:drawableEndCompat=\"@null\" />\n\n            <com.google.android.material.switchmaterial.SwitchMaterial\n                android:id=\"@+id/subtitles_remove_captions\"\n                style=\"@style/SettingsItem\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:fontFamily=\"@font/google_sans\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusUp=\"@id/subtitles_remove_bloat\"\n                android:nextFocusDown=\"@id/subtitles_filter_sub_lang\"\n                android:text=\"@string/subtitles_remove_captions\"\n                app:trackTint=\"@color/toggle_selector\"\n                app:drawableEndCompat=\"@null\" />\n\n            <com.google.android.material.switchmaterial.SwitchMaterial\n                android:id=\"@+id/subtitles_filter_sub_lang\"\n                style=\"@style/SettingsItem\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:fontFamily=\"@font/google_sans\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusUp=\"@id/subtitles_remove_captions\"\n                android:nextFocusDown=\"@id/subtitles_uppercase\"\n                android:text=\"@string/subtitles_filter_lang\"\n                app:trackTint=\"@color/toggle_selector\"\n                app:drawableEndCompat=\"@null\" />\n\n            <com.google.android.material.switchmaterial.SwitchMaterial\n                android:id=\"@+id/subtitles_uppercase\"\n                style=\"@style/SettingsItem\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:fontFamily=\"@font/google_sans\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusUp=\"@id/subtitles_filter_sub_lang\"\n                android:nextFocusDown=\"@id/subtitles_bold\"\n                android:text=\"@string/uppercase_all_subtitles\"\n                app:trackTint=\"@color/toggle_selector\"\n                app:drawableEndCompat=\"@null\" />\n\n            <com.google.android.material.switchmaterial.SwitchMaterial\n                android:id=\"@+id/subtitles_bold\"\n                style=\"@style/SettingsItem\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:fontFamily=\"@font/google_sans\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusUp=\"@id/subtitles_uppercase\"\n                android:nextFocusDown=\"@id/subtitles_italic\"\n                android:text=\"@string/all_subtitles_bold\"\n                app:trackTint=\"@color/toggle_selector\"\n                app:drawableEndCompat=\"@null\" />\n\n            <com.google.android.material.switchmaterial.SwitchMaterial\n                android:id=\"@+id/subtitles_italic\"\n                style=\"@style/SettingsItem\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:fontFamily=\"@font/google_sans\"\n                android:nextFocusLeft=\"@id/apply_btt\"\n                android:nextFocusRight=\"@id/cancel_btt\"\n                android:nextFocusUp=\"@id/subtitles_bold\"\n                android:nextFocusDown=\"@id/apply_btt\"\n                android:text=\"@string/all_subtitles_italic\"\n                app:trackTint=\"@color/toggle_selector\"\n                app:drawableEndCompat=\"@null\" />\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_rowWeight=\"1\"\n\n                android:gravity=\"center\"\n                android:text=\"@string/subs_hold_to_reset_to_default\"\n                android:textColor=\"?attr/textColor\"\n                android:textSize=\"14sp\" />\n\n            <TextView\n                android:id=\"@+id/subs_import_text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_rowWeight=\"1\"\n                android:gravity=\"center\"\n                android:text=\"@string/subs_import_text\"\n                android:textColor=\"?attr/textColor\"\n                android:textSize=\"14sp\" />\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"60dp\"\n                android:layout_gravity=\"bottom\"\n                android:gravity=\"bottom|end\"\n                android:orientation=\"horizontal\">\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/apply_btt\"\n                    style=\"@style/WhiteButton\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical|end\"\n                    android:nextFocusRight=\"@id/cancel_btt\"\n                    android:nextFocusUp=\"@id/subtitles_italic\"\n                    android:text=\"@string/sort_apply\"\n                    android:visibility=\"visible\">\n\n                    <requestFocus />\n                </com.google.android.material.button.MaterialButton>\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/cancel_btt\"\n                    style=\"@style/BlackButton\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical|end\"\n                    android:nextFocusLeft=\"@id/apply_btt\"\n                    android:nextFocusUp=\"@id/subtitles_remove_captions\"\n                    android:text=\"@string/sort_cancel\" />\n            </LinearLayout>\n        </LinearLayout>\n    </ScrollView>\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/subtitle_settings_dialog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/subtitle_fragment_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/toast.xml",
    "content": "<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n        android:id=\"@+id/toast_layout_root\"\n        android:orientation=\"horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:padding=\"5dp\"\n        app:cardCornerRadius=\"10dp\"\n        app:cardBackgroundColor=\"?attr/primaryBlackBackground\"\n        android:background=\"?attr/primaryBlackBackground\">\n\n    <TextView\n            android:padding=\"20dp\"\n            android:id=\"@+id/text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:textColor=\"?attr/textColor\" />\n\n</androidx.cardview.widget.CardView>\n"
  },
  {
    "path": "app/src/main/res/layout/trailer_custom_layout.xml",
    "content": "<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/player_holder\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    tools:orientation=\"vertical\">\n\n    <ImageView\n        android:visibility=\"gone\"\n        android:id=\"@+id/video_outline\"\n        android:src=\"@drawable/video_outline\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n    </ImageView>\n\n\n    <TextView\n        android:id=\"@+id/player_time_text\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"200dp\"\n        android:gravity=\"center\"\n        android:shadowColor=\"@android:color/black\"\n        android:shadowRadius=\"10.0\"\n        android:textColor=\"@android:color/white\"\n        android:textSize=\"30sp\"\n        tools:text=\"+100\" />\n\n    <FrameLayout\n        android:id=\"@+id/subtitle_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <View\n            android:id=\"@+id/shadow_overlay\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/black_overlay\" />\n    </FrameLayout>\n\n\n    <FrameLayout\n        android:id=\"@+id/player_intro_play\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <!--     <View\n                     android:layout_width=\"match_parent\"\n                     android:layout_height=\"match_parent\"\n                     android:background=\"@drawable/player_gradient_tv\" />\n     -->\n\n        <!--\n        <ImageView\n            android:id=\"@+id/result_trailer_thumbnail\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center\"\n            android:scaleType=\"centerCrop\" />-->\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"60dp\"\n            android:layout_gravity=\"bottom\"\n            android:background=\"@drawable/background_shadow\" />\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"start|bottom\"\n            android:padding=\"15dp\"\n            android:text=\"@string/trailer\"\n            android:textColor=\"@android:color/white\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\" />\n\n        <ImageView\n            android:layout_width=\"60dp\"\n            android:layout_height=\"60dp\"\n            android:layout_gravity=\"center\"\n            android:src=\"@drawable/play_button\" />\n    </FrameLayout>\n\n    <FrameLayout\n        android:id=\"@+id/player_top_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:visibility=\"gone\">\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"80dp\"\n            android:layout_marginTop=\"20dp\"\n            android:layout_marginEnd=\"32dp\"\n            android:orientation=\"vertical\">\n\n            <LinearLayout\n                android:id=\"@+id/player_video_title_holder\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center\">\n                <TextView\n                    android:maxLines=\"2\"\n                    android:id=\"@+id/player_video_title\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"end\"\n                    android:textColor=\"@color/white\"\n                    android:textSize=\"16sp\"\n                    android:textStyle=\"bold\"\n                    tools:text=\"Hello world\" />\n                <TextView\n                    android:id=\"@+id/player_video_info\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginStart=\"6dp\"\n                    android:layout_marginBottom=\"2.5dp\"\n                    android:textColor=\"@color/white\"\n                    android:textSize=\"10sp\"\n                    android:visibility=\"gone\"\n                    tools:text=\"HDR10 • HEVC\" />\n                <ImageView\n                    android:id=\"@+id/offline_pin\"\n                    android:layout_width=\"16dp\"\n                    android:layout_height=\"16dp\"\n                    android:layout_marginStart=\"2dp\"\n                    android:src=\"@drawable/ic_offline_pin_24\"\n                    android:visibility=\"gone\"\n                    tools:visibility=\"visible\"\n                    android:layout_gravity=\"center\"/>\n            </LinearLayout>\n            <TextView\n                android:id=\"@+id/player_video_title_rez\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"end\"\n                android:textColor=\"@color/white\"\n                android:textSize=\"16sp\"\n                tools:text=\"1920x1080\" />\n\n            <FrameLayout\n                android:id=\"@+id/player_episode_filler_holder\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"end\"\n                android:layout_marginTop=\"2dp\"\n                android:visibility=\"gone\">\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/player_episode_filler\"\n                    style=\"@style/SmallBlackButton\"\n                    android:text=\"@string/filler\" />\n            </FrameLayout>\n        </LinearLayout>\n\n        <!-- Removed as it has no use anymore-->\n        <!--<androidx.mediarouter.app.MediaRouteButton\n                android:id=\"@+id/player_media_route_button\"\n                android:layout_width=\"70dp\"\n                android:layout_height=\"70dp\"\n                android:layout_gravity=\"end\"\n                android:layout_margin=\"5dp\"\n                android:mediaRouteTypes=\"user\"\n                android:visibility=\"visible\"\n                app:layout_constraintRight_toRightOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\" />-->\n\n        <LinearLayout\n            android:id=\"@+id/player_go_back_holder\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"20dp\"\n            app:layout_constraintStart_toStartOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\">\n\n            <LinearLayout\n                android:id=\"@+id/player_go_back_root\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"10dp\"\n                android:orientation=\"vertical\">\n\n                <ImageView\n                    android:id=\"@+id/player_go_back\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"@drawable/video_tap_button_always_white\"\n                    android:clickable=\"true\"\n                    android:contentDescription=\"@string/go_back_img_des\"\n                    android:focusable=\"true\"\n                    android:nextFocusLeft=\"@id/player_go_back\"\n                    android:nextFocusRight=\"@id/player_restart\"\n                    android:nextFocusUp=\"@id/player_go_back\"\n                    android:nextFocusDown=\"@id/player_pause_play\"\n                    android:src=\"@drawable/ic_baseline_arrow_back_24\"\n                    android:tag=\"@string/tv_no_focus_tag\"\n                    app:tint=\"@android:color/white\" />\n\n                <TextView\n                    android:id=\"@+id/player_go_back_text\"\n                    style=\"@style/ResultMarqueeButtonText\"\n                    android:text=\"@string/go_back_img_des\"\n                    android:visibility=\"gone\" />\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:id=\"@+id/player_restart_root\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"40dp\"\n                android:layout_marginEnd=\"10dp\"\n                android:orientation=\"vertical\">\n\n                <ImageView\n                    android:id=\"@+id/player_restart\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"@drawable/video_tap_button_always_white\"\n                    android:clickable=\"true\"\n                    android:contentDescription=\"@string/restart\"\n                    android:focusable=\"true\"\n                    android:nextFocusLeft=\"@id/player_go_back\"\n                    android:nextFocusRight=\"@id/player_go_forward\"\n                    android:nextFocusUp=\"@id/player_restart\"\n                    android:nextFocusDown=\"@id/player_pause_play\"\n                    android:src=\"@drawable/ic_baseline_replay_24\"\n                    android:tag=\"@string/tv_no_focus_tag\"\n                    app:tint=\"@android:color/white\" />\n\n                <TextView\n                    android:id=\"@+id/player_restart_text\"\n                    style=\"@style/ResultMarqueeButtonText\"\n                    android:text=\"@string/restart\"\n                    android:visibility=\"gone\" />\n\n            </LinearLayout>\n\n            <LinearLayout\n                android:id=\"@+id/player_go_forward_root\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"80dp\"\n                android:layout_marginEnd=\"10dp\"\n                android:orientation=\"vertical\">\n\n                <ImageView\n                    android:id=\"@+id/player_go_forward\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"@drawable/video_tap_button_always_white\"\n                    android:clickable=\"true\"\n                    android:contentDescription=\"@string/next_episode\"\n                    android:focusable=\"true\"\n                    android:nextFocusLeft=\"@id/player_restart\"\n                    android:nextFocusRight=\"@id/player_go_forward\"\n                    android:nextFocusUp=\"@id/player_go_forward\"\n                    android:nextFocusDown=\"@id/player_pause_play\"\n                    android:src=\"@drawable/ic_baseline_skip_next_rounded_24\"\n                    android:tag=\"@string/tv_no_focus_tag\"\n                    app:tint=\"@android:color/white\" />\n\n                <TextView\n                    android:id=\"@+id/player_go_forward_text\"\n                    style=\"@style/ResultMarqueeButtonText\"\n                    android:text=\"@string/next_episode\"\n                    android:visibility=\"gone\" />\n\n            </LinearLayout>\n\n        </LinearLayout>\n    </FrameLayout>\n\n\n    <androidx.constraintlayout.widget.ConstraintLayout\n        android:id=\"@+id/player_video_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/skip_chapter_button\"\n            style=\"@style/NiceButton\"\n            android:layout_width=\"150dp\"\n            android:layout_height=\"40dp\"\n            android:layout_marginEnd=\"100dp\"\n            android:backgroundTint=\"@color/skipOpTransparent\"\n            android:maxLines=\"1\"\n            android:padding=\"10dp\"\n            android:textColor=\"@color/white\"\n            android:visibility=\"gone\"\n            app:cornerRadius=\"@dimen/rounded_button_radius\"\n            app:layout_constraintBottom_toTopOf=\"@+id/bottom_player_bar\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:strokeColor=\"@color/white\"\n            app:strokeWidth=\"1dp\"\n            tools:text=\"Skip Opening\"\n            tools:visibility=\"visible\" />\n\n        <!--use for thinner app:trackThickness=\"3dp\" com.google.android.material.progressindicator.CircularProgressIndicator-->\n        <ProgressBar\n            android:id=\"@+id/player_buffering\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n\n            android:clickable=\"false\"\n            android:focusable=\"false\"\n            android:focusableInTouchMode=\"false\"\n\n            android:indeterminate=\"true\"\n            android:visibility=\"gone\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintRight_toRightOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            tools:visibility=\"visible\" />\n\n\n        <androidx.constraintlayout.widget.ConstraintLayout\n            android:id=\"@+id/player_center_menu\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"100dp\"\n            android:layout_gravity=\"center\"\n            android:gravity=\"center\"\n            android:orientation=\"horizontal\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintRight_toRightOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\">\n\n            <FrameLayout\n                android:id=\"@+id/player_rew_holder\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|start\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toLeftOf=\"parent\"\n                app:layout_constraintRight_toLeftOf=\"@id/player_ffwd_holder\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                app:layout_constraintWidth_percent=\"0.5\">\n\n                <TextView\n                    android:id=\"@+id/exo_rew_text\"\n                    android:layout_width=\"200dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_gravity=\"center\"\n\n                    android:gravity=\"center\"\n                    android:textColor=\"@color/white\"\n                    android:textSize=\"19sp\"\n\n                    android:textStyle=\"bold\"\n                    tools:text=\"10\" />\n\n                <ImageButton\n                    android:id=\"@id/player_rew\"\n                    android:layout_width=\"70dp\"\n                    android:layout_height=\"70dp\"\n                    android:layout_gravity=\"center\"\n\n                    android:background=\"@drawable/video_tap_button_skip\"\n                    android:nextFocusLeft=\"@id/player_rew\"\n                    android:nextFocusUp=\"@id/player_go_back\"\n                    android:nextFocusDown=\"@id/player_lock\"\n                    android:padding=\"10dp\"\n                    android:scaleType=\"fitCenter\"\n                    android:scaleX=\"-1\"\n                    android:src=\"@drawable/netflix_skip_forward\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"@color/white\"\n                    tools:ignore=\"ContentDescription\" />\n            </FrameLayout>\n            <!-- This nested layout is necessary because of buffering and clicking-->\n            <FrameLayout\n                android:id=\"@+id/player_pause_play_holder_holder\"\n                android:layout_width=\"100dp\"\n                android:layout_height=\"100dp\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toLeftOf=\"parent\"\n                app:layout_constraintRight_toRightOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\">\n\n                <ImageView\n                    android:id=\"@+id/player_pause_play\"\n                    android:layout_width=\"70dp\"\n                    android:layout_height=\"70dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"@drawable/video_tap_button\"\n                    android:nextFocusLeft=\"@id/player_rew\"\n\n                    android:nextFocusRight=\"@id/player_ffwd\"\n\n                    android:nextFocusUp=\"@id/player_go_back\"\n                    android:nextFocusDown=\"@id/player_lock\"\n\n                    android:src=\"@drawable/netflix_pause\"\n                    app:tint=\"@color/white\"\n                    tools:ignore=\"ContentDescription\" />\n            </FrameLayout>\n\n            <FrameLayout\n                android:id=\"@+id/player_ffwd_holder\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|end\"\n                app:layout_constraintBottom_toBottomOf=\"parent\"\n                app:layout_constraintLeft_toRightOf=\"@id/player_rew_holder\"\n                app:layout_constraintRight_toRightOf=\"parent\"\n                app:layout_constraintTop_toTopOf=\"parent\"\n                app:layout_constraintWidth_percent=\"0.5\">\n\n                <TextView\n                    android:id=\"@+id/exo_ffwd_text\"\n                    android:layout_width=\"200dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_gravity=\"center\"\n                    android:gravity=\"center\"\n                    android:textColor=\"@color/white\"\n                    android:textSize=\"19sp\"\n                    android:textStyle=\"bold\"\n                    tools:text=\"10\" />\n\n                <ImageButton\n                    android:id=\"@id/player_ffwd\"\n                    android:layout_width=\"70dp\"\n                    android:layout_height=\"70dp\"\n                    android:layout_gravity=\"center\"\n\n                    android:background=\"@drawable/video_tap_button_skip\"\n                    android:nextFocusRight=\"@id/player_rew\"\n                    android:nextFocusUp=\"@id/player_go_back\"\n                    android:nextFocusDown=\"@id/player_lock\"\n                    android:padding=\"10dp\"\n                    android:scaleType=\"fitCenter\"\n                    android:src=\"@drawable/netflix_skip_forward\"\n                    android:tintMode=\"src_in\"\n                    app:tint=\"@color/white\"\n                    tools:ignore=\"ContentDescription\" />\n            </FrameLayout>\n\n            <LinearLayout\n                android:visibility=\"gone\"\n                android:id=\"@+id/download_both_header\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\">\n\n                <FrameLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\">\n\n                    <ImageView\n                        android:id=\"@+id/download_header_toggle\"\n                        android:layout_width=\"40dp\"\n                        android:layout_height=\"40dp\"\n                        android:layout_gravity=\"center_vertical|end\"\n                        android:layout_marginEnd=\"60dp\"\n                        android:background=\"@drawable/video_tap_button_always_white\"\n                        android:padding=\"10dp\"\n                        android:src=\"@drawable/baseline_downloading_24\"\n                        app:tint=\"@color/white\">\n\n                    </ImageView>\n\n                    <androidx.cardview.widget.CardView\n                        android:id=\"@+id/download_header\"\n                        android:layout_width=\"200dp\"\n                        android:layout_height=\"80dp\"\n                        android:layout_gravity=\"end|center_vertical\"\n                        android:layout_margin=\"10dp\"\n                        android:elevation=\"10dp\"\n                        app:cardBackgroundColor=\"@color/darkBar\"\n                        app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n                        <LinearLayout\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"match_parent\"\n                            android:layout_margin=\"10dp\"\n                            android:gravity=\"end|center_vertical\"\n                            android:orientation=\"vertical\">\n\n                            <TextView\n                                android:id=\"@+id/download_header_toggle_text\"\n                                style=\"@style/ResultMarqueeButtonText\"\n                                android:layout_marginTop=\"5dp\"\n                                android:text=\"@string/torrent_singular\"\n                                android:visibility=\"gone\" />\n\n                            <TextView\n                                android:id=\"@+id/downloaded_progress_text\"\n                                android:layout_width=\"wrap_content\"\n                                android:layout_height=\"wrap_content\"\n                                android:textColor=\"@color/white\"\n                                tools:text=\"10MB / 20MB\" />\n\n                            <TextView\n                                android:id=\"@+id/downloaded_progress_speed_text\"\n                                android:layout_width=\"wrap_content\"\n                                android:layout_height=\"wrap_content\"\n                                android:textColor=\"@color/white\"\n                                tools:text=\"10MB/s - 12 seeders\" />\n\n                            <com.google.android.material.progressindicator.LinearProgressIndicator\n                                android:id=\"@+id/downloaded_progress\"\n                                style=\"@style/RoundProgressbar\"\n                                android:layout_width=\"match_parent\"\n                                android:layout_height=\"wrap_content\"\n                                android:layout_marginTop=\"5dp\"\n                                android:indeterminate=\"false\"\n                                android:indeterminateTint=\"?attr/colorPrimary\"\n                                android:progressBackgroundTint=\"?attr/colorPrimary\"\n                                android:progressTint=\"?attr/colorPrimary\"\n                                tools:progress=\"20\" />\n\n                        </LinearLayout>\n                    </androidx.cardview.widget.CardView>\n                </FrameLayout>\n\n            </LinearLayout>\n\n        </androidx.constraintlayout.widget.ConstraintLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"bottom\"\n            android:layout_marginBottom=\"20dp\"\n            android:gravity=\"center\"\n            android:orientation=\"horizontal\"\n            android:paddingTop=\"4dp\"\n            android:visibility=\"gone\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintEnd_toEndOf=\"parent\">\n\n            <ImageButton\n                android:id=\"@id/exo_prev\"\n                style=\"@style/ExoMediaButton.Previous\"\n                android:tintMode=\"src_in\"\n                app:tint=\"?attr/colorPrimaryDark\"\n                tools:ignore=\"ContentDescription\" />\n\n\n            <ImageButton\n                android:id=\"@id/exo_repeat_toggle\"\n                style=\"@style/ExoMediaButton\"\n                android:tintMode=\"src_in\"\n                app:tint=\"?attr/colorPrimaryDark\"\n                tools:ignore=\"ContentDescription\" />\n\n\n            <ImageButton\n                android:id=\"@id/exo_next\"\n                style=\"@style/ExoMediaButton.Next\"\n                android:tintMode=\"src_in\"\n                app:tint=\"?attr/colorPrimaryDark\"\n                tools:ignore=\"ContentDescription\" />\n\n            <ImageButton\n                android:id=\"@id/exo_vr\"\n                style=\"@style/ExoMediaButton.VR\"\n                android:tintMode=\"src_in\"\n                app:tint=\"?attr/colorPrimaryDark\"\n                tools:ignore=\"ContentDescription\" />\n\n            <ImageButton\n                android:id=\"@id/exo_play\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"0dp\"\n                android:tintMode=\"src_in\"\n                app:tint=\"?attr/colorPrimaryDark\"\n                tools:ignore=\"ContentDescription\" />\n\n            <ImageButton\n                android:id=\"@id/exo_pause\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"0dp\"\n                android:tintMode=\"src_in\"\n                app:tint=\"?attr/colorPrimaryDark\"\n                tools:ignore=\"ContentDescription\" />\n        </LinearLayout>\n\n        <FrameLayout\n            android:id=\"@+id/piphide\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n\n        <ImageView\n            android:id=\"@+id/player_open_source\"\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:layout_margin=\"20dp\"\n            android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n            android:src=\"@drawable/ic_baseline_public_24\"\n            app:layout_constraintEnd_toEndOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            app:tint=\"@color/white\" />\n\n        <LinearLayout\n            android:id=\"@+id/bottom_player_bar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"10dp\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintEnd_toEndOf=\"parent\">\n\n            <androidx.constraintlayout.widget.ConstraintLayout\n                android:id=\"@+id/player_video_bar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layoutDirection=\"ltr\"\n                android:orientation=\"horizontal\">\n\n                <TextView\n                    android:id=\"@id/exo_position\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center\"\n                    android:layout_marginStart=\"20dp\"\n                    android:gravity=\"end|center_vertical\"\n                    android:includeFontPadding=\"false\"\n                    android:minWidth=\"50dp\"\n                    android:paddingLeft=\"4dp\"\n                    android:paddingRight=\"4dp\"\n                    android:textColor=\"@android:color/white\"\n                    android:textSize=\"14sp\"\n                    android:textStyle=\"normal\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:layout_constraintStart_toStartOf=\"parent\"\n                    tools:text=\"15:30\" />\n\n                <FrameLayout\n                    android:id=\"@+id/previewFrameLayout\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"0dp\"\n                    android:layout_marginStart=\"16dp\"\n                    android:layout_marginEnd=\"16dp\"\n                    android:layout_marginBottom=\"16dp\"\n                    android:background=\"@drawable/video_frame\"\n                    android:visibility=\"invisible\"\n                    app:layout_constraintBottom_toTopOf=\"@+id/exo_progress\"\n                    app:layout_constraintDimensionRatio=\"16:9\"\n                    app:layout_constraintEnd_toEndOf=\"parent\"\n                    app:layout_constraintHorizontal_bias=\"0.0\"\n                    app:layout_constraintStart_toStartOf=\"parent\"\n                    app:layout_constraintWidth_default=\"percent\"\n                    app:layout_constraintWidth_percent=\"0.25\"\n                    tools:visibility=\"visible\">\n\n                    <ImageView\n                        android:id=\"@+id/previewImageView\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:layout_margin=\"@dimen/video_frame_width\"\n                        android:importantForAccessibility=\"no\"\n                        android:scaleType=\"centerCrop\" />\n                </FrameLayout>\n\n                <com.github.rubensousa.previewseekbar.media3.PreviewTimeBar\n                    android:id=\"@id/exo_progress\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_weight=\"1\"\n                    app:bar_height=\"2dp\"\n                    app:layout_constraintBottom_toBottomOf=\"@id/exo_position\"\n                    app:layout_constraintEnd_toStartOf=\"@id/exo_duration\"\n                    app:layout_constraintStart_toEndOf=\"@+id/exo_position\"\n                    app:played_color=\"?attr/colorPrimary\"\n\n                    app:scrubber_color=\"?attr/colorPrimary\"\n                    app:scrubber_dragged_size=\"26dp\"\n                    app:scrubber_enabled_size=\"24dp\"\n                    app:unplayed_color=\"@color/videoProgress\" />\n\n                <TextView\n                    android:id=\"@id/exo_duration\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center|center_vertical\"\n\n                    android:layout_marginEnd=\"30dp\"\n                    android:includeFontPadding=\"false\"\n                    android:minWidth=\"50dp\"\n                    android:paddingLeft=\"4dp\"\n                    android:paddingRight=\"4dp\"\n                    android:textColor=\"@android:color/white\"\n                    android:textSize=\"14sp\"\n                    android:textStyle=\"normal\"\n                    app:layout_constraintBaseline_toBaselineOf=\"@id/exo_position\"\n                    app:layout_constraintEnd_toEndOf=\"@id/player_fullscreen\"\n                    tools:text=\"23:20\" />\n\n                <TextView\n                    android:id=\"@+id/time_left\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"30dp\"\n                    android:layout_gravity=\"center|center_vertical\"\n\n                    android:layout_marginEnd=\"30dp\"\n                    android:includeFontPadding=\"false\"\n                    android:minWidth=\"50dp\"\n                    android:paddingLeft=\"4dp\"\n                    android:paddingRight=\"4dp\"\n                    android:textColor=\"@android:color/white\"\n                    android:textSize=\"14sp\"\n                    android:textStyle=\"normal\"\n                    android:visibility=\"gone\"\n                    app:layout_constraintBaseline_toBaselineOf=\"@id/exo_position\"\n                    app:layout_constraintEnd_toEndOf=\"@id/player_fullscreen\"\n                    tools:text=\"-23:20\" />\n\n                <ImageView\n                    android:id=\"@+id/player_fullscreen\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_marginEnd=\"20dp\"\n\n                    android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                    android:src=\"@drawable/baseline_fullscreen_24\"\n                    app:layout_constraintBottom_toBottomOf=\"parent\"\n                    app:layout_constraintEnd_toEndOf=\"parent\"\n                    app:tint=\"@color/white\" />\n            </androidx.constraintlayout.widget.ConstraintLayout>\n\n\n            <HorizontalScrollView\n                android:id=\"@+id/player_controls_scroll\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:visibility=\"gone\">\n\n                <LinearLayout\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"60dp\"\n                    android:gravity=\"center\"\n                    android:orientation=\"horizontal\"\n                    android:paddingTop=\"10dp\"\n                    android:paddingBottom=\"10dp\">\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/player_rotate_btt\"\n                        style=\"@style/VideoButton\" />\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/player_lock\"\n                        style=\"@style/VideoButton\"\n                        android:nextFocusLeft=\"@id/player_skip_episode\"\n                        android:nextFocusRight=\"@id/player_resize_btt\"\n                        android:text=\"@string/video_lock\"\n                        app:icon=\"@drawable/video_locked\"\n\n                        app:iconSize=\"30dp\" />\n\n                    <LinearLayout\n                        android:id=\"@+id/player_lock_holder\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"match_parent\"\n                        android:orientation=\"horizontal\">\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_resize_btt\"\n                            style=\"@style/VideoButton\"\n                            android:nextFocusLeft=\"@id/player_lock\"\n\n                            android:nextFocusRight=\"@id/player_speed_btt\"\n                            android:text=\"@string/video_aspect_ratio_resize\"\n                            app:icon=\"@drawable/ic_baseline_aspect_ratio_24\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_speed_btt\"\n                            style=\"@style/VideoButton\"\n                            android:nextFocusLeft=\"@id/player_resize_btt\"\n\n                            android:nextFocusRight=\"@id/player_subtitle_offset_btt\"\n                            app:icon=\"@drawable/ic_baseline_speed_24\"\n                            tools:text=\"Speed\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_subtitle_offset_btt\"\n                            style=\"@style/VideoButton\"\n                            android:nextFocusLeft=\"@id/player_speed_btt\"\n                            android:nextFocusRight=\"@id/player_sources_btt\"\n                            android:text=\"@string/subtitle_offset\"\n\n                            android:visibility=\"gone\"\n                            app:icon=\"@drawable/ic_outline_subtitles_24\"\n                            tools:visibility=\"visible\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_sources_btt\"\n                            style=\"@style/VideoButton\"\n                            android:layout_height=\"40dp\"\n\n                            android:nextFocusLeft=\"@id/player_subtitle_offset_btt\"\n                            android:nextFocusRight=\"@id/player_tracks_btt\"\n                            android:text=\"@string/video_source\"\n                            app:icon=\"@drawable/ic_baseline_playlist_play_24\" />\n\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_tracks_btt\"\n                            style=\"@style/VideoButton\"\n                            android:layout_height=\"40dp\"\n\n                            android:nextFocusLeft=\"@id/player_sources_btt\"\n                            android:nextFocusRight=\"@id/player_skip_op\"\n                            android:text=\"@string/tracks\"\n                            app:icon=\"@drawable/ic_baseline_playlist_play_24\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_skip_op\"\n                            style=\"@style/VideoButton\"\n                            android:nextFocusLeft=\"@id/player_sources_btt\"\n\n                            android:nextFocusRight=\"@id/player_skip_episode\"\n                            android:text=\"@string/video_skip_op\"\n                            app:icon=\"@drawable/ic_baseline_fast_forward_24\" />\n\n                        <com.google.android.material.button.MaterialButton\n                            android:id=\"@+id/player_skip_episode\"\n                            style=\"@style/VideoButton\"\n                            android:nextFocusLeft=\"@id/player_skip_op\"\n\n                            android:nextFocusRight=\"@id/player_lock\"\n                            android:text=\"@string/next_episode\"\n                            app:icon=\"@drawable/ic_baseline_skip_next_24\" />\n                    </LinearLayout>\n                </LinearLayout>\n            </HorizontalScrollView>\n\n        </LinearLayout>\n\n    </androidx.constraintlayout.widget.ConstraintLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"horizontal\">\n\n        <RelativeLayout\n            android:id=\"@+id/player_progressbar_left_holder\"\n            android:layout_width=\"100dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:gravity=\"start\"\n            android:visibility=\"gone\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintLeft_toLeftOf=\"parent\"\n            app:layout_constraintRight_toLeftOf=\"@+id/centerMenuView\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            tools:alpha=\"1\"\n            tools:visibility=\"visible\">\n            <!--VERY hacky layout -->\n            <ImageView\n                android:id=\"@+id/player_progressbar_left_icon\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_marginBottom=\"220dp\"\n                android:src=\"@drawable/ic_baseline_volume_up_24\"\n                app:tint=\"@android:color/white\"\n                tools:ignore=\"ContentDescription\">\n\n            </ImageView>\n\n            <ProgressBar\n                android:id=\"@+id/player_progressbar_left_level1\"\n                android:layout_width=\"4dp\"\n                android:layout_height=\"150dp\"\n                android:layout_centerInParent=\"true\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginStart=\"40dp\"\n                android:indeterminate=\"false\"\n                android:max=\"100\"\n                android:progress=\"100\"\n                android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                android:progressTint=\"@color/white\"\n                android:progressTintMode=\"src_in\"\n                tools:progress=\"30\"\n                style=\"@android:style/Widget.Material.ProgressBar.Horizontal\" />\n\n            <ProgressBar\n                android:id=\"@+id/player_progressbar_left_level2\"\n                android:layout_width=\"4dp\"\n                android:layout_height=\"150dp\"\n                android:layout_centerInParent=\"true\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginStart=\"40dp\"\n                android:indeterminate=\"false\"\n                android:max=\"100\"\n                android:progress=\"0\"\n                android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                android:progressTint=\"@color/colorPrimaryOrange\"\n                android:progressTintMode=\"src_in\"\n                tools:progress=\"0\"\n                style=\"@android:style/Widget.Material.ProgressBar.Horizontal\" />\n        </RelativeLayout>\n\n        <RelativeLayout\n            android:id=\"@+id/player_progressbar_right_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:gravity=\"right\"\n            android:visibility=\"gone\"\n            app:layout_constraintBottom_toBottomOf=\"parent\"\n            app:layout_constraintLeft_toRightOf=\"@+id/centerMenuView\"\n            app:layout_constraintRight_toRightOf=\"parent\"\n            app:layout_constraintTop_toTopOf=\"parent\"\n            tools:alpha=\"1\"\n            tools:ignore=\"RtlHardcoded\"\n            tools:visibility=\"visible\">\n\n            <ImageView\n                android:id=\"@+id/player_progressbar_right_icon\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_marginBottom=\"220dp\"\n                android:src=\"@drawable/ic_baseline_brightness_7_24\"\n                app:tint=\"@android:color/white\"\n                tools:ignore=\"ContentDescription\">\n\n            </ImageView>\n\n            <ProgressBar\n                android:id=\"@+id/player_progressbar_right_level1\"\n                style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n                android:layout_width=\"4dp\"\n                android:layout_height=\"150dp\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_centerVertical=\"true\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginEnd=\"40dp\"\n                android:indeterminate=\"false\"\n                android:max=\"100\"\n                android:progress=\"100\"\n                android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                android:progressTint=\"@color/white\"\n                android:progressTintMode=\"src_in\" />\n\n            <ProgressBar\n                android:id=\"@+id/player_progressbar_right_level2\"\n                style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n                android:layout_width=\"4dp\"\n                android:layout_height=\"150dp\"\n                android:layout_centerHorizontal=\"true\"\n                android:layout_centerVertical=\"true\"\n                android:layout_gravity=\"end|center_vertical\"\n                android:layout_marginEnd=\"40dp\"\n                android:indeterminate=\"false\"\n                android:max=\"100\"\n                android:progress=\"0\"\n                android:progressDrawable=\"@drawable/progress_drawable_vertical\"\n                android:progressTint=\"@color/colorPrimaryOrange\"\n                android:progressTintMode=\"src_in\" />\n        </RelativeLayout>\n    </LinearLayout>\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/player_speedup_button\"\n        style=\"@style/Widget.MaterialComponents.Button.OutlinedButton\"\n        android:layout_width=\"45dp\"\n        android:layout_height=\"45dp\"\n        android:layout_gravity=\"center_horizontal\"\n        android:layout_marginTop=\"30dp\"\n        app:iconPadding=\"0dp\"\n        app:iconGravity=\"textStart\"\n        android:clickable=\"false\"\n        android:focusable=\"false\"\n        android:textAllCaps=\"false\"\n        android:visibility=\"gone\"\n        app:icon=\"@drawable/speedup\"\n        app:iconTint=\"@color/textColor\"\n        android:foreground=\"@null\"\n        android:backgroundTint=\"@color/skipOpTransparent\"\n        tools:visibility=\"visible\" />\n\n    <LinearLayout\n        android:id=\"@+id/player_episodes_button_root\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:layout_gravity=\"end|center_vertical\"\n        android:visibility=\"gone\"\n        >\n        <ImageView\n            android:padding=\"15dp\"\n            android:id=\"@+id/player_episodes_button\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:foregroundGravity=\"center\"\n            android:src=\"@drawable/ic_baseline_arrow_back_ios_24\"\n            android:background=\"@drawable/video_tap_button_always_white\"\n            app:tint=\"@android:color/white\"\n            tools:ignore=\"ContentDescription\" />\n        <TextView\n            android:id=\"@+id/player_episodes_button_text\"\n            style=\"@style/ResultMarqueeButtonText\"\n            android:layout_marginTop=\"5dp\"\n            android:text=\"@string/episodes\"\n            android:visibility=\"invisible\"\n            tools:visibility=\"visible\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/player_episode_overlay\"\n        android:visibility=\"gone\"\n        android:padding=\"5dp\"\n        android:background=\"?attr/primaryBlackBackground\"\n        android:orientation=\"vertical\"\n        android:layout_gravity=\"end\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\">\n\n        <TextView\n            android:id=\"@+id/player_episode_overlay_title\"\n            android:padding=\"10dp\"\n            style=\"@style/WatchHeaderText\"\n            android:textSize=\"15sp\"\n            android:layout_marginEnd=\"0dp\"\n            android:text=\"@string/episodes\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"/>\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:requiresFadingEdge=\"vertical\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            android:id=\"@+id/player_episode_list\"\n            tools:listitem=\"@layout/player_episodes\"\n            android:nextFocusLeft=\"@id/player_episodes_button\"\n            android:layout_width=\"400dp\"\n            android:layout_height=\"match_parent\"\n            android:clipToPadding=\"false\"\n            android:descendantFocusability=\"afterDescendants\">\n\n        </androidx.recyclerview.widget.RecyclerView>\n    </LinearLayout>\n\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/tvtypes_chips.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<com.google.android.material.chip.ChipGroup android:layout_width=\"match_parent\"\n    style=\"@style/ChipParent\"\n    android:layout_height=\"wrap_content\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:paddingStart=\"8dp\"\n    android:paddingEnd=\"8dp\"\n    android:id=\"@+id/home_select_group\"\n    android:descendantFocusability=\"afterDescendants\"\n    app:singleSelection=\"false\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_movies\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/movies\" />\n\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_tv_series\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/tv_series\" />\n\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_anime\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/anime\" />\n\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_asian\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/asian_drama\" />\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_cartoons\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/cartoons\" />\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_documentaries\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/documentaries\" />\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_livestreams\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/livestreams\" />\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_torrents\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/torrent\" />\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_nsfw\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/nsfw\" />\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/home_select_others\"\n        style=\"@style/ChipFilled\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/others\" />\n</com.google.android.material.chip.ChipGroup>"
  },
  {
    "path": "app/src/main/res/layout/tvtypes_chips_scroll.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<HorizontalScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/tv_types_scroll_view\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:fadingEdge=\"horizontal\"\n    android:requiresFadingEdge=\"horizontal\">\n\n    <include\n        android:descendantFocusability=\"afterDescendants\"\n        android:id=\"@+id/tvtypes_chips\"\n        layout=\"@layout/tvtypes_chips\" />\n</HorizontalScrollView>"
  },
  {
    "path": "app/src/main/res/layout/view_test.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<androidx.cardview.widget.CardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.Material3.CardView.Elevated\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    app:cardBackgroundColor=\"?attr/primaryBlackBackground\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingBottom=\"10dp\">\n\n        <LinearLayout\n            android:id=\"@+id/main_test_section\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@drawable/outline_drawable_less\"\n            android:gravity=\"center\"\n            android:orientation=\"horizontal\"\n            android:paddingHorizontal=\"10dp\"\n            android:paddingVertical=\"10dp\">\n\n            <TextView\n                android:id=\"@+id/main_test_header\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:textSize=\"17sp\"\n                tools:text=\"Homepage test\" />\n\n            <TextView\n                android:id=\"@+id/main_test_section_progress\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:gravity=\"end\"\n                android:textSize=\"17sp\"\n                tools:text=\"67 / 120 \" />\n        </LinearLayout>\n\n        <androidx.cardview.widget.CardView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"10dp\"\n            app:cardBackgroundColor=\"?attr/primaryGrayBackground\"\n            app:cardCornerRadius=\"@dimen/rounded_image_radius\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:orientation=\"vertical\">\n\n                <LinearLayout\n                    android:id=\"@+id/passed_test_section\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:background=\"@drawable/outline_drawable_less\"\n                    android:gravity=\"center\"\n                    android:orientation=\"horizontal\"\n                    android:padding=\"10dp\">\n\n                    <TextView\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_weight=\"1\"\n                        android:text=\"Tests passed\"\n                        android:textSize=\"17sp\" />\n\n                    <TextView\n                        android:id=\"@+id/passed_test_section_progress\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_weight=\"1\"\n                        android:gravity=\"end\"\n                        android:textSize=\"17sp\"\n                        tools:text=\"55\" />\n                </LinearLayout>\n\n                <LinearLayout\n                    android:id=\"@+id/failed_test_section\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:background=\"@drawable/outline_drawable_less\"\n                    android:gravity=\"center\"\n                    android:orientation=\"horizontal\"\n                    android:padding=\"10dp\">\n\n                    <TextView\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_weight=\"1\"\n                        android:text=\"Tests failed\"\n                        android:textSize=\"17sp\" />\n\n                    <TextView\n                        android:id=\"@+id/failed_test_section_progress\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_weight=\"1\"\n                        android:gravity=\"end\"\n                        android:textSize=\"17sp\"\n                        tools:text=\"12\" />\n                </LinearLayout>\n\n            </LinearLayout>\n\n\n        </androidx.cardview.widget.CardView>\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/tests_play_pause\"\n            style=\"@style/WhiteButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_margin=\"10dp\"\n            android:text=\"@string/start\"\n            app:icon=\"@drawable/ic_baseline_play_arrow_24\">\n\n        </com.google.android.material.button.MaterialButton>\n\n    </LinearLayout>\n\n\n    <androidx.core.widget.ContentLoadingProgressBar\n        android:id=\"@+id/test_total_progress\"\n        style=\"@android:style/Widget.Material.ProgressBar.Horizontal\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"5dp\"\n        android:layout_gravity=\"bottom\"\n        android:layout_marginBottom=\"-1.5dp\"\n        android:progressBackgroundTint=\"?attr/colorPrimary\"\n        android:progressTint=\"?attr/colorPrimary\"\n        android:visibility=\"gone\"\n        tools:progress=\"50\" />\n\n</androidx.cardview.widget.CardView>\n"
  },
  {
    "path": "app/src/main/res/layout-port/player_select_source_and_subs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"8dp\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <LinearLayout\n            android:id=\"@+id/sort_sources_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:layout_marginBottom=\"8dp\"\n            android:orientation=\"vertical\">\n\n            <LinearLayout\n                android:id=\"@+id/profiles_click_settings\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:orientation=\"horizontal\"\n                android:padding=\"10dp\">\n\n                <TextView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:text=\"@string/pick_source\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"20sp\"\n                    android:textStyle=\"bold\" />\n\n                <TextView\n                    android:id=\"@+id/source_settings_btt\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center\"\n                    android:minWidth=\"140dp\"\n                    android:paddingHorizontal=\"10dp\"\n                    android:textColor=\"?attr/textColor\"\n                    android:textSize=\"15sp\"\n                    app:drawableEndCompat=\"@drawable/ic_outline_settings_24\"\n                    tools:text=\"@string/profile_number\" />\n            </LinearLayout>\n\n            <ListView\n                android:id=\"@+id/sort_providers\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:layout_weight=\"1\"\n                android:background=\"?attr/primaryBlackBackground\"\n                android:listSelector=\"@drawable/outline_drawable_forced\"\n                android:requiresFadingEdge=\"vertical\"\n                tools:listitem=\"@layout/sort_bottom_single_choice\" />\n        </LinearLayout>\n\n        <LinearLayout\n            android:id=\"@+id/sort_subtitles_holder\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                android:gravity=\"center_vertical\"\n                android:padding=\"10dp\">\n\n                <LinearLayout\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:orientation=\"horizontal\"\n                    android:gravity=\"center_vertical\">\n\n                    <TextView\n                        android:id=\"@+id/subtitles_text\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"@string/pick_subtitle\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"20sp\"\n                        android:textStyle=\"bold\" />\n\n                    <TextView\n                        android:id=\"@+id/subtitles_encoding_format\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_marginStart=\"8dp\"\n                        android:layout_marginTop=\"3dp\"\n                        android:textColor=\"?attr/textColor\"\n                        android:textSize=\"14sp\"\n                        android:ellipsize=\"end\"\n                        android:singleLine=\"true\"\n                        tools:text=\"Thai (TIS 620-2533/ISO 8859-11)\" />\n                </LinearLayout>\n\n                <ImageView\n                    android:id=\"@+id/subtitle_settings_btt\"\n                    android:layout_width=\"44dp\"\n                    android:layout_height=\"44dp\"\n                    android:contentDescription=\"@string/subtitles_settings\"\n                    android:foreground=\"@drawable/outline_drawable_forced\"\n                    android:padding=\"10dp\"\n                    android:src=\"@drawable/ic_outline_settings_24\" />\n            </LinearLayout>\n\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:layout_weight=\"1\"\n                android:baselineAligned=\"false\"\n                android:orientation=\"horizontal\">\n\n                <ListView\n                    android:id=\"@+id/sort_subtitles\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_weight=\"1\"\n                    android:background=\"?attr/primaryBlackBackground\"\n                    android:listSelector=\"@drawable/outline_drawable_forced\"\n                    android:requiresFadingEdge=\"vertical\"\n                    tools:listitem=\"@layout/sort_bottom_single_choice\" />\n\n                <ListView\n                    android:id=\"@+id/sort_subtitles_options\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"match_parent\"\n                    android:layout_weight=\"1\"\n                    android:background=\"?attr/primaryBlackBackground\"\n                    android:listSelector=\"@drawable/outline_drawable_forced\"\n                    android:requiresFadingEdge=\"vertical\"\n                    tools:listitem=\"@layout/sort_bottom_single_choice\" />\n            </LinearLayout>\n        </LinearLayout>\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"end|center_vertical\"\n        android:padding=\"8dp\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/sort_apply\"\n            style=\"@style/WhiteButton\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/sort_cancel\"\n            style=\"@style/BlackButton\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout-port/player_select_source_priority.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <LinearLayout\n        android:id=\"@+id/sort_sources_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\"\n        android:paddingBottom=\"8dp\">\n        \n        <LinearLayout\n            android:id=\"@+id/subtitles_click_settings\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            android:gravity=\"center_vertical\"\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\">\n\n            <TextView\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:text=\"@string/pick_source\"\n                android:textColor=\"?attr/textColor\"\n                android:textSize=\"20sp\"\n                android:textStyle=\"bold\" />\n\n            <ImageView\n                android:id=\"@+id/help_btt\"\n                android:layout_width=\"44dp\"\n                android:layout_height=\"44dp\"\n                android:background=\"?attr/selectableItemBackgroundBorderless\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/baseline_help_outline_24\"\n                android:contentDescription=\"@string/help\" />\n        </LinearLayout>\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/sort_sources\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:background=\"?attr/primaryBlackBackground\"\n            android:requiresFadingEdge=\"vertical\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            tools:layout_height=\"200dp\"\n            tools:listitem=\"@layout/player_prioritize_item\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/sort_subtitles_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\"\n        android:paddingBottom=\"8dp\">\n        \n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"10dp\"\n            android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n            android:paddingTop=\"10dp\"\n            android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n            android:paddingBottom=\"10dp\"\n            android:text=\"@string/qualities\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\" />\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/sort_qualities\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\"\n            android:background=\"?attr/primaryBlackBackground\"\n            android:requiresFadingEdge=\"vertical\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            tools:layout_height=\"200dp\"\n            tools:listfooter=\"@layout/sort_bottom_footer_add_choice\"\n            tools:listitem=\"@layout/player_prioritize_item\" />\n    </LinearLayout>\n\n    <LinearLayout\n        android:id=\"@+id/apply_btt_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"60dp\"\n        android:orientation=\"horizontal\"\n        android:gravity=\"center_vertical\"\n        android:paddingHorizontal=\"?android:attr/listPreferredItemPaddingStart\">\n\n        <EditText\n            android:id=\"@+id/profile_text_editable\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:autofillHints=\"username\"\n            android:inputType=\"text\"\n            android:maxLength=\"32\"\n            android:textColor=\"?attr/textColor\"\n            android:textSize=\"20sp\"\n            android:textStyle=\"bold\"\n            tools:text=\"@string/profile_number\"\n            tools:ignore=\"LabelFor\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/save_btt\"\n            android:layout_width=\"wrap_content\"\n            android:text=\"@string/sort_save\"\n            style=\"@style/WhiteButton\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/close_btt\"\n            android:layout_width=\"wrap_content\"\n            android:text=\"@string/sort_close\"\n            style=\"@style/BlackButton\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout-port/subtitle_offset.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:padding=\"8dp\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\">\n\n        <TextView\n            android:id=\"@+id/no_subtitles_loaded_notice\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:textSize=\"18sp\"\n            android:textStyle=\"italic\"\n            android:alpha=\"0.7\"\n            android:text=\"@string/no_subtitles_loaded\" />\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/subtitle_offset_recyclerview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:paddingVertical=\"10dp\"\n            android:requiresFadingEdge=\"vertical\"\n            app:layoutManager=\"androidx.recyclerview.widget.LinearLayoutManager\"\n            tools:listitem=\"@layout/subtitle_offset_item\"\n            tools:visibility=\"gone\" />\n    </FrameLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:gravity=\"center_horizontal\"\n        android:paddingVertical=\"10dp\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_margin=\"0dp\"\n            android:paddingTop=\"10dp\"\n            android:text=\"@string/subtitle_offset_title\"\n            style=\"@style/WatchHeaderText\" />\n\n        <TextView\n            android:id=\"@+id/subtitle_offset_sub_title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textColor=\"?attr/grayTextColor\"\n            tools:text=\"@string/subtitle_offset_extra_hint_none_format\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            android:gravity=\"center\"\n            android:paddingTop=\"8dp\">\n\n            <ImageView\n                android:id=\"@+id/subtitle_offset_subtract_more\"\n                android:layout_width=\"44dp\"\n                android:layout_height=\"44dp\"\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/ic_baseline_keyboard_arrow_left_24\"\n                app:tint=\"?attr/white\"\n                tools:ignore=\"ContentDescription\" />\n\n            <ImageView\n                android:id=\"@+id/subtitle_offset_subtract\"\n                android:layout_width=\"44dp\"\n                android:layout_height=\"44dp\"\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/baseline_remove_24\"\n                app:tint=\"?attr/white\"\n                tools:ignore=\"ContentDescription\" />\n\n            <EditText\n                android:id=\"@+id/subtitle_offset_input\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:gravity=\"center\"\n                android:autofillHints=\"no\"\n                android:hint=\"@string/subtitle_offset_hint\"\n                android:inputType=\"numberSigned\"\n                tools:ignore=\"LabelFor\" />\n\n            <ImageView\n                android:id=\"@+id/subtitle_offset_add\"\n                android:layout_width=\"44dp\"\n                android:layout_height=\"44dp\"\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/ic_baseline_add_24\"\n                app:tint=\"?attr/white\"\n                tools:ignore=\"ContentDescription\" />\n\n            <ImageView\n                android:id=\"@+id/subtitle_offset_add_more\"\n                android:layout_width=\"44dp\"\n                android:layout_height=\"44dp\"\n                android:background=\"?android:attr/selectableItemBackgroundBorderless\"\n                android:padding=\"10dp\"\n                android:src=\"@drawable/ic_baseline_keyboard_arrow_right_24\"\n                app:tint=\"?attr/white\"\n                tools:ignore=\"ContentDescription\" />\n        </LinearLayout>\n    </LinearLayout>\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"end|center_vertical\"\n        android:orientation=\"horizontal\"\n        android:padding=\"8dp\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/apply_btt\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/sort_apply\"\n            style=\"@style/WhiteButton\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/reset_btt\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/reset_btn\"\n            style=\"@style/BlackButton\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/cancel_btt\"\n            android:layout_width=\"0dp\"\n            android:layout_weight=\"1\"\n            android:text=\"@string/sort_cancel\"\n            style=\"@style/BlackButton\" />\n    </LinearLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/menu/bottom_nav_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n        <item\n            android:id=\"@+id/navigation_home\"\n            android:icon=\"@drawable/home_icon_selector\"\n            android:title=\"@string/title_home\" />\n        <item\n            android:id=\"@+id/navigation_search\"\n            android:icon=\"@drawable/search_icon\"\n            android:title=\"@string/title_search\" />\n        <item\n            android:id=\"@+id/navigation_library\"\n            android:icon=\"@drawable/library_icon_selector\"\n            android:title=\"@string/library\" />\n        <item\n            android:id=\"@+id/navigation_downloads\"\n            android:icon=\"@drawable/netflix_download\"\n            android:title=\"@string/title_downloads\" />\n        <item\n            android:id=\"@+id/navigation_settings\"\n            android:icon=\"@drawable/settings_icon_selector\"\n            android:title=\"@string/title_settings\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/cast_expanded_controller_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n      xmlns:app=\"http://schemas.android.com/apk/res-auto\" >\n    <item\n            android:id=\"@+id/media_route_menu_item\"\n            app:actionProviderClass=\"androidx.mediarouter.app.MediaRouteActionProvider\"\n            app:showAsAction=\"always\"\n            android:title=\"\"/>\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/download_queue.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/cancel_all\"\n        android:icon=\"@drawable/clear_all_24px\"\n        android:title=\"@string/cancel_all\"\n        app:showAsAction=\"always\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/library_menu.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/search_button\"\n        android:icon=\"@drawable/search_icon\"\n        android:title=\"@string/title_search\"\n        app:searchHintIcon=\"@drawable/search_icon\"\n        app:showAsAction=\"collapseActionView|ifRoom\"\n        app:actionViewClass=\"com.lagradost.cloudstream3.ui.library.MenuSearchView\" />\n    <item\n        android:id=\"@+id/sort_button\"\n        android:icon=\"@drawable/ic_baseline_sort_24\"\n        android:title=\"Sort\"\n        app:showAsAction=\"collapseActionView|ifRoom\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/repository.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n<!--        app:searchHintIcon=\"@drawable/search_icon\"-->\n<!--        android:icon=\"@drawable/search_icon\"-->\n    <item\n        android:id=\"@+id/search_button\"\n        android:title=\"@string/title_search\"\n        android:icon=\"@drawable/search_icon\"\n        android:searchIcon=\"@drawable/search_icon\"\n        app:actionViewClass=\"androidx.appcompat.widget.SearchView\"\n        app:showAsAction=\"always|collapseActionView\"\n        tools:ignore=\"AppCompatResource\" />\n    <item\n        android:id=\"@+id/lang_filter\"\n        android:icon=\"@drawable/ic_baseline_language_24\"\n        android:title=\"@string/provider_lang_settings\"\n        app:showAsAction=\"collapseActionView|ifRoom\" />\n    <item\n        android:id=\"@+id/download_all\"\n        android:icon=\"@drawable/netflix_download\"\n        android:title=\"@string/batch_download\"\n        app:showAsAction=\"collapseActionView|ifRoom\"\n        android:visible=\"false\"/>\n</menu>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_banner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_banner_background\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_cloudstream_monochrome\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_cloudstream_monochrome\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/navigation/mobile_navigation.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<navigation xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/mobile_navigation\"\n    app:startDestination=\"@+id/navigation_home\">\n    <action\n        android:id=\"@+id/global_to_navigation_results_tv\"\n        app:destination=\"@id/navigation_results_tv\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <argument\n            android:name=\"url\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"apiName\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"startAction\"\n            android:defaultValue=\"0\"\n            app:argType=\"integer\" />\n        <argument\n            android:name=\"startValue\"\n            android:defaultValue=\"0\"\n            app:argType=\"integer\" />\n        <argument\n            android:name=\"restart\"\n            android:defaultValue=\"false\"\n            app:argType=\"boolean\" />\n    </action>\n    <action\n        android:id=\"@+id/global_to_navigation_results_phone\"\n        app:destination=\"@id/navigation_results_phone\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <argument\n            android:name=\"url\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"apiName\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"name\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"startAction\"\n            android:defaultValue=\"0\"\n            app:argType=\"integer\" />\n        <argument\n            android:name=\"startValue\"\n            android:defaultValue=\"0\"\n            app:argType=\"integer\" />\n        <argument\n            android:name=\"restart\"\n            android:defaultValue=\"false\"\n            app:argType=\"boolean\" />\n    </action>\n    <action\n        android:id=\"@+id/global_to_navigation_player\"\n        app:destination=\"@id/navigation_player\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <argument\n            android:name=\"data\"\n            android:defaultValue=\"@null\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"uriData\"\n            android:defaultValue=\"@null\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"resumePosition\"\n            android:defaultValue=\"0L\"\n            app:argType=\"long\" />\n    </action>\n\n    <action\n        android:id=\"@+id/global_to_navigation_home\"\n        app:destination=\"@id/navigation_home\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n\n    <action\n        android:id=\"@+id/global_to_navigation_subtitles\"\n        app:destination=\"@id/navigation_subtitles\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <argument\n            android:name=\"hide\"\n            android:defaultValue=\"true\"\n            app:argType=\"boolean\" />\n    </action>\n\n    <action\n        android:id=\"@+id/global_to_navigation_chrome_subtitles\"\n        app:destination=\"@id/navigation_chrome_subtitles\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <argument\n            android:name=\"hide\"\n            android:defaultValue=\"true\"\n            app:argType=\"boolean\" />\n    </action>\n\n    <action\n        android:id=\"@+id/global_to_navigation_settings_plugins\"\n        app:destination=\"@id/navigation_settings_plugins\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <argument\n            android:name=\"name\"\n            android:defaultValue=\"@null\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"url\"\n            android:defaultValue=\"@null\"\n            app:argType=\"string\" />\n        <argument\n            android:name=\"isLocal\"\n            android:defaultValue=\"false\"\n            app:argType=\"boolean\" />\n    </action>\n\n    <fragment\n        android:id=\"@+id/navigation_settings_player\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.SettingsPlayer\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <action\n            android:id=\"@+id/action_navigation_settings_player_to_navigation_subtitles\"\n            app:destination=\"@id/navigation_subtitles\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n        <action\n            android:id=\"@+id/action_navigation_settings_player_to_navigation_chrome_subtitles\"\n            app:destination=\"@id/navigation_chrome_subtitles\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_settings_ui\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.SettingsUI\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n\n    <fragment\n        android:id=\"@+id/navigation_library\"\n        android:name=\"com.lagradost.cloudstream3.ui.library.LibraryFragment\"\n        android:label=\"@string/library\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n\n    <fragment\n        android:id=\"@+id/navigation_settings_general\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.SettingsGeneral\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <action\n            android:id=\"@+id/action_navigation_settings_general_to_easterEggMonkeFragment\"\n            app:destination=\"@id/easterEggMonkeFragment\"\n            app:enterAnim=\"@anim/go_right\"\n            app:exitAnim=\"@anim/go_left\"\n            app:popEnterAnim=\"@anim/go_right\"\n            app:popExitAnim=\"@anim/go_left\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_settings_extensions\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.extensions.ExtensionsFragment\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_extensions\">\n        <action\n            android:id=\"@+id/navigation_settings_extensions_to_navigation_settings_plugins\"\n            app:destination=\"@id/navigation_settings_plugins\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\">\n            <argument\n                android:name=\"name\"\n                android:defaultValue=\"@null\"\n                app:argType=\"string\" />\n            <argument\n                android:name=\"url\"\n                android:defaultValue=\"@null\"\n                app:argType=\"string\" />\n            <argument\n                android:name=\"isLocal\"\n                android:defaultValue=\"false\"\n                app:argType=\"boolean\" />\n        </action>\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_settings_plugins\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.extensions.PluginsFragment\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_plugins\" />\n\n    <fragment\n        android:id=\"@+id/navigation_webview\"\n        android:name=\"com.lagradost.cloudstream3.ui.WebviewFragment\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_webview\" />\n\n    <fragment\n        android:id=\"@+id/navigation_settings_providers\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.SettingsProviders\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n\n    <fragment\n        android:id=\"@+id/navigation_settings_updates\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.SettingsUpdates\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n\n    <fragment\n        android:id=\"@+id/navigation_settings_account\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.SettingsAccount\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n\n    <action\n        android:id=\"@+id/global_to_navigation_quick_search\"\n        app:destination=\"@id/navigation_quick_search\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <argument\n            android:name=\"mainapi\"\n            android:defaultValue=\"true\"\n            app:argType=\"boolean\" />\n        <argument\n            android:name=\"autosearch\"\n            android:defaultValue=\"@null\"\n            app:argType=\"string\" />\n    </action>\n\n    <fragment\n        android:id=\"@+id/navigation_home\"\n        android:name=\"com.lagradost.cloudstream3.ui.home.HomeFragment\"\n        android:label=\"@string/title_home\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_home\">\n        <action\n            android:id=\"@+id/action_navigation_home_to_navigation_quick_search\"\n            app:destination=\"@id/navigation_quick_search\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_search\"\n        android:name=\"com.lagradost.cloudstream3.ui.search.SearchFragment\"\n        android:label=\"@string/title_search\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_search\">\n        <argument\n            android:name=\"search_query\"\n            android:defaultValue=\"\"\n            app:argType=\"string\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_downloads\"\n        android:name=\"com.lagradost.cloudstream3.ui.download.DownloadFragment\"\n        android:label=\"@string/title_downloads\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_downloads\">\n\n        <action\n            android:id=\"@+id/action_navigation_downloads_to_navigation_download_child\"\n            app:destination=\"@id/navigation_download_child\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\">\n            <argument\n                android:name=\"name\"\n                app:argType=\"string\" />\n            <argument\n                android:name=\"folder\"\n                app:argType=\"string\" />\n        </action>\n        <action\n            android:id=\"@+id/action_navigation_downloads_to_navigation_player\"\n            app:destination=\"@id/navigation_player\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n    <fragment\n        android:id=\"@+id/navigation_settings\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.SettingsFragment\"\n        android:layout_height=\"match_parent\"\n        android:label=\"@string/title_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/main_settings\" />\n    <action\n        android:id=\"@+id/action_navigation_global_to_navigation_settings_ui\"\n        app:destination=\"@id/navigation_settings_ui\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n    <action\n        android:id=\"@+id/action_navigation_global_to_navigation_settings_providers\"\n        app:destination=\"@id/navigation_settings_providers\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n    <action\n        android:id=\"@+id/action_navigation_global_to_navigation_settings_player\"\n        app:destination=\"@id/navigation_settings_player\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n    <action\n        android:id=\"@+id/action_navigation_global_to_navigation_settings_updates\"\n        app:destination=\"@id/navigation_settings_updates\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n    <action\n        android:id=\"@+id/action_navigation_global_to_navigation_settings_account\"\n        app:destination=\"@id/navigation_settings_account\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n    <action\n        android:id=\"@+id/action_navigation_global_to_navigation_settings_general\"\n        app:destination=\"@id/navigation_settings_general\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n    <action\n        android:id=\"@+id/action_navigation_global_to_navigation_settings_extensions\"\n        app:destination=\"@id/navigation_settings_extensions\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\" />\n\n    <fragment\n        android:id=\"@+id/navigation_subtitles\"\n        android:name=\"com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment\"\n        android:layout_height=\"match_parent\"\n        android:label=\"@string/subtitles_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/subtitle_settings\" />\n\n    <fragment\n        android:id=\"@+id/navigation_chrome_subtitles\"\n        android:name=\"com.lagradost.cloudstream3.ui.subtitles.ChromecastSubtitlesFragment\"\n        android:layout_height=\"match_parent\"\n        android:label=\"@string/chromecast_subtitles_settings\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/chromecast_subtitle_settings\" />\n\n    <fragment\n        android:id=\"@+id/navigation_quick_search\"\n        android:name=\"com.lagradost.cloudstream3.ui.quicksearch.QuickSearchFragment\"\n        android:layout_height=\"match_parent\"\n        android:label=\"@string/search\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/quick_search\" />\n\n    <fragment\n        android:id=\"@+id/navigation_download_child\"\n        android:name=\"com.lagradost.cloudstream3.ui.download.DownloadChildFragment\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_child_downloads\">\n        <action\n            android:id=\"@+id/action_navigation_download_child_to_navigation_player\"\n            app:destination=\"@id/navigation_player\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_download_queue\"\n        android:name=\"com.lagradost.cloudstream3.ui.download.queue.DownloadQueueFragment\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_download_queue\" />\n\n    <action\n        android:id=\"@+id/action_navigation_global_to_navigation_download_queue\"\n        app:destination=\"@id/navigation_download_queue\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n    </action>\n\n    <fragment\n        android:id=\"@+id/navigation_results_phone\"\n        android:name=\"com.lagradost.cloudstream3.ui.result.ResultTrailerPlayer\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_result_swipe\">\n        <action\n            android:id=\"@+id/action_navigation_results_phone_to_navigation_quick_search\"\n            app:destination=\"@id/navigation_quick_search\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n        <action\n            android:id=\"@+id/action_navigation_results_phone_to_navigation_player\"\n            app:destination=\"@id/navigation_player\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_results_tv\"\n        android:name=\"com.lagradost.cloudstream3.ui.result.ResultFragmentTv\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_result_swipe\">\n        <action\n            android:id=\"@+id/action_navigation_results_tv_to_navigation_quick_search\"\n            app:destination=\"@id/navigation_quick_search\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n        <action\n            android:id=\"@+id/action_navigation_results_tv_to_navigation_player\"\n            app:destination=\"@id/navigation_player\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <!--<fragment\n        android:id=\"@+id/navigation_results\"\n        android:name=\"com.lagradost.cloudstream3.ui.result.ResultFragment\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_result_swipe\">\n        <action\n            android:id=\"@+id/action_navigation_results_to_navigation_quick_search\"\n            app:destination=\"@id/navigation_quick_search\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n        <action\n            android:id=\"@+id/action_navigation_results_to_navigation_player\"\n            app:destination=\"@id/navigation_player\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>-->\n\n    <fragment\n        android:id=\"@+id/navigation_player\"\n        android:name=\"com.lagradost.cloudstream3.ui.player.GeneratorPlayer\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_player\" />\n\n    <fragment\n        android:id=\"@+id/navigation_test_providers\"\n        android:name=\"com.lagradost.cloudstream3.ui.settings.testing.TestFragment\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_testing\">\n        <action\n            android:id=\"@+id/action_navigation_global_to_navigation_test_providers\"\n            app:destination=\"@id/navigation_test_providers\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_setup_language\"\n        android:name=\"com.lagradost.cloudstream3.ui.setup.SetupFragmentLanguage\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_setup_language\">\n        <action\n            android:id=\"@+id/action_navigation_setup_language_to_navigation_setup_provider_languages\"\n            app:destination=\"@id/navigation_setup_provider_languages\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <action\n        android:id=\"@+id/action_navigation_global_to_navigation_setup_extensions\"\n        app:destination=\"@id/navigation_setup_extensions\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\">\n        <argument\n            android:name=\"isSetup\"\n            android:defaultValue=\"false\"\n            app:argType=\"boolean\" />\n    </action>\n\n    <fragment\n        android:id=\"@+id/navigation_setup_extensions\"\n        android:name=\"com.lagradost.cloudstream3.ui.setup.SetupFragmentExtensions\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_setup_extensions\">\n        <action\n            android:id=\"@+id/action_navigation_setup_extensions_to_navigation_setup_provider_languages\"\n            app:destination=\"@id/navigation_setup_provider_languages\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n        <action\n            android:id=\"@+id/action_navigation_setup_extensions_to_navigation_setup_media\"\n            app:destination=\"@id/navigation_setup_media\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_setup_provider_languages\"\n        android:name=\"com.lagradost.cloudstream3.ui.setup.SetupFragmentProviderLanguage\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_setup_provider_languages\">\n        <action\n            android:id=\"@+id/navigation_setup_provider_languages_to_navigation_setup_media\"\n            app:destination=\"@id/navigation_setup_media\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_setup_media\"\n        android:name=\"com.lagradost.cloudstream3.ui.setup.SetupFragmentMedia\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_setup_media\">\n        <action\n            android:id=\"@+id/navigation_setup_media_to_navigation_setup_layout\"\n            app:destination=\"@id/navigation_setup_layout\"\n            app:enterAnim=\"@anim/enter_anim\"\n            app:exitAnim=\"@anim/exit_anim\"\n            app:popEnterAnim=\"@anim/enter_anim\"\n            app:popExitAnim=\"@anim/exit_anim\" />\n    </fragment>\n\n    <fragment\n        android:id=\"@+id/navigation_setup_layout\"\n        android:name=\"com.lagradost.cloudstream3.ui.setup.SetupFragmentLayout\"\n        android:layout_height=\"match_parent\"\n        app:enterAnim=\"@anim/enter_anim\"\n        app:exitAnim=\"@anim/exit_anim\"\n        app:popEnterAnim=\"@anim/enter_anim\"\n        app:popExitAnim=\"@anim/exit_anim\"\n        tools:layout=\"@layout/fragment_setup_media\" />\n\n    <activity\n        android:id=\"@+id/accountSelectActivity\"\n        android:name=\"com.lagradost.cloudstream3.ui.account.AccountSelectActivity\"\n        android:label=\"AccountSelectActivity\"\n        tools:layout=\"@layout/activity_account_select\" />\n\n    <fragment\n        android:id=\"@+id/easterEggMonkeFragment\"\n        android:name=\"com.lagradost.cloudstream3.ui.EasterEggMonkeFragment\"\n        android:label=\"EasterEggMonkeFragment\"\n        tools:layout=\"@layout/fragment_easter_egg_monke\" />\n</navigation>\n"
  },
  {
    "path": "app/src/main/res/values/array.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <array name=\"cast_mini_controller_control_buttons\">\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_play_pause_toggle</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n    <array name=\"cast_expanded_controller_control_buttons\">\n        <!-- Fake sources button -->\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n        <!-- Actually fake to make the skip op button the same style -->\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n\n    <array name=\"dns_pref\">\n        <item>@string/none</item>\n        <item>Google</item>\n        <item>Cloudflare</item>\n        <!--        <item>OpenDns</item>-->\n        <item>AdGuard</item>\n        <item>DNS.WATCH</item>\n        <item>Quad9</item>\n        <item>DNS.SB</item>\n        <item>Canadian Shield</item>\n    </array>\n    <array name=\"dns_pref_values\">\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n        <!--        <item>3</item>-->\n        <item>4</item>\n        <item>5</item>\n        <item>6</item>\n        <item>7</item>\n        <item>8</item>\n    </array>\n\n    <array name=\"apk_installer_pref\">\n        <item>@string/apk_installer_package_installer</item>\n        <item>@string/apk_installer_legacy</item>\n    </array>\n    <array name=\"apk_installer_values\">\n        <item>0</item>\n        <item>1</item>\n    </array>\n\n    <!-- MainAPI enum: AutoDownloadMode -->\n    <array name=\"auto_download_plugin\">\n        <item>@string/disable</item>\n        <item>@string/subtitles_filter_lang</item>\n        <item>@string/all</item>\n        <item>@string/nsfw</item>\n    </array>\n\n    <array name=\"title_info_pref_names\">\n        <item>@string/source_name</item>\n        <item>@string/resolution</item>\n        <item>@string/video_info</item>\n    </array>\n\n    <array name=\"title_info_pref_values\">\n        <item>@string/show_name_key</item>\n        <item>@string/show_resolution_key</item>\n        <item>@string/show_media_info_key</item>\n    </array>\n\n\n    <array name=\"limit_title_pref_names\">\n        <item>@string/none</item>\n        <item>16 characters</item>\n        <item>32 characters</item>\n        <item>64 characters</item>\n        <item>128 characters</item>\n        <item>Hide Title</item>\n    </array>\n    <array name=\"limit_title_pref_values\">\n        <item>0</item>\n        <item>16</item>\n        <item>32</item>\n        <item>64</item>\n        <item>128</item>\n        <item>-1</item>\n    </array>\n\n    <array name=\"skip_sec_values\">\n        <item>5</item>\n        <item>10</item>\n        <item>15</item>\n        <item>20</item>\n        <item>25</item>\n        <item>30</item>\n    </array>\n\n    <array name=\"video_buffer_length_names\">\n        <item>@string/automatic</item>\n        <item>1min</item>\n        <item>1min 30s</item>\n        <item>2min</item>\n        <item>2min 30s</item>\n        <item>3min</item>\n        <item>3min 30s</item>\n        <item>4min</item>\n        <item>5min</item>\n        <item>6min</item>\n        <item>7min</item>\n        <item>8min</item>\n        <item>9min</item>\n        <item>10min</item>\n        <item>15min</item>\n        <item>20min</item>\n        <item>30min</item>\n    </array>\n\n    <string-array name=\"periodic_work_names\">\n        <item>@string/none</item>\n        <item>3h</item>\n        <item>6h</item>\n        <item>12h</item>\n        <item>24h</item>\n        <item>3d</item>\n        <item>7d</item>\n    </string-array>\n    <!-- Values in hours -->\n    <integer-array name=\"periodic_work_values\">\n        <item>0</item>\n        <item>3</item>\n        <item>6</item>\n        <item>12</item>\n        <item>24</item>\n        <item>72</item>\n        <item>168</item>\n    </integer-array>\n\n    <array name=\"video_buffer_length_values\">\n        <item>0</item>\n        <item>60</item>\n        <item>90</item>\n        <item>120</item>\n        <item>150</item>\n        <item>180</item>\n        <item>210</item>\n        <item>240</item>\n        <item>300</item>\n        <item>360</item>\n        <item>420</item>\n        <item>480</item>\n        <item>540</item>\n        <item>600</item>\n        <item>900</item>\n        <item>1200</item>\n        <item>1800</item>\n    </array>\n\n    <array name=\"video_buffer_size_names\">\n        <item>@string/automatic</item>\n        <item>10MB</item>\n        <item>20MB</item>\n        <item>30MB</item>\n        <item>40MB</item>\n        <item>50MB</item>\n        <item>60MB</item>\n        <item>70MB</item>\n        <item>80MB</item>\n        <item>90MB</item>\n        <item>100MB</item>\n        <item>150MB</item>\n        <item>200MB</item>\n        <item>250MB</item>\n        <item>300MB</item>\n        <item>350MB</item>\n        <item>400MB</item>\n        <item>450MB</item>\n        <item>500MB</item>\n    </array>\n\n    <array name=\"video_buffer_size_values\">\n        <item>0</item>\n        <item>10</item>\n        <item>20</item>\n        <item>30</item>\n        <item>40</item>\n        <item>50</item>\n        <item>60</item>\n        <item>70</item>\n        <item>80</item>\n        <item>90</item>\n        <item>100</item>\n        <item>150</item>\n        <item>200</item>\n        <item>250</item>\n        <item>300</item>\n        <item>350</item>\n        <item>400</item>\n        <item>450</item>\n        <item>500</item>\n    </array>\n\n    <array name=\"poster_ui_options\">\n        <item>@string/show_hd</item>\n        <item>@string/show_dub</item>\n        <item>@string/show_sub</item>\n        <item>@string/show_rating</item>\n        <item>@string/show_title</item>\n        <item>@string/show_episode_text</item>\n    </array>\n\n    <array name=\"poster_ui_options_values\">\n        <item>@string/show_hd_key</item>\n        <item>@string/show_dub_key</item>\n        <item>@string/show_sub_key</item>\n        <item>@string/show_rating_key</item>\n        <item>@string/show_title_key</item>\n        <item>@string/show_episode_text_key</item>\n    </array>\n\n    <array name=\"app_layout\">\n        <item>@string/automatic</item>\n        <item>@string/phone_layout</item>\n        <item>@string/tv_layout</item>\n        <item>@string/emulator_layout</item>\n    </array>\n\n    <array name=\"app_layout_values\">\n        <item>-1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n    </array>\n\n    <array name=\"software_decoding_switch\">\n        <item>@string/automatic</item>\n        <item>HW+SW</item>\n        <item>SW+HW</item>\n        <item>HW</item>\n    </array>\n\n    <array name=\"software_decoding_switch_values\">\n        <item>-1</item> <!-- Auto-->\n        <item>0</item>  <!-- HW+SW, aka on but prefer hw -->\n        <item>2</item>  <!-- SW+HW, aka on but prefer sw -->\n        <item>1</item>  <!-- HW, aka off -->\n    </array>\n\n    <array name=\"confirm_exit\">\n        <item>@string/automatic</item>\n        <item>@string/show</item>\n        <item>@string/dont_show</item>\n    </array>\n    <array name=\"confirm_exit_values\">\n        <item>-1</item>\n        <item>0</item>\n        <item>1</item>\n    </array>\n\n    <string-array name=\"themes_overlay_names\">\n        <item>Normal</item>\n        <item>Dandelion Yellow</item>\n        <item>Carnation Pink</item>\n        <item>Orange</item>\n        <item>Dark Green</item>\n        <item>Maroon</item>\n        <item>Navy Blue</item>\n        <item>Grey</item>\n        <item>White</item>\n        <item>Cool Blue</item>\n        <item>Brown</item>\n        <item>Cool</item>\n        <item>Fire</item>\n        <item>Burple</item>\n        <item>Green</item>\n        <item>Apple</item>\n        <item>Banana</item>\n        <item>Party</item>\n        <item>Pink Pain</item>\n        <item>Lavender</item>\n        <item>Material You</item>\n        <item>Material You (Secondary)</item>\n    </string-array>\n    <string-array name=\"themes_overlay_names_values\">\n        <item>Normal</item>\n        <item>DandelionYellow</item>\n        <item>CarnationPink</item>\n        <item>Orange</item>\n        <item>DarkGreen</item>\n        <item>Maroon</item>\n        <item>NavyBlue</item>\n        <item>Grey</item>\n        <item>White</item>\n        <item>CoolBlue</item>\n        <item>Brown</item>\n        <item>Blue</item>\n        <item>Red</item>\n        <item>Purple</item>\n        <item>Green</item>\n        <item>GreenApple</item>\n        <item>Banana</item>\n        <item>Party</item>\n        <item>Pink</item>\n        <item>Lavender</item>\n        <item>Monet</item>\n        <item>Monet2</item>\n    </string-array>\n\n    <string-array name=\"themes_names\">\n        <item>Dark</item>\n        <item>Gray</item>\n        <item>Amoled</item>\n        <item>Flashbang</item>\n        <item>System</item>\n        <item>Material You</item>\n        <item>Dracula</item>\n        <item>Lavender Dreams</item>\n        <item>Silent Blue</item>\n    </string-array>\n    <string-array name=\"themes_names_values\">\n        <item>AmoledLight</item>\n        <item>Black</item>\n        <item>Amoled</item>\n        <item>Light</item>\n        <item>System</item>\n        <item>Monet</item>\n        <item>Dracula</item>\n        <item>Lavender</item>\n        <item>SilentBlue</item>\n    </string-array>\n\n    <string-array name=\"extension_statuses\">\n        <item>Down</item>\n        <!-- \"Ok\" is usually capitalized as \"OK\". Ok android studio 🤓-->\n        <item>Ok</item>\n        <item>Slow</item>\n        <item>Beta</item>\n    </string-array>\n\n    <!--https://github.com/videolan/vlc-android/blob/72ccfb93db027b49855760001d1a930fa657c5a8/application/resources/src/main/res/values/arrays.xml#L266-->\n    <string-array name=\"subtitles_encoding_list\" tools:ignore=\"TypographyDashes\">\n        <item>@string/automatic</item>\n        <item>Universal (UTF-8)</item>\n        <item>Universal (UTF-16)</item>\n        <item>Universal (big endian UTF-16)</item>\n        <item>Universal (little endian UTF-16)</item>\n        <item>Universal, Chinese (GB18030)</item>\n        <item>Western European (Latin-9)</item>\n        <item>Western European (Windows-1252)</item>\n        <item>Western European (IBM 00850)</item>\n        <item>Eastern European (Latin-2)</item>\n        <item>Eastern European (Windows-1250)</item>\n        <item>Esperanto (Latin-3)</item>\n        <item>Nordic (Latin-6)</item>\n        <item>Cyrillic (Windows-1251)</item>\n        <item>Russian (KOI8-R)</item>\n        <item>Ukrainian (KOI8-U)</item>\n        <item>Arabic (ISO 8859-6)</item>\n        <item>Arabic (Windows-1256)</item>\n        <item>Greek (ISO 8859-7)</item>\n        <item>Greek (Windows-1253)</item>\n        <item>Hebrew (ISO 8859-8)</item>\n        <item>Hebrew (Windows-1255)</item>\n        <item>Turkish (ISO 8859-9)</item>\n        <item>Turkish (Windows-1254)</item>\n        <item>Thai (TIS 620-2533/ISO 8859-11)</item>\n        <item>Thai (Windows-874)</item>\n        <item>Baltic (Latin-7)</item>\n        <item>Baltic (Windows-1257)</item>\n        <item>Celtic (Latin-8)</item>\n        <item>South-Eastern European (Latin-10)</item>\n        <item>Simplified Chinese (ISO-2022-CN-EXT)</item>\n        <item>Simplified Chinese Unix (EUC-CN)</item>\n        <item>Japanese (7-bits JIS/ISO-2022-JP-2)</item>\n        <item>Japanese Unix (EUC-JP)</item>\n        <item>Japanese (Shift JIS)</item>\n        <item>Korean (EUC-KR/CP949)</item>\n        <item>Korean (ISO-2022-KR)</item>\n        <item>Traditional Chinese (Big5)</item>\n        <item>Traditional Chinese Unix (EUC-TW)</item>\n        <item>Hong-Kong Supplementary (HKSCS)</item>\n        <item>Vietnamese (VISCII)</item>\n        <item>Vietnamese (Windows-1258)</item>\n    </string-array>\n    <string-array name=\"subtitles_encoding_values\" translatable=\"false\" tools:ignore=\"TypographyDashes\">\n        <item></item>\n        <item>UTF-8</item>\n        <item>UTF-16</item>\n        <item>UTF-16BE</item>\n        <item>UTF-16LE</item>\n        <item>GB18030</item>\n        <item>ISO-8859-15</item>\n        <item>Windows-1252</item>\n        <item>IBM850</item>\n        <item>ISO-8859-2</item>\n        <item>Windows-1250</item>\n        <item>ISO-8859-3</item>\n        <item>ISO-8859-10</item>\n        <item>Windows-1251</item>\n        <item>KOI8-R</item>\n        <item>KOI8-U</item>\n        <item>ISO-8859-6</item>\n        <item>Windows-1256</item>\n        <item>ISO-8859-7</item>\n        <item>Windows-1253</item>\n        <item>ISO-8859-8</item>\n        <item>Windows-1255</item>\n        <item>ISO-8859-9</item>\n        <item>Windows-1254</item>\n        <item>ISO-8859-11</item>\n        <item>Windows-874</item>\n        <item>ISO-8859-13</item>\n        <item>Windows-1257</item>\n        <item>ISO-8859-14</item>\n        <item>ISO-8859-16</item>\n        <item>ISO-2022-CN-EXT</item>\n        <item>EUC-CN</item>\n        <item>ISO-2022-JP-2</item>\n        <item>EUC-JP</item>\n        <item>Shift_JIS</item>\n        <item>CP949</item>\n        <item>ISO-2022-KR</item>\n        <item>Big5</item>\n        <item>ISO-2022-TW</item>\n        <item>Big5-HKSCS</item>\n        <item>VISCII</item>\n        <item>Windows-1258</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"FlowLayout_Layout\">\n        <attr name=\"itemSpacing\" format=\"dimension\" />\n    </declare-styleable>\n    <declare-styleable name=\"FlowLayout_Layout_layout_space\" />\n\n    <declare-styleable name=\"CustomCast\">\n        <attr name=\"customCastBackgroundColor\" format=\"color\" />\n    </declare-styleable>\n\n    <style name=\"customCastDefColor\">\n        <item name=\"customCastBackgroundColor\">?attr/colorPrimary</item>\n    </style>\n\n    <declare-styleable name=\"Focus\">\n        <attr name=\"focusBackground\" format=\"reference\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"TestView\">\n        <attr name=\"header_text\" format=\"string\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"PieFetchButton\">\n        <attr name=\"download_layout\" format=\"reference\" />\n        <attr name=\"download_background_progress\" format=\"reference\" />\n        <attr name=\"download_outline_active\" format=\"reference\" />\n        <attr name=\"download_outline_non_active\" format=\"reference\" />\n        <attr name=\"download_waiting_animation\" format=\"reference\" />\n        <attr name=\"download_progress_drawable\" format=\"reference\" />\n        <attr name=\"download_animate_waiting\" format=\"boolean\" />\n        <attr name=\"download_fill_color\" format=\"color\" />\n        <attr name=\"download_outline_color\" format=\"color\" />\n        <attr name=\"download_icon_color\" format=\"color\" />\n        <attr name=\"download_icon_scale\" format=\"float\" />\n\n        <attr name=\"download_fill\" format=\"enum\">\n            <enum name=\"clockwise\" value=\"0\" />\n            <enum name=\"counter_clockwise\" value=\"1\" />\n            <enum name=\"small_to_large\" value=\"2\" />\n            <!--<enum name=\"top_to_bottom\" value=\"3\" />-->\n        </attr>\n\n        <attr name=\"download_fill_override\" format=\"reference\" />\n\n        <attr name=\"download_hide_when_icon\" format=\"boolean\" />\n\n        <attr name=\"download_icon_init\" format=\"reference\" />\n        <attr name=\"download_icon_error\" format=\"reference\" />\n        <attr name=\"download_icon_complete\" format=\"reference\" />\n        <attr name=\"download_icon_active\" format=\"reference\" />\n        <attr name=\"download_icon_waiting\" format=\"reference\" />\n        <attr name=\"download_icon_removed\" format=\"reference\" />\n        <attr name=\"download_icon_paused\" format=\"reference\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"MainColors\">\n        <attr name=\"colorPrimary\" format=\"color\" />\n        <attr name=\"colorSearch\" format=\"color\" />\n        <attr name=\"colorOngoing\" format=\"color\" />\n        <attr name=\"colorPrimaryDark\" format=\"color\" />\n\n        <attr name=\"primaryGrayBackground\" format=\"color\" />\n        <attr name=\"primaryBlackBackground\" format=\"color\" />\n        <attr name=\"iconGrayBackground\" format=\"color\" />\n        <attr name=\"boxItemBackground\" format=\"color\" />\n\n        <attr name=\"textColor\" format=\"color\" />\n        <attr name=\"grayTextColor\" format=\"color\" />\n        <attr name=\"iconColor\" format=\"color\" />\n        <attr name=\"white\" format=\"color\" />\n        <attr name=\"black\" format=\"color\" />\n    </declare-styleable>\n\n    <declare-styleable name=\"PercentageCropImageView\">\n        <attr name=\"cropYCenterOffsetPct\" format=\"float\" />\n        <attr name=\"cropXCenterOffsetPct\" format=\"float\" />\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3d50fa</color>\n    <color name=\"colorPrimarySecond\">@color/colorPrimary</color>\n    <color name=\"colorSearch\">#303135</color> <!--#3444D1 @color/itemBackground-->\n    <color name=\"colorOngoing\">#F53B66</color> <!--FF8181-->\n    <color name=\"colorPrimaryDark\">#3700B3</color>\n    <color name=\"colorAccent\">#3b65f5</color> <!-- 818fff-->\n\n    <color name=\"primaryGrayBackground\">#2B2C30</color> <!--0f0f10 0E0E10 303135 2B2C30-->\n    <color name=\"primaryBlackBackground\">#111111</color> <!--1C1C20 191a1f 19181E 202125 1C1C20-->\n    <color name=\"iconGrayBackground\">#1C1C20</color> <!--141419 202125-->\n    <color name=\"boxItemBackground\">#161616</color> <!-- 17171B 1B1B20-->\n\n    <color name=\"textColor\">#e9eaee</color> <!--FFF-->\n    <color name=\"grayTextColor\">#9ba0a4</color> <!-- 5e5f62-->\n    <color name=\"grayShimmer\">#DCDCDC</color> <!-- 5e5f62-->\n\n    <color name=\"searchColorTransparent\">#1AFFFFFF</color> <!--DADADA-->\n    <color name=\"transparent\">#00000000</color>\n\n    <color name=\"white\">#FFF</color>\n    <color name=\"black\">#000</color>\n    <color name=\"gray_200\">#EEEEEE</color>\n    <color name=\"gray_400\">#BDBDBD</color>\n\n    <color name=\"whiteText\">#FFF</color>\n    <color name=\"blackText\">#000</color>\n\n    <color name=\"progressBackgroundColor\">#1AFFFFFF</color>\n\n    <color name=\"dubColorText\">#121950</color> <!--3b65f5 f18c82 8294F1-->\n    <color name=\"amoledModeLight\">#121213</color>\n\n    <color name=\"dubColorBg\">#3B65F5</color>\n    <color name=\"subColorText\">#571711</color> <!--F53B66 FA3D79-->\n    <color name=\"subColorBg\">#F53B66</color>\n    <color name=\"typeColorText\">#BEC8FF</color>\n    <color name=\"typeColorBg\">#3700B3</color>\n\n    <!--\n    <color name=\"ratingColor\">#4C3115</color>\n    <color name=\"ratingColorBg\">#FFA662</color>\n    -->\n\n    <color name=\"adultColor\">#FF6F63</color> <!-- same as sub color -->\n\n    <color name=\"video_ripple\">#80FFFFFF</color>\n    <color name=\"video_button_ripple\">#32FFFFFF</color>\n\n    <color name=\"black_overlay\">#66000000</color>\n    <color name=\"darkBarTransparent\">#C0121212</color>\n    <color name=\"skipOpTransparent\">#4D121212</color>\n    <color name=\"darkBar\">#121212</color>\n    <color name=\"videoProgress\">#66B5B5B5</color> <!--66B5B5B5-->\n    <!--<color name=\"videoCache\">#663D50FA</color>--> <!--66B5B5B5-->\n\n    <color name=\"iconColor\">#9ba0a6</color>\n\n    <!-- <color name=\"usedStorageColor\">?attr/white</color>#fff-->\n    <!-- <color name=\"freeStorageColor\">?attr/grayTextColor</color> #676767-->\n\n    <!--Light Mode -->\n    <color name=\"lightPrimaryGrayBackground\">#f1f1f1</color>\n    <color name=\"lightBitDarkerGrayBackground\">#fff</color>\n    <color name=\"lightGrayBackground\">#eeeeee</color>\n    <color name=\"lightItemBackground\">#eeeeee</color>\n    <color name=\"lightTextColor\">#202125</color>\n    <color name=\"lightGrayTextColor\">#5f6267</color>\n    <color name=\"lightIconColor\">#5f6267</color>\n\n    <!--Dracula Theme-->\n    <color name=\"DraculaPrimaryGrayBackground\">#414450</color>\n    <color name=\"DraculaBitDarkerGrayBackground\">#282a36</color>\n    <color name=\"DraculaGrayBackground\">#44475A</color>\n    <color name=\"DraculaItemBackground\">#373844</color>\n    <color name=\"DraculaTextColor\">#F8F8F2</color>\n    <color name=\"DraculaGrayTextColor\">#6272A4</color>\n    <color name=\"DraculaIconColor\">#6272A4</color>\n\n    <!-- Lavender Dreams Theme -->\n    <color name=\"LavenderPrimaryGrayBackground\">#f7eefc</color>\n    <color name=\"LavenderBitDarkerGrayBackground\">#fdf0fb</color>\n    <color name=\"LavenderGrayBackground\">#b794f6</color>\n    <color name=\"LavenderItemBackground\">#f8f5ff</color>\n    <color name=\"LavenderTextColor\">#2d1b47</color>\n    <color name=\"LavenderGrayTextColor\">#9ab3ff</color>\n    <color name=\"LavenderIconColor\">#7c3aed</color>\n\n    <!--Silent Blue Theme-->\n    <color name=\"SilentBluePrimaryGrayBackground\">#282f49</color>\n    <color name=\"SilentBlueBitDarkerGrayBackground\">#151a30</color>\n    <color name=\"SilentBlueGrayBackground\">#3A446A</color>\n    <color name=\"SilentBlueItemBackground\">#3A446A</color>\n    <color name=\"SilentBlueTextColor\">#E0E1F3</color>\n    <color name=\"SilentBlueGrayTextColor\">#7B83B0</color>\n    <color name=\"SilentBlueIconColor\">#7B83B0</color>\n\n    <!--Other Colors -->\n    <color name=\"colorPrimaryBlue\">#5664B7</color>\n    <color name=\"colorPrimaryRed\">#D50000</color>\n    <color name=\"colorPrimaryPurple\">#6200EA</color> <!-- Burple-->\n    <color name=\"colorPrimaryGreen\">#00BFA5</color>\n    <color name=\"colorPrimaryGreenApple\">#48E484</color>\n    <color name=\"colorPrimaryBanana\">#E4D448</color>\n    <color name=\"colorPrimaryParty\">#ea596e</color>\n    <color name=\"colorPrimaryPink\">#ff1493</color>\n\n    <color name=\"colorPrimaryCarnationPink\">#BD5DA5</color>\n    <color name=\"colorPrimaryDarkGreen\">#004500</color>\n    <color name=\"colorPrimaryMaroon\">#451010</color>\n    <color name=\"colorPrimaryNavyBlue\">#000080</color>\n    <color name=\"colorPrimaryGrey\">#515151</color>\n    <color name=\"colorPrimaryWhite\">#FFFFFF</color>\n    <color name=\"colorPrimaryBrown\">#622C00</color>\n    <color name=\"colorPrimaryOrange\">#CE8500</color>\n    <color name=\"colorPrimaryDandelionYellow\">#F5BB00</color>\n    <color name=\"colorPrimaryCoolBlue\">#408cac</color>\n    <color name=\"colorPrimaryLavender\">#6F55AF</color>\n\n    <color name=\"colorTestPass\">#48E484</color>\n    <color name=\"colorTestFail\">#ea596e</color>\n    <color name=\"colorTestWarning\">#FF9800</color>\n    <color name=\"playIconBackground\">#B3000000</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"rounded_image_radius\">10dp</dimen>\n    <dimen name=\"rounded_button_radius\">4dp</dimen>\n\n    <dimen name=\"navbar_height\">0dp</dimen>\n    <dimen name=\"card_corner_radius\">2dp</dimen>\n    <dimen name=\"result_padding\">15dp</dimen>\n\n    <dimen name=\"loading_line_height\">15dp</dimen>\n    <dimen name=\"loading_radius\">3dp</dimen>\n    <dimen name=\"loading_margin\">15dp</dimen>\n\n    <integer name=\"loading_time\">2000</integer>\n\n    <dimen name=\"storage_radius\">3dp</dimen>\n    <dimen name=\"navbar_width\">0dp</dimen>\n\n    <dimen name=\"nav_view_height\">70dp</dimen>\n    <dimen name=\"nav_rail_view_width\">62dp</dimen>\n\n    <dimen name=\"download_size\">50dp</dimen>\n    <dimen name=\"video_frame_width\">1dp</dimen>\n\n    <dimen name=\"account_select_linear_item_size\">100dp</dimen>\n    <dimen name=\"dialog_buttons_inset\">5dp</dimen>\n\n    <dimen name=\"home_poster_progress_size\">50dp</dimen>\n    <dimen name=\"episode_progress_size\">40dp</dimen>\n    <dimen name=\"continue_watching_progress_size\">25dp</dimen>\n    <dimen name=\"circular_progress_thickness\">2dp</dimen>\n    <dimen name=\"download_header_progress_size\">35dp</dimen>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/donottranslate-strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- KEYS -->\n    <string name=\"search_providers_list_key\">search_providers_list</string>\n    <string name=\"locale_key\">app_locale</string>\n    <string name=\"search_types_list_key\">search_type_list</string>\n    <string name=\"auto_update_key\">auto_update</string>\n    <string name=\"auto_update_plugins_key\">auto_update_plugins</string>\n    <string name=\"auto_download_plugins_key\">auto_download_plugins_key2</string>\n    <string name=\"skip_update_key\">skip_update_key</string>\n    <string name=\"install_prerelease_key\">install_prerelease_key</string>\n    <string name=\"manual_check_update_key\">manual_check_update</string>\n    <string name=\"fast_forward_button_time_key\">fast_forward_button_time</string>\n    <string name=\"benene_count\">benene_count</string>\n    <string name=\"subtitle_settings_key\">subtitle_settings_key</string>\n    <string name=\"test_providers_key\">test_providers_key</string>\n    <string name=\"subtitle_settings_chromecast_key\">subtitle_settings_chromecast_key</string>\n    <string name=\"quality_pref_key\">quality_pref_key</string>\n    <string name=\"quality_pref_mobile_data_key\">quality_pref_mobile_data_key</string>\n    <string name=\"player_default_key\">player_default_key</string>\n    <string name=\"prefer_limit_title_key\">prefer_limit_title_key</string>\n    <string name=\"prefer_limit_show_player_info\">prefer_limit_show_player_info</string>\n    <string name=\"apk_installer_key\">apk_installer_key</string>\n    <string name=\"video_buffer_size_key\">video_buffer_size_key</string>\n    <string name=\"video_buffer_length_key\">video_buffer_length_key</string>\n    <string name=\"video_buffer_clear_key\">video_buffer_clear_key</string>\n    <string name=\"video_buffer_disk_key\">video_buffer_disk_key</string>\n    <string name=\"use_system_brightness_key\">use_system_brightness_key</string>\n    <string name=\"swipe_enabled_key\">swipe_enabled_key</string>\n    <string name=\"playback_speed_enabled_key\">playback_speed_enabled_key</string>\n    <string name=\"player_resize_enabled_key\">player_resize_enabled_key</string>\n    <string name=\"player_source_priority_key\">player_source_priority_key</string>\n    <string name=\"pip_enabled_key\">pip_enabled_key</string>\n    <string name=\"double_tap_enabled_key\">double_tap_enabled_key</string>\n    <string name=\"double_tap_pause_enabled_key\">double_tap_pause_enabled_key</string>\n    <string name=\"double_tap_seek_time_key\">double_tap_seek_time_key2</string>\n    <string name=\"android_tv_interface_off_seek_key\">android_tv_interface_off_seek_key</string>\n    <string name=\"android_tv_interface_on_seek_key\">android_tv_interface_on_seek_key</string>\n    <string name=\"swipe_vertical_enabled_key\">swipe_vertical_enabled_key</string>\n    <string name=\"autoplay_next_key\">autoplay_next_key</string>\n    <string name=\"display_sub_key\">display_sub_key</string>\n    <string name=\"show_fillers_key\">show_fillers_key</string>\n    <string name=\"show_trailers_key\">show_trailers_key</string>\n    <string name=\"show_kitsu_posters_key\">show_kitsu_posters_key</string>\n    <string name=\"show_cast_in_details_key\">show_cast_in_details_key</string>\n    <string name=\"random_button_key\">random_button_key</string>\n    <string name=\"provider_lang_key\">provider_lang_key</string>\n    <string name=\"dns_key\">dns_key</string>\n    <string name=\"jsdelivr_proxy_key\">jsdelivr_proxy_key</string>\n    <string name=\"download_path_key\">download_path_key</string>\n    <string name=\"download_parallel_key\">download_parallel_key</string>\n    <string name=\"download_concurrent_key\">download_concurrent_key</string>\n    <string name=\"download_path_key_visual\">download_path_key_visual</string>\n    <string name=\"app_name_download_path\">Cloudstream</string>\n    <string name=\"app_layout_key\">app_layout_key</string>\n    <string name=\"primary_color_key\">primary_color_key</string>\n    <string name=\"restore_key\">restore_key</string>\n    <string name=\"backup_key\">backup_key</string>\n    <string name=\"automatic_backup_key\">automatic_backup_key</string>\n    <string name=\"prefer_media_type_key\">prefer_media_type_key_2</string>\n    <string name=\"app_theme_key\">app_theme_key</string>\n    <string name=\"episode_sync_enabled_key\">episode_sync_enabled_key</string>\n    <string name=\"log_enabled_key\">log_enabled_key</string>\n    <string name=\"show_logcat_key\">show_logcat_key</string>\n    <string name=\"bottom_title_key\">bottom_title_key</string>\n    <string name=\"poster_ui_key\">poster_ui_key</string>\n    <string name=\"overscan_key\">overscan_key</string>\n    <string name=\"poster_size_key\">poster_size_key</string>\n    <string name=\"subtitles_encoding_key\">subtitles_encoding_key</string>\n    <string name=\"override_site_key\">override_site_key</string>\n    <string name=\"redo_setup_key\">redo_setup_key</string>\n    <string name=\"filter_sub_lang_key\">filter_sub_lang_key</string>\n    <string name=\"pref_filter_search_quality_key\">pref_filter_search_quality_key</string>\n    <string name=\"enable_nsfw_on_providers_key\">enable_nsfw_on_providers_key</string>\n    <string name=\"skip_startup_account_select_key\">skip_startup_account_select_key</string>\n    <string name=\"enable_skip_op_from_database\">enable_skip_op_from_database</string>\n    <string name=\"rotate_video_key\">rotate_video_key</string>\n    <string name=\"auto_rotate_video_key\">auto_rotate_video_key</string>\n    <string name=\"biometric_key\">biometric_key</string>\n    <string name=\"battery_optimisation_key\">battery_optimisation</string>\n    <string name=\"show_hd_key\">show_hd_key</string>\n    <string name=\"show_dub_key\">show_dub_key</string>\n    <string name=\"show_sub_key\">show_sub_key</string>\n    <string name=\"show_rating_key\">show_rating_key</string>\n    <string name=\"show_title_key\">show_title_key</string>\n    <string name=\"show_episode_text_key\">show_episode_text_key</string>\n    <string name=\"hide_player_control_names_key\">hide_player_control_names_key</string>\n    <string name=\"preview_seekbar_key\">preview_seekbar_key</string>\n    <string name=\"backup_path_key\">backup_path_key</string>\n    <string name=\"backup_dir_key\">backup_dir_key</string>\n    <string name=\"confirm_exit_key\">confirm_exit_key</string>\n    <string name=\"software_decoding_key\">software_decoding_key2</string>\n    <string name=\"manual_update_plugins_key\">manual_update_plugins</string>\n    <string name=\"legal_notice_key\">legal_notice_key</string>\n    <string name=\"speedup_key\">speedup_key</string>\n    <string name=\"anilist_key\">anilist_key</string>\n    <string name=\"simkl_key\">simkl_key</string>\n    <string name=\"mal_key\">mal_key</string>\n    <string name=\"kitsu_key\">kitsu_key</string>\n    <string name=\"opensubtitles_key\">opensubtitles_key</string>\n    <string name=\"subdl_key\">subdl_key</string>\n\n    <string name=\"pref_category_security_key\">pref_category_security_key</string>\n    <string name=\"pref_category_gestures_key\">pref_category_gestures_key</string>\n    <string name=\"pref_category_android_tv_key\">pref_category_android_tv_key</string>\n\n    <string name=\"tv_no_focus_tag\">tv_no_focus_tag</string>\n\n    <!-- FORMAT WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"extra_info_format\" formatted=\"true\">%1$d %2$s | %3$s</string>\n    <string name=\"storage_size_format\" formatted=\"true\">%1$s • %2$s</string>\n    <string name=\"download_format\" formatted=\"true\">%1$s - %2$s</string>\n    <string name=\"download_size_format\" formatted=\"true\">%1$s / %2$s</string>\n    <string name=\"episode_name_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"episode_text\">S1E1</string>\n    <string name=\"ffw_text_format\" formatted=\"true\">+%d</string>\n    <string name=\"rew_text_format\" formatted=\"true\">-%d</string>\n    <string name=\"ffw_text_regular_format\" formatted=\"true\">%d</string>\n    <string name=\"rew_text_regular_format\" formatted=\"true\">%d</string>\n    <string name=\"rating_format\" formatted=\"true\">%s/10.0</string>\n    <string name=\"year_format\" formatted=\"true\">%d</string>\n\n    <string name=\"episode_play_img_des\">@string/play_episode</string>\n    <string name=\"change_providers_img_des\">@string/home_change_provider_img_des</string>\n    <string name=\"result_plot\">@string/synopsis</string>\n\n    <string name=\"subtitles_none\">@string/none</string>\n    <string name=\"type_none\">@string/none</string>\n    <string name=\"duplicate_cancel\">@string/cancel</string>\n    <string name=\"sort_cancel\">@string/cancel</string>\n    <string name=\"default_subtitles\">@string/action_default</string>\n    <string name=\"default_account\">@string/action_default</string>\n\n    <string name=\"show_name_key\">show_name</string>\n    <string name=\"show_resolution_key\">show_resolution</string>\n    <string name=\"show_media_info_key\">show_media_info</string>\n    <string name=\"prefer_title_limit_key\">prefer_title_limit</string>\n\n    <string name=\"legal_notice_text\">Any legal issues regarding the content on this application\n        should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.\n\n        In case of copyright infringement, please directly contact the responsible parties or the streaming websites.\n\n        The app is purely for educational and personal use.\n\n        CloudStream does not host any content on the app, and has no control over what media is put up or taken down.\n        CloudStream functions like any other search engine, such as Google. CloudStream does not host, upload or\n        manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient,\n        user-friendly interface.\n\n        It merely scrapes 3rd-party websites that are publicly accessible via any regular web browser. It is the\n        responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use\n        CloudStream at your own risk.\n    </string>\n\n    <plurals name=\"episodes\">\n        <item quantity=\"one\">@string/episode</item>\n        <item quantity=\"other\">@string/episodes</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_launcher_background\">#000000</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!--https://newbedev.com/concatenate-multiple-strings-in-xml--><resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Cast: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episode %d will be released in</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Season %1$d Episode %2$d will be released in</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Poster</string>\n    <string name=\"episode_poster_img_des\">Episode Poster</string>\n    <string name=\"home_main_poster_img_des\">Main Poster</string>\n    <string name=\"home_next_random_img_des\">Next Random</string>\n    <string name=\"go_back_img_des\">Go back</string>\n    <string name=\"play_from_beginning_img_des\">Play from the Beginning</string>\n    <string name=\"home_change_provider_img_des\">Change Provider</string>\n    <string name=\"preview_background_img_des\">Preview Background</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Speed (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Rated: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">New update found!\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Filler</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Play with CloudStream</string>\n    <string name=\"title_home\">Home</string>\n    <string name=\"title_search\">Search</string>\n    <string name=\"title_downloads\">Downloads</string>\n    <string name=\"download_queue\">Download queue</string>\n    <string name=\"title_settings\">Settings</string>\n    <string name=\"search_hint\">Search…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Search %s…</string>\n    <string name=\"speech_recognition_unavailable\">Speech recognition is not available</string>\n    <string name=\"begin_speaking\">Begin Speaking…</string>\n    <string name=\"no_data\">No Data</string>\n    <string name=\"episode_more_options_des\">More Options</string>\n    <string name=\"next_episode\">Next episode</string>\n    <string name=\"result_tags\">Genres</string>\n    <string name=\"result_share\">Share</string>\n    <string name=\"result_open_in_browser\">Open In Browser</string>\n    <string name=\"browser\">Browser</string>\n    <string name=\"skip_loading\">Skip Loading</string>\n    <string name=\"loading\">Loading…</string>\n    <string name=\"type_watching\">Watching</string>\n    <string name=\"type_on_hold\">On-Hold</string>\n    <string name=\"type_completed\">Completed</string>\n    <string name=\"type_dropped\">Dropped</string>\n    <string name=\"type_plan_to_watch\">Plan to Watch</string>\n    <string name=\"type_re_watching\">Rewatching</string>\n    <string name=\"play_movie_button\">Play Movie</string>\n    <string name=\"play_trailer_button\">Play Trailer</string>\n    <string name=\"play_livestream_button\">Play Livestream</string>\n    <string name=\"play_torrent_button\">Stream Torrent</string>\n    <string name=\"play_full_series_button\">Play Full Series</string>\n    <string name=\"torrent_info\">This video is a Torrent, this means that your video activity can be tracked.\\nMake sure you understand Torrenting before continuing.</string>\n    <string name=\"pick_source\">Sources</string>\n    <string name=\"pick_subtitle\">Subtitles</string>\n    <string name=\"reload_error\">Retry connection…</string>\n    <string name=\"go_back\">Go Back</string>\n    <string name=\"play_episode\">Play Episode</string>\n    <!--<string name=\"need_storage\">Allow to download episodes</string>-->\n    <string name=\"download\">Download</string>\n    <string name=\"downloaded\">Downloaded</string>\n    <string name=\"downloading\">Downloading</string>\n    <string name=\"download_paused\">Download Paused</string>\n    <string name=\"download_started\">Download Started</string>\n    <string name=\"download_failed\">Download Failed</string>\n    <string name=\"download_canceled\">Download Canceled</string>\n    <string name=\"download_done\">Download Done</string>\n    <string name=\"downloads_delete_select\">Select Items to Delete</string>\n    <string name=\"downloads_empty\">There are currently no downloads.</string>\n    <string name=\"queue_empty_message\">There are currently no queued downloads.</string>\n    <string name=\"offline_file\">Available for watching offline</string>\n    <string name=\"select_all\">Select All</string>\n    <string name=\"deselect_all\">Deselect All</string>\n    <string name=\"update_started\">Update Started</string>\n    <string name=\"stream\">Network stream</string>\n    <string name=\"open_local_video\">Open local video</string>\n    <string name=\"error_loading_links_toast\">Error Loading Links</string>\n    <string name=\"links_reloaded_toast\">Links Reloaded</string>\n    <string name=\"download_storage_text\">Internal Storage</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Delete File</string>\n    <string name=\"popup_play_file\">Play File</string>\n    <string name=\"popup_resume_download\">Resume Download</string>\n    <string name=\"popup_pause_download\">Pause Download</string>\n    <string name=\"home_more_info\">More info</string>\n    <string name=\"home_expanded_hide\">Hide</string>\n    <string name=\"home_play\">Play</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"filter_bookmarks\">Filter Bookmarks</string>\n    <string name=\"error_bookmarks_text\">Bookmarks</string>\n    <string name=\"action_remove_from_bookmarks\">Remove</string>\n    <string name=\"action_add_to_bookmarks\">Set watch status</string>\n    <string name=\"sort_apply\">Apply</string>\n    <string name=\"sort_copy\">Copy</string>\n    <string name=\"sort_close\">Close</string>\n    <string name=\"sort_clear\">Clear</string>\n    <string name=\"sort_save\">Save</string>\n    <string name=\"repo_copy_label\">Repository name and URL</string>\n    <string name=\"toast_copied\">copied!</string>\n    <string name=\"subscribe_tooltip\">New episode notification</string>\n    <string name=\"result_search_tooltip\">Search in other extensions</string>\n    <string name=\"recommendations_tooltip\">Show recommendations</string>\n    <string name=\"player_speed\">Player Speed</string>\n    <string name=\"subtitles_settings\">Subtitle Settings</string>\n    <string name=\"subs_text_color\">Text Color</string>\n    <string name=\"subs_outline_color\">Outline Color</string>\n    <string name=\"subs_background_color\">Background Color</string>\n    <string name=\"subs_window_color\">Window Color</string>\n    <string name=\"subs_edge_type\">Edge Type</string>\n    <string name=\"subs_subtitle_elevation\">Subtitle Elevation</string>\n    <string name=\"subs_font\">Font</string>\n    <string name=\"subs_font_size\">Font Size</string>\n    <string name=\"search_provider_text_providers\">Search using providers</string>\n    <string name=\"search_provider_text_types\">Search using types</string>\n    <string name=\"benene_count_text\">%d Benenes given to devs</string>\n    <string name=\"benene_count_text_none\">No Benenes given</string>\n    <string name=\"subs_auto_select_language\">Auto-Select Language</string>\n    <string name=\"subs_download_languages\">Download Languages</string>\n    <string name=\"subs_subtitle_languages\">Subtitle Language</string>\n    <string name=\"subs_hold_to_reset_to_default\">Hold to reset to default</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Import fonts by placing them in %s</string>\n    <string name=\"continue_watching\">Continue Watching</string>\n    <string name=\"action_remove_watching\">Remove</string>\n    <string name=\"action_open_watching\">More Info</string>\n    <string name=\"action_open_play\">@string/home_play </string>\n    <string name=\"vpn_might_be_needed\">A VPN might be needed for this provider to work correctly</string>\n    <string name=\"vpn_torrent\">This provider is a torrent, a VPN is recommended</string>\n    <string name=\"provider_info_meta\">Metadata is not provided by site, video loading will fail if it does not exist on site.</string>\n    <string name=\"torrent_plot\">Description</string>\n    <string name=\"normal_no_plot\">No Plot Found</string>\n    <string name=\"torrent_no_plot\">No Description Found</string>\n    <string name=\"show_log_cat\">Show Logcat 🐈</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"picture_in_picture\">Picture-in-picture</string>\n    <string name=\"picture_in_picture_des\">Continues playback in a miniature player on top of other apps</string>\n    <string name=\"player_size_settings\">Player resize button</string>\n    <string name=\"player_size_settings_des\">Remove the black borders</string>\n    <string name=\"player_subtitles_settings\">Subtitles</string>\n    <string name=\"player_subtitles_settings_des\">Player subtitles settings</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast Subtitles</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast subtitles settings</string>\n    <string name=\"eigengraumode_settings\">Playback speed</string>\n    <string name=\"speed_setting_summary\">Adds a speed option in the player</string>\n    <string name=\"swipe_to_seek_settings\">Swipe to seek</string>\n    <string name=\"swipe_to_seek_settings_des\">Swipe from side to side to control your position in a video</string>\n    <string name=\"swipe_to_change_settings\">Swipe to change settings</string>\n    <string name=\"swipe_to_change_settings_des\">Slide up or down on the left or right side to change brightness or volume</string>\n    <string name=\"autoplay_next_settings\">Autoplay next episode</string>\n    <string name=\"autoplay_next_settings_des\">Start the next episode when the current one ends</string>\n    <string name=\"double_tap_to_seek_settings\">Double tap to seek</string>\n    <string name=\"double_tap_to_pause_settings\">Double tap to pause</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Player seek amount (Seconds)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Tap twice on the right or left side to seek forwards or backwards\n    </string>\n    <string name=\"double_tap_to_pause_settings_des\">Tap twice in the middle to pause</string>\n    <string name=\"use_system_brightness_settings\">Use system brightness</string>\n    <string name=\"use_system_brightness_settings_des\">Use system brightness in the app player instead of a dark\n        overlay\n    </string>\n    <string name=\"extra_brightness_settings\">Extra brightness</string>\n    <string name=\"extra_brightness_settings_des\">Enable brightness filter when 100% display brightness is exceeded</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"episode_sync_settings\">Update watch progress</string>\n    <string name=\"episode_sync_settings_des\">Automatically sync your current episode progress</string>\n    <string name=\"restore_settings\">Restore data from backup</string>\n    <string name=\"backup_settings\">Back up data</string>\n    <string name=\"backup_frequency\">Backup frequency</string>\n    <string name=\"restore_success\">Loaded backup file</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Failed to restore data from file %s</string>\n    <string name=\"backup_success\">Data stored</string>\n    <string name=\"backup_failed\">Storage permissions missing. Please try again.</string>\n    <string name=\"backup_failed_error_format\">Error backing up %s</string>\n    <string name=\"search\">Search</string>\n    <string name=\"library\">Library</string>\n    <string name=\"category_account\">Accounts and Security</string>\n    <string name=\"category_updates\">Updates and Backup</string>\n    <string name=\"settings_info\">Info</string>\n    <string name=\"advanced_search\">Advanced Search</string>\n    <string name=\"advanced_search_des\">Gives you the search results separated by provider</string>\n    <string name=\"search_suggestions\">Search Suggestions</string>\n    <string name=\"search_suggestions_des\">Show search suggestions while typing</string>\n    <string name=\"clear_suggestions\">Clear Suggestions</string>\n    <string name=\"show_fillers_settings\">Show filler episode for anime</string>\n    <string name=\"show_trailers_settings\">Show trailers</string>\n    <string name=\"kitsu_settings\">Show posters from Kitsu</string>\n    <string name=\"show_cast_in_details\">Show cast panel</string>\n    <string name=\"pref_filter_search_quality\">Hide selected video quality in search results</string>\n    <string name=\"automatic_plugin_updates\">Automatic plugin updates</string>\n    <string name=\"automatic_plugin_download\">Automatically download plugins</string>\n    <string name=\"automatic_plugin_download_mode_title\">Select mode to filter plugins download</string>\n    <string name=\"automatic_plugin_download_summary\">Automatically install all not yet installed plugins from added repositories.</string>\n    <string name=\"updates_settings\">Show app updates</string>\n    <string name=\"updates_settings_des\">Automatically search for new updates after starting the app.</string>\n    <string name=\"redo_setup_process\">Redo setup process</string>\n    <string name=\"install_prerelease\">Install pre-release version</string>\n    <string name=\"prerelease_already_installed\">Pre-release is already installed.</string>\n    <string name=\"prerelease_install_failed\">Failed to install pre-release.</string>\n    <string name=\"apk_installer_settings\">APK Installer</string>\n    <string name=\"apk_installer_settings_des\">Some devices do not support the new package installer. Try the legacy option if updates do not install.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Light novel app by the same devs</string>\n    <string name=\"anim\">Anime app by the same devs</string>\n    <string name=\"discord\">Join Discord</string>\n    <string name=\"benene\">Give a benene to the devs</string>\n    <string name=\"benene_des\">Given benene</string>\n    <string name=\"app_language\">App Language</string>\n    <string name=\"no_chromecast_support_toast\">This provider has no Chromecast support</string>\n    <string name=\"no_links_found_toast\">No Links Found</string>\n    <string name=\"copy_link_toast\">Link copied to clipboard</string>\n    <string name=\"play_episode_toast\">Play Episode</string>\n    <string name=\"subs_default_reset_toast\">Reset to default value</string>\n    <string name=\"season\">Season</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">No Season</string>\n    <string name=\"episode\">Episode</string>\n    <string name=\"episodes\">Episodes</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Upcoming in %s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">No Episodes found</string>\n    <string name=\"delete\">Delete</string>\n    <string name=\"delete_file\">Delete File</string>\n    <string name=\"delete_files\">Delete Files</string>\n    <string name=\"delete_format\" formatted=\"true\">Delete (%1$d | %2$s)</string>\n    <string name=\"cancel\">Cancel</string>\n    <string name=\"pause\">Pause</string>\n    <string name=\"start\">Start</string>\n    <string name=\"test_failed\">Failed</string>\n    <string name=\"test_passed\">Passed</string>\n    <string name=\"test_warning\">Warning</string>\n    <string name=\"resume\">Resume</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">This will permanently delete %s\\nAre you sure?</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Are you sure you want to permanently delete the following items?\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Are you sure you want to permanently delete the following episodes in %1$s?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">You will also permanently delete all episodes in the following series:\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Are you sure you want to permanently delete all episodes in the following series?\\n\\n%s</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\\nremaining</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\nremaining</string>\n    <string name=\"status_ongoing\">Ongoing</string>\n    <string name=\"status_completed\">Completed</string>\n    <string name=\"status\">Status</string>\n    <string name=\"year\">Year</string>\n    <string name=\"rating\">Rating</string>\n    <string name=\"duration\">Duration</string>\n    <string name=\"site\">Site</string>\n    <string name=\"synopsis\">Synopsis</string>\n    <string name=\"queued\">queued</string>\n    <string name=\"no_subtitles\">No Subtitles</string>\n    <string name=\"action_default\">Default</string>\n    <string name=\"free_storage\">Free</string>\n    <string name=\"used_storage\">Used</string>\n    <string name=\"app_storage\">App</string>\n    <!--plural-->\n    <string name=\"movies\">Movies</string>\n    <string name=\"tv_series\">TV Series</string>\n    <string name=\"cartoons\">Cartoons</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"documentaries\">Documentaries</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Asian Dramas</string>\n    <string name=\"livestreams\">Livestreams</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Others</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Movie</string>\n    <string name=\"tv_series_singular\">Series</string>\n    <string name=\"cartoons_singular\">Cartoon</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Documentary</string>\n    <string name=\"asian_drama_singular\">Asian Drama</string>\n    <string name=\"live_singular\">Livestream</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"music_singlar\">Music</string>\n    <string name=\"audio_book_singular\">Audio Book</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"source_error\">Source error</string>\n    <string name=\"remote_error\">Remote error</string>\n    <string name=\"render_error\">Renderer error</string>\n    <string name=\"encoding_error\">Encoding error</string>\n    <string name=\"unsupported_error\">Unsupported error</string>\n    <string name=\"unexpected_error\">Unexpected player error</string>\n    <string name=\"storage_error\">Download error, check storage permissions</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast episode</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast mirror</string>\n    <string name=\"episode_action_cast_mirror\">Cast mirror</string>\n    <string name=\"episode_action_play_in_app\">Play in app</string>\n    <string name=\"episode_action_play_mirror\">Play mirror</string>\"\n    <string name=\"episode_action_play_in_format\">Play in %s</string>\n    <string name=\"episode_action_auto_download\">Auto download</string>\n    <string name=\"episode_action_download_mirror\">Download mirror</string>\n    <string name=\"episode_action_reload_links\">Reload links</string>\n    <string name=\"episode_action_download_subtitle\">Download subtitles</string>\n    <string name=\"show_hd\">Quality label</string>\n    <string name=\"show_dub\">Dub label</string>\n    <string name=\"show_sub\">Sub label</string>\n    <string name=\"show_rating\">Rating Label</string>\n    <string name=\"show_title\">Title</string>\n    <string name=\"show_episode_text\">Episode Text</string>\n    <string name=\"poster_ui_settings\">Toggle UI elements on poster</string>\n    <string name=\"no_update_found\">No Update Found</string>\n    <string name=\"check_for_update\">Check for Update</string>\n    <string name=\"video_lock\">Lock</string>\n    <string name=\"video_aspect_ratio_resize\">Resize</string>\n    <string name=\"video_source\">Source</string>\n    <string name=\"video_skip_op\">Skip OP</string>\n    <string name=\"dont_show_again\">Don\\'t show again</string>\n    <string name=\"skip_update\">Skip this Update</string>\n    <string name=\"update\">Update</string>\n    <string name=\"watch_quality_pref\">Preferred watch quality (WiFi)</string>\n    <string name=\"watch_quality_pref_data\">Preferred watch quality (Mobile Data)</string>\n    <string name=\"limit_title\">Video player title max chars</string>\n    <string name=\"limit_title_rez\">Show player information</string>\n    <string name=\"video_buffer_size_settings\">Video buffer size</string>\n    <string name=\"video_buffer_length_settings\">Video buffer length</string>\n    <string name=\"video_buffer_disk_settings\">Video cache on disk</string>\n    <string name=\"video_buffer_clear_settings\">Clear video and image cache</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Player Shown - Seek Amount</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">The seek amount used when the player is visible</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Player Hidden - Seek Amount</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">The seek amount used when the player is hidden</string>\n    <string name=\"video_ram_description\">Causes crashes if set too high on devices with low memory, such as Android TV.</string>\n    <string name=\"video_disk_description\">Causes problems if set too high on devices with low storage space, such as Android TV.</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"dns_pref_summary\">Useful for bypassing ISP blocks</string>\n    <string name=\"jsdelivr_proxy\">GitHub Proxy</string>\n    <string name=\"jsdelivr_enabled\">Could not reach GitHub. Turning on jsDelivr proxy…</string>\n    <string name=\"jsdelivr_proxy_summary\">Bypass blocking of raw github URLs using jsDelivr. May cause updates to be delayed by few days.</string>\n    <string name=\"add_site_pref\">Clone site</string>\n    <string name=\"remove_site_pref\">Remove site</string>\n    <string name=\"add_site_summary\">Add a clone of an existing site, with a different URL</string>\n    <string name=\"download_path_pref\">Download path</string>\n    <string name=\"nginx_url_pref\">NGINX server URL</string>\n    <string name=\"display_subbed_dubbed_settings\">Display Dubbed/Subbed Anime</string>\n    <string name=\"resize_fit\">Fit to screen</string>\n    <string name=\"resize_fill\">Stretch</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"legal_notice\">Disclaimer</string>\n    <string name=\"pref_category_bypass\">ISP Bypasses</string>\n    <string name=\"pref_category_links\">Links</string>\n    <string name=\"pref_category_app_updates\">App updates</string>\n    <string name=\"pref_category_backup\">Backup</string>\n    <string name=\"pref_category_extensions\">Extensions</string>\n    <string name=\"pref_category_actions\">Actions</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"pref_category_gestures\">Gestures</string>\n    <string name=\"pref_category_security\">Security</string>\n    <string name=\"pref_category_accounts\">Accounts</string>\n    <string name=\"pref_category_player_features\">Player features</string>\n    <string name=\"pref_category_subtitles\">Subtitles</string>\n    <string name=\"pref_category_player_layout\">Layout</string>\n    <string name=\"pref_category_defaults\">Defaults</string>\n    <string name=\"pref_category_looks\">Looks</string>\n    <string name=\"pref_category_ui_features\">Features</string>\n    <string name=\"category_general\">General</string>\n    <string name=\"random_button_settings\">Random Button</string>\n    <string name=\"random_button_settings_desc\">Show random button on Homepage and Library</string>\n    <string name=\"provider_lang_settings\">Extension languages</string>\n    <string name=\"app_layout\">App Layout</string>\n    <string name=\"preferred_media_settings\">Preferred media</string>\n    <string name=\"enable_nsfw_on_providers\">Enable NSFW on supported Extensions</string>\n    <string name=\"subtitles_encoding\">Subtitle encoding</string>\n    <string name=\"category_providers\">Providers</string>\n    <string name=\"category_provider_test\">Provider test</string>\n    <string name=\"test_extensions\">Test all Extensions</string>\n    <string name=\"test_extensions_summary\">This Test is meant for developers only and does not verifies or denies working of any extension.</string>\n    <string name=\"category_ui\">Layout</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"tv_layout\">TV layout</string>\n    <string name=\"phone_layout\">Phone layout</string>\n    <string name=\"emulator_layout\">Emulator layout</string>\n    <string name=\"primary_color_settings\">Primary color</string>\n    <string name=\"app_theme_settings\">App theme</string>\n    <string name=\"bottom_title_settings\">Poster title location</string>\n    <string name=\"bottom_title_settings_des\">Put the title under the poster</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">password123</string>\n    <string name=\"example_username\">Username</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NewSiteName</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">Language code (en)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">account</string>\n    <string name=\"logout\">Log out</string>\n    <string name=\"login\">Log in</string>\n    <string name=\"auth_locally\">Auth Locally</string>\n    <string name=\"switch_account\">Switch account</string>\n    <string name=\"add_account\">Add account</string>\n    <string name=\"create_account\">Create account</string>\n    <string name=\"add_sync\">Add tracking</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Added %s</string>\n    <string name=\"upload_sync\">Sync</string>\n    <string name=\"sync_score\">Rated</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s authenticated</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Could not log in at %s</string>\n    <!-- ============ -->\n    <string name=\"disable\">Disable</string>\n    <string name=\"none\">None</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">All</string>\n    <string name=\"max\">Max</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Outline</string>\n    <string name=\"subtitles_depressed\">Depressed</string>\n    <string name=\"subtitles_shadow\">Shadow</string>\n    <string name=\"subtitles_raised\">Raised</string>\n    <string name=\"subtitle_offset\">Sync subs</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Subtitle delay</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Use this if the subtitles are shown %d ms too early</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Use this if subtitles are shown %d ms too late</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">No subtitle delay</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">The quick brown fox jumps over the lazy dog</string>\n    <string name=\"recommended\">Recommended</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Loaded %s</string>\n    <string name=\"player_load_subtitles\">Load from file</string>\n    <string name=\"player_load_subtitles_online\">Load from Internet</string>\n    <string name=\"player_load_one_subtitle_online\">Load first available</string>\n    <string name=\"downloaded_file\">Downloaded file</string>\n    <string name=\"actor_main\">Main</string>\n    <string name=\"actor_supporting\">Supporting</string>\n    <string name=\"actor_background\">Background</string>\n    <string name=\"home_source\">Source</string>\n    <string name=\"home_random\">Random</string>\n    <string name=\"coming_soon\">Coming soon…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Poster Image</string>\n    <string name=\"qr_image\">QR Code Image</string>\n    <string name=\"category_player\">Player</string>\n    <string name=\"resolution_and_title\">Resolution and title</string>\n    <string name=\"title\">Title</string>\n    <string name=\"resolution\">Resolution</string>\n    <string name=\"video_info\">Media Info</string>\n    <string name=\"error_invalid_id\">Invalid ID</string>\n    <string name=\"error_invalid_data\">Invalid data</string>\n    <string name=\"error_invalid_url\">Invalid URL</string>\n    <string name=\"error\">Error</string>\n    <string name=\"subtitles_remove_captions\">Remove closed captions from subtitles</string>\n    <string name=\"subtitles_remove_bloat\">Remove bloat from subtitles</string>\n    <string name=\"subtitles_filter_lang\">Filter by preferred media language</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"referer\">Referer (optional)</string>\n    <string name=\"next\">Next</string>\n    <string name=\"provider_languages_tip\">Watch videos in these languages</string>\n    <string name=\"previous\">Previous</string>\n    <string name=\"skip_setup\">Skip setup</string>\n    <string name=\"app_layout_subtext\">Change the look of the app to suit your device</string>\n    <string name=\"preferred_media_subtext\">What do you want to see</string>\n    <string name=\"setup_done\">Done</string>\n    <string name=\"extensions\">Extensions</string>\n    <string name=\"add_repository\">Add repository</string>\n    <string name=\"repository_name_hint\">Repository name (Optional)</string>\n    <string name=\"repository_url_hint\">Repository URL or Shortcode</string>\n    <string name=\"plugin_loaded\">Plugin Loaded</string>\n    <string name=\"plugin_downloaded\">Plugin Downloaded</string>\n    <string name=\"plugin_deleted\">Plugin Deleted</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Could not load %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Started downloading %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Downloaded %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">All %s already downloaded</string>\n    <string name=\"no_plugins_found_error\">No plugins found in repository</string>\n    <string name=\"no_repository_found_error\">Repository not found, check the URL and try VPN</string>\n    <string name=\"batch_download\">Batch download</string>\n    <string name=\"plugin_singular\">plugin</string>\n    <string name=\"plugin\">plugins</string>\n    <string name=\"delete_repository_plugins\">This will also delete all repository plugins</string>\n    <string name=\"delete_repository\">Delete repository</string>\n    <string name=\"delete_plugin\">Delete plugin</string>\n    <string name=\"setup_extensions_subtext\">Download the list of sites you want to use</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Downloaded: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Disabled: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Not downloaded: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Updated %d plugins</string>\n    <string name=\"blank_repo_message\">CloudStream has no sites installed by default. You need to install the sites from repositories.\n\\n\n\\nJoin our Discord or search online.</string>\n    <string name=\"view_public_repositories_button\">View community repositories</string>\n    <string name=\"view_public_repositories_button_short\">Public list</string>\n    <string name=\"uppercase_all_subtitles\">Uppercase all subtitles</string>\n    <string name=\"download_all_plugins_from_repo\">Warning: CloudStream does not take any responsibility for using third-party extensions and does not provide any support for them!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Disabled)</string>\n    <string name=\"tracks\">Tracks</string>\n    <string name=\"audio_tracks\">Audio tracks</string>\n    <string name=\"video_tracks\">Video tracks</string>\n    <string name=\"apply_on_restart\">Restart the app to see changes.</string>\n    <string name=\"restart\">Restart</string>\n    <string name=\"stop\">Stop</string>\n    <string name=\"safe_mode_title\">Safe mode on</string>\n    <string name=\"safe_mode_description\">All extensions were turned off due to a crash to help you find the one causing trouble.</string>\n    <string name=\"safe_mode_crash_info\">View crash info</string>\n    <string name=\"extension_rating\" formatted=\"true\">Rating: %s</string>\n    <string name=\"extension_description\">Description</string>\n    <string name=\"extension_version\">Version</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"extension_size\">Size</string>\n    <string name=\"extension_authors\">Authors</string>\n    <string name=\"extension_types\">Supported</string>\n    <string name=\"extension_language\">Language</string>\n    <string name=\"extension_install_first\">Install the extension first</string>\n    <string name=\"hls_playlist\">HLS Playlist</string>\n    <string name=\"player_pref\">Preferred video player</string>\n    <string name=\"player_settings_play_in_app\">Internal player</string>\n    <string name=\"player_settings_always_ask\">Always ask</string>\n    <string name=\"player_settings_select_cast_device\">Select cast device</string>\n    <string name=\"app_not_found_error\">App not found</string>\n    <string name=\"all_languages_preference\">All Languages</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Skip %s</string>\n    <string name=\"skip_type_op\">Opening</string>\n    <string name=\"skip_type_ed\">Ending</string>\n    <string name=\"skip_type_recap\">Recap</string>\n    <string name=\"skip_type_mixed_ed\">Mixed ending</string>\n    <string name=\"skip_type_mixed_op\">Mixed opening</string>\n    <string name=\"skip_type_creddits\">Credits</string>\n    <string name=\"skip_type_intro\">Intro</string>\n    <string name=\"clear_history\">Clear history</string>\n    <string name=\"history\">History</string>\n    <string name=\"enable_skip_op_from_database_des\">Show skip popups for opening/ending</string>\n    <string name=\"clipboard_too_large\">Too much text. Unable to save to clipboard.</string>\n    <string name=\"clipboard_permission_error\">Error accessing Clipboard, Please try again.</string>\n    <string name=\"clipboard_unknown_error\">Error copying, Please copy logcat and contact app support.</string>\n    <string name=\"action_mark_as_watched\">Mark as watched</string>\n    <string name=\"action_remove_from_watched\">Remove from watched</string>\n    <string name=\"confirm_exit_dialog\">Are you sure you want to exit\\?</string>\n    <string name=\"yes\">Yes</string>\n    <string name=\"no\">No</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"dismiss\">Dismiss</string>\n    <string name=\"open_downloaded_repo\">Open repository</string>\n    <string name=\"battery_dialog_title\">Disable Battery optimization</string>\n    <string name=\"battery_dialog_message\">To ensure uninterrupted downloads and notifications for subscribed\n        TV shows, CloudStream needs permission to run in background. By pressing \"OK\", you\\'ll be shown a request dialog.\n        Please press \\'Allow\\'.\\n\\nPlease note, this permission does not mean CS3 will drain your battery. It will only operate in the background when necessary, such as\n        when receiving notifications or downloading videos from official extensions.</string>\n    <string name=\"app_unrestricted_toast\">App battery usage is already set to unrestricted</string>\n    <string name=\"app_info_intent_error\">Unable to open CloudStream\\'s App info.</string>\n    <string name=\"update_notification_downloading\">Downloading app update…</string>\n    <string name=\"update_notification_installing\">Installing app update…</string>\n    <string name=\"update_notification_failed\">Could not install the new version of the app</string>\n    <string name=\"apk_installer_legacy\">Legacy</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"delayed_update_notice\">App will be updated upon exit</string>\n    <string name=\"sort_by\">Sort by</string>\n    <string name=\"sort\">Sort</string>\n    <string name=\"sort_rating_desc\">Rating (High to Low)</string>\n    <string name=\"sort_rating_asc\">Rating (Low to High)</string>\n    <string name=\"sort_updated_new\">Updated (New to Old)</string>\n    <string name=\"sort_updated_old\">Updated (Old to New)</string>\n    <string name=\"sort_alphabetical_a\">Alphabetical (A to Z)</string>\n    <string name=\"sort_alphabetical_z\">Alphabetical (Z to A)</string>\n    <string name=\"sort_episodes_number_asc\">Episode (Ascending)</string>\n    <string name=\"sort_episodes_number_desc\">Episode (Descending)</string>\n    <string name=\"sort_episodes_rating_high_low\">Rating (Highest)</string>\n    <string name=\"sort_episodes_rating_low_high\">Rating (Lowest)</string>\n    <string name=\"sort_episodes_date_newest\">Air Date (Newest)</string>\n    <string name=\"sort_episodes_date_oldest\">Air Date (Oldest)</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_rating\">Rating %s</string>\n    <string name=\"sort_button_date\">Date %s</string>\n    <string name=\"select_library\">Select Library</string>\n    <string name=\"open_with\">Open with</string>\n    <string name=\"empty_library_no_accounts_message\">Your library is empty :(\n\\nLog in on a library account or add shows to your local library.</string>\n    <string name=\"empty_library_logged_in_message\">This list is empty. Try switching to another one.</string>\n    <string name=\"safe_mode_file\">Safe mode file found!\\nNot loading any extensions on startup until file is removed.</string>\n    <string name=\"revert\">Revert</string>\n    <string name=\"subscription_in_progress_notification\">Updating subscribed shows</string>\n    <string name=\"subscription_list_name\">Subscribed</string>\n    <string name=\"subscription_new\">Subscribed to %s</string>\n    <string name=\"subscription_deleted\">Unsubscribed from %s</string>\n    <string name=\"subscription_episode_released\">Episode %d released!</string>\n    <string name=\"action_subscribe\">Subscribe</string>\n    <string name=\"action_unsubscribe\">Unsubscribe</string>\n    <string name=\"profile_number\">Profile %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Mobile data</string>\n    <string name=\"set_default\">Set default</string>\n    <string name=\"use\">Use</string>\n    <string name=\"edit\">Edit</string>\n    <string name=\"source_priority\">Source priority</string>\n    <string name=\"source_priority_help\">Decide how video sources should be sorted in the player</string>\n    <string name=\"profiles\">Profiles</string>\n    <string name=\"help\">Help</string>\n    <string name=\"quality_profile_help\">\n        Here you can change how the sources are ordered. If a video has a higher priority it will appear higher in the source selection.\n        The sum of the source priority and the quality priority is the video priority.\n        \\n\\nSource A: 3\n        \\nQuality B: 7\n        \\nWill have a combined video priority of 10.\n\n        \\n\\nNOTE: If the sum is 10 or more the player will automatically skip loading when that link is loaded!\n    </string>\n    <string name=\"qualities\">Qualities</string>\n    <string name=\"profile_background_des\">Profile background</string>\n    <string name=\"unable_to_inflate\">UI was unable to be created correctly, this is a MAJOR BUG and should be reported immediately %s</string>\n    <string name=\"already_voted\">You have already voted</string>\n    <string name=\"favorites_list_name\">Favorites</string>\n    <string name=\"favorite_added\">%s added to favorites</string>\n    <string name=\"favorite_removed\">%s removed from favorites</string>\n    <string name=\"action_add_to_favorites\">Add to favorites</string>\n    <string name=\"action_remove_from_favorites\">Remove from favorites</string>\n    <string name=\"duplicate_title\">Potential Duplicate Found</string>\n    <string name=\"duplicate_add\">Add</string>\n    <string name=\"duplicate_replace\">Replace</string>\n    <string name=\"duplicate_replace_all\">Replace All</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">\n        It appears that a potentially duplicate item already exists in your library: \\'%s.\\'\n\n        \\n\\nWould you like to add this item anyway, replace the existing one, or cancel the action?\n    </string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">\n        Potential duplicate items have been found in your library:\n\n        \\n\\n%s\n\n        \\n\\nWould you like to add this item anyway, replace the existing ones, or cancel the action?\n    </string>\n    <string name=\"enter_pin\">Enter PIN</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Enter PIN for %s</string>\n    <string name=\"enter_current_pin\">Enter Current PIN</string>\n    <string name=\"lock_profile\">Lock Profile</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"pin_error_incorrect\">Incorrect PIN. Please try again.</string>\n    <string name=\"pin_error_length\">PIN must be 4 characters</string>\n    <string name=\"select_an_account\">Select an Account</string>\n    <string name=\"no_account\">No account</string>\n    <string name=\"manage_accounts\">Manage Accounts</string>\n    <string name=\"edit_account\">Edit account</string>\n    <string name=\"logged_account\" formatted=\"true\">Logged in as %s</string>\n    <string name=\"skip_startup_account_select_pref\">Skip account selection at startup</string>\n    <string name=\"use_default_account\">Use Default Account</string>\n    <string name=\"rotate_video\">Rotate</string>\n    <string name=\"rotate_video_desc\">Display a toggle button for screen orientation</string>\n    <string name=\"auto_rotate_video_desc\">Enable automatic switching of screen orientation based on video orientation</string>\n    <string name=\"auto_rotate_video\">Auto rotate</string>\n    <string name=\"favorite\">Favorite</string>\n    <string name=\"unfavorite\">Unfavorite</string>\n    <!-- For Biometrics -->\n    <string name=\"biometric_authentication_title\">Unlock CloudStream</string>\n    <string name=\"biometric_setting\">Lock with Biometrics</string>\n    <string name=\"password_pin_authentication_title\">Password/PIN Authentication</string>\n    <string name=\"biometric_unsupported\">Biometric authentication is not supported on this device</string>\n    <string name=\"biometric_setting_summary\">Unlock the app with Fingerprint, Face ID, PIN, Pattern and Password.</string>\n    <string name=\"biometric_prompt_description\">After a few failed attempts, the prompt will close. Simply restart the app to try again.</string>\n    <string name=\"biometric_warning\">Your CloudStream data has been backed up now. Although the possibility of this is very low, all devices can behave differently. In the rare case, that you get locked out from accessing the app, clear the app data completely and restore from a backup. We are very sorry for any inconvenience arising from this.</string>\n    <string name=\"reset_btn\">Reset</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"device_pin_url_message\">Visit <b>%s</b> on your smartphone or computer and enter the above code</string>\n    <string name=\"device_pin_error_message\">Can\\'t get the device PIN code, try local authentication</string>\n    <string name=\"device_pin_expired_message\">PIN code is now expired !</string>\n    <string name=\"device_pin_counter_text\">Code expires in %1$dm %2$ds</string>\n    <string name=\"sort_release_date_new\">Release Date (New to Old)</string>\n    <string name=\"sort_release_date_old\">Release Date (Old to New)</string>\n    <string name=\"hide_player_control_names\">Hide names of the player\\'s controls</string>\n    <string name=\"preview_seekbar\">Seekbar preview</string>\n    <string name=\"preview_seekbar_desc\">Enable preview thumbnail on seekbar</string>\n    <string name=\"no_subtitles_loaded\">No subtitles loaded yet</string>\n    <string name=\"backup_path_title\">Backup folder location</string>\n    <string name=\"custom\">Custom</string>\n    <!--confirm exit dialog-->\n    <string name=\"confirm_before_exiting_title\">Confirm before exiting</string>\n    <string name=\"confirm_before_exiting_desc\">Show dialog before exiting the app</string>\n    <!--confirm exit dialog-->\n    <string name=\"show\">Show</string>\n    <string name=\"dont_show\">Don\\'t Show</string>\n    <string name=\"subs_edge_size\">Edge Size</string>\n    <string name=\"torrent_preferred_media\">Enable torrent in Settings/Providers/Preferred media</string>\n    <string name=\"torrent_not_accepted\">Restart app and accept Stream Torrent pop-up to proceed.</string>\n    <string name=\"software_decoding\">Software decoding</string>\n    <string name=\"software_decoding_desc\">Software decoding enables the player to play video files not supported by your device, but may cause laggy or unstable playback on high resolution.</string>\n    <string name=\"volume_exceeded_100\">Volume has exceeded 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Slide up again to go beyond 100%</string>\n    <string name=\"update_plugins\">Update Plugins</string>\n    <!--Manual Update Button-->\n    <string name=\"update_plugins_manually\">Update plugins manually</string>\n    <string name=\"starting_plugin_update_manually\">Starting plugin update process!</string>\n    <string name=\"plugins_updated_manually\">Successfully updated %d plugin(s)!</string>\n    <string name=\"no_plugins_updated_manually\">No plugins were updated.</string>\n    <string name=\"player_notification_channel_name\">Player notifications</string>\n    <string name=\"player_notification_channel_description\">The player notification for controlling the playback from the background</string>\n    <string name=\"subtitles_from_embedded\">Embedded</string>\n    <string name=\"subtitles_from_online\">Online</string>\n    <string name=\"all_subtitles_bold\">Make all subtitles bold</string>\n    <string name=\"all_subtitles_italic\">Make all subtitles italic</string>\n    <string name=\"background_radius\">Background Radius</string>\n    <string name=\"download_parallel_settings_des\">How many different items that can be downloaded in parallel</string>\n    <string name=\"parallel_downloads\">Parallel downloads</string>\n    <string name=\"concurrent_connections\">Concurrent connections</string>\n    <string name=\"concurrent_connections_settings_des\">How many concurrent connections each download can use while downloading</string>\n    <string name=\"go_to_downloads\">Go to Downloads</string>\n    <string name=\"no_internet_connection\">\n        No internet connection.\n        \\n\\nPlease connect to the internet and try again, or watch your downloads while you are offline.\n    </string>\n    <string name=\"overscan_settings_des\">Changes the bounds of the screen</string>\n    <string name=\"overscan_settings\">Overscan</string>\n    <string name=\"poster_size_settings_des\">Changes size of posters</string>\n    <string name=\"poster_size_settings\">Poster size</string>\n    <string name=\"speedup_title\">LongPress Speed Toggle</string>\n    <string name=\"speedup_summary\">Hold to get 2x speed</string>\n    <string name=\"edit_profile_image_title\">Edit Profile Image</string>\n    <string name=\"edit_profile_image_hint\">Enter Profile Image URL</string>\n    <string name=\"edit_profile_image_error_empty\">No URL Found</string>\n    <string name=\"edit_profile_image_error_invalid\">Invalid URL or Image</string>\n    <string name=\"edit_profile_image_success\">Successfully Image Updated</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Mark as watched up to this episode</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Remove watched up to this episode</string>\n    <string name=\"action_reload\">Reloaded</string>\n    <string name=\"reload_provider\">Reload Provider</string>\n    <string name=\"name\">Name</string>\n    <string name=\"source_name\">Source Name</string>\n    <string name=\"resolution_and_name\">Resolution and name</string>\n    <string name=\"download_all\">Download all</string>\n    <string name=\"cancel_all\">Cancel all</string>\n    <string name=\"download_episode_range\">Do you want to download episode %s?</string>\n    <string name=\"cancel_queue_message\">Do you want to cancel all queued downloads?</string>\n    <string name=\"subs_subtitle_alignment\">Subtitle Alignment</string>\n    <string name=\"bottom_left\">Bottom left</string>\n    <string name=\"bottom_center\">Bottom center</string>\n    <string name=\"bottom_right\">Bottom right</string>\n    <string name=\"middle_left\">Middle left</string>\n    <string name=\"middle_center\">Middle center</string>\n    <string name=\"middle_right\">Middle right</string>\n    <string name=\"top_left\">Top left</string>\n    <string name=\"top_center\">Top center</string>\n    <string name=\"top_right\">Top right</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d active download</item>\n        <item quantity=\"other\">%d active downloads</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d download queued</item>\n        <item quantity=\"other\">%d downloads queued</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <!-- Base application theme. Material3 -->\n    <style name=\"AppTheme\" parent=\"Theme.Material3.Dark.NoActionBar\">\n        <item name=\"android:windowBackground\">@drawable/splash_background</item>\n        <item name=\"android:colorEdgeEffect\">?attr/textColor</item>\n\n        <item name=\"android:navigationBarColor\">?attr/primaryBlackBackground</item>\n        <item name=\"android:statusBarColor\">?attr/iconGrayBackground</item>\n\n        <item name=\"android:windowTranslucentStatus\">true</item>\n        <item name=\"android:windowTranslucentNavigation\">false</item>\n\n        <item name=\"android:scrollbarThumbVertical\">@null</item>\n        <item name=\"android:scrollbarThumbHorizontal\">@null</item>\n\n        <item name=\"android:textViewStyle\">@style/AppTextViewStyle</item>\n        <item name=\"android:buttonStyle\">@style/AppButtonStyle</item>\n        <item name=\"android:editTextStyle\">@style/AppEditStyle</item>\n        <item name=\"alertDialogTheme\">@style/Theme.AlertDialog</item>\n        <item name=\"materialButtonStyle\">@style/AppMaterialButtonStyle</item>\n        <item name=\"preferenceFragmentCompatStyle\">@style/PreferenceTheme</item>\n        <item name=\"bottomSheetDialogTheme\">@style/AppBottomSheetDialogTheme</item>\n        <item name=\"searchViewStyle\">@style/AppSearchViewStyle</item>\n        <item name=\"android:searchViewStyle\">@style/AndroidSearchView</item>\n\n        <item name=\"tabStyle\">@style/Theme.Widget.Tabs</item>\n        <item name=\"android:divider\">@color/transparent</item>\n        <item name=\"divider\">@color/transparent</item>\n        <item name=\"android:dividerHeight\">0dp</item>\n        <item name=\"showDividers\">none</item>\n        <item name=\"android:listViewStyle\">@style/ListViewStyle</item>\n\n        <item name=\"castExpandedControllerStyle\">\n            @style/CustomCastExpandedController\n        </item>\n        <item name=\"castMiniControllerStyle\">@style/CustomCastMiniController</item>\n        <!--<item name=\"mediaRouteButtonTint\">?attr/colorPrimary</item>-->\n\n        <!-- Preference -->\n        <item name=\"android:textColor\">?attr/textColor</item>\n        <item name=\"android:textColorSecondary\">?attr/grayTextColor</item>\n\n        <item name=\"android:textColorHint\">?attr/grayTextColor</item>\n        <item name=\"android:editTextColor\">?attr/textColor</item>\n        <item name=\"android:colorForeground\">?attr/textColor</item>\n        <item name=\"android:colorControlHighlight\">?attr/textColor</item> <!--iconRipple-->\n\n        <item name=\"android:windowAllowReturnTransitionOverlap\">true</item>\n        <item name=\"android:windowAllowEnterTransitionOverlap\">true</item>\n        <!--<item name=\"preferenceTheme\">@style/PreferencesTheme</item>-->\n\n        <!-- DEF STYLE -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"textColor\">@color/textColor</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <item name=\"grayTextColor\">@color/grayTextColor</item>\n        <item name=\"primaryGrayBackground\">@color/primaryGrayBackground</item>\n        <item name=\"primaryBlackBackground\">@color/primaryBlackBackground</item>\n        <item name=\"iconGrayBackground\">@color/iconGrayBackground</item>\n        <item name=\"boxItemBackground\">@color/boxItemBackground</item>\n        <item name=\"iconColor\">@color/iconColor</item>\n        <item name=\"white\">@color/white</item>\n        <item name=\"black\">@color/black</item>\n        <item name=\"focusBackground\">?android:attr/selectableItemBackground</item>\n        <item name=\"preferenceTheme\">@style/CustomPreferenceThemeOverlay</item>\n\n        <item name=\"download_icon_color\">?attr/white</item>\n        <item name=\"download_fill_color\">?attr/white</item>\n        <item name=\"download_outline_color\">?attr/white</item>\n        <item name=\"download_icon_scale\">1.0</item>\n\n        <item name=\"cpv_focusBorderColor\">?attr/white</item>\n    </style>\n\n    <style name=\"AppThemeTvOverlay\">\n        <item name=\"focusBackground\">@drawable/outline_drawable_less</item>\n    </style>\n\n    <style name=\"ListViewStyle\" parent=\"Widget.AppCompat.ListView\">\n        <item name=\"android:divider\">@null</item>\n        <item name=\"android:listSelector\">@drawable/outline_drawable_forced</item>\n        <item name=\"android:drawSelectorOnTop\">false</item>\n    </style>\n\n    <style name=\"AmoledModeLight\" parent=\"AmoledMode\">\n        <item name=\"primaryGrayBackground\">@color/amoledModeLight</item>\n        <item name=\"boxItemBackground\">@color/amoledModeLight</item>\n    </style>\n\n    <style name=\"ChipFilled\" parent=\"@style/Widget.Material3.Chip.Filter\">\n        <item name=\"chipBackgroundColor\">@color/chip_color</item>\n        <item name=\"chipStrokeColor\">@color/white_transparent_toggle</item>\n        <!--        <item name=\"chipStrokeColor\">@color/transparent</item>-->\n        <item name=\"chipStrokeWidth\">2dp</item>\n        <item name=\"textColor\">@color/chip_color_text</item>\n        <item name=\"android:textColor\">@color/chip_color_text</item>\n        <item name=\"checkedIconTint\">@color/chip_color_text</item>\n        <item name=\"fontFamily\">@font/google_sans</item>\n        <item name=\"chipIconTint\">@color/chip_color_text</item>\n        <item name=\"android:fontFamily\">@font/google_sans</item>\n        <item name=\"android:tag\">@string/tv_no_focus_tag</item>\n        <item name=\"chipMinTouchTargetSize\">0dp</item>\n        <item name=\"checkedIconVisible\">false</item>\n    </style>\n\n    <style name=\"RoundProgressbar\">\n        <item name=\"indicatorTrackGapSize\">0dp</item>\n        <item name=\"trackStopIndicatorSize\">0dp</item>\n        <item name=\"trackColor\">@color/color_primary_transparent</item>\n    </style>\n\n    <style name=\"ChipFilledSemiTransparent\" parent=\"@style/ChipFilled\">\n        <item name=\"chipBackgroundColor\">@color/transparent</item>\n        <item name=\"chipSurfaceColor\">#33FFFFFF</item>\n        <item name=\"backgroundColor\">@color/transparent</item>\n        <item name=\"android:textColor\">@color/textColor</item>\n        <item name=\"textColor\">@color/textColor</item>\n    </style>\n\n    <style name=\"ChipParent\">\n        <item name=\"chipSpacingVertical\">-5dp</item>\n        <item name=\"chipSpacingHorizontal\">5dp</item>\n        <item name=\"textColor\">?attr/textColor</item>\n    </style>\n\n    <style name=\"AmoledMode\">\n        <item name=\"primaryGrayBackground\">@color/black</item>\n        <item name=\"primaryBlackBackground\">@color/black</item>\n        <item name=\"iconGrayBackground\">@color/primaryBlackBackground</item>\n        <item name=\"boxItemBackground\">@color/black</item>\n        <item name=\"textColor\">@color/textColor</item>\n        <item name=\"grayTextColor\">@color/grayTextColor</item>\n        <item name=\"white\">@color/white</item>\n        <item name=\"black\">@color/black</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n    </style>\n\n    <style name=\"DubButton\" parent=\"@style/SearchBox\">\n        <item name=\"android:text\">@string/app_dubbed_text</item>\n        <!-- Background is set programmatically -->\n        <item name=\"textColor\">?attr/primaryGrayBackground</item>\n        <item name=\"android:textColor\">?attr/primaryGrayBackground</item>\n    </style>\n\n    <style name=\"SubButton\" parent=\"@style/SearchBox\">\n        <item name=\"android:text\">@string/app_subbed_text</item>\n    </style>\n    <style name=\"EpisodeTextButton\" parent=\"@style/SearchBox\">\n        <item name=\"android:text\">@string/episode_text</item>\n    </style>\n\n    <!--<style name=\"RatingButton\" parent=\"@style/SearchBox\">\n        <item name=\"android:background\">@drawable/rating_bg_color</item>\n        <item name=\"android:textColor\">@color/ratingColor</item>\n    </style>-->\n\n    <style name=\"RatingButton\" parent=\"@style/SearchBox\">\n        <item name=\"android:minWidth\">40dp</item>\n        <item name=\"drawableTint\">?attr/textColor</item>\n        <item name=\"drawableSize\">10sp</item>\n\n        <item name=\"drawableEndCompat\">@drawable/kid_star_24px</item>\n    </style>\n\n    <style name=\"TypeButton\" parent=\"@style/SearchBox\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:text\">@string/quality_hd</item>\n    </style>\n\n    <style name=\"LightMode\">\n        <item name=\"primaryGrayBackground\">@color/lightPrimaryGrayBackground</item>\n        <item name=\"primaryBlackBackground\">@color/lightBitDarkerGrayBackground</item>\n        <item name=\"iconGrayBackground\">@color/lightGrayBackground</item>\n        <item name=\"boxItemBackground\">@color/lightItemBackground</item>\n        <item name=\"textColor\">@color/lightTextColor</item>\n        <item name=\"grayTextColor\">@color/lightGrayTextColor</item>\n        <item name=\"white\">@color/black</item>\n        <item name=\"black\">@color/white</item>\n        <item name=\"colorOnPrimary\">@color/blackText</item>\n        <item name=\"isLightTheme\">true</item>\n        <item name=\"android:windowLightNavigationBar\" tools:targetApi=\"o_mr1\">true</item>\n    </style>\n\n    <style name=\"DraculaMode\">\n        <item name=\"primaryGrayBackground\">@color/DraculaPrimaryGrayBackground</item>\n        <item name=\"primaryBlackBackground\">@color/DraculaBitDarkerGrayBackground</item>\n        <item name=\"iconGrayBackground\">@color/DraculaGrayBackground</item>\n        <item name=\"boxItemBackground\">@color/DraculaItemBackground</item>\n        <item name=\"textColor\">@color/DraculaTextColor</item>\n        <item name=\"iconColor\">@color/DraculaIconColor</item>\n        <item name=\"white\">@color/DraculaTextColor</item>\n        <item name=\"black\">@color/DraculaPrimaryGrayBackground</item>\n        <item name=\"colorOnPrimary\">@color/DraculaTextColor</item>\n    </style>\n\n\n    <style name=\"SilentBlueMode\">\n        <item name=\"primaryGrayBackground\">@color/SilentBluePrimaryGrayBackground</item>\n        <item name=\"primaryBlackBackground\">@color/SilentBlueBitDarkerGrayBackground</item>\n        <item name=\"iconGrayBackground\">@color/SilentBlueGrayBackground</item>\n        <item name=\"boxItemBackground\">@color/SilentBlueItemBackground</item>\n        <item name=\"textColor\">@color/SilentBlueTextColor</item>\n        <item name=\"iconColor\">@color/SilentBlueIconColor</item>\n        <item name=\"white\">@color/SilentBlueTextColor</item>\n        <item name=\"black\">@color/SilentBluePrimaryGrayBackground</item>\n        <item name=\"colorOnPrimary\">@color/SilentBlueTextColor</item>\n    </style>\n\n    <style name=\"LavenderMode\">\n        <item name=\"primaryGrayBackground\">@color/LavenderPrimaryGrayBackground</item>\n        <item name=\"primaryBlackBackground\">@color/LavenderBitDarkerGrayBackground</item>\n        <item name=\"iconGrayBackground\">@color/LavenderGrayBackground</item>\n        <item name=\"boxItemBackground\">@color/LavenderItemBackground</item>\n        <item name=\"textColor\">@color/LavenderTextColor</item>\n        <item name=\"iconColor\">@color/LavenderIconColor</item>\n        <item name=\"white\">@color/LavenderTextColor</item>\n        <item name=\"black\">@color/LavenderPrimaryGrayBackground</item>\n        <item name=\"colorOnPrimary\">@color/LavenderTextColor</item>\n        <item name=\"isLightTheme\">true</item>\n        <item name=\"android:windowLightNavigationBar\" tools:targetApi=\"o_mr1\">true</item>\n    </style>\n\n    <style name=\"MonetMode\">\n        <item name=\"primaryGrayBackground\">@color/material_dynamic_neutral20</item>\n        <item name=\"primaryBlackBackground\">@color/material_dynamic_neutral10</item>\n        <item name=\"iconGrayBackground\">@color/material_dynamic_neutral20</item>\n        <item name=\"boxItemBackground\">@color/material_dynamic_neutral20</item>\n        <item name=\"textColor\">@color/material_dynamic_neutral90</item>\n        <item name=\"grayTextColor\">@color/material_dynamic_neutral60</item>\n        <item name=\"white\">@color/material_dynamic_neutral90</item>\n        <item name=\"black\">@color/material_dynamic_neutral10</item>\n        <item name=\"colorOnPrimary\">@color/material_on_primary_emphasis_medium</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorNormal\">\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!-- Needed for leanback fuckery -->\n        <item name=\"android:colorAccent\">@color/colorAccent</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorMonet\">\n        <item name=\"colorPrimary\">@color/material_dynamic_primary80</item>\n        <item name=\"android:colorPrimary\">@color/material_dynamic_primary80</item>\n        <item name=\"colorPrimaryDark\">@color/material_dynamic_primary30</item>\n        <item name=\"colorAccent\">@color/material_dynamic_primary80</item>\n        <item name=\"colorOnPrimary\">@color/material_dynamic_primary20</item>\n        <!-- Needed for leanback fuckery -->\n        <item name=\"android:colorAccent\">@color/material_dynamic_primary80</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorMonetTwo\">\n        <item name=\"colorPrimary\">@color/material_dynamic_secondary80</item>\n        <item name=\"android:colorPrimary\">@color/material_dynamic_secondary80</item>\n        <item name=\"colorPrimaryDark\">@color/material_dynamic_secondary30</item>\n        <item name=\"colorAccent\">@color/material_dynamic_secondary80</item>\n        <item name=\"colorOnPrimary\">@color/material_dynamic_secondary20</item>\n        <!-- Needed for leanback fuckery -->\n        <item name=\"android:colorAccent\">@color/material_dynamic_secondary80</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorBlue\">\n        <item name=\"colorPrimary\">@color/colorPrimaryBlue</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryBlue</item>\n        <item name=\"colorPrimaryDark\">#4855A2</item>\n        <item name=\"colorAccent\">#5A6BCB</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!-- Needed for leanback fuckery -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryBlue</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorPurple\">\n        <item name=\"colorPrimary\">@color/colorPrimaryPurple</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryPurple</item>\n        <item name=\"colorPrimaryDark\">#4704A3</item>\n        <item name=\"colorAccent\">#7125DB</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <item name=\"android:colorAccent\">@color/colorPrimaryPurple</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorGreen\">\n        <item name=\"colorPrimary\">@color/colorPrimaryGreen</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryGreen</item>\n        <item name=\"colorPrimaryDark\">#007363</item>\n        <item name=\"colorAccent\">#39C1AE</item>\n        <item name=\"colorOnPrimary\">@color/blackText</item>\n        <item name=\"android:colorAccent\">@color/colorPrimaryGreen</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorGreenApple\">\n        <item name=\"colorPrimary\">@color/colorPrimaryGreenApple</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryGreenApple</item>\n        <item name=\"colorPrimaryDark\">#319B5A</item>\n        <item name=\"colorAccent\">#51C57E</item>\n        <item name=\"colorOnPrimary\">@color/blackText</item>\n        <item name=\"android:colorAccent\">@color/colorPrimaryGreenApple</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorRed\">\n        <item name=\"colorPrimary\">@color/colorPrimaryRed</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryRed</item>\n        <item name=\"colorPrimaryDark\">#B62B2B</item>\n        <item name=\"colorAccent\">@color/colorPrimaryRed</item> <!--#F53B3B-->\n        <item name=\"colorOnPrimary\">@color/whiteText</item> <!--#EC3838-->\n        <!-- Needed for leanback fuckery -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryRed</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorBanana\">\n        <item name=\"colorPrimary\">@color/colorPrimaryBanana</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryBanana</item>\n        <item name=\"colorPrimaryDark\">#9B7D31</item>\n        <item name=\"colorAccent\">#C5B251</item>\n        <item name=\"colorOnPrimary\">@color/blackText</item>\n        <item name=\"android:colorAccent\">@color/colorPrimaryBanana</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorParty\">\n        <item name=\"colorPrimary\">@color/colorPrimaryParty</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryParty</item>\n        <item name=\"colorPrimaryDark\">#C1495B</item>\n        <item name=\"colorAccent\">#FD798C</item>\n        <item name=\"colorOnPrimary\">@color/blackText</item>\n        <item name=\"android:colorAccent\">@color/colorPrimaryParty</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorPink\">\n        <item name=\"colorPrimary\">@color/colorPrimaryPink</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryPink</item>\n        <item name=\"colorPrimaryDark\">#DD1280</item>\n        <item name=\"colorAccent\">#FF4DAE</item>\n        <item name=\"colorOnPrimary\">@color/blackText</item>\n        <item name=\"android:colorAccent\">@color/colorPrimaryPink</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorCarnationPink\">\n        <item name=\"colorPrimary\">@color/colorPrimaryCarnationPink</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryCarnationPink</item>\n        <item name=\"colorPrimaryDark\">#83366f</item>\n        <item name=\"colorAccent\">#BD5DA5</item>\n        <item name=\"colorOnPrimary\">@color/blackText</item>\n        <!--   Needed for leanback fuckery   -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryCarnationPink</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorMaroon\">\n        <item name=\"colorPrimary\">@color/colorPrimaryMaroon</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryMaroon</item>\n        <item name=\"colorPrimaryDark\">#370C0C</item>\n        <item name=\"colorAccent\">#451010</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!--   Needed for leanback fuckery   -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryMaroon</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorDarkGreen\">\n        <item name=\"colorPrimary\">@color/colorPrimaryDarkGreen</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryDarkGreen</item>\n        <item name=\"colorPrimaryDark\">#003d00</item>\n        <item name=\"colorAccent\">#004500</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!--   Needed for leanback fuckery   -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryDarkGreen</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorNavyBlue\">\n        <item name=\"colorPrimary\">@color/colorPrimaryNavyBlue</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryNavyBlue</item>\n        <item name=\"colorPrimaryDark\">#000073</item>\n        <item name=\"colorAccent\">#000080</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!--   Needed for leanback fuckery   -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryNavyBlue</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorGrey\">\n        <item name=\"colorPrimary\">@color/colorPrimaryGrey</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryGrey</item>\n        <item name=\"colorPrimaryDark\">#484848</item>\n        <item name=\"colorAccent\">#515151</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!--   Needed for leanback fuckery   -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryGrey</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorWhite\">\n        <item name=\"colorPrimary\">@color/colorPrimaryWhite</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryWhite</item>\n        <item name=\"colorPrimaryDark\">#CCCCCC</item>\n        <item name=\"colorAccent\">#FFFFFF</item>\n        <item name=\"colorOnPrimary\">@color/blackText</item>\n        <!--   Needed for leanback fuckery   -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryWhite</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorBrown\">\n        <item name=\"colorPrimary\">@color/colorPrimaryBrown</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryBrown</item>\n        <item name=\"colorPrimaryDark\">#582700</item>\n        <item name=\"colorAccent\">#622C00</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!--   Needed for leanback fuckery   -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryBrown</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorOrange\">\n        <item name=\"colorPrimary\">@color/colorPrimaryOrange</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryOrange</item>\n        <item name=\"colorPrimaryDark\">#A66B00</item>\n        <item name=\"colorAccent\">#CE8500</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!--    Needed for leanback fuckery    -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryOrange</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorDandelionYellow\">\n        <item name=\"colorPrimary\">@color/colorPrimaryDandelionYellow</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryDandelionYellow</item>\n        <item name=\"colorPrimaryDark\">#C49600</item>\n        <item name=\"colorAccent\">#F5BB00</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!--    Needed for leanback fuckery    -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryDandelionYellow</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorCoolBlue\">\n        <item name=\"colorPrimary\">@color/colorPrimaryCoolBlue</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryCoolBlue</item>\n        <item name=\"colorPrimaryDark\">#306981</item>\n        <item name=\"colorAccent\">#51b0d7</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!--    Needed for leanback fuckery    -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryCoolBlue</item>\n    </style>\n\n    <style name=\"OverlayPrimaryColorLavender\">\n        <item name=\"colorPrimary\">@color/colorPrimaryLavender</item>\n        <item name=\"android:colorPrimary\">@color/colorPrimaryLavender</item>\n        <item name=\"colorPrimaryDark\">#6B51AB</item>\n        <item name=\"colorAccent\">#7961B4</item>\n        <item name=\"colorOnPrimary\">@color/whiteText</item>\n        <!--    Needed for leanback fuckery    -->\n        <item name=\"android:colorAccent\">@color/colorPrimaryLavender</item>\n    </style>\n\n    <style name=\"customRatingBar\" parent=\"@style/Widget.AppCompat.RatingBar\">\n\n        <item name=\"android:progressDrawable\">@drawable/abc_ratingbar_indicator_material</item>\n        <item name=\"android:indeterminateDrawable\">@drawable/abc_ratingbar_indicator_material</item>\n    </style>\n\n    <style name=\"LoadedStyle\">\n        <item name=\"android:navigationBarColor\">?attr/primaryGrayBackground</item>\n        <item name=\"android:windowBackground\">?attr/primaryBlackBackground</item>\n    </style>\n\n    <style name=\"AndroidSearchView\" parent=\"AppSearchViewStyle\">\n        <item name=\"android:paddingStart\">-10dp</item>\n    </style>\n\n    <style name=\"AppSearchViewStyle\" parent=\"Theme.MaterialComponents.NoActionBar\">\n        <item name=\"android:searchIcon\">@drawable/search_icon</item>\n        <item name=\"android:queryHint\">@string/search_hint</item>\n        <item name=\"android:background\">@color/transparent</item>\n        <item name=\"android:fontFamily\">@font/google_sans</item>\n        <item name=\"closeIcon\">@drawable/ic_baseline_close_24</item>\n    </style>\n\n    <style name=\"AppBottomSheetDialogTheme\">\n        <item name=\"android:navigationBarColor\">?attr/boxItemBackground</item>\n        <item name=\"android:windowCloseOnTouchOutside\">true</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:windowAnimationStyle\">@style/Animation.Design.BottomSheetDialog</item>\n        <item name=\"bottomSheetStyle\">@style/AppModalStyle</item>\n    </style>\n\n    <style name=\"AppModalStyle\">\n        <item name=\"android:windowCloseOnTouchOutside\">true</item>\n        <item name=\"behavior_hideable\">true</item>\n        <item name=\"behavior_skipCollapsed\">true</item>\n        <item name=\"shapeAppearance\">@null</item>\n        <item name=\"shapeAppearanceOverlay\">@null</item>\n        <item name=\"backgroundTint\">?attr/primaryBlackBackground</item>\n        <item name=\"android:background\">@drawable/rounded_dialog</item>\n        <item name=\"behavior_peekHeight\">512dp</item>\n    </style>\n\n    <style name=\"PreferenceTheme\" parent=\"@style/AppTheme\" />\n\n    <style name=\"Theme.AlertDialog\" parent=\"ThemeOverlay.MaterialComponents.Dialog.Alert\">\n        <item name=\"android:windowMinWidthMajor\">@dimen/abc_dialog_min_width_major</item>\n        <item name=\"android:windowMinWidthMinor\">@dimen/abc_dialog_min_width_minor</item>\n        <item name=\"android:windowBackground\">@drawable/dialog__window_background</item>\n        <item name=\"textAllCaps\">false</item>\n        <item name=\"android:textColorPrimary\">?attr/grayTextColor</item>\n\n        <item name=\"buttonBarPositiveButtonStyle\">@style/WhiteButton.Dialog</item>\n        <item name=\"buttonBarNegativeButtonStyle\">@style/BlackButton.Dialog</item>\n        <item name=\"buttonBarNeutralButtonStyle\">@style/BlackButton.Dialog</item>\n    </style>\n\n    <style name=\"TabNoCaps\" parent=\"TextAppearance.Design.Tab\">\n        <item name=\"textAllCaps\">false</item>\n        <item name=\"fontFamily\">@font/google_sans</item>\n    </style>\n\n    <style name=\"AppTextViewStyle\" parent=\"android:Widget.TextView\">\n        <item name=\"android:fontFamily\">@font/google_sans</item>\n    </style>\n\n    <style name=\"AppButtonStyle\" parent=\"android:Widget.Holo.Button\">\n        <item name=\"android:fontFamily\">@font/google_sans</item>\n    </style>\n\n    <style name=\"AppEditStyle\" parent=\"android:Widget.EditText\">\n        <item name=\"android:fontFamily\">@font/google_sans</item>\n    </style>\n\n    <style name=\"ResultInfoText\">\n        <item name=\"android:layout_gravity\">center_vertical</item>\n        <item name=\"textColor\">?attr/white</item>\n\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:minHeight\">24dp</item>\n        <item name=\"android:minWidth\">0dp</item>\n        <!--   <item name=\"android:paddingStart\">5dp</item>\n           <item name=\"android:paddingEnd\">5dp</item>-->\n    </style>\n\n    <style name=\"AppMaterialButtonStyle\" parent=\"Widget.MaterialComponents.Button\">\n        <item name=\"android:fontFamily\">@font/google_sans</item>\n    </style>\n\n    <style name=\"Theme.Widget.Tabs\" parent=\"Widget.MaterialComponents.TabLayout.Colored\">\n        <!--<item name=\"tabGravity\">center</item>\n        <item name=\"backgroundTint\">@color/transparent</item>\n        <item name=\"tabIndicator\">@drawable/tab_selector</item>\n        <item name=\"tabIndicatorColor\">?attr/colorPrimary</item>\n        <item name=\"tabTextColor\">?attr/colorPrimary</item>\n        <item name=\"tabIndicatorFullWidth\">false</item>\n        <item name=\"tabIndicatorHeight\">3dp</item>\n        <item name=\"tabInlineLabel\">true</item>\n        <item name=\"tabMinWidth\">75dp</item>\n        <item name=\"tabMode\">scrollable</item>-->\n    </style>\n\n    <style name=\"DarkFragment\" parent=\"AppTheme\">\n        <item name=\"android:navigationBarColor\">?attr/colorPrimary</item>\n    </style>\n\n    <style name=\"AlertDialogCustom\" parent=\"Theme.AlertDialog\">\n        <item name=\"android:windowFullscreen\">true</item>\n        <item name=\"android:textColor\">?attr/textColor</item>\n        <item name=\"android:textColorPrimary\">?attr/textColor</item>\n        <!--<item name=\"android:background\">@color/darkBackground</item>-->\n        <item name=\"android:textAllCaps\">false</item>\n        <!--<item name=\"android:colorBackground\">@color/darkBackground</item>-->\n        <item name=\"textColorAlertDialogListItem\">?attr/textColor</item>\n        <item name=\"colorControlNormal\">?attr/textColor</item>\n        <!-- colorPrimarySecond used because colorPrimary fails for no reason -->\n        <item name=\"colorControlActivated\">?attr/colorPrimary</item>\n\n        <item name=\"android:windowMinWidthMajor\">@dimen/abc_dialog_min_width_major</item>\n        <item name=\"android:windowMinWidthMinor\">@dimen/abc_dialog_min_width_minor</item>\n        <item name=\"android:windowBackground\">@drawable/dialog__window_background</item>\n    </style>\n\n    <style name=\"AlertDialogCustomTransparent\" parent=\"Theme.AppCompat.Dialog.Alert\">\n        <item name=\"android:windowBackground\">@color/transparent</item>\n    </style>\n\n    <style name=\"DialogFullscreen\">\n        <item name=\"android:windowEnterAnimation\">@anim/enter_anim</item>\n        <item name=\"android:windowExitAnimation\">@anim/exit_anim</item>\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:windowActionBar\">false</item>\n        <item name=\"android:windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"DialogFullscreenPlayer\" parent=\"DialogFullscreen\">\n        <item name=\"android:windowBackground\">?attr/primaryBlackBackground</item>\n        <item name=\"android:windowTranslucentNavigation\">false</item>\n        <item name=\"android:windowTranslucentStatus\">false</item>\n\n        <item name=\"android:windowIsFloating\">false</item>\n        <item name=\"android:navigationBarColor\">?attr/primaryBlackBackground</item>\n        <item name=\"android:statusBarColor\">?attr/primaryBlackBackground</item>\n        <item name=\"android:windowLightStatusBar\" tools:targetApi=\"m\">?attr/isLightTheme</item>\n    </style>\n\n    <style name=\"DialogHalfFullscreen\" parent=\"AlertDialogCustom\">\n        <item name=\"android:windowEnterAnimation\">@anim/enter_anim</item>\n        <item name=\"android:windowExitAnimation\">@anim/exit_anim</item>\n\n        <item name=\"android:windowMinWidthMajor\">45%</item> <!-- 65% -->\n        <item name=\"android:windowMinWidthMinor\">95%</item> <!-- 95% -->\n    </style>\n\n    <style name=\"AlertDialogCustomBlack\" parent=\"Theme.AppCompat.Dialog.Alert\">\n        <item name=\"android:windowBackground\">?attr/primaryBlackBackground</item>\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">match_parent</item>\n\n        <!-- No backgrounds, titles or window float -->\n        <item name=\"android:windowNoTitle\">true</item>\n        <item name=\"android:windowIsFloating\">false</item>\n        <item name=\"android:navigationBarColor\">?attr/primaryBlackBackground</item>\n    </style>\n\n    <style name=\"PopupMenu\" parent=\"@android:style/Widget.PopupMenu\">\n        <item name=\"android:backgroundTint\">?attr/primaryBlackBackground</item>\n    </style>\n\n    <style name=\"CustomPreferenceThemeOverlay\" parent=\"@style/PreferenceThemeOverlay\">\n        <item name=\"android:layout\">@layout/settings_title_top</item>\n        <item name=\"preferenceStyle\">@style/CustomPreferenceStyle</item>\n        <item name=\"switchPreferenceStyle\">@style/CustomSwitchPreferenceStyle</item>\n        <item name=\"seekBarPreferenceStyle\">@style/CustomSeekBarPreferenceStyle</item>\n    </style>\n\n    <!--\n    <style name=\"CustomPreferenceCategoryStyle\" parent=\"@style/Preference.Category.Material\">\n        <item name=\"android:layout\">@layout/custom_preference_category_material</item>\n    </style>-->\n\n    <style name=\"CustomSwitchPreferenceStyle\" parent=\"@style/Preference.SwitchPreference.Material\">\n        <item name=\"android:layout\">@layout/custom_preference_material</item>\n    </style>\n\n    <style name=\"CustomSeekBarPreferenceStyle\" parent=\"@style/Preference.SeekBarPreference.Material\">\n        <item name=\"android:layout\">@layout/custom_preference_widget_seekbar</item>\n    </style>\n\n    <style name=\"CustomPreferenceStyle\" parent=\"@style/Preference.Material\">\n        <item name=\"android:layout\">@layout/custom_preference_material</item>\n    </style>\n\n    <style name=\"SettingsItem\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">50dp</item>\n        <item name=\"android:gravity\">center_vertical</item>\n        <item name=\"android:paddingStart\">20dp</item>\n        <item name=\"android:paddingEnd\">20dp</item>\n        <item name=\"android:selectAllOnFocus\">true</item>\n        <item name=\"android:background\">?attr/focusBackground</item>\n        <item name=\"android:textColor\">?attr/textColor</item>\n        <item name=\"android:textAppearance\">?android:attr/textAppearanceListItemSmall</item>\n        <item name=\"drawableEndCompat\">@drawable/ic_baseline_keyboard_arrow_right_24</item>\n    </style>\n\n    <style name=\"WatchHeaderText\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:textColor\">?attr/textColor</item>\n        <item name=\"android:gravity\">center_vertical</item>\n        <item name=\"android:textSize\">18sp</item>\n        <item name=\"android:layout_marginEnd\">50dp</item>\n        <item name=\"android:textStyle\">bold</item>\n    </style>\n\n    <style name=\"SearchBox\">\n        <item name=\"android:background\">@drawable/bg_color_both</item>\n        <item name=\"android:minWidth\">40dp</item>\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:paddingLeft\">7dp</item>\n        <item name=\"android:paddingRight\">7dp</item>\n        <item name=\"android:paddingTop\">3dp</item>\n        <item name=\"android:paddingBottom\">3dp</item>\n        <item name=\"android:textSize\">10sp</item>\n        <item name=\"textColor\">?attr/textColor</item>\n        <item name=\"android:textColor\">?attr/textColor</item>\n        <item name=\"android:layout_marginLeft\">1dp</item>\n        <item name=\"android:layout_marginRight\">1dp</item>\n        <item name=\"android:layout_marginTop\">1dp</item>\n    </style>\n\n    <style name=\"NiceButton\">\n        <!--removes shadow-->\n        <item name=\"android:stateListAnimator\">@null</item>\n\n        <item name=\"android:padding\">5dp</item>\n        <item name=\"android:layout_marginStart\">5dp</item>\n        <item name=\"android:layout_marginEnd\">5dp</item>\n        <item name=\"android:layout_height\">40dp</item>\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"android:textAllCaps\">false</item>\n        <item name=\"iconGravity\">textStart</item>\n        <item name=\"iconSize\">20dp</item>\n        <item name=\"cornerRadius\">@dimen/rounded_button_radius</item>\n        <item name=\"android:textSize\">15sp</item>\n\n        <item name=\"android:insetTop\">0dp</item>\n        <item name=\"android:insetBottom\">0dp</item>\n        <item name=\"android:foreground\">@drawable/outline_drawable_less</item>\n        <item name=\"android:tag\">@string/tv_no_focus_tag</item>\n    </style>\n\n    <style name=\"WhiteButton\" parent=\"NiceButton\">\n        <item name=\"strokeColor\">?attr/iconGrayBackground</item>\n        <item name=\"backgroundTint\">?attr/textColor</item>\n        <item name=\"iconTint\">?attr/iconGrayBackground</item>\n        <item name=\"android:textColor\">?attr/iconGrayBackground</item>\n        <item name=\"rippleColor\">?attr/primaryBlackBackground</item>\n    </style>\n    <!-- This is so shit, because android has no native way to either changing the layout (android:layout) or changing the layout_height for no reason.\n    So the only way to shrink the buttons is by using insetTop+insetBottom along with the drawable.\n    https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/layout/alert_dialog.xml <- old xml for reference, but new use m3_alert_dialog\n    -->\n    <style name=\"BlackButton.Dialog\" parent=\"BlackButton\">\n        <item name=\"android:foreground\">@drawable/outline_drawable_less_inset</item>\n        <item name=\"android:insetTop\">@dimen/dialog_buttons_inset</item>\n        <item name=\"android:insetBottom\">@dimen/dialog_buttons_inset</item>\n    </style>\n\n    <style name=\"WhiteButton.Dialog\" parent=\"WhiteButton\">\n        <item name=\"android:foreground\">@drawable/outline_drawable_less_inset</item>\n        <item name=\"android:insetTop\">@dimen/dialog_buttons_inset</item>\n        <item name=\"android:insetBottom\">@dimen/dialog_buttons_inset</item>\n    </style>\n\n    <style name=\"BlackLabel\" parent=\"@style/Widget.MaterialComponents.Tooltip\">\n        <item name=\"backgroundTint\">?attr/iconGrayBackground</item>\n        <item name=\"android:textColor\">?attr/textColor</item>\n    </style>\n\n    <style name=\"CheckLabel\" parent=\"@style/NoCheckLabel\">\n\n        <!--        <item name=\"drawableTint\">@color/check_selection_color</item>-->\n        <!--        Set color in the drawable instead of tint to allow multiple drawables-->\n        <item name=\"android:checkMark\">?android:attr/listChoiceIndicatorSingle</item>\n        <item name=\"drawableStartCompat\">@drawable/ic_baseline_check_24_listview</item>\n    </style>\n\n\n    <style name=\"NoCheckLabel\" parent=\"@style/AppTextViewStyle\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:minHeight\">?android:attr/listPreferredItemHeightSmall</item>\n        <item name=\"android:textColor\">@color/text_selection_color</item>\n        <item name=\"android:textSize\">16sp</item>\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"android:gravity\">center_vertical</item>\n        <item name=\"android:paddingStart\">12dp</item>\n        <item name=\"android:paddingEnd\">12dp</item>\n        <item name=\"android:ellipsize\">marquee</item>\n        <item name=\"android:foreground\">?attr/selectableItemBackgroundBorderless</item>\n        <item name=\"android:drawablePadding\">20dp</item>\n    </style>\n\n    <!-- https://github.com/material-components/material-components-android/blob/4e4e8f3388beb7e82a87cb67142aa34444a79740/lib/java/com/google/android/material/navigation/res/values/attrs.xml#L129 -->\n    <!-- https://developer.android.com/design/ui/tv/guides/components/navigation-drawer -->\n    <style name=\"CustomIndicator\" parent=\"Widget.Material3Expressive.NavigationRailView.ActiveIndicator\">\n        <item name=\"expandedHeight\">48dp</item>\n        <item name=\"expandedWidth\">180dp</item>\n        <item name=\"android:height\">48dp</item>\n        <item name=\"android:width\">48dp</item>\n\n        <item name=\"expandedActiveIndicatorPaddingTop\">0dp</item>\n        <item name=\"expandedActiveIndicatorPaddingBottom\">0dp</item>\n    </style>\n\n    <style name=\"BlackButton\" parent=\"NiceButton\">\n        <item name=\"strokeColor\">?attr/textColor</item>\n        <item name=\"backgroundTint\">?attr/iconGrayBackground</item>\n        <item name=\"iconTint\">?attr/textColor</item>\n        <item name=\"android:textColor\">?attr/textColor</item>\n        <item name=\"rippleColor\">@color/black_button_ripple</item>\n    </style>\n\n    <style name=\"SmallBlackButton\" parent=\"BlackButton\">\n        <item name=\"android:layout_height\">24dp</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:textSize\">12sp</item>\n        <item name=\"android:layout_marginStart\">0dp</item>\n        <item name=\"android:layout_marginEnd\">0dp</item>\n        <item name=\"android:stateListAnimator\">@null</item>\n        <item name=\"iconPadding\">0dp</item>\n        <item name=\"android:paddingTop\">0dp</item>\n        <item name=\"android:paddingBottom\">0dp</item>\n        <item name=\"android:minWidth\">0dp</item>\n    </style>\n\n    <style name=\"SmallWhiteButton\" parent=\"WhiteButton\">\n        <item name=\"android:layout_height\">24dp</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:textSize\">12sp</item>\n        <item name=\"android:layout_marginStart\">0dp</item>\n        <item name=\"android:layout_marginEnd\">0dp</item>\n        <item name=\"android:stateListAnimator\">@null</item>\n        <item name=\"iconPadding\">0dp</item>\n        <item name=\"android:paddingTop\">0dp</item>\n        <item name=\"android:paddingBottom\">0dp</item>\n        <item name=\"android:minWidth\">0dp</item>\n    </style>\n\n    <style name=\"RoundedSelectableButtonIcon\" parent=\"RoundedSelectableButton\">\n        <item name=\"minWidth\">0dp</item>\n        <item name=\"iconTint\">?attr/textColor</item>\n        <item name=\"iconGravity\">textStart</item>\n        <item name=\"iconPadding\">0dp</item>\n        <item name=\"android:layout_width\">35dp</item>\n        <!--<item name=\"android:layout_height\">35dp</item>-->\n    </style>\n\n    <style name=\"ExtendedFloatingActionButton\">\n        <item name=\"elevation\">0dp</item>\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"backgroundTint\">?attr/primaryGrayBackground</item>\n        <item name=\"tint\">?attr/colorPrimary</item>\n        <item name=\"textColor\">?attr/colorPrimary</item>\n        <item name=\"iconTint\">?attr/textColor</item>\n        <item name=\"android:layout_margin\">16dp</item>\n        <item name=\"android:layout_gravity\">end|bottom</item>\n        <item name=\"textAllCaps\">false</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n    </style>\n\n    <style name=\"RoundedSelectableButton\">\n        <item name=\"backgroundTint\">@color/toggle_button</item>\n        <item name=\"rippleColor\">@color/textColor</item>\n        <item name=\"android:textColor\">@color/toggle_button_text</item>\n        <item name=\"cornerRadius\">100dp</item>\n        <item name=\"strokeWidth\">1dp</item>\n        <item name=\"strokeColor\">@color/toggle_button_outline</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">45dp</item>\n        <item name=\"android:paddingTop\">0dp</item>\n        <item name=\"android:paddingBottom\">0dp</item>\n        <item name=\"android:paddingStart\">10dp</item>\n        <item name=\"android:paddingEnd\">10dp</item>\n        <!--<item name=\"android:layout_marginStart\">10dp</item>-->\n        <item name=\"android:layout_marginEnd\">5dp</item>\n        <item name=\"textAllCaps\">false</item>\n        <item name=\"android:textSize\">13sp</item>\n    </style>\n\n    <style name=\"MultiSelectButton\" parent=\"BlackButton\">\n        <item name=\"android:layout_height\">40dp</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n\n        <item name=\"strokeColor\">?attr/textColor</item>\n        <item name=\"backgroundTint\">?attr/iconGrayBackground</item>\n        <item name=\"iconTint\">?attr/textColor</item>\n        <item name=\"android:textColor\">?attr/textColor</item>\n        <item name=\"rippleColor\">?attr/textColor</item>\n    </style>\n\n    <style name=\"SelectableButton\" parent=\"NiceButton\">\n        <item name=\"android:layout_height\">40dp</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n\n        <item name=\"strokeColor\">@color/selectable_black</item>\n        <item name=\"backgroundTint\">@color/selectable_white</item>\n        <item name=\"iconTint\">@color/selectable_black</item>\n        <item name=\"android:textColor\">@color/selectable_black</item>\n        <item name=\"rippleColor\">@color/selectable_black</item>\n    </style>\n\n    <style name=\"VideoButton\">\n        <item name=\"android:stateListAnimator\">@null</item>\n        <item name=\"strokeColor\">@color/transparent</item>\n        <item name=\"backgroundTint\">@color/transparent</item>\n        <item name=\"rippleColor\">@color/video_button_ripple</item>\n        <item name=\"android:shadowColor\">@color/transparent</item>\n\n        <item name=\"cornerRadius\">3dp</item>\n        <item name=\"iconTint\">@color/white</item>\n        <item name=\"textColor\">@color/white</item>\n        <item name=\"android:textColor\">@color/white</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">45dp</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:layout_gravity\">center</item>\n        <item name=\"textAllCaps\">false</item>\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"android:textSize\">10sp</item>\n        <item name=\"android:layout_marginStart\">10dp</item>\n        <item name=\"android:layout_marginEnd\">10dp</item>\n    </style>\n\n    <style name=\"SyncButton\" parent=\"NiceButton\">\n        <item name=\"rippleColor\">?attr/white</item>\n        <item name=\"iconTint\">?attr/textColor</item>\n        <item name=\"android:layout_columnWeight\">1</item>\n        <item name=\"android:layout_rowWeight\">1</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:textColor\">?attr/textColor</item>\n        <item name=\"backgroundTint\">@color/toggle_button</item>\n        <item name=\"android:layout_marginBottom\">10dp</item>\n        <item name=\"strokeWidth\">1dp</item>\n        <item name=\"strokeColor\">@color/toggle_button_outline</item>\n    </style>\n\n    <style name=\"Tag\" parent=\"Widget.MaterialComponents.Button.OutlinedButton\">\n        <item name=\"strokeColor\">@color/tag_stroke_color</item>\n    </style>\n\n    <style name=\"ResultButtonTV\" parent=\"@style/RegularButtonTV\">\n        <item name=\"android:tag\">@string/tv_no_focus_tag</item>\n        <item name=\"iconGravity\">start</item>\n        <item name=\"android:gravity\">center_vertical</item>\n        <item name=\"android:layout_width\">250dp</item>\n        <item name=\"android:layout_marginBottom\">5dp</item>\n        <item name=\"android:layout_marginStart\">0dp</item>\n        <item name=\"android:layout_marginEnd\">0dp</item>\n    </style>\n\n    <style name=\"SelectableButtonTV\" parent=\"RegularButtonTV\">\n        <item name=\"icon\">@drawable/ic_baseline_check_24_listview</item>\n        <item name=\"iconTint\">@color/button_selector_color</item>\n    </style>\n\n    <style name=\"RegularButtonTV\">\n        <item name=\"android:tag\">@string/tv_no_focus_tag</item>\n        <item name=\"android:stateListAnimator\">@null</item>\n        <item name=\"strokeColor\">@color/transparent</item>\n        <item name=\"backgroundTint\">@null</item>\n        <item name=\"android:background\">@drawable/player_button_tv_attr</item>\n        <item name=\"rippleColor\">@color/white</item>\n        <item name=\"android:shadowColor\">@color/transparent</item>\n\n        <item name=\"iconTint\">@color/player_on_button_tv_attr</item>\n        <item name=\"textColor\">@color/player_on_button_tv_attr</item>\n        <item name=\"android:textColor\">@color/player_on_button_tv_attr</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">40dp</item>\n        <item name=\"iconSize\">16dp</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:layout_gravity\">center</item>\n        <item name=\"android:baselineAligned\">false</item>\n        <item name=\"textAllCaps\">false</item>\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"android:textSize\">14sp</item>\n        <item name=\"android:layout_marginStart\">4dp</item>\n        <item name=\"android:layout_marginEnd\">4dp</item>\n        <item name=\"android:insetBottom\">0dp</item>\n        <item name=\"android:insetTop\">0dp</item>\n    </style>\n\n    <style name=\"ResultSmallButtonTV\">\n        <item name=\"android:tag\">@string/tv_no_focus_tag</item>\n        <item name=\"android:stateListAnimator\">@null</item>\n        <item name=\"strokeColor\">@color/transparent</item>\n        <item name=\"backgroundTint\">@null</item>\n        <item name=\"android:background\">@drawable/player_button_tv_attr</item>\n        <item name=\"rippleColor\">@color/white</item>\n        <item name=\"android:shadowColor\">@color/transparent</item>\n        <item name=\"iconTint\">@color/player_on_button_tv_attr</item>\n        <item name=\"iconGravity\">textStart</item>\n        <item name=\"android:layout_width\">60dp</item>\n        <item name=\"android:layout_height\">40dp</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:layout_gravity\">center</item>\n        <item name=\"android:layout_marginStart\">4dp</item>\n        <item name=\"android:layout_marginEnd\">4dp</item>\n        <item name=\"android:layout_marginBottom\">4dp</item>\n    </style>\n\n    <style name=\"ResultMarqueeButtonText\">\n        <item name=\"android:layout_width\">match_parent</item>\n        <item name=\"android:layout_height\">wrap_content</item>\n        <item name=\"android:gravity\">top|center_horizontal</item>\n        <item name=\"android:singleLine\">true</item>\n        <item name=\"android:scrollHorizontally\">true</item>\n        <item name=\"android:marqueeRepeatLimit\">marquee_forever</item>\n        <item name=\"android:ellipsize\">marquee</item>\n    </style>\n\n    <style name=\"VideoButtonTV\">\n        <item name=\"android:tag\">@string/tv_no_focus_tag</item>\n        <item name=\"android:stateListAnimator\">@null</item>\n        <item name=\"strokeColor\">@color/transparent</item>\n        <item name=\"backgroundTint\">@null</item>\n        <item name=\"android:background\">@drawable/player_button_tv</item>\n        <item name=\"rippleColor\">@color/white</item>\n        <item name=\"android:shadowColor\">@color/transparent</item>\n\n        <item name=\"iconTint\">@color/player_on_button_tv</item>\n        <item name=\"textColor\">@color/player_on_button_tv</item>\n        <item name=\"android:textColor\">@color/player_on_button_tv</item>\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">25dp</item>\n        <item name=\"iconSize\">16dp</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:layout_gravity\">center</item>\n        <item name=\"android:baselineAligned\">false</item>\n        <item name=\"textAllCaps\">false</item>\n        <item name=\"android:textStyle\">bold</item>\n        <item name=\"android:textSize\">10sp</item>\n        <item name=\"android:layout_marginStart\">4dp</item>\n        <item name=\"android:layout_marginEnd\">4dp</item>\n        <item name=\"android:insetBottom\">0dp</item>\n        <item name=\"android:insetTop\">0dp</item>\n    </style>\n\n    <!--@color/white ?attr/colorPrimary-->\n    <!--CHECK ?attr/darkBackground ?attr/colorPrimary-->\n    <!-- CHROMECAST -->\n    <style name=\"CustomCastExpandedController\" parent=\"CastExpandedController\">\n        <item name=\"castControlButtons\">\n            @array/cast_expanded_controller_control_buttons\n        </item>\n        <!-- <item name=\"castButtonColor\">@null</item>\n\n         <item name=\"castSeekBarSecondaryProgressColor\">@color/darkBar\n         </item>\n         -->\n        <item name=\"castSeekBarProgressAndThumbColor\">?attr/colorPrimary</item>\n        <item name=\"castBackground\">?attr/colorPrimary</item>\n        <item name=\"castProgressBarColor\">?attr/colorPrimary</item>\n        <item name=\"castPlayButtonDrawable\">@drawable/ic_baseline_play_arrow_24</item>\n        <item name=\"castPauseButtonDrawable\">@drawable/netflix_pause</item>\n        <item name=\"castStopButtonDrawable\">@drawable/cast_ic_expanded_controller_stop</item>\n        <item name=\"castSkipPreviousButtonDrawable\">\n            @drawable/cast_ic_expanded_controller_skip_previous\n        </item>\n        <item name=\"castSkipNextButtonDrawable\">@drawable/cast_ic_expanded_controller_skip_next\n        </item>\n        <item name=\"castRewind30ButtonDrawable\">@drawable/go_back_30</item>\n        <item name=\"castForward30ButtonDrawable\">@drawable/go_forward_30</item>\n    </style>\n\n    <style name=\"CustomCastMiniController\" parent=\"CastMiniController\">\n        <item name=\"castMiniControllerLoadingIndicatorColor\">?attr/colorPrimary</item>\n        <item name=\"castShowImageThumbnail\">true</item>\n\n        <item name=\"castTitleTextAppearance\">@style/TextAppearance.AppCompat.Subhead</item>\n        <item name=\"castSubtitleTextAppearance\">@style/TextAppearance.AppCompat.Caption</item>\n        <item name=\"castBackground\">@color/transparent\n        </item> <!--CHECK bitDarkerGrayBackground darkBackground-->\n        <item name=\"castProgressBarColor\">?attr/colorPrimary</item>\n        <item name=\"castStopButtonDrawable\">@drawable/cast_ic_mini_controller_stop</item>'\n        <item name=\"castLargeStopButtonDrawable\">@drawable/cast_ic_mini_controller_stop_large</item>\n        <item name=\"castSkipPreviousButtonDrawable\">@drawable/cast_ic_mini_controller_skip_prev\n        </item>\n        <item name=\"castSkipNextButtonDrawable\">@drawable/cast_ic_mini_controller_skip_next</item>\n        <item name=\"castRewind30ButtonDrawable\">@drawable/go_back_30</item>\n        <item name=\"castForward30ButtonDrawable\">@drawable/go_forward_30</item>\n        <item name=\"castMuteToggleButtonDrawable\">@drawable/cast_ic_mini_controller_mute</item>\n        <item name=\"castClosedCaptionsButtonDrawable\">\n            @drawable/cast_ic_mini_controller_closed_caption\n        </item>\n    </style>\n\n    <style name=\"RoundedImageView\">\n        <item name=\"cornerFamily\">rounded</item>\n        <item name=\"cornerSize\">50%</item>\n    </style>\n\n    <style name=\"PlayUnderlayProgress\">\n        <item name=\"shapeAppearanceOverlay\">@style/RoundedImageView</item>\n        <item name=\"android:scaleType\">center</item>\n        <item name=\"android:src\">@drawable/netflix_play</item>\n        <item name=\"android:layout_gravity\">center</item>\n    </style>\n\n    <style name=\"CircularProgress\">\n        <item name=\"trackThickness\">@dimen/circular_progress_thickness</item>\n        <item name=\"android:layout_gravity\">center</item>\n        <item name=\"indicatorColor\">@color/white</item>\n        <item name=\"indicatorTrackGapSize\">0dp</item>\n        <item name=\"trackColor\">@color/white_attr_20</item>\n    </style>\n\n    <style name=\"HomePlayUnderlayProgress\" parent=\"PlayUnderlayProgress\">\n        <item name=\"tint\">@color/white</item>\n        <item name=\"android:layout_width\">@dimen/home_poster_progress_size</item>\n        <item name=\"android:layout_height\">@dimen/home_poster_progress_size</item>\n        <item name=\"android:background\">@color/playIconBackground</item>\n    </style>\n\n    <style name=\"HomeCircularProgress\" parent=\"CircularProgress\">\n        <item name=\"android:layout_width\">@dimen/home_poster_progress_size</item>\n        <item name=\"android:layout_height\">@dimen/home_poster_progress_size</item>\n        <item name=\"indicatorSize\">@dimen/home_poster_progress_size</item>\n    </style>\n\n    <style name=\"EpisodePlayUnderlayProgress\" parent=\"PlayUnderlayProgress\">\n        <item name=\"tint\">@color/white</item>\n        <item name=\"android:layout_width\">40dp</item>\n        <item name=\"android:layout_height\">40dp</item>\n        <item name=\"android:background\">@color/playIconBackground</item>\n    </style>\n\n    <style name=\"EpisodeCircularProgress\" parent=\"CircularProgress\">\n        <item name=\"android:layout_width\">@dimen/episode_progress_size</item>\n        <item name=\"android:layout_height\">@dimen/episode_progress_size</item>\n        <item name=\"indicatorSize\">@dimen/episode_progress_size</item>\n    </style>\n\n    <style name=\"ContinueWatchingPlayUnderlayProgress\">\n        <item name=\"android:layout_width\">@dimen/continue_watching_progress_size</item>\n        <item name=\"android:layout_height\">@dimen/continue_watching_progress_size</item>\n        <item name=\"android:src\">@drawable/play_button_transparent</item>\n        <item name=\"android:layout_gravity\">center</item>\n    </style>\n\n    <style name=\"ContinueWatchingCircularProgress\" parent=\"CircularProgress\">\n        <item name=\"android:layout_width\">@dimen/continue_watching_progress_size</item>\n        <item name=\"android:layout_height\">@dimen/continue_watching_progress_size</item>\n        <item name=\"indicatorSize\">@dimen/continue_watching_progress_size</item>\n    </style>\n\n    <style name=\"DownloadHeaderCircularProgress\" parent=\"CircularProgress\">\n        <item name=\"android:layout_width\">@dimen/download_header_progress_size</item>\n        <item name=\"android:layout_height\">@dimen/download_header_progress_size</item>\n        <item name=\"indicatorSize\">@dimen/download_header_progress_size</item>\n    </style>\n    <style name=\"DownloadHeaderPlayUnderlayProgress\" parent=\"PlayUnderlayProgress\">\n        <item name=\"tint\">@color/white</item>\n        <item name=\"android:layout_width\">@dimen/download_header_progress_size</item>\n        <item name=\"android:layout_height\">@dimen/download_header_progress_size</item>\n        <item name=\"android:background\">@color/playIconBackground</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-arz/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-b+af/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"action_remove_from_bookmarks\">Verwyder</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Spoed (%.2fx)</string>\n    <string name=\"error_bookmarks_text\">Boekmerke</string>\n    <string name=\"download_started\">Aflaai het begin</string>\n    <string name=\"home_next_random_img_des\">Volgende lukraak</string>\n    <string name=\"preview_background_img_des\">Voorskou Agtergrond</string>\n    <string name=\"play_movie_button\">Speel Fliek</string>\n    <string name=\"subs_hold_to_reset_to_default\">Hou in om terug te stel na standaard</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"sort_clear\">Maak leeg</string>\n    <string name=\"subs_outline_color\">Omtrek kleur</string>\n    <string name=\"search_poster_img_des\">Plakkaat</string>\n    <string name=\"filter_bookmarks\">Filter boekmerke</string>\n    <string name=\"subs_font_size\">Lettertipe grootte</string>\n    <string name=\"type_plan_to_watch\">Beplan om te Kyk</string>\n    <string name=\"update_started\">Opdatering het begin</string>\n    <string name=\"sort_copy\">Kopieer</string>\n    <string name=\"home_more_info\">Meer inligting</string>\n    <string name=\"title_downloads\">Aflaaie</string>\n    <string name=\"subs_auto_select_language\">Outo-kies taal</string>\n    <string name=\"error_loading_links_toast\">Kon nie skakels laai nie</string>\n    <string name=\"subs_edge_type\">Rand tipe</string>\n    <string name=\"download_done\">Klaar Afgelaai</string>\n    <string name=\"continue_watching\">Kyk verder</string>\n    <string name=\"new_update_format\" formatted=\"true\">Nuwe opdatering gevind!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"subs_download_languages\">Laai Tale af</string>\n    <string name=\"search_provider_text_providers\">Soek deur verskaffers te gebruik</string>\n    <string name=\"go_back_img_des\">Gaan terug</string>\n    <string name=\"downloading\">Laai tans af</string>\n    <string name=\"episode_more_options_des\">Meer Opsies</string>\n    <string name=\"play_episode\">Speel Episode</string>\n    <string name=\"player_speed\">Spelerspoed</string>\n    <string name=\"benene_count_text\">%d Benenes gegee aan devs</string>\n    <string name=\"type_watching\">Kyk tans</string>\n    <string name=\"result_tags\">Genres</string>\n    <string name=\"episode_poster_img_des\">Episode plakkaat</string>\n    <string name=\"type_dropped\">Geval</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Soek %s…</string>\n    <string name=\"filler\" formatted=\"true\">Vuller</string>\n    <string name=\"benene_count_text_none\">Geen Benenes gegee</string>\n    <string name=\"subs_subtitle_languages\">Onderskriftaal</string>\n    <string name=\"home_change_provider_img_des\">Verander Verskaffer</string>\n    <string name=\"subs_background_color\">Agtergrondkleur</string>\n    <string name=\"search_hint\">Soek…</string>\n    <string name=\"popup_pause_download\">Laat aflaai rus</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"subtitles_settings\">Onderskrifinstellings</string>\n    <string name=\"subs_window_color\">Venster kleur</string>\n    <string name=\"play_torrent_button\">Stroom Torrent</string>\n    <string name=\"download_canceled\">Aflaai gekanselleer</string>\n    <string name=\"rated_format\" formatted=\"true\">Gegradeer: %.1f</string>\n    <string name=\"home_expanded_hide\">Versteek</string>\n    <string name=\"sort_apply\">Pas toe</string>\n    <string name=\"browser\">Blaaier</string>\n    <string name=\"pick_subtitle\">Onderskrifte</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$du %3$dm</string>\n    <string name=\"next_episode\">Volgende episode</string>\n    <string name=\"download_paused\">Aflaai op rus</string>\n    <string name=\"download\">Laai af</string>\n    <string name=\"reload_error\">Probeer weer verbind…</string>\n    <string name=\"popup_delete_file\">Vee lêer uit</string>\n    <string name=\"downloaded\">Afgelaai</string>\n    <string name=\"popup_resume_download\">Hervat aflaai</string>\n    <string name=\"subs_text_color\">Teks kleur</string>\n    <string name=\"type_completed\">Voltooi</string>\n    <string name=\"play_trailer_button\">Speel Lokprent</string>\n    <string name=\"play_livestream_button\">Speel Regstreeks</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"result_poster_img_des\">Plakkaat</string>\n    <string name=\"popup_play_file\">Speel lêer</string>\n    <string name=\"type_re_watching\">Herkyk tans</string>\n    <string name=\"result_open_in_browser\">Maak Oop In Blaaier</string>\n    <string name=\"no_data\">Geen Data</string>\n    <string name=\"subs_font\">Lettertipe</string>\n    <string name=\"go_back\">Gaan Terug</string>\n    <string name=\"title_home\">Tuis</string>\n    <string name=\"skip_loading\">Slaan Laai Oor</string>\n    <string name=\"home_info\">Inligting</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episode %d sal vrygestel word in</string>\n    <string name=\"sort_save\">Stoor</string>\n    <string name=\"download_failed\">Aflaai het misluk</string>\n    <string name=\"result_share\">Deel</string>\n    <string name=\"home_main_poster_img_des\">Hoofplakkaat</string>\n    <string name=\"pick_source\">Bronne</string>\n    <string name=\"title_settings\">Instellings</string>\n    <string name=\"title_search\">Soek</string>\n    <string name=\"loading\">Laai tans…</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"action_remove_watching\">Verwyder</string>\n    <string name=\"stream\">Netwerk stroom</string>\n    <string name=\"type_on_hold\">Op rus</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"home_play\">Speel</string>\n    <string name=\"download_storage_text\">Interne Berging</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"sort_close\">Maak toe</string>\n    <string name=\"action_add_to_bookmarks\">Stel kykstatus</string>\n    <string name=\"play_with_app_name\">Speel met CloudStream</string>\n    <string name=\"subs_subtitle_elevation\">Onderskrif hoogte</string>\n    <string name=\"search_provider_text_types\">Soek met behulp van tipes</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Voer lettertipes in deur dit in %s te plaas</string>\n    <string name=\"cast_format\" formatted=\"true\">Rolverdeling: %s</string>\n    <string name=\"subscribe_tooltip\">Nuwe episode notifikasie</string>\n    <string name=\"free_storage\">Gratis</string>\n    <string name=\"use\">Gebruik</string>\n    <string name=\"delete\">Wis Uit</string>\n    <string name=\"cancel\">Kanselleer</string>\n    <string name=\"actor_background\">Agtergrond</string>\n    <string name=\"previous\">Vorige</string>\n    <string name=\"settings_info\">Inligting</string>\n    <string name=\"edit\">Wysig</string>\n    <string name=\"season\">Seisoen</string>\n    <string name=\"select_all\">Kies Alles</string>\n    <string name=\"downloads_delete_select\">Kies items om te verwyder</string>\n    <string name=\"duplicate_replace\">Vervang</string>\n    <string name=\"pin_error_length\">PIN moet 4 karakters bevat</string>\n    <string name=\"pin_error_incorrect\">Verkeerde PIN. Probeer weer.</string>\n    <string name=\"category_providers\">Verskaffers</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+am/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s ክፍል %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">ተዋናዮች: %s</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">ፍጥነት(%.2fx)</string>\n    <string name=\"home_next_random_img_des\">ቀጣይ በዘፈቀደ</string>\n    <string name=\"preview_background_img_des\">ዳራ ቅድም እይታ</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dሰዓት %2$dደቂቃ</string>\n    <string name=\"search_poster_img_des\">ፖስተር</string>\n    <string name=\"title_downloads\">የወረዱ</string>\n    <string name=\"new_update_format\" formatted=\"true\">አዲስ ማሻሻያ ተገኝቷል!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"go_back_img_des\">ተመለስ</string>\n    <string name=\"episode_more_options_des\">ተጨማሪ አማራጮች</string>\n    <string name=\"type_watching\">በማየት ላይ</string>\n    <string name=\"result_tags\">ዘውጎች</string>\n    <string name=\"episode_poster_img_des\">የክፍሉ ፖስተር</string>\n    <string name=\"search_hint_site\" formatted=\"true\">%sን ፈልግ…</string>\n    <string name=\"filler\" formatted=\"true\">መሙያ</string>\n    <string name=\"home_change_provider_img_des\">አቅራቢ ቀይር</string>\n    <string name=\"search_hint\">ፍለጋ…</string>\n    <string name=\"rated_format\" formatted=\"true\">ተመዘነ: %.1f</string>\n    <string name=\"browser\">አሳሽ</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dቀን %2$dሰዓት %3$dደቂቃ</string>\n    <string name=\"next_episode\">ቀጣይ ክፍል</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dደቂቃ</string>\n    <string name=\"duration_format\" formatted=\"true\">%d ደቂቃ</string>\n    <string name=\"result_poster_img_des\">ፖስተር</string>\n    <string name=\"result_open_in_browser\">በአሳሽ ውስጥ ይክፈቱ</string>\n    <string name=\"no_data\">ውሂብ የለም</string>\n    <string name=\"title_home\">መነሻ</string>\n    <string name=\"skip_loading\">መጫንን ዝለል</string>\n    <string name=\"next_episode_format\" formatted=\"true\">ክፍል %d በ ይለቀቃል</string>\n    <string name=\"result_share\">ማጋሪያ</string>\n    <string name=\"home_main_poster_img_des\">ዋና ፖስተር</string>\n    <string name=\"title_settings\">ቅንብሮች</string>\n    <string name=\"title_search\">መፈለጊያ</string>\n    <string name=\"loading\">በመጫን ላይ…</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">በCloudStream አጫውት</string>\n    <string name=\"action_remove_from_bookmarks\">ያስወግዱ</string>\n    <string name=\"error_bookmarks_text\">ዕልባቶች</string>\n    <string name=\"download_started\">ማውረድ ተጀምሯል</string>\n    <string name=\"play_movie_button\">ሙቪ አጫውት</string>\n    <string name=\"sort_clear\">አጽዳ</string>\n    <string name=\"subs_outline_color\">የዳርቻ ቀለም</string>\n    <string name=\"filter_bookmarks\">ዕልባቶችን ማጣሪያ</string>\n    <string name=\"type_plan_to_watch\">በእቅድ ላይ</string>\n    <string name=\"update_started\">ማዘመን ተጀምሯል</string>\n    <string name=\"sort_copy\">ቅዳ</string>\n    <string name=\"home_more_info\">ተጨማሪ መረጃ</string>\n    <string name=\"error_loading_links_toast\">አገናኞችን መጫን ላይ ስህተት</string>\n    <string name=\"subs_edge_type\">የጠርዝ ዓይነት</string>\n    <string name=\"download_done\">ማውረድ ተከናውኗል</string>\n    <string name=\"downloading\">በማውረድ ላይ</string>\n    <string name=\"play_episode\">ክፍልን አጫውት</string>\n    <string name=\"player_speed\">የአጫዋች ፍጥነት</string>\n    <string name=\"type_dropped\">የተተወ</string>\n    <string name=\"subs_background_color\">የዳራ ቀለም</string>\n    <string name=\"popup_pause_download\">ማውረድ ለአፍታ አቁም</string>\n    <string name=\"app_dubbed_text\">ትርጉም ድምጽ</string>\n    <string name=\"subtitles_settings\">የትርጉም ጽሑፍ ቅንብሮች</string>\n    <string name=\"subs_window_color\">የዊንዶው ቀለም</string>\n    <string name=\"play_torrent_button\">Torrent አጫውት</string>\n    <string name=\"download_canceled\">ማውረድ ተቋርጧል</string>\n    <string name=\"home_expanded_hide\">ደብቅ</string>\n    <string name=\"sort_apply\">አጽድቅ</string>\n    <string name=\"pick_subtitle\">የትርጉም ጽሑፎች</string>\n    <string name=\"download_paused\">ማውረድ ቆሟል</string>\n    <string name=\"download\">ማውረጃ</string>\n    <string name=\"reload_error\">ግንኙነትን እንደገና ይሞሩ…</string>\n    <string name=\"popup_delete_file\">ፋይል አጥፋ</string>\n    <string name=\"downloaded\">ወርዷል</string>\n    <string name=\"popup_resume_download\">ማውረድ ቀጥል</string>\n    <string name=\"subs_text_color\">የጽሑፍ ቀለም</string>\n    <string name=\"type_completed\">የተጠናቀቀ</string>\n    <string name=\"play_trailer_button\">የፊልም ማስታወቂያ አጫውት</string>\n    <string name=\"play_livestream_button\">የቀጥታ ስርጭት አጫውት</string>\n    <string name=\"popup_play_file\">ፋይል አጫውት</string>\n    <string name=\"type_re_watching\">እንደገና በማየት ላይ</string>\n    <string name=\"go_back\">ወደ ኋላ መመለሻ</string>\n    <string name=\"home_info\">መረጃ</string>\n    <string name=\"sort_save\">ያስቀምጡ</string>\n    <string name=\"download_failed\">ማውረድ አልተሳካም</string>\n    <string name=\"pick_source\">ምንጮች</string>\n    <string name=\"app_subbed_text\">ትርጉም ጽሁፍ</string>\n    <string name=\"stream\">ዥረት</string>\n    <string name=\"type_on_hold\">በመቆየት ላይ</string>\n    <string name=\"home_play\">አጫውት</string>\n    <string name=\"download_storage_text\">ውስጣዊ ማከማቻ</string>\n    <string name=\"sort_close\">ዝጋ</string>\n    <string name=\"action_add_to_bookmarks\">የምልከታ ሁኔታን ያቀናብሩ</string>\n    <string name=\"subs_hold_to_reset_to_default\">ወደ ነባሪ ዳግም ለማስጀመር ጫን አድርገው ይያዙ</string>\n    <string name=\"subs_font_size\">የቅርጸ-ቁምፊ መጠን</string>\n    <string name=\"subs_auto_select_language\">ቋንቋን በራስ ይምረጥ</string>\n    <string name=\"continue_watching\">መመልከትዎን ይቀጥሉ</string>\n    <string name=\"subs_download_languages\">ቋንቋዎችን ያውርዱ</string>\n    <string name=\"search_provider_text_providers\">አቅራቢዎችን በመጠቀም ይፈልጉ</string>\n    <string name=\"benene_count_text\">%d ሙዝ ለዴቭሎፐሮቹ ተሰጥቷል</string>\n    <string name=\"vpn_might_be_needed\">ይህ አቅራቢ በትክክል እንዲሰራ ቪፒኤን ሊያስፈልግ ይችላል</string>\n    <string name=\"benene_count_text_none\">ምንም ሙዝ አልተሰጠም</string>\n    <string name=\"subs_subtitle_languages\">የትርጉም ጽሑፍ ቋንቋ</string>\n    <string name=\"provider_info_meta\">ሜታዳታ በድረ-ገጹ ላይ አይገኝም፣ ቪድዮ መጫን ሜታዳታ ድረ-ገጹ ላይ ከሌለ አይሳካም።</string>\n    <string name=\"vpn_torrent\">ይህ አቅራቢ ቶረንት ነው፣ ቪፒኤን ይመከራል</string>\n    <string name=\"subs_font\">ቅርጸ-ቁምፊ</string>\n    <string name=\"torrent_plot\">መግለጫ</string>\n    <string name=\"action_remove_watching\">ያስወግዱ</string>\n    <string name=\"action_open_watching\">ተጨማሪ መረጃ</string>\n    <string name=\"search_provider_text_types\">ዓይነቶችን በመጠቀም ይፈልጉ</string>\n    <string name=\"subs_import_text\" formatted=\"true\">ቅርጸ-ቁምፊዎችን በ%s ውስጥ በማስቀመጥ ያጫኑ</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+apc/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"player_speed_text_format\" formatted=\"true\">السرعة (%.2fx)</string>\n    <string name=\"home_change_provider_img_des\">غير المصدر</string>\n    <string name=\"next_episode_format\" formatted=\"true\">حتنزل الحلقة %d ب</string>\n    <string name=\"title_downloads\">التنزيلات</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$sالحلقة %2$d</string>\n    <string name=\"delete_file\">محي الملف</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"preview_background_img_des\">شوف الخلفية</string>\n    <string name=\"play_movie_button\">مشّي الفيلم</string>\n    <string name=\"subs_hold_to_reset_to_default\">ضلّ كابس لترجع السَتِنگز كيف كانة أول ما نزلتو الآپ</string>\n    <string name=\"season_format\">%1$s%2$d%3$s</string>\n    <string name=\"subs_default_reset_toast\">رجِعت السَتِنگز ل كيف كانت أساسًا</string>\n    <string name=\"subs_outline_color\">لون حدود الكتيبة</string>\n    <string name=\"search_poster_img_des\">پوستر</string>\n    <string name=\"backup_frequency\">كلّ قديش بيعمل الآپ نسخة إحتياطية</string>\n    <string name=\"kitsu_settings\">فرجي الپوسترات من موقع \\\"كيتسو\\\"</string>\n    <string name=\"updates_settings_des\">تلقائيًا نبش على تجديدات جديدة بعد ما ينفتح الآپ.</string>\n    <string name=\"show_fillers_settings\">فرجي حلقات الفِلِر بال أنمي</string>\n    <string name=\"double_tap_to_pause_settings\">كبسو مرتين لتحطو پوز</string>\n    <string name=\"subs_font_size\">حجم الكتيبة</string>\n    <string name=\"no_links_found_toast\">م لقينا روابط</string>\n    <string name=\"type_plan_to_watch\">ناوي إحضر</string>\n    <string name=\"benene_des\">الموزززات المنعطية</string>\n    <string name=\"subs_auto_select_language\">تحديد اللغة تلقائيًا</string>\n    <string name=\"double_tap_to_seek_amount_settings\">كم ثانية بتقدم وبترجع</string>\n    <string name=\"subs_edge_type\">نوع حدود الكتيبة</string>\n    <string name=\"show_log_cat\">فرجي الـLogcat 🐈</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"continue_watching\">كفي حضر</string>\n    <string name=\"new_update_format\" formatted=\"true\">في أپدايت جديدة!\n\\n%1$s ← %2$s</string>\n    <string name=\"subs_download_languages\">نزل الترجمات مع الڤيديو</string>\n    <string name=\"search_provider_text_providers\">عوزو المصادر لَ تنبّشو</string>\n    <string name=\"go_back_img_des\">رجاع</string>\n    <string name=\"discord\">انضم لگروپ \\\"كلود ستريم\\\" ع الـ\\\"ديسكورد\\\"</string>\n    <string name=\"episode_more_options_des\">بعد خيارات</string>\n    <string name=\"backup_success\">تسيّڤة النسخة الإحتياطية</string>\n    <string name=\"benene_count_text\">صرتو عاطين %d موزززة للمطورين</string>\n    <string name=\"swipe_to_seek_settings\">سحابو لتقدمو وترجعو</string>\n    <string name=\"backup_failed\">إذن الوصول لذاكرة التخزين مفقود. پليز جرب بعد مرّة.</string>\n    <string name=\"type_watching\">عم إحضر</string>\n    <string name=\"automatic_plugin_updates\">تجديد الإضافات تلقائيًا</string>\n    <string name=\"delete_message\" formatted=\"true\">متأكِدي إنو بدك تمحي %s؟</string>\n    <string name=\"pause\">پوز</string>\n    <string name=\"automatic_plugin_download\">تنزيل الإضافات تلقائيًا</string>\n    <string name=\"result_tags\">النوع</string>\n    <string name=\"go_back_30\">−30</string>\n    <string name=\"episode_poster_img_des\">پوستر تبع الحلقة</string>\n    <string name=\"vpn_might_be_needed\">يمكن عايزين \\\"ڤي پي أن\\\" (VPN) لتمَشّو هيدا المصدر</string>\n    <string name=\"type_dropped\">موقف</string>\n    <string name=\"search_hint_site\" formatted=\"true\">نبّش %s…</string>\n    <string name=\"github\">\\\"گِت هَب\\\"</string>\n    <string name=\"episode_sync_settings\">سيّڤ تاريخ المشاهدة</string>\n    <string name=\"filler\" formatted=\"true\">فيلير</string>\n    <string name=\"benene_count_text_none\">مش عاطين ولا موزززة</string>\n    <string name=\"backup_settings\">عمول نسخة إحتياطية</string>\n    <string name=\"restore_success\">رجِعِت ع النسخة الإحتياطية</string>\n    <string name=\"subs_subtitle_languages\">لغة الترجمة</string>\n    <string name=\"subs_background_color\">لون الخلفية</string>\n    <string name=\"episode_sync_settings_des\">بتسيّڤ تاريخ المشاهدة و لوين وصلت بال ڤيديو</string>\n    <string name=\"search_hint\">نبّش…</string>\n    <string name=\"provider_info_meta\">هيدا المصدر مش عاطي \\\"ميتا داتا\\\". إزا مش موجودة بال مصدر، م رح يمشي الڤيديو.</string>\n    <string name=\"no_season\">مافي أجزاء</string>\n    <string name=\"play_episode_toast\">مشّي الحلقة</string>\n    <string name=\"category_account\">الحسابات وال أمان</string>\n    <string name=\"eigengraumode_settings\">سرعة الڤيديو</string>\n    <string name=\"resume\">كَمِّل</string>\n    <string name=\"test_log\">سِجِل</string>\n    <string name=\"torrent_no_plot\">م نلاقى الوصف</string>\n    <string name=\"subtitles_settings\">سَتِنگز الترجمة</string>\n    <string name=\"subs_window_color\">لون العلبة</string>\n    <string name=\"play_torrent_button\">عمول ستريم للتورنت</string>\n    <string name=\"automatic_plugin_download_summary\">تلقائيًا نَزِل كل الإضافات من الريپويات يللي نزادِت.</string>\n    <string name=\"delete\">محي</string>\n    <string name=\"start\">بلش</string>\n    <string name=\"apk_installer_settings_des\">فيه أجهزة م فيها تعوز الطريقة الجديدة لتجديد الآپات. جربو \\\"الطريقة القديمة\\\" إزا م عم تنزل التجديدات.</string>\n    <string name=\"picture_in_picture_des\">بعد ما تسكر \\\"كلود ستريم\\\"، بكفي الڤيديو بشِباك زغير فوق غير آپ</string>\n    <string name=\"no_chromecast_support_toast\">هيدا المصدر م بيدعم \\\"كروم كاست\\\"</string>\n    <string name=\"advanced_search\">تنبيش منظّم</string>\n    <string name=\"chromecast_subtitles_settings\">ترجمة \\\"كروم كاست\\\"</string>\n    <string name=\"swipe_to_change_settings\">سحابو لتتحكمو بال صوت وال ضو</string>\n    <string name=\"rated_format\" formatted=\"true\">رايتينگ: %.1f</string>\n    <string name=\"chromecast_subtitles_settings_des\">سَتِنگز تبع ترجمة \\\"كروم كاست\\\"</string>\n    <string name=\"browser\">متصفح الوَب</string>\n    <string name=\"double_tap_to_seek_settings_des\">كبوس مرتين على اليمين أو الشمال حتى تقرب أو ترَجِع الڤيديو</string>\n    <string name=\"normal_no_plot\">م نلاقى وصف الأحداث</string>\n    <string name=\"next_episode\">الحلقة يللي بَعدها</string>\n    <string name=\"updates_settings\">فرجي تجديدات الآپ</string>\n    <string name=\"library\">رفّ</string>\n    <string name=\"lightnovel\">آپ من نفس المطورين للروايات الخفيفة، بدل من الڤيديوات</string>\n    <string name=\"automatic_plugin_download_mode_title\">حدد الوضع لَتفَلتِر تنزيل الإضافات</string>\n    <string name=\"episode\">حلقة</string>\n    <string name=\"autoplay_next_settings_des\">مَشّي الحلقة يللي بعدا تلقائيًا بعد ما تُخلَص الحلقة</string>\n    <string name=\"subs_text_color\">لون الكتيبة</string>\n    <string name=\"type_completed\">مخلص</string>\n    <string name=\"use_system_brightness_settings_des\">عوز قوة ضوّ الشاشة تبع السيستام بدل من تغميئ الڤيديو</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">فشل ترجيع النسخة الإحتياطية من ملف\n\\n%s</string>\n    <string name=\"play_trailer_button\">مشّي المقطع الدعائي</string>\n    <string name=\"play_livestream_button\">مشّي البث المباشر</string>\n    <string name=\"no_episodes_found\">م لقينا ولا حلقة</string>\n    <string name=\"duration_format\" formatted=\"true\">دقايق: %d</string>\n    <string name=\"vpn_torrent\">هيدا المصدر \\\"تورنت\\\". بينّصح إستعمال \\\"ڤي پي أن\\\" (VPN)</string>\n    <string name=\"test_failed\">فشل</string>\n    <string name=\"result_poster_img_des\">پوستر</string>\n    <string name=\"advanced_search_des\">بقسم نتايج كل مصدر لحالا</string>\n    <string name=\"type_re_watching\">عم إرجع إحضر</string>\n    <string name=\"cancel\">كَنسِل</string>\n    <string name=\"result_open_in_browser\">فتحو بمتصفح الوَب</string>\n    <string name=\"use_system_brightness_settings\">عوز ضوّ السيستام</string>\n    <string name=\"double_tap_to_pause_settings_des\">كبوس مرتين بال نُصّ حتى توقف الڤيديو</string>\n    <string name=\"no_data\">مافي بيانات</string>\n    <string name=\"player_subtitles_settings\">الترجمة</string>\n    <string name=\"subs_font\">الخط</string>\n    <string name=\"redo_setup_process\">رجاع عمول عملية الإعداد</string>\n    <string name=\"episodes_range\">%1$d–%2$d</string>\n    <string name=\"benene\">عطي المطورين موزززة</string>\n    <string name=\"restore_settings\">عوز النسخة الإحتياطية</string>\n    <string name=\"select_an_account\">نقي أكونت</string>\n    <string name=\"swipe_to_change_settings_des\">سحابو ل فوق وتحت من اليمين أو الشمال ل تتحكمو بقوة الصوت أو قوة الضو</string>\n    <string name=\"copy_link_toast\">ننسخ الرابط</string>\n    <string name=\"torrent_plot\">الوصف</string>\n    <string name=\"search\">تنبيش</string>\n    <string name=\"settings_info\">معلومات</string>\n    <string name=\"title_home\">الرئيسية</string>\n    <string name=\"skip_loading\">أفّو اللودينگ</string>\n    <string name=\"anim\">آپ للأنمي من نفس المطورين</string>\n    <string name=\"swipe_to_seek_settings_des\">سحابو من جِهة لَ جِهة لتقدمو وترَجِعو الڤيديو</string>\n    <string name=\"player_size_settings\">كبسة تغيير حجم الڤيديو</string>\n    <string name=\"result_share\">شّار</string>\n    <string name=\"home_main_poster_img_des\">الپوسر الأساسية</string>\n    <string name=\"pick_source\">المصادر</string>\n    <string name=\"double_tap_to_seek_settings\">كبوسو مرتين لتقفو</string>\n    <string name=\"title_settings\">سَتِنگز</string>\n    <string name=\"title_search\">التنبيش</string>\n    <string name=\"loading\">لودينگ…</string>\n    <string name=\"action_remove_watching\">شيل</string>\n    <string name=\"action_open_watching\">بَعِد مَعلومات</string>\n    <string name=\"category_updates\">التجديدات وال نسخات الاحتياطية</string>\n    <string name=\"pref_filter_search_quality\">خبي هيدي الجودات من نتايج التنبيش</string>\n    <string name=\"type_on_hold\">موقف موقتًا</string>\n    <string name=\"app_name\">كلود ستريم</string>\n    <string name=\"player_size_settings_des\">شيل الأسود من الأطراف</string>\n    <string name=\"season_short\">ج</string>\n    <string name=\"apk_installer_settings\">طريقة تجديد الآپ</string>\n    <string name=\"autoplay_next_settings\">تلقائيًا مشّي الحلقة الّي بعدا</string>\n    <string name=\"picture_in_picture\">كفي فوق غير آپ</string>\n    <string name=\"player_subtitles_settings_des\">سَتِنگز ترجمة الڤيديو</string>\n    <string name=\"app_language\">لغة الآپ</string>\n    <string name=\"show_trailers_settings\">فرجي المقاطع الدعائية</string>\n    <string name=\"test_passed\">نجح</string>\n    <string name=\"play_with_app_name\">مَشّي بـ\\\"كلود ستريم\\\"</string>\n    <string name=\"subs_subtitle_elevation\">إرتفاع الترجمة</string>\n    <string name=\"search_provider_text_types\">عوزو الأنواع ل تنبّشو</string>\n    <string name=\"episodes\">حلقات</string>\n    <string name=\"subs_import_text\" formatted=\"true\">لتزيدو خط مش موجود، نزلو من الإنترنت وحطو بهيدا الملف: %s</string>\n    <string name=\"backup_failed_error_format\">فشل تسيڤ النسخة الإحتياطية %s</string>\n    <string name=\"episode_short\">ح</string>\n    <string name=\"season\">جزء</string>\n    <string name=\"tv_series\">مسلسلات</string>\n    <string name=\"movies\">أفلام</string>\n    <string name=\"free_storage\">فاضي</string>\n    <string name=\"year\">سنة</string>\n    <string name=\"no_subtitles\">طفي الترجمة</string>\n    <string name=\"synopsis\">القصة</string>\n    <string name=\"used_storage\">مستعمل</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dد\n\\nباقي</string>\n    <string name=\"status_ongoing\">عم ينعرض حاليًا</string>\n    <string name=\"queued\">بلايحة النَطر</string>\n    <string name=\"status\">حالة</string>\n    <string name=\"rating\">رايتينگ</string>\n    <string name=\"status_completed\">كتمل</string>\n    <string name=\"app_storage\">آپ</string>\n    <string name=\"action_default\">الإفتراضي</string>\n    <string name=\"duration\">طولو</string>\n    <string name=\"site\">موقع</string>\n    <string name=\"torrent\">تورنت</string>\n    <string name=\"documentaries\">أفلام وثائقية</string>\n    <string name=\"cartoons\">رسوم مُتَحَرِكة</string>\n    <string name=\"ova\">أوڤا</string>\n    <string name=\"asian_drama\">دراما آسيوية</string>\n    <string name=\"nsfw\">18+</string>\n    <string name=\"anime\">أنمي</string>\n    <string name=\"livestreams\">بث مباشر</string>\n    <string name=\"video_source\">مصدر</string>\n    <string name=\"android_tv_interface_off_seek_settings\">المشغل متخبى - مدة التقديم</string>\n    <string name=\"movies_singular\">فيلم</string>\n    <string name=\"torrent_singular\">تورنت</string>\n    <string name=\"no_update_found\">م لقينا تجديد</string>\n    <string name=\"check_for_update\">شوف إزا فيه تجديد</string>\n    <string name=\"render_error\">في مشكلة بجهاز العرض (Renderer error)</string>\n    <string name=\"show_title\">العِنوان</string>\n    <string name=\"jsdelivr_proxy\">پروكسي \\\"گِت هَب\\\"</string>\n    <string name=\"limit_title_rez\">جودة مشغل الڤيديو</string>\n    <string name=\"show_sub\">ملصق الترجمة</string>\n    <string name=\"ova_singular\">أوڤا</string>\n    <string name=\"episode_action_download_mirror\">نَزِل من مصادر وجودات مختلفة</string>\n    <string name=\"update\">جَدِد</string>\n    <string name=\"show_dub\">ملصق مدبلج</string>\n    <string name=\"nsfw_singular\">18+</string>\n    <string name=\"episode_action_play_in_format\">مشي بـ\\\"%s\\\"</string>\n    <string name=\"episode_action_download_subtitle\">نزل الترجمة</string>\n    <string name=\"dont_show_again\">م تفرجيها بعد مرة</string>\n    <string name=\"video_buffer_clear_settings\">فضّي التخزين الموقت للصور وال ڤيديوات</string>\n    <string name=\"video_skip_op\">أفي المقدمة</string>\n    <string name=\"watch_quality_pref\">الجودة المفضلة (Wi-Fi)</string>\n    <string name=\"cartoons_singular\">رسوم مُتَحَرِكة</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">مدة التقديم لم ما يكون مشغل الڤيديو مبين</string>\n    <string name=\"other_singular\">ڤيديو</string>\n    <string name=\"live_singular\">بث مباشر</string>\n    <string name=\"android_tv_interface_on_seek_settings\">المشغل مبين - مدة التقديم</string>\n    <string name=\"unexpected_error\">مشكلة مش متوقع بمشغل الڤيديو (Unexpected player error)</string>\n    <string name=\"video_disk_description\">بسبِب أعطال إزا نحط على مستوى عالي كتير على الأجهزة يللي م بتساع كتير، متل تلفزيون \\\"أندرويد\\\".</string>\n    <string name=\"others\">شي غير</string>\n    <string name=\"skip_update\">أفي هيدا التجديد</string>\n    <string name=\"episode_action_play_in_app\">مَشي بال آپ</string>\n    <string name=\"dns_pref_summary\">مفيد لتجاوز المنع من مزود خدمة الإنترنت</string>\n    <string name=\"tv_series_singular\">مسلسل</string>\n    <string name=\"video_aspect_ratio_resize\">غير الحجم</string>\n    <string name=\"show_hd\">ملصق الجودة</string>\n    <string name=\"episode_action_reload_links\">رجاع عمول لُود لَلروابط</string>\n    <string name=\"watch_quality_pref_data\">جودة المشاهدة المفضلة (3G/4G…)</string>\n    <string name=\"episode_action_auto_download\">التنزيل التلقائي</string>\n    <string name=\"episode_action_chromecast_mirror\">مراية \\\"كروم كاست\\\"</string>\n    <string name=\"poster_ui_settings\">شيل العناصر من الپوستر</string>\n    <string name=\"jsdelivr_enabled\">م قدرنا نوصل ل \\\"گِت هَب\\\". عم ندَوِر پروكسي JSDelivr …</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">مدة التقديم لم ما يكون مشغل الڤيديو مش مبين</string>\n    <string name=\"video_lock\">قفل</string>\n    <string name=\"storage_error\">مشكلة بال تنزيل. شوف إذن التخزين (storage permission)</string>\n    <string name=\"anime_singular\">أنيمي</string>\n    <string name=\"dns_pref\">DNS عبر HTTPS</string>\n    <string name=\"remote_error\">في مشكلة (Remote error)</string>\n    <string name=\"video_buffer_size_settings\">حجم ذاكرة التخزين المتوقت للڤيديو</string>\n    <string name=\"video_buffer_length_settings\">طول التخزين المتوقت</string>\n    <string name=\"episode_action_chromecast_episode\">حلقة \\\"كروم كاست\\\"</string>\n    <string name=\"asian_drama_singular\">دراما آسيوية</string>\n    <string name=\"video_ram_description\">بسبِب أعطال إذا نحط على مستوى عالي كتير على الأجهزة يللي ذِكرتها زغيرة، متل تلفزيون \\\"أندرويد\\\".</string>\n    <string name=\"source_error\">مشكلة بال مصدر</string>\n    <string name=\"video_buffer_disk_settings\">التخزين الموقت للڤيديو على الديسك</string>\n    <string name=\"documentaries_singular\">فلم وثائقي</string>\n    <string name=\"limit_title\">الحد الأعلى للحروف بعنوان الڤيديو</string>\n    <string name=\"pref_category_looks\">المظاهر</string>\n    <string name=\"pref_category_app_updates\">تجديدات الآپ</string>\n    <string name=\"provider_lang_settings\">لغات الإضافات</string>\n    <string name=\"category_general\">عام</string>\n    <string name=\"download_path_pref\">ممر التنزيل</string>\n    <string name=\"legal_notice\">إخلاء مسؤولية</string>\n    <string name=\"nginx_url_pref\">رابط سيرڤر \\\"أنجن أكس\\\" (Nginx)</string>\n    <string name=\"add_site_pref\">نسوخ موقع (clone site)</string>\n    <string name=\"random_button_settings\">زر العشوائي</string>\n    <string name=\"resize_fill\">مدو</string>\n    <string name=\"random_button_settings_desc\">فرجي زر \\\"عشوائي\\\" بال صفحة الرئيسية و بصفحة الرفّ</string>\n    <string name=\"pref_category_ui_features\">الميزات</string>\n    <string name=\"display_subbed_dubbed_settings\">فرجي أنمي المدبلج-المترجم</string>\n    <string name=\"pref_category_backup\">النسخ الإحتياطي</string>\n    <string name=\"pref_category_actions\">الإجراءات</string>\n    <string name=\"jsdelivr_proxy_summary\">تجاوز منع روابط \\\"گِت هَب\\\" الـ\\\"raw\\\" بستعمال JSDelivr. معقول تقدي لتأخير تجديدات الآپ بكم يوم.</string>\n    <string name=\"pref_category_player_features\">ميزات مشغل الڤيديوات</string>\n    <string name=\"remove_site_pref\">شيل موقع</string>\n    <string name=\"pref_category_player_layout\">مظهر</string>\n    <string name=\"add_site_summary\">زيد نسخة لموقع موجود بس عنده نسخة، بإستعمال رابط موقع النسخة</string>\n    <string name=\"pref_category_subtitles\">الترجمة</string>\n    <string name=\"pref_category_cache\">الذاكرة الموقتة</string>\n    <string name=\"pref_category_extensions\">الإضافات</string>\n    <string name=\"pref_category_links\">الروابط</string>\n    <string name=\"resize_zoom\">زوم</string>\n    <string name=\"resize_fit\">سيعه بال شاشة</string>\n    <string name=\"pref_category_defaults\">الإفتراضات</string>\n    <string name=\"pref_category_android_tv\">تلفزيون \\\"أندرويد\\\"</string>\n    <string name=\"pref_category_bypass\">تجاوز مزود خدمة الإنترنت</string>\n    <string name=\"action_remove_from_bookmarks\">شيل</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"error_bookmarks_text\">إشارات المرجعية</string>\n    <string name=\"download_started\">التنزيل بَلَش</string>\n    <string name=\"logged_account\" formatted=\"true\">فتّو على الأكونت \\\"%s\\\"</string>\n    <string name=\"bottom_title_settings\">محل عنوان الپوستر</string>\n    <string name=\"category_ui\">الشكل</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$d ساعة %2$d ديقة</string>\n    <string name=\"sort_clear\">فضّى</string>\n    <string name=\"example_username\">إسم الأكونت</string>\n    <string name=\"filter_bookmarks\">فَلتِر الإشارات المرجعية</string>\n    <string name=\"update_started\">بَلَش التجديد</string>\n    <string name=\"sort_copy\">نسخ</string>\n    <string name=\"home_more_info\">بَعد معلومات</string>\n    <string name=\"error_loading_links_toast\">في مشكلة بفتح الروابط</string>\n    <string name=\"app_layout\">شكل الآپ</string>\n    <string name=\"lock_profile\">حط قفل على الأكونت</string>\n    <string name=\"use_default_account\">ستعمل الأكونت الإفتراضية</string>\n    <string name=\"download_done\">خُلِص التنزيل</string>\n    <string name=\"skip_startup_account_select_pref\">م تطلبو مني نقي أكونت لمّا إفتح الآپ</string>\n    <string name=\"emulator_layout\">الشكل المعمول للكمپيوتر</string>\n    <string name=\"downloading\">عم يتنَزَل</string>\n    <string name=\"play_episode\">مشّي الحلقة</string>\n    <string name=\"player_speed\">سرعة الڤيديو</string>\n    <string name=\"manage_accounts\">تحكمو بال أكونتات</string>\n    <string name=\"example_lang_name\">رمز اللغة (ar)</string>\n    <string name=\"create_account\">عمول أكونت</string>\n    <string name=\"enable_nsfw_on_providers\">تمكين محتوى 18+ في الامتدادات الداعمة</string>\n    <string name=\"preferred_media_settings\">المحتوى المفضل</string>\n    <string name=\"switch_account\">غَيِر الأكونت</string>\n    <string name=\"popup_pause_download\">حط پوز على التنزيل</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"app_dubbed_text\">مدبلج</string>\n    <string name=\"automatic\">أوتوماتيك</string>\n    <string name=\"edit_account\">عدلو الأكونت</string>\n    <string name=\"pin_error_incorrect\">الأرقام السرية يللي نحطت مش صحيحة. جرب مرة أخرى.</string>\n    <string name=\"tv_layout\">الشكل المعمول للتلفزيون</string>\n    <string name=\"download_canceled\">نلغى التنزيل</string>\n    <string name=\"account\">أكونت</string>\n    <string name=\"home_expanded_hide\">خبي</string>\n    <string name=\"sort_apply\">طَبِق</string>\n    <string name=\"pick_subtitle\">الترجمة</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d يوم %2$d ساعة %3$d ديقة</string>\n    <string name=\"example_password\">پاسورد123</string>\n    <string name=\"pin_error_length\">لازم يكونو 4 أرقام</string>\n    <string name=\"download_paused\">محطوت پوز على التنزيل</string>\n    <string name=\"download\">نَزِل</string>\n    <string name=\"subtitles_encoding\">نوع الكتيبة بال ترجمة</string>\n    <string name=\"popup_delete_file\">محي الملف</string>\n    <string name=\"downloaded\">منَزَل</string>\n    <string name=\"popup_resume_download\">كفي التنزيل</string>\n    <string name=\"example_email\">إي مايل (ع شكل: email@example.com)</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d ديقة</string>\n    <string name=\"category_provider_test\">فحص المصادر</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_site_name\">إسم الوب سيت الجديدة</string>\n    <string name=\"popup_play_file\">فتاح ومَشّي الملف</string>\n    <string name=\"app_theme_settings\">نوع الألون</string>\n    <string name=\"go_back\">رجاع</string>\n    <string name=\"phone_layout\">الشكل المعمول للتليفون</string>\n    <string name=\"pref_category_gestures\">تَحَكُم بلا كَبسات</string>\n    <string name=\"logout\">طلاع من الأكونت</string>\n    <string name=\"home_info\">معلومات</string>\n    <string name=\"sort_save\">سَيِڤ</string>\n    <string name=\"download_failed\">فِشِل التنزيل</string>\n    <string name=\"primary_color_settings\">اللون الاساسي</string>\n    <string name=\"login\">فوت ع الأكونت</string>\n    <string name=\"app_subbed_text\">مترجم</string>\n    <string name=\"stream\">بِث من الإنترنت</string>\n    <string name=\"home_play\">مشي</string>\n    <string name=\"download_storage_text\">التخزين الجُواني</string>\n    <string name=\"add_account\">زيد أكونت</string>\n    <string name=\"sort_close\">سكّر</string>\n    <string name=\"action_add_to_bookmarks\">عدل حالة الحَضِر</string>\n    <string name=\"pin\">الأرقام السرية</string>\n    <string name=\"bottom_title_settings_des\">حط العنوان تحت الپوستر</string>\n    <string name=\"category_providers\">المصادر</string>\n    <string name=\"cast_format\" formatted=\"true\">ممثلين: %s</string>\n    <string name=\"repository_url_hint\">رابط أو كود الريپو</string>\n    <string name=\"subtitles_depressed\">مدپرس</string>\n    <string name=\"safe_mode_description\">من ورا عطل، كل الإضفات نطفت لنساعدكن تلاقو أيا إضافة عم بتسبب المشكلة.</string>\n    <string name=\"view_public_repositories_button_short\">لايحة عامة</string>\n    <string name=\"favorite_removed\">\\\"%s\\\" نشال من المفضل</string>\n    <string name=\"subscription_new\">شتركتو لـ\\\"%s\\\"</string>\n    <string name=\"added_sync_format\" formatted=\"true\">زِدت %s</string>\n    <string name=\"favorites_list_name\">المفضلين</string>\n    <string name=\"favorite_added\">\\\"%s\\\" نزاد ع المفضل</string>\n    <string name=\"home_next_random_img_des\">العشوائي يللي بعده</string>\n    <string name=\"subtitles_shadow\">خيال</string>\n    <string name=\"subscription_in_progress_notification\">عم نجدِد المثلثلات يللي مشتركينلها</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">مبين إنو فيه عنصر متل هيدا موجود بال مكتبة عندكن:\n\\n\n\\n%s\n\\n\n\\nبدكن تزيدو هيدا العنصر بأيّ حال، أو تستبدلوه مع العنصر الموجود، أو تلغو الإجراء؟</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">نزلت %1$d %2$s</string>\n    <string name=\"error_invalid_id\">معرف مش صالح</string>\n    <string name=\"skip_type_format\" formatted=\"true\">أفّي %s</string>\n    <string name=\"title\">العنوان</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">حطو الأرقام السرية لـ\\\"%s\\\"</string>\n    <string name=\"apk_installer_legacy\">الطريقة القديمة</string>\n    <string name=\"subtitles_raised\">معلى</string>\n    <string name=\"blank_repo_message\">\\\"كلود ستريم\\\" م بتجي مع مصادر ڤيديوات. لازم تنزلو المصادر من ريپويات.\n\\n\n\\nفيه معلومات على الـ\\\"ديسكورد\\\" تبعنا، أو فيكن تنبشو ع معلومات على الإنترنت.</string>\n    <string name=\"add_sync\">زبد تتبع</string>\n    <string name=\"mobile_data\">3G/4G…</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">نفَتح %s</string>\n    <string name=\"update_notification_failed\">م قدرنا ننزل الإصدار الجديد تبع الآپ</string>\n    <string name=\"extension_authors\">المؤلفين</string>\n    <string name=\"plugin_singular\">إضافة</string>\n    <string name=\"duplicate_title\">معقول يكون موجود أصلًا</string>\n    <string name=\"subscription_list_name\">مشتركينلو</string>\n    <string name=\"all_languages_preference\">كل اللغات</string>\n    <string name=\"uppercase_all_subtitles\">دايمًا كتوب ب أحرف كاپيتال، A بدل a</string>\n    <string name=\"player_pref\">مشغل الڤيديو المفضل</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">بَلَش تنزيل %1$d %2$s\n\\n…</string>\n    <string name=\"extension_description\">الوصف</string>\n    <string name=\"view_public_repositories_button\">شوف الريپويات تبع مجتمع \\\"كلاود ستريم\\\"</string>\n    <string name=\"safe_mode_title\">إنت هلّق بال وضع الآمن</string>\n    <string name=\"revert\">سترجاع</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">مش منزل: %d</string>\n    <string name=\"next\">اللي بعده</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"select_library\">نقي الرفّ</string>\n    <string name=\"subscription_deleted\">وقفتو الإشتراك لـ\\\"%s\\\"</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"no\">لأ</string>\n    <string name=\"action_add_to_favorites\">زيدو ع المفضل</string>\n    <string name=\"subtitle_offset_title\">تأخير الترجمة</string>\n    <string name=\"normal\">عادي</string>\n    <string name=\"extension_install_first\">نزل الإضافة قبل</string>\n    <string name=\"all\">الكل</string>\n    <string name=\"sort_rating_desc\">رايتينگ (من العالي للواطي)</string>\n    <string name=\"profiles\">الپروفيلات</string>\n    <string name=\"setup_done\">خلصت</string>\n    <string name=\"clear_history\">محي السجل</string>\n    <string name=\"sort_updated_old\">تجَدَد (من قديم للجديد)</string>\n    <string name=\"quality_cam_rip\">كاميرا</string>\n    <string name=\"quality_webrip\">وَب</string>\n    <string name=\"sort_alphabetical_z\">أبجديًا (من الياء للألف)</string>\n    <string name=\"enable_skip_op_from_database_des\">فرجي كبسة ل تأفّي المقدمة وال خاتمة</string>\n    <string name=\"skip_setup\">أفّى الإعداد</string>\n    <string name=\"authenticated_user\" formatted=\"true\">فتت ع أكونت \\\"%s\\\" تبعك</string>\n    <string name=\"subtitles_outline\">حدود خطية</string>\n    <string name=\"unable_to_inflate\">في مشكلة بطعمير الـUI. هيدي مشكبة كبيرة. پليز بَلِغ عنّا\n\\n(UI was unable to be created correctly)\n\\n%s</string>\n    <string name=\"edit\">عَدِل</string>\n    <string name=\"sort_updated_new\">تجَدَد (من الجديد للقديم)</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"min\">الحد الأدنى</string>\n    <string name=\"none\">ولا شي</string>\n    <string name=\"duplicate_replace_all\">ستبدلوّن كلن</string>\n    <string name=\"downloaded_file\">الملفات المنزلة</string>\n    <string name=\"wifi\">واي فاي</string>\n    <string name=\"profile_background_des\">خلفية الپروفيل</string>\n    <string name=\"skip_type_mixed_ed\">نهاية مختلطة</string>\n    <string name=\"extras\">زيادات</string>\n    <string name=\"coming_soon\">قريبًا…</string>\n    <string name=\"skip_type_recap\">التلخيص</string>\n    <string name=\"yes\">إِيه</string>\n    <string name=\"actor_main\">الرئيسي</string>\n    <string name=\"apply_on_restart\">سكر الآپ حتى تطبق التغيرات.</string>\n    <string name=\"help\">ساعدوني</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">عوز هيدا إذا عم بتبين الترجمة %d ميلي ثانية بعد ما لازم</string>\n    <string name=\"app_not_found_error\">م نلاقا الآپ</string>\n    <string name=\"actor_supporting\">الممثل المساعد</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">كل\\\"%s\\\" منزلة أصلًا</string>\n    <string name=\"recommended\">مقترح</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"player_load_subtitles_online\">فتاح من الإنترنت</string>\n    <string name=\"app_layout_subtext\">غَير شكل الآپ حتى يتناسب مع جهازك</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">مطفي: %d</string>\n    <string name=\"stop\">وقف</string>\n    <string name=\"empty_library_logged_in_message\">هيدي للايحة فاضية. جربو تبدلو ع غيرا.</string>\n    <string name=\"profile_number\">پروفيل %d</string>\n    <string name=\"sort_by\">ترتيب حسب</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">عوز هيدا إزا عم بتبين الترجمة %d ميلي ثانية قبل ما لازم</string>\n    <string name=\"skip_type_op\">الإفتتاح</string>\n    <string name=\"resolution_and_title\">الجودة وال عنوان</string>\n    <string name=\"action_unsubscribe\">شيل الإشتراك</string>\n    <string name=\"tracks\">جودة وصوت</string>\n    <string name=\"duplicate_replace\">ستبدل</string>\n    <string name=\"sync_total_episodes_none\">/؟؟</string>\n    <string name=\"actor_background\">الخلفية</string>\n    <string name=\"sort_alphabetical_a\">أبجديًا (من الألف للياء)</string>\n    <string name=\"previous\">اللي قبله</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"plugin_downloaded\">تنزلت الإضافة</string>\n    <string name=\"reload_error\">رجاع جَرِب تعمل إتصال…</string>\n    <string name=\"duplicate_add\">زيد</string>\n    <string name=\"batch_download\">نزل المصادر بال جملة</string>\n    <string name=\"open_with\">فتاح بـ</string>\n    <string name=\"sync_score\">راينيگ</string>\n    <string name=\"delete_repository_plugins\">محي الريپو كمان بمحي الإضافات يللي فيه</string>\n    <string name=\"extension_language\">اللغة</string>\n    <string name=\"action_subscribe\">شترك</string>\n    <string name=\"plugin_deleted\">نمحت الإضافة</string>\n    <string name=\"restart\">سكّر ورجاع فتاح</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"extensions\">الإضافات</string>\n    <string name=\"subtitles_remove_bloat\">شيل الإعلانات من الترجمة</string>\n    <string name=\"empty_library_no_accounts_message\">رفّكن فاضي ☹\n\\nفوتو على أكونت فيها رفّ الڤيديوات يللي حضرينها أو زيدو ڤيديوات بال رفّ المحلي.</string>\n    <string name=\"repository_name_hint\">اسم الريپو (مش ضروري)</string>\n    <string name=\"qualities\">الجودات</string>\n    <string name=\"error_invalid_data\">بيانات مش صالحة</string>\n    <string name=\"use\">عوز</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_cam_hd\">كاميرا</string>\n    <string name=\"action_remove_from_favorites\">شيلو من المفضل</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"plugin_loaded\">نزادت الإضافة</string>\n    <string name=\"extension_size\">الحجم</string>\n    <string name=\"upload_sync\">مزامنة</string>\n    <string name=\"safe_mode_crash_info\">شوفو معلومات عن المشكلة</string>\n    <string name=\"extension_types\">مدعوم</string>\n    <string name=\"subtitle_offset\">ظبّط وقت الترجمة</string>\n    <string name=\"skip_type_mixed_op\">افتتاح مختلط</string>\n    <string name=\"trailer\">مقطع دعائي</string>\n    <string name=\"provider_languages_tip\">حضار الڤيديوات بهيدي اللغات</string>\n    <string name=\"history\">السجل</string>\n    <string name=\"subscription_episode_released\">نَزَلو الحلقة %d!</string>\n    <string name=\"update_notification_downloading\">عم ننزل تجديد الآپ…</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">نزلت: %d</string>\n    <string name=\"subtitles_example_text\">أبجد هوز حطي كلمن سعفص قرشت ثخذ ضظغ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"sort_rating_asc\">رايتينگ (من الواطي للعالي)</string>\n    <string name=\"player_load_subtitles\">فتاح من ملف</string>\n    <string name=\"disable\">طفي</string>\n    <string name=\"safe_mode_file\">لقينا ملف الوضع الآمن!\n\\nمش رح نعوز إضافيات وقت ما ينفَتَح الآپ حتّى ينشال الملف.</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">مش مغير وقت الترجمة</string>\n    <string name=\"error\">مشكلة</string>\n    <string name=\"home_source\">مصدر</string>\n    <string name=\"sort\">ترتيب</string>\n    <string name=\"video_tracks\">الڤيديو</string>\n    <string name=\"skip_type_intro\">المقدمة</string>\n    <string name=\"poster_image\">صورة الپوستر</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d/10</string>\n    <string name=\"clipboard_too_large\">النص كبير كتير. مافينا ننسخو.</string>\n    <string name=\"plugins_updated\" formatted=\"true\">عدد الإضافيات يللي تجددت: %d</string>\n    <string name=\"delayed_update_notice\">رح يتجدد الآپ وقتا تطلعو مِنو</string>\n    <string name=\"hls_playlist\">پلاي ليست \\\"ايش أل أس\\\"</string>\n    <string name=\"add_repository\">زيد ريپو</string>\n    <string name=\"action_mark_as_watched\">علم إنو حضرتو</string>\n    <string name=\"preferred_media_subtext\">شو بَدَك تشوف</string>\n    <string name=\"subtitles_remove_captions\">شيل المعلومات يللي محطوطة بال ترجمة ل يللي عندن فقد سمعي</string>\n    <string name=\"no_repository_found_error\">م لقينا ريپو. تأكدو إنو الرابط صح وجربو تعوزو \\\"ڤي پي أن\\\" (VPN)</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">فشل الفوت ع الأكونت \\\"%s\\\"</string>\n    <string name=\"max\">الحد الأعلى</string>\n    <string name=\"update_notification_installing\">عم نتطبق تجديد الآپ…</string>\n    <string name=\"plugin\">إضافات</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">م قدرنا نفتح %s</string>\n    <string name=\"extension_rating\" formatted=\"true\">رايتينگ: %s</string>\n    <string name=\"download_all_plugins_from_repo\">تحزير: \\\"كلاود ستريم 3\\\" مش مسؤولة عن الإضافات المش رسمية، و م بتدعمن أبدًا!</string>\n    <string name=\"extension_status\">الحالة</string>\n    <string name=\"delete_repository\">محي الريپو</string>\n    <string name=\"category_player\">مشغل الڤيديو</string>\n    <string name=\"skip_type_ed\">النهاية</string>\n    <string name=\"home_random\">عشوائي</string>\n    <string name=\"already_voted\">إنتو أصلًا مصوتين</string>\n    <string name=\"quality_cam\">كاميرا</string>\n    <string name=\"no_plugins_found_error\">م لقينا ولا إضافة بال ريپو</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">مبين إنو في عنصر متل هيدا موجود بالمكتبة عندكن:\n\\n\\\"%s\\\"\n\\n\n\\nبدكن تزيدو هيدا العنصر بأيّ حال، أو تستبدلوّ مع العنصر الموجود، أو تلغو الإجراء؟</string>\n    <string name=\"error_invalid_url\">رايط مش صالح</string>\n    <string name=\"subtitle_offset_hint\">1000 مللي ثانية</string>\n    <string name=\"extension_version\">إصدار</string>\n    <string name=\"apk_installer_package_installer\">الطريقة الجديدة (PackageInstaller)</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (مَنزوعة)</string>\n    <string name=\"quality_dvd\">دي ڤي دي</string>\n    <string name=\"resolution\">الجودة</string>\n    <string name=\"set_default\">عين الافتراضي</string>\n    <string name=\"referer\">المرجع (إختياري)</string>\n    <string name=\"player_settings_play_in_app\">المشغل يللي ب \\\"كلود ستريم\\\"</string>\n    <string name=\"setup_extensions_subtext\">نزل لايحة المواقع يللي بدك تعوزهن</string>\n    <string name=\"enter_pin\">حطو الأرقام السرية</string>\n    <string name=\"subtitles_filter_lang\">فَلتِر حسب اللغة المفضلة</string>\n    <string name=\"confirm_exit_dialog\">أكيد بدكون تطلعو؟</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"action_remove_from_watched\">شيلو من لايحة المحتوى الحاضرينو</string>\n    <string name=\"skip_type_creddits\">الإعتمادات</string>\n    <string name=\"quality_profile_help\">فيكُن هون تغيرو طريقة ترتيب المصادر. المصدر يللي عنده أولوية أكتر بينحط أعلى بلايحت تنقايت المصدر. إنتو بتنقو الأولوية يإستعمال الأرقام. حطو الرقم الأعلى للمصادر والجودات يللي بتفضلوها.\n\\n\n\\nمتلًا:\n\\nإزا المصدر \\\"أ\\\" بتفضلوه، بتعطوه كتير نقات (متلًا 8).\n\\nإزا الجودة 480 ما بتحبوها، بتعطوها نقات قليلة (متلًا 1).\n\\n\n\\nعلامت المصدر وال جودة تبعه بينجمعو مع بعض (8 + 1 = 9). يللي علامته 10 أو أعلى، بينحط تلقائيًا، من دون ما ينعمل لود لكل المصادر!</string>\n    <string name=\"enter_current_pin\">حطو الأرقام السرية الحالية</string>\n    <string name=\"audio_tracks\">صوت</string>\n    <string name=\"rotate_video_desc\">حط كبسة لبرم إتجاه الشاشة</string>\n    <string name=\"auto_rotate_video\">برم الشاشة أوتوماتيكيًا</string>\n    <string name=\"rotate_video\">برومو</string>\n    <string name=\"auto_rotate_video_desc\">غير إتجاه الشاشة أوتوماتيكيًا حسب شكل الڤيديو</string>\n    <string name=\"links_reloaded_toast\">رجع نعمل لاود لاللينك</string>\n    <string name=\"result_search_tooltip\">نبش بغير مصادر</string>\n    <string name=\"subscribe_tooltip\">نوتيفيكايشن عن حلقات جديدة</string>\n    <string name=\"recommendations_tooltip\">فرجي الاقترحات</string>\n    <string name=\"speed_setting_summary\">بتزيد خيار السرعة بال مشغل</string>\n    <string name=\"test_extensions\">فحاص كل المصادر</string>\n    <string name=\"test_extensions_summary\">هيدا الفحص معمول للمطورين و م بأكد لحاله إزا المصدر عم يشتغل.</string>\n    <string name=\"favorite\">المفضلة</string>\n    <string name=\"biometric_authentication_title\">فتح قفل كلودستريم</string>\n    <string name=\"biometric_setting\">قفل بواسطة المقاييس الحيوية</string>\n    <string name=\"password_pin_authentication_title\">رمز/كلمة مرور للمصادقة</string>\n    <string name=\"biometric_setting_summary\">فتاح التطبيق باستعمال البصمة، آي دي الوج، پِن، النمط، أو الپاسورد.</string>\n    <string name=\"biometric_prompt_description\">بعد كذا محاولة فاشلة، هيدا الشباك رح يسكر. بكل بساطة، سكر الآپ ورجاع فتحه حتى تجرب بعد مرة.</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nباقي</string>\n    <string name=\"biometric_unsupported\">المصادقة البيومترية مش مدعومة ع هالجهاز</string>\n    <string name=\"unfavorite\">شيله من المفضل</string>\n    <string name=\"repo_copy_label\">اسم وعنوان الريپو</string>\n    <string name=\"toast_copied\">نتسخ!</string>\n    <string name=\"clipboard_permission_error\">فيه ارور بال وصول ل الكليپ-بورد. پليز جرب مرة أخرى.</string>\n    <string name=\"clipboard_unknown_error\">فيه ارور بال نسخ. پليز نسوخ الـLogcat 🐈 وبعته ل المسؤولين عن دعم الآپ.</string>\n    <string name=\"biometric_warning\">هلّق نعمل نسخة احتياطية للداتا تبع \\\"كلود ستريم\\\". إذا مابق ينفتح ويمشي الآپ، فيك تعمل كلير للداتا تبعه وترَجع الداتا من النسخة الاحتياطية اللي هلّق عملنالك ياها.\n\\nالاحتمال انو مابق ينفتح الآپ احتمالية زغيرة كتير، بس كل جهاز بيتصرف بشكل مختلف، ونحنا منعتذر إذا سببنا أي إزعاج.</string>\n    <string name=\"ok\">أوكي</string>\n    <string name=\"battery_dialog_title\">وقف اپتميزايشن بطارية جهازك</string>\n    <string name=\"app_unrestricted_toast\">بطارية الآپ اصلًا محطوطة ع «غير مقيد» \\\"Unrestricted\\\"</string>\n    <string name=\"app_info_intent_error\">م قدرنا نفتح معلومات الآپ تبع \\\"كلود ستريم\\\".</string>\n    <string name=\"music_singlar\">موسيقى</string>\n    <string name=\"audio_book_singular\">أوديو بوك</string>\n    <string name=\"custom_media_singluar\">الميديا</string>\n    <string name=\"battery_dialog_message\">ت تضمن عدم انقطاع التنزيلات والنوتيفيكايشنات للبرامج التلفزيونية يللي مشتركلها، الآپ \\\"كلود ستريم\\\" بده إذن ليمشي ب الباكگراوند. ازا كبست أوكي، رح يفتح شباك إذن زغير، كبوس «سماح».\\n\\nملاحظة إنو هيدا الإذن ما بيعني إنو \\\"كلود ستريم 3\\\" رح تستنزف البطارية. ومش رح يشتغل الآپ بال باكگراوند إلّا عند الضرورة، متل لمّا تتلقا نوتيفيكايشن أو تنزل ڤيديو من الريپو الاصلي.</string>\n    <string name=\"reset_btn\">ريسات</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">رح ينزل ب %s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">الحلقة ال %2$d من الجزء ال%1$d رح تنزل ب</string>\n    <string name=\"episode_action_cast_mirror\">كاست مراية</string>\n    <string name=\"player_settings_select_cast_device\">نقي جهاز الكاست</string>\n    <string name=\"cs3wiki\">ويكي \\\"كلود ستريم\\\"</string>\n    <string name=\"pref_category_accounts\">أكونتات</string>\n    <string name=\"pref_category_security\">سكوريتي</string>\n    <string name=\"qr_image\">صورة الـ\\\"كيو آر\\\" كود</string>\n    <string name=\"device_pin_error_message\">فشلنا ب فتح پِن الجهاز، جرب تفوت ع أكونت محليًا</string>\n    <string name=\"device_pin_expired_message\">خلصت مدة الپِن!</string>\n    <string name=\"device_pin_counter_text\">بتخلص مدة الپِن ب %1$d دقايق و%2$d ثانية</string>\n    <string name=\"auth_locally\">فوت عال أكونت محليًا</string>\n    <string name=\"dismiss\">تجاهل</string>\n    <string name=\"open_downloaded_repo\">فتاح الريپو</string>\n    <string name=\"device_pin_url_message\">فتاح <b>%s</b> ع تلفونك أو كمپيوترك، وحط الكود اللي فوق</string>\n    <string name=\"play_from_beginning_img_des\">بلشه من الأول</string>\n    <string name=\"test_warning\">تحذير</string>\n    <string name=\"open_local_video\">فتاح الڤيديو اللي ع جهازك</string>\n    <string name=\"downloads_empty\">مافي تنزيلات هلّق.</string>\n    <string name=\"delete_plugin\">محي الإضافة</string>\n    <string name=\"hide_player_control_names\">محي اسامي كبسات صيطرة مشغل الڤيديو</string>\n    <string name=\"sort_release_date_new\">نهار اللي نزل (من جديد ل قديم)</string>\n    <string name=\"sort_release_date_old\">نهار اللي نزل (من قديم ل جديد)</string>\n    <string name=\"downloads_delete_select\">نقي الإشيا اللي بدك تمحيها</string>\n    <string name=\"offline_file\">موجود لينحضر بلا إنترنت</string>\n    <string name=\"delete_files\">محي الفايلات</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">متأكد إنو بدك تمحي هيدي الإشيا ل الأبد؟\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">رح كمان تمحي ل الأبد كل الحلقات اللي ب هيدا المسلسل؟\n\\n\n\\n%s</string>\n    <string name=\"select_all\">نقي كل شي</string>\n    <string name=\"deselect_all\">شيل التنقاية</string>\n    <string name=\"delete_format\" formatted=\"true\">محي (%1$d | %2$s)</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">متأكد إنو بدك تمحي هيدي الحلقات من %1$s؟\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">متأكد إنو بدك تمحي كل الحلقات اللي بهيدا المسلسل؟\n\\n\n\\n%s</string>\n    <string name=\"preview_seekbar\">صورة زغيرة مع التقريب وال تبعيد</string>\n    <string name=\"preview_seekbar_desc\">بت حط صورة زغير من الڤيديو إنت و عم بت قرب أو ترجع بال ڤيديو</string>\n    <string name=\"no_subtitles_loaded\">بعد مش معمول لود لولا ترجمة</string>\n    <string name=\"show\">فرجي</string>\n    <string name=\"dont_show\">م تفرجي</string>\n    <string name=\"confirm_before_exiting_desc\">طلوب تأكيد قبلما تطلع من الآپ</string>\n    <string name=\"confirm_before_exiting_title\">أكّد إنو بدك تطلع</string>\n    <string name=\"backup_path_title\">محل النسخة الاحتياطية</string>\n    <string name=\"custom\">حدد غير محل</string>\n    <string name=\"torrent_info\">هيدا الڤيديو تورينت. هيدا بيعني إنه فيه ينعمله تراك، يعني بينعرف شو عم تحضر.\\nإزا م بتعرف شو التورينت، م تستعمله.</string>\n    <string name=\"subs_edge_size\">حجم الحفّة</string>\n    <string name=\"podcast_singluar\">پودكاست</string>\n    <string name=\"audio_singluar\">صوت</string>\n    <string name=\"unsupported_error\">أرور، مش مدعوم</string>\n    <string name=\"encoding_error\">أرور بال إنكودينگ</string>\n    <string name=\"player_load_one_subtitle_online\">أفّي اللودينگ تلقائيًا</string>\n    <string name=\"torrent_preferred_media\">سماح ب إستعمال الـTorrent بال سَتِنگز/المصادر/المحتوى المفضل</string>\n    <string name=\"torrent_not_accepted\">سكر الآپ و رجاع فتحه، و قبال دعم التورنت ت تكفي.</string>\n    <string name=\"software_decoding_desc\">السوفتوار ديكودينگ بخلي مشغل الڤيديو يمشّي أنواع فيلات ڤيديو م بيدعمها جهازك، بس هال شي معقول يخلي الڤيديو يعلق، خاصتًا إزا كانت الجودة عالية.</string>\n    <string name=\"software_decoding\">سوفتوار ديكودينگ</string>\n    <string name=\"sort_episodes_rating_low_high\">رايتينگ (أوطا)</string>\n    <string name=\"sort_episodes_date_newest\">نهار اللي نزل (أجدد)</string>\n    <string name=\"sort_episodes_date_oldest\">نهار اللي نزل (أقدم)</string>\n    <string name=\"sort_button_date\">تاريخ %s</string>\n    <string name=\"update_plugins\">جدد الإضافات</string>\n    <string name=\"update_plugins_manually\">جدد الإضافات يدويًا</string>\n    <string name=\"sort_episodes_rating_high_low\">رايتينگ (أعلى)</string>\n    <string name=\"sort_episodes_number_asc\">الحلقة (من الواطي ل العالي)</string>\n    <string name=\"player_notification_channel_name\">شغل الڤيديو عبر النوتيفيكايشنز</string>\n    <string name=\"sort_episodes_number_desc\">الحلقة (من العالي ل الواطي)</string>\n    <string name=\"sort_button_episode\">ح %s</string>\n    <string name=\"no_plugins_updated_manually\">م تجدد شي.</string>\n    <string name=\"sort_button_rating\">رايتينگ %s</string>\n    <string name=\"starting_plugin_update_manually\">بلشت عملية تجديد الإضافات!</string>\n    <string name=\"plugins_updated_manually\">نجح تجديد %d إضافات!</string>\n    <string name=\"player_notification_channel_description\">نوتيفيكايشن بت خليك تتحكم بال ڤيديو لما م يكون الآپ مفتوح</string>\n    <string name=\"subtitles_from_online\">اونلاين</string>\n    <string name=\"subtitles_from_embedded\">داخلياً</string>\n    <string name=\"speech_recognition_unavailable\">التعرّف الصوتي مش موجود</string>\n    <string name=\"begin_speaking\">بَلّش حكي…</string>\n    <string name=\"volume_exceeded_100\">تعلى الصوت ل أعلى من 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">سحاب بعد ت تعليه فوق الـ100%</string>\n    <string name=\"all_subtitles_bold\">عمول خط الترجمة بولد</string>\n    <string name=\"all_subtitles_italic\">عمول خط الترجمة أيتاليك</string>\n    <string name=\"background_radius\">قوة برمة الخلفية</string>\n    <string name=\"download_parallel_settings_des\">كم شغلة مختلفة فيها تتنزل ب نفس الوقت</string>\n    <string name=\"parallel_downloads\">تنزيل ب نفس الوقت</string>\n    <string name=\"concurrent_connections\">كم إتصال ب نفص الوقت</string>\n    <string name=\"concurrent_connections_settings_des\">كم إتصال ب نفس الوقت فيه يستعمل كل تنزيل</string>\n    <string name=\"go_to_downloads\">فتاح التنزيلات</string>\n    <string name=\"no_internet_connection\">مافي إنترنت.\\n\\nپليز جرب مرّة تانية لمّا يكون عندك إنترنت، أو حضار الإشيا اللي منزلها إنت و أفلاين.</string>\n    <string name=\"overscan_settings_des\">بت غير حدود الشاشة</string>\n    <string name=\"overscan_settings\">أوڤر سكان</string>\n    <string name=\"poster_size_settings_des\">بت غيّر حجم الپوستر</string>\n    <string name=\"poster_size_settings\">حجم الپوستر</string>\n    <string name=\"player_settings_always_ask\">دايمًا سئالوني</string>\n    <string name=\"speedup_title\">خليك كابس حتى تسرع</string>\n    <string name=\"speedup_summary\">خليك كابس كرمال سرعة الـ2x</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dساعة %2$dد %3$dث</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dد %2$dث</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$dث</string>\n    <string name=\"show_rating\">لايبل الرايتينگ</string>\n    <string name=\"no_account\">لا يوجد حساب</string>\n    <string name=\"edit_profile_image_title\">عدّل صورة الملف</string>\n    <string name=\"edit_profile_image_hint\">ادخل لينك ( عنوان ال URL ) تبع صورة الملف</string>\n    <string name=\"edit_profile_image_success\">تم تعديل الصورة بنجاح</string>\n    <string name=\"play_full_series_button\">بلّش كل المسلسل</string>\n    <string name=\"install_prerelease\">نزل النسخة التجريبية من الآپ</string>\n    <string name=\"prerelease_already_installed\">أصلًا عندك النسخة التجريبية.</string>\n    <string name=\"prerelease_install_failed\">فشل تنزيل النسخة التجريبية.</string>\n    <string name=\"episode_action_play_mirror\">ستعمل مصدر بديل</string>\"\n    <string name=\"show_episode_text\">كتيبة الحلقة</string>\n    <string name=\"edit_profile_image_error_empty\">م لقينا الرابط</string>\n    <string name=\"edit_profile_image_error_invalid\">الرابط أو الصورة مش صالحة</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">عتبر الحلقات محدورة لحد هون</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">وقف إعتبار الحلقات محدورة لحد هون</string>\n    <string name=\"action_reload\">عملنا ري-لوود</string>\n    <string name=\"reload_provider\">عمول ري-لوود للمصدر</string>\n    <string name=\"name\">اسم</string>\n    <string name=\"resolution_and_name\">الجودة وال اسم</string>\n    <string name=\"subs_subtitle_alignment\">ميلة الترجمة</string>\n    <string name=\"bottom_left\">تحت، عال شمال</string>\n    <string name=\"bottom_center\">تحت، بال نُص</string>\n    <string name=\"bottom_right\">تحت، عال يمين</string>\n    <string name=\"middle_left\">نُص، شمال</string>\n    <string name=\"middle_center\">نُص النُص</string>\n    <string name=\"middle_right\">نُص، عال يمين</string>\n    <string name=\"top_left\">فوق، عال شمال</string>\n    <string name=\"top_center\">فوق، بال نُص</string>\n    <string name=\"top_right\">فوق، عال يمين</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">ملصق</string>\n    <string name=\"search_poster_img_des\">الصورة الدعائية</string>\n    <string name=\"episode_poster_img_des\">ملصق الحلقة</string>\n    <string name=\"home_main_poster_img_des\">الملصق الرئيسي</string>\n    <string name=\"home_next_random_img_des\">التالي عشوائي</string>\n    <string name=\"go_back_img_des\">رجوع</string>\n    <string name=\"home_change_provider_img_des\">تغيير المصدر</string>\n    <string name=\"preview_background_img_des\">معاينة الخلفية</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">سرعة (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">تقييم: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">يوجد تحديث جديد!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration_format\" formatted=\"true\">%d دقيقة</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">تشغيل بواسطة CloudStream</string>\n    <string name=\"title_home\">الرئيسية</string>\n    <string name=\"title_search\">البحث</string>\n    <string name=\"title_downloads\">التنزيلات</string>\n    <string name=\"title_settings\">الإعدادات</string>\n    <string name=\"search_hint\">بحث…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">بحث %s…</string>\n    <string name=\"no_data\">لايوجد بيانات</string>\n    <string name=\"episode_more_options_des\">المزيد من الخيارات</string>\n    <string name=\"next_episode\">الحلقة التالية</string>\n    <string name=\"result_tags\">النوع</string>\n    <string name=\"result_share\">مشاركة</string>\n    <string name=\"result_open_in_browser\">فتح في الويب</string>\n    <string name=\"skip_loading\">تخطي التحميل</string>\n    <string name=\"loading\">تحميل…</string>\n    <string name=\"type_watching\">أشاهده</string>\n    <string name=\"type_on_hold\">في الإنتظار</string>\n    <string name=\"type_completed\">مكتمل</string>\n    <string name=\"type_dropped\">مهمل</string>\n    <string name=\"type_plan_to_watch\">أخطط لمشاهدته</string>\n    <string name=\"type_re_watching\">إعادة المشاهدة</string>\n    <string name=\"play_movie_button\">مشاهدة الفيلم</string>\n    <string name=\"play_livestream_button\">تشغيل بث حي</string>\n    <string name=\"play_torrent_button\">تشغيل تورنت</string>\n    <string name=\"pick_source\">المصادر</string>\n    <string name=\"pick_subtitle\">الترجمة</string>\n    <string name=\"reload_error\">إعادة محاولة الاتصال …</string>\n    <string name=\"go_back\">ارجع للخلف</string>\n    <string name=\"play_episode\">تشغيل الحلقة</string>\n    <!--<string name=\"need_storage\">السماح بتنزيل الحلقات</string>-->\n    <string name=\"download\">تحميل</string>\n    <string name=\"downloaded\">تم التنزيل</string>\n    <string name=\"downloading\">جاري التنزيل</string>\n    <string name=\"download_paused\">توقف التنزيل مؤقتًا</string>\n    <string name=\"download_started\">بدأ التنزيل</string>\n    <string name=\"download_failed\">فشل التنزيل</string>\n    <string name=\"download_canceled\">تم إلغاء التنزيل</string>\n    <string name=\"download_done\">تم التنزيل</string>\n    <string name=\"stream\">دفق الشبكة</string>\n    <string name=\"error_loading_links_toast\">خطأ في تحميل الرابط</string>\n    <string name=\"download_storage_text\">التخزين الداخلي</string>\n    <string name=\"app_dubbed_text\">مدبلج</string>\n    <string name=\"app_subbed_text\">مترجم</string>\n    <string name=\"popup_delete_file\">حذف ملف</string>\n    <string name=\"popup_play_file\">تشغيل الملف</string>\n    <string name=\"popup_resume_download\">متابعة التنزيل</string>\n    <string name=\"popup_pause_download\">إيقاف التنزيل مؤقتًا</string>\n    <string name=\"home_more_info\">مزيد من المعلومات</string>\n    <string name=\"home_expanded_hide\">إخفاء</string>\n    <string name=\"home_play\">تشغيل</string>\n    <string name=\"home_info\">معلومات</string>\n    <string name=\"filter_bookmarks\">تصفية الاشارات المرجعية</string>\n    <string name=\"error_bookmarks_text\">إشارات مرجعية</string>\n    <string name=\"action_remove_from_bookmarks\">ازالة</string>\n    <string name=\"action_add_to_bookmarks\">إعداد حالة المشاهدة</string>\n    <string name=\"sort_apply\">تطبيق</string>\n    <string name=\"sort_copy\">نسخ</string>\n    <string name=\"sort_close\">إغلاق</string>\n    <string name=\"sort_clear\">مسح</string>\n    <string name=\"sort_save\">حفظ</string>\n    <string name=\"player_speed\">سرعة المُشغل</string>\n    <string name=\"subtitles_settings\">إعدادات الترجمة</string>\n    <string name=\"subs_text_color\">لون الخط</string>\n    <string name=\"subs_outline_color\">لون المخطط التفصيلي</string>\n    <string name=\"subs_background_color\">لون الخلفية</string>\n    <string name=\"subs_window_color\">لون النافذة</string>\n    <string name=\"subs_edge_type\">نوع الحافة</string>\n    <string name=\"subs_subtitle_elevation\">إرتفاع الترجمة</string>\n    <string name=\"subs_font\">الخط</string>\n    <string name=\"subs_font_size\">حجم الخط</string>\n    <string name=\"search_provider_text_providers\">البحث باستخدام المصادر</string>\n    <string name=\"search_provider_text_types\">البحث باستخدام الأنواع</string>\n    <string name=\"benene_count_text\">%d الموزات المعطاة الى المطورين</string>\n    <string name=\"benene_count_text_none\">لم يتم إعطاء موز</string>\n    <string name=\"subs_auto_select_language\">تحديد اللغة تلقائيًا</string>\n    <string name=\"subs_download_languages\">لغات التحميل</string>\n    <string name=\"subs_subtitle_languages\">لغة الترجمة</string>\n    <string name=\"subs_hold_to_reset_to_default\">إضغط بإستمرار لإعادة التعيين للإعدادات الافتراضية</string>\n    <string name=\"subs_import_text\" formatted=\"true\">إستيراد خطوط بوضعها هنا %s</string>\n    <string name=\"continue_watching\">متابعة المشاهدة</string>\n    <string name=\"action_remove_watching\">ازالة</string>\n    <string name=\"action_open_watching\">المزيد من المعلومات</string>\n    <string name=\"vpn_might_be_needed\">قد تكون هناك حاجة إلى VPN لكي يعمل هذا المزود بشكل صحيح</string>\n    <string name=\"vpn_torrent\">هذا المزود هو تورنت، يوصى باستخدام شبكة ظاهرية خاصة</string>\n    <string name=\"provider_info_meta\">لا يتم توفير البيانات الوصفية بواسطة الموقع، وسيفشل تحميل الفيديو إذا لم يكن موجودًا في الموقع.</string>\n    <string name=\"torrent_plot\">الوصف</string>\n    <string name=\"normal_no_plot\">لم يتم العثور على حبكة</string>\n    <string name=\"torrent_no_plot\">لم يتم العثور على وصف</string>\n    <string name=\"show_log_cat\">عرض سجل الاخطاء 🐈</string>\n    <string name=\"picture_in_picture\">نافذة منبثقة</string>\n    <string name=\"picture_in_picture_des\">يستمر في التشغيل في مُشغل مصغر فوق التطبيقات الأخرى</string>\n    <string name=\"player_size_settings\">زر تغيير حجم المُشغل</string>\n    <string name=\"player_size_settings_des\">إزالة الحدود السوداء</string>\n    <string name=\"player_subtitles_settings\">الترجمة</string>\n    <string name=\"player_subtitles_settings_des\">إعدادات ترجمة المُشغل</string>\n    <string name=\"chromecast_subtitles_settings\">ترجمة كروم كاست</string>\n    <string name=\"chromecast_subtitles_settings_des\">إعدادات ترجمة كروم كاست</string>\n    <string name=\"eigengraumode_settings\">سرعة التشغيل</string>\n    <string name=\"swipe_to_seek_settings\">السحب لتقديم</string>\n    <string name=\"swipe_to_seek_settings_des\">اسحب من جانب إلى آخر للتحكم في موضعك في مقطع فيديو</string>\n    <string name=\"swipe_to_change_settings\">السحب لتغيير الإعدادات</string>\n    <string name=\"swipe_to_change_settings_des\">مرر لأعلى أو لأسفل على الجانب الأيسر أو الأيمن لتغيير السطوع أو مستوى الصوت</string>\n    <string name=\"autoplay_next_settings\">تشغيل الحلقة التالية تلقائيًا</string>\n    <string name=\"autoplay_next_settings_des\">تبدأ الحلقة التالية عندما تنتهي الحالية</string>\n    <string name=\"double_tap_to_seek_settings\">النقر مرتان للتقديم للأمام أو للخلف</string>\n    <string name=\"double_tap_to_pause_settings\">الضغط مرتان لإيقاف مؤقت</string>\n    <string name=\"double_tap_to_seek_amount_settings\">التحكم في مدى تقديم المُشغل(ثوان)</string>\n    <string name=\"double_tap_to_seek_settings_des\">إضغط مرتين على الجانب الأيمن أو الأيسر للتقديم للأمام أو للخلف</string>\n    <string name=\"double_tap_to_pause_settings_des\">اضغط مرتين في المنتصف للتوقف</string>\n    <string name=\"use_system_brightness_settings\">استخدم سطوع النظام</string>\n    <string name=\"use_system_brightness_settings_des\">استخدم سطوع النظام في مُشغل التطبيق بدلاً من التراكب الداكن</string>\n    <string name=\"episode_sync_settings\">تحديث تقدم المشاهدة</string>\n    <string name=\"episode_sync_settings_des\">مزامنة التقدم في الحلقة الحالية تلقائيًا</string>\n    <string name=\"restore_settings\">إسترجاع البيانات من النسخة الإحتياطية</string>\n    <string name=\"backup_settings\">نسخ إحتياطي للبيانات</string>\n    <string name=\"restore_success\">تم تحميل ملف النسخة الاحتياطية</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">فشل استيراد البيانات من الملف %s</string>\n    <string name=\"backup_success\">البيانات المخزنة</string>\n    <string name=\"backup_failed\">إذن الوصول الى ذاكرة التخزين مفقود, من فضلك حاول مجددا.</string>\n    <string name=\"backup_failed_error_format\">فشل إنشاء نسخة احتياطية %s</string>\n    <string name=\"search\">بحث</string>\n    <string name=\"category_account\">الحسابات والأمن</string>\n    <string name=\"category_updates\">التحديثات والنسخ الاحتياطية</string>\n    <string name=\"settings_info\">معلومات</string>\n    <string name=\"advanced_search\">البحث المتقدم</string>\n    <string name=\"advanced_search_des\">يعطيك نتائج البحث مفصولة عن طريق المزود</string>\n    <string name=\"show_fillers_settings\">عرض حلقات الفلر للأنمي</string>\n    <string name=\"show_trailers_settings\">عرض المقاطع الدعائية</string>\n    <string name=\"kitsu_settings\">عرض ملصقات من كيتسو</string>\n    <string name=\"pref_filter_search_quality\">إخفاء جودة الفيديو المختارة من نتائج البحث</string>\n    <string name=\"automatic_plugin_updates\">تحديث الإضافات تلقائيًا</string>\n    <string name=\"automatic_plugin_download\">تنزيل الإضافات تلقائيًا</string>\n    <string name=\"updates_settings\">التحديث التلقائي</string>\n    <string name=\"updates_settings_des\">ابحث تلقائيا عن التحديثات الجديدة بعد بدء التطبيق.</string>\n    <string name=\"github\">غيت هاب</string>\n    <string name=\"lightnovel\">تطبيق روايات خفيف من نفس المطورين</string>\n    <string name=\"anim\">تطبيق أنمي من نفس المطورين</string>\n    <string name=\"discord\">انضم إلى الديسكورد</string>\n    <string name=\"benene\">إعط موزة للمطورين</string>\n    <string name=\"benene_des\">الموز المُعطي</string>\n    <string name=\"app_language\">لغة التطبيق</string>\n    <string name=\"no_chromecast_support_toast\">هذا المزود ليس لديه دعم كروم كاست</string>\n    <string name=\"no_links_found_toast\">لم يتم العثور على روابط</string>\n    <string name=\"copy_link_toast\">تم نسخ الرابط إلى الحافظة</string>\n    <string name=\"play_episode_toast\">تشغيل الحلقة</string>\n    <string name=\"subs_default_reset_toast\">إعادة التعيين إلى القيمة الافتراضية</string>\n    <string name=\"season\">موسم</string>\n    <string name=\"no_season\">لا موسم</string>\n    <string name=\"episode\">حلقة</string>\n    <string name=\"episodes\">حلقات</string>\n    <string name=\"season_short\">م</string>\n    <string name=\"episode_short\">ح</string>\n    <string name=\"no_episodes_found\">لم يتم العثور على أي حلقات</string>\n    <string name=\"delete_file\">حذف الملف</string>\n    <string name=\"delete\">حذف</string>\n    <string name=\"cancel\">إلغاء</string>\n    <string name=\"pause\">إيقاف مؤقت</string>\n    <string name=\"resume\">إستئناف</string>\n    <string name=\"go_back_30\">-٣٠</string>\n    <string name=\"go_forward_30\">+٣٠</string>\n    <string name=\"delete_message\">سوف يتم الحذف نهائيا %s\n\\nهل أنت متأكد?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nمتبقية</string>\n    <string name=\"status_ongoing\">جاري التنفيذ</string>\n    <string name=\"status_completed\">اكتمل</string>\n    <string name=\"status\">الحالة</string>\n    <string name=\"year\">سنة</string>\n    <string name=\"rating\">تقييم</string>\n    <string name=\"duration\">المدة الزمنية</string>\n    <string name=\"site\">موقع</string>\n    <string name=\"synopsis\">القصة</string>\n    <string name=\"queued\">في قائمة الانتظار</string>\n    <string name=\"no_subtitles\">الترجمة ليست موجودة</string>\n    <string name=\"action_default\">الإفتراضي</string>\n    <string name=\"free_storage\">فارغ</string>\n    <string name=\"used_storage\">مستخدم</string>\n    <string name=\"app_storage\">التطبيق</string>\n    <!--plural-->\n    <string name=\"movies\">أفلام</string>\n    <string name=\"tv_series\">مسلسلات</string>\n    <string name=\"cartoons\">رسوم متحركة</string>\n    <string name=\"anime\">أنمي</string>\n    <string name=\"torrent\">تورنت</string>\n    <string name=\"documentaries\">أفلام وثائقية</string>\n    <string name=\"ova\">أوفا</string>\n    <string name=\"asian_drama\">دراما آسيوية</string>\n    <string name=\"livestreams\">بث حي</string>\n    <string name=\"nsfw\">+18</string>\n    <string name=\"others\">أخرى</string>\n    <!--singular-->\n    <string name=\"movies_singular\">فيلم</string>\n    <string name=\"tv_series_singular\">مسلسل</string>\n    <string name=\"cartoons_singular\">كرتون</string>\n    <string name=\"anime_singular\">أنيمي</string>\n    <string name=\"ova_singular\">أوفا</string>\n    <string name=\"torrent_singular\">تورنت</string>\n    <string name=\"documentaries_singular\">وثائقي</string>\n    <string name=\"asian_drama_singular\">الدراما الآسيوية</string>\n    <string name=\"live_singular\">بث حي</string>\n    <string name=\"nsfw_singular\">+18</string>\n    <string name=\"other_singular\">فيديو</string>\n    <string name=\"source_error\">خطأ في المصدر</string>\n    <string name=\"remote_error\">خطأ بعيد</string>\n    <string name=\"render_error\">خطأ في جهاز العرض</string>\n    <string name=\"unexpected_error\">خطأ غير متوقع في المُشغل</string>\n    <string name=\"storage_error\">خطأ في التنزيل ، تحقق من أذونات التخزين</string>\n    <string name=\"episode_action_chromecast_episode\">حلقة كروم كاست</string>\n    <string name=\"episode_action_chromecast_mirror\">مرآة كروم كاست</string>\n    <string name=\"episode_action_play_in_app\">تشغيل في التطبيق</string>\n    <string name=\"episode_action_play_in_format\">%s تشغيل في</string>\n    <string name=\"episode_action_auto_download\">التحميل التلقائي</string>\n    <string name=\"episode_action_download_mirror\">تحميل بجودات مختلفة</string>\n    <string name=\"episode_action_reload_links\">إعادة تحميل الروابط</string>\n    <string name=\"episode_action_download_subtitle\">تحميل الترجمة</string>\n    <string name=\"show_hd\">ملصق الجودة</string>\n    <string name=\"show_dub\">ملصق مدبلج</string>\n    <string name=\"show_sub\">ملصق مترجم</string>\n    <string name=\"show_title\">العنوان</string>\n    <string name=\"poster_ui_settings\">التحكم في عناصر الواجهة على الملصق</string>\n    <string name=\"no_update_found\">لم يتم العثور على تحديثات</string>\n    <string name=\"check_for_update\">تحقق من التحديثات</string>\n    <string name=\"video_lock\">قفل</string>\n    <string name=\"video_aspect_ratio_resize\">تغيير الحجم</string>\n    <string name=\"video_source\">مصدر</string>\n    <string name=\"video_skip_op\">تخطي المقدمة</string>\n    <string name=\"dont_show_again\">لا تظهر مرة أخرى</string>\n    <string name=\"skip_update\">تخطي هذا التحديث</string>\n    <string name=\"update\">تحديث</string>\n    <string name=\"watch_quality_pref\">جودة المشاهدة المفضلة (WiFi)</string>\n    <string name=\"limit_title\">أقصى عدد لحروف عنوان مُشغل الفيديو</string>\n    <string name=\"limit_title_rez\">عرض معلومات المشغل</string>\n    <string name=\"video_buffer_size_settings\">حجم ذاكرة التخزين المؤقت للفيديو</string>\n    <string name=\"video_buffer_length_settings\">طول التخزين المؤقت</string>\n    <string name=\"video_buffer_disk_settings\">التخزين المؤقت للفيديو على القرص</string>\n    <string name=\"video_buffer_clear_settings\">مسح التخزين المؤقت للصورة والفيديو</string>\n    <string name=\"video_ram_description\">يتسبب في حدوث أعطال إذا تم ضبطه على مستوى مرتفع جدا على الأجهزة ذات الذاكرة المنخفضة، مثل تلفزيون أندرويد.</string>\n    <string name=\"video_disk_description\">يسبب مشاكل إذا تم ضبطه على مستوى مرتفع جدا على الأجهزة ذات مساحة التخزين المنخفضة، مثل تلفزيون أندرويد.</string>\n    <string name=\"dns_pref\">إستخدام DNS بدلا من HTTPS</string>\n    <string name=\"dns_pref_summary\">مفيد لتجاوز حجب مزود خدمة الإنترنت</string>\n    <string name=\"add_site_pref\">موقع بديل (نسخة)</string>\n    <string name=\"remove_site_pref\">حذف موقع</string>\n    <string name=\"add_site_summary\">إضافة نسخة من موقع موجود، بعنوان URL مختلف</string>\n    <string name=\"download_path_pref\">مسار التنزيل</string>\n    <string name=\"nginx_url_pref\">عنوان URL لخادم NGINX</string>\n    <string name=\"display_subbed_dubbed_settings\">عرض أنمي مدبلج / مترجم</string>\n    <string name=\"resize_fit\">ملائمة الشاشة</string>\n    <string name=\"resize_fill\">امتداد</string>\n    <string name=\"resize_zoom\">تكبير</string>\n    <string name=\"legal_notice\">إخلاء مسؤولية</string>\n    <string name=\"category_general\">عام</string>\n    <string name=\"random_button_settings\">زر العشوائي</string>\n    <string name=\"random_button_settings_desc\">إظهار زر عشوائي على الصفحة الرئيسية والمكتبة</string>\n    <string name=\"provider_lang_settings\">لغات الامتداد</string>\n    <string name=\"app_layout\">واجهة التطبيق</string>\n    <string name=\"preferred_media_settings\">المحتوى المفضل</string>\n    <string name=\"enable_nsfw_on_providers\">تفعيل محتوى خاص للبالغين داخل الإمتداد المدعوم</string>\n    <string name=\"subtitles_encoding\">فك تشفير الترجمة</string>\n    <string name=\"category_providers\">المصادر</string>\n    <string name=\"category_ui\">الواجهة</string>\n    <string name=\"automatic\">أوتوماتيك</string>\n    <string name=\"tv_layout\">واجهة التلفاز</string>\n    <string name=\"phone_layout\">واجهة الهاتف</string>\n    <string name=\"emulator_layout\">واجهة المحاكي</string>\n    <string name=\"primary_color_settings\">اللون الأساسي</string>\n    <string name=\"app_theme_settings\">مظهر التطبيق</string>\n    <string name=\"bottom_title_settings\">مكان عنوان الملصق</string>\n    <string name=\"bottom_title_settings_des\">وضع العنوان تحت الملصق</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">كلمة المرور</string>\n    <string name=\"example_username\">إسم المستخدم</string>\n    <string name=\"example_email\">البريد الإلكتروني</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">إسم الموقع الجديد</string>\n    <string name=\"example_site_url\">رابط الموقع مثلا : https://example.com</string>\n    <string name=\"example_lang_name\">اللغة (الإنجليزية)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">حساب</string>\n    <string name=\"logout\">تسجيل الخروج</string>\n    <string name=\"login\">تسجيل الدخول</string>\n    <string name=\"switch_account\">تبديل الحساب</string>\n    <string name=\"add_account\">إضافة حساب</string>\n    <string name=\"create_account\">إنشاء حساب</string>\n    <string name=\"add_sync\">إضافة تتبع</string>\n    <string name=\"added_sync_format\" formatted=\"true\">تم إضافة %s</string>\n    <string name=\"upload_sync\">مزامنة</string>\n    <string name=\"sync_score\">تقييم</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s تم التوثيق</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">تعذر تسجيل الدخول في %s</string>\n    <!-- ============ -->\n    <string name=\"none\">لا شيء</string>\n    <string name=\"normal\">عادي</string>\n    <string name=\"all\">الكل</string>\n    <string name=\"max\">الحد الاقصي</string>\n    <string name=\"min\">الحد الأدنى</string>\n    <string name=\"subtitles_outline\">الخطوط المحيطة</string>\n    <string name=\"subtitles_depressed\">النمط المنخفض</string>\n    <string name=\"subtitles_shadow\">ظل</string>\n    <string name=\"subtitles_raised\">رفع</string>\n    <string name=\"subtitle_offset\">مزامنة الترجمة</string>\n    <string name=\"subtitle_offset_hint\">1000 مللي ثانية</string>\n    <string name=\"subtitle_offset_title\">تأخير الترجمة</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">إستعملْ هذا إذا تَظْهرُ الترجماتَ %d m في وقت مبكر جداً</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">استخدم هذا إذا تم عرض الترجمة %d مللي ثانية متأخرًا جدًا</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">لا تأخير في الترجمة</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see:\n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">نصٌّ حكيمٌ لهُ سِرٌّ قاطِعٌ وَذُو شَأنٍ عَظيمٍ مكتوبٌ على ثوبٍ أخضرَ ومُغلفٌ بجلدٍ أزرق</string>\n    <string name=\"recommended\">مُوصى به</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">تم تحميل %s</string>\n    <string name=\"player_load_subtitles\">إختيار ملف</string>\n    <string name=\"player_load_subtitles_online\">تحميل من الانترنت</string>\n    <string name=\"downloaded_file\">الملف الذي تم تنزيله</string>\n    <string name=\"actor_main\">رئيسي</string>\n    <string name=\"actor_supporting\">ممثل مساعد</string>\n    <string name=\"actor_background\">الخلفية</string>\n    <string name=\"home_source\">مصدر</string>\n    <string name=\"home_random\">عشوائي</string>\n    <string name=\"coming_soon\">قريبا…</string>\n    <string name=\"quality_cam\">تصوير كام</string>\n    <string name=\"quality_cam_rip\">تصوير كام قطع</string>\n    <string name=\"quality_cam_hd\">تصوير كام جودة عالية</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">عالِ الدقة</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">بلو راي</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">دقة فائقة</string>\n    <string name=\"quality_hdr\">المستوى الديناميكي العالي</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">الويب</string>\n    <string name=\"poster_image\">صورة الملصق</string>\n    <string name=\"category_player\">المُشغل</string>\n    <string name=\"resolution_and_title\">الأبعاد والعنوان</string>\n    <string name=\"title\">العنوان</string>\n    <string name=\"resolution\">الأبعاد</string>\n    <string name=\"error_invalid_id\">معرف غير صالح</string>\n    <string name=\"error_invalid_data\">بيانات غير صالحة</string>\n    <string name=\"error_invalid_url\">عنون رابط غير صالح</string>\n    <string name=\"error\">خطأ</string>\n    <string name=\"subtitles_remove_captions\">ازالة التسميات التوضيحية من الترجمة</string>\n    <string name=\"subtitles_remove_bloat\">ازالة البرمجيات الخبيثة من الترجمة</string>\n    <string name=\"subtitles_filter_lang\">تصفية حسب لغة الوسائط المفضلة</string>\n    <string name=\"extras\">اكسترا</string>\n    <string name=\"trailer\">مقطع دعائي</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"referer\">المرجع (اختياري)</string>\n    <string name=\"next\">التالي</string>\n    <string name=\"provider_languages_tip\">شاهد الفيديوهات بهذه اللغات</string>\n    <string name=\"previous\">السابق</string>\n    <string name=\"skip_setup\">تخطي الإعداد</string>\n    <string name=\"app_layout_subtext\">قم بتغيير مظهر التطبيق ليناسب جهازك</string>\n    <string name=\"preferred_media_subtext\">ماذا تريد ان تري</string>\n    <string name=\"setup_done\">تم</string>\n    <string name=\"extensions\">الإضافات</string>\n    <string name=\"add_repository\">إضافة مستودع</string>\n    <string name=\"repository_name_hint\">إسم المستودع (اختياري)</string>\n    <string name=\"repository_url_hint\">عنوان URL للمستودع أو الشفرة القصيرة</string>\n    <string name=\"plugin_loaded\">تم تحميل الإضافة</string>\n    <string name=\"plugin_deleted\">تم إزالة الإضافة</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">تعذر التحميل %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">بدأ تنزيل %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">تم تنزيل %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">جميع %s محملة بالفعل</string>\n    <string name=\"batch_download\">تحميل مكثف</string>\n    <string name=\"plugin_singular\">إضافة</string>\n    <string name=\"plugin\">إضافات</string>\n    <string name=\"delete_repository_plugins\">سوف يتم محو جميع إضافات المستودع</string>\n    <string name=\"delete_repository\">ازالة مستودع</string>\n    <string name=\"setup_extensions_subtext\">تحميل قائمة المواقع التي تريد استخدامها</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">تم تحميل: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">مُعطل %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">غير مُحمل: %d</string>\n    <string name=\"blank_repo_message\">لا يحتوي CloudStream على مواقع مثبتة افتراضيًا. تحتاج إلى تثبيت المواقع من المستودعات.\n\\n\n\\nانضم إلى ديسكورد أو ابحث عبر الإنترنت.</string>\n    <string name=\"view_public_repositories_button\">عرض مستودعات المجتمع</string>\n    <string name=\"view_public_repositories_button_short\">قائمة عامة</string>\n    <string name=\"uppercase_all_subtitles\">جميع الترجمات حروف كبيرة</string>\n    <string name=\"download_all_plugins_from_repo\">تحذير: لا يتحمل CloudStream 3 أي مسؤولية عن استخدام ملحقات الطرف الثالث ولا يقدم أي دعم لها!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (معطل)</string>\n    <string name=\"tracks\">المسارات</string>\n    <string name=\"audio_tracks\">مسار الصوت</string>\n    <string name=\"video_tracks\">مسار الفيديو</string>\n    <string name=\"apply_on_restart\">أعد تشغيل التطبيق لرؤية التغييرات.</string>\n    <string name=\"safe_mode_title\">الوضع الآمن قيد التشغيل</string>\n    <string name=\"safe_mode_description\">تم إيقاف تشغيل جميع الملحقات بسبب عطل لمساعدتك في العثور على الإضافة التي تسبب مشكلة.</string>\n    <string name=\"safe_mode_crash_info\">عرض بيانات الاعطال</string>\n    <string name=\"extension_rating\" formatted=\"true\">تقييم: %s</string>\n    <string name=\"extension_description\">الوصف</string>\n    <string name=\"extension_version\">إصدار</string>\n    <string name=\"extension_status\">الحالة</string>\n    <string name=\"extension_size\">الحجم</string>\n    <string name=\"extension_authors\">المؤلفون</string>\n    <string name=\"extension_types\">مدعوم</string>\n    <string name=\"extension_language\">اللغة</string>\n    <string name=\"hls_playlist\">قائمة HLS</string>\n    <string name=\"player_pref\">مُشغل الفيديو المفضل</string>\n    <string name=\"clear_history\">مسح السجل</string>\n    <string name=\"history\">السجل</string>\n    <string name=\"enable_skip_op_from_database_des\">عرض زر تخطي المقدمة/الخاتمة</string>\n    <string name=\"cast_format\" formatted=\"true\">طاقم العمل: %s</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d يوم %2$d ساعة %3$d دقيقة</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$d ساعة %2$d دقيقة</string>\n    <string name=\"filler\" formatted=\"true\">الفيلير</string>\n    <string name=\"action_open_play\">فتح(تشغيل)</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"plugins_updated\" formatted=\"true\">المكونات الإضافية المحدثة %d</string>\n    <string name=\"skip_type_format\" formatted=\"true\">تخطي %s</string>\n    <string name=\"skip_type_op\">الافتتاح</string>\n    <string name=\"skip_type_ed\">النهاية</string>\n    <string name=\"skip_type_recap\">الخلاصة</string>\n    <string name=\"skip_type_mixed_ed\">نهاية مختلطة</string>\n    <string name=\"skip_type_mixed_op\">افتتاح مختلط</string>\n    <string name=\"skip_type_intro\">المقدمة</string>\n    <string name=\"clipboard_too_large\">النص كثير جدا. تعذر الحفظ في الحافظة.</string>\n    <string name=\"action_mark_as_watched\">علّمه كفيديو تمت مشاهدته</string>\n    <string name=\"yes\">نعم</string>\n    <string name=\"no\">ﻻ</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s الحلقة %2$d</string>\n    <string name=\"next_episode_format\" formatted=\"true\">سيتم إصدار الحلقة %d في</string>\n    <string name=\"update_notification_failed\">تعذر تثبيت الإصدار الجديد من التطبيق</string>\n    <string name=\"extension_install_first\">تثبيت الإضافة أولا</string>\n    <string name=\"player_settings_play_in_app\">مشغل داخلي</string>\n    <string name=\"app_not_found_error\">لم يتم العثور على التطبيق</string>\n    <string name=\"all_languages_preference\">جميع اللغات</string>\n    <string name=\"skip_type_creddits\">الإعتمادات</string>\n    <string name=\"update_notification_downloading\">‌تنزيل تحديث التطبيق…</string>\n    <string name=\"update_notification_installing\">‏تثبيت تحديث التطبيق…</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d دقيقة</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"confirm_exit_dialog\">هل أنت متأكد أنك تريد الخروج؟</string>\n    <string name=\"automatic_plugin_download_summary\">قم بتثبيت جميع المكونات الإضافية التي لم يتم تثبيتها بعد تلقائيا من المستودعات المضافة.</string>\n    <string name=\"apk_installer_settings\">مثبت الحزم</string>\n    <string name=\"apk_installer_settings_des\">بعض الاجهزة لا تدعم مثبت الحزمة الجديد. جرب الخيار القديم إذا لم يتم تثبيت التحديثات.</string>\n    <string name=\"apk_installer_legacy\">قياسي</string>\n    <string name=\"apk_installer_package_installer\">مثبت الحزمة</string>\n    <string name=\"pref_category_player_layout\">التخطيط</string>\n    <string name=\"redo_setup_process\">إعادة عملية الإعداد</string>\n    <string name=\"pref_category_links\">الروابط</string>\n    <string name=\"pref_category_app_updates\">تحديثات التطبيق</string>\n    <string name=\"pref_category_backup\">النسخ الإحتياطي</string>\n    <string name=\"pref_category_extensions\">الإضافات</string>\n    <string name=\"pref_category_actions\">الإجراءات</string>\n    <string name=\"pref_category_cache\">الذاكرة المؤقتة</string>\n    <string name=\"pref_category_gestures\">الإيماءات</string>\n    <string name=\"pref_category_player_features\">ميزات المشغل</string>\n    <string name=\"pref_category_subtitles\">الترجمات</string>\n    <string name=\"pref_category_defaults\">الإفتراضي</string>\n    <string name=\"pref_category_ui_features\">المميزات</string>\n    <string name=\"pref_category_looks\">المظهر</string>\n    <string name=\"play_trailer_button\">تشغيل المقطع الدعائي</string>\n    <string name=\"delayed_update_notice\">سيتم تحديث التطبيق عند الخروج</string>\n    <string name=\"update_started\">بدأ التحديث</string>\n    <string name=\"plugin_downloaded\">تم تنزيل الإضافة</string>\n    <string name=\"action_remove_from_watched\">إزالة من المشاهدة</string>\n    <string name=\"sort_alphabetical_a\">الترتيب الأبجدي (من الألف إلى الياء)</string>\n    <string name=\"select_library\">اختر المكتبة</string>\n    <string name=\"browser\">المتصفح</string>\n    <string name=\"sort_updated_new\">محدث (من الأحدث إلى الأقدم)</string>\n    <string name=\"empty_library_logged_in_message\">هذه القائمة فارغة ، حاول التبديل إلى قائمة أخرى.</string>\n    <string name=\"sort_rating_desc\">التقييم (من الأعلى إلى الأدنى)</string>\n    <string name=\"sort_rating_asc\">التقييم (من الأدنى إلى الأعلى)</string>\n    <string name=\"sort_alphabetical_z\">الترتيب الأبجدي (من ي إلى أ)</string>\n    <string name=\"empty_library_no_accounts_message\">مكتبتك فارغة :(\n\\nقم بتسجيل الدخول على حساب مكتبة أو أضف عروضا إلى مكتبتك المحلية.</string>\n    <string name=\"sort_updated_old\">محدث (من القديم إلى الجديد)</string>\n    <string name=\"sort_by\">فرز حسب</string>\n    <string name=\"sort\">افرز</string>\n    <string name=\"open_with\">فتح بواسطة</string>\n    <string name=\"library\">المكتبة</string>\n    <string name=\"safe_mode_file\">تم العثور على ملف الوضع الآمن!\n\\nلا يتم تحميل أي ملحقات عند بدء التشغيل حتى تتم إزالة الملف.</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">مدة التقديم عنما يكون المشغل مخفيا</string>\n    <string name=\"android_tv_interface_off_seek_settings\">مدة التقديم - المشغل مخفي</string>\n    <string name=\"pref_category_android_tv\">تلفزيون أندرويد</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">مدة التقديم عنما يكون المشغل مرئيا</string>\n    <string name=\"android_tv_interface_on_seek_settings\">مدة التقديم- المشغل المرئي</string>\n    <string name=\"test_failed\">فشل</string>\n    <string name=\"test_passed\">نجح</string>\n    <string name=\"category_provider_test\">إختبار المزود</string>\n    <string name=\"restart\">إعادة التشغيل</string>\n    <string name=\"test_log\">سجل</string>\n    <string name=\"start\">بَدأ</string>\n    <string name=\"stop\">إيقاف</string>\n    <string name=\"subscription_in_progress_notification\">تحديث العروض التي تم الاشتراك فيها</string>\n    <string name=\"subscription_deleted\">إلغاء الاشتراك من %s</string>\n    <string name=\"subscription_episode_released\">تم إصدار الحلقة %d!</string>\n    <string name=\"subscription_list_name\">مشترك</string>\n    <string name=\"subscription_new\">مشترك في %s</string>\n    <string name=\"pref_category_bypass\">تجاوز مزود خدمة الإنترنت</string>\n    <string name=\"revert\">استرجاع</string>\n    <string name=\"jsdelivr_enabled\">تعذر الوصول إلى جيثب. تشغيل وكيل jsDelivr …</string>\n    <string name=\"jsdelivr_proxy_summary\">تجاوز حظر عناوين URL الأولية لـ github باستخدام jsDelivr. قد يتسبب في تأخير التحديثات لبضعة أيام.</string>\n    <string name=\"jsdelivr_proxy\">وكيل github</string>\n    <string name=\"watch_quality_pref_data\">جودة المشاهدة المفضلة (بيانات الجوال)</string>\n    <string name=\"profile_number\">الملف الشخصي %d</string>\n    <string name=\"wifi\">واي فاي</string>\n    <string name=\"mobile_data\">بيانات الهاتف</string>\n    <string name=\"set_default\">تعيين الافتراضي</string>\n    <string name=\"use\">استخدام</string>\n    <string name=\"edit\">تعديل</string>\n    <string name=\"profiles\">الملفات التعريفية</string>\n    <string name=\"help\">مساعدة</string>\n    <string name=\"quality_profile_help\">‎‎هنا يمكنك تغيير طريقة ترتيب المصادر. إذا كان للفيديو أولوية أعلى ، فسيظهر في الأعلى في اختيار المصدر. يمثل مجموع أولوية المصدر وأولوية الجودة أولوية الفيديو.\n\\n\n\\nالمصدر أ: 3\n\\nالجودة ب: 7\n\\nسيكون لها أولوية فيديو مجمعة تبلغ 10.\n\\n\n\\nملاحظة: إذا كان المجموع 10 أو أكثر ، فسيتخطى المشغل التحميل تلقائيًا عند تحميل هذا الرابط!</string>\n    <string name=\"qualities\">النوعيات</string>\n    <string name=\"profile_background_des\">خلفية الملف الشخصي</string>\n    <string name=\"unable_to_inflate\">تعذر إنشاء واجهة المستخدم بشكل صحيح ، وهذا خطأ كبير ويجب الإبلاغ عنه على الفور %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">حدد الوضع لتصفية تنزيل المكونات الإضافية</string>\n    <string name=\"disable\">تعطيل</string>\n    <string name=\"no_plugins_found_error\">لا توجد اضافة في المستودع</string>\n    <string name=\"no_repository_found_error\">المستودع لم يتم العثور عليه، تحقق من العنوان اوجرب شبكة افتراضية خاصة(vpn)</string>\n    <string name=\"already_voted\">لقد صوتت بالفعل</string>\n    <string name=\"backup_frequency\">معدل النسخ الإحتياطي</string>\n    <string name=\"favorite_removed\">تمت إزالة %s من المفضلة</string>\n    <string name=\"favorites_list_name\">المفضلة</string>\n    <string name=\"favorite_added\">تمت إضافة %s إلى المفضلة</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">احتمال وجود تكرارات في مكتبتك.\n\\n\n\\n%s\n\\n\n\\nهل تريد الاضافة على اي حال مستبدلاً النسخة الموجودة بالفعل, أم تفضل إلغاء العملية؟</string>\n    <string name=\"duplicate_title\">احتمال أن يكون موجود بالفعل</string>\n    <string name=\"lock_profile\">قفل الحساب</string>\n    <string name=\"action_add_to_favorites\">اضافة الى المفضلة</string>\n    <string name=\"duplicate_replace_all\">تبديل الكل</string>\n    <string name=\"pin_error_incorrect\">رقم PIN غير صحيح. برجاء المحاولة مرة اخرى.</string>\n    <string name=\"action_unsubscribe\">إلغاء الاشتراك</string>\n    <string name=\"pin_error_length\">رقم ال PIN يجب ان يكون 4 ارقام</string>\n    <string name=\"duplicate_replace\">استبدال</string>\n    <string name=\"duplicate_add\">اضافة</string>\n    <string name=\"action_subscribe\">إشترك</string>\n    <string name=\"action_remove_from_favorites\">إزالة من المفضلة</string>\n    <string name=\"select_an_account\">اختار حساب</string>\n    <string name=\"duplicate_message_single\">يبدو أن هناك عنصرًا مكررًا موجود بالفعل في مكتبتك: \\'%s\\'.\n\\n\n\\nهل ترغب في إضافة هذا العنصر على أية حال، أو استبدال العنصر الموجود، أو إلغاء الإجراء؟</string>\n    <string name=\"enter_pin\">ادخال ال PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">أدخل ال PIN الحالي</string>\n    <string name=\"logged_account\" formatted=\"true\">تم تسجيل الدخول كـ %s</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">أدخل رقم التعريف الشخصي لـ %s</string>\n    <string name=\"use_default_account\">استخدم الحساب الافتراضي</string>\n    <string name=\"skip_startup_account_select_pref\">تخطي اختيار الحساب عند بدء التشغيل</string>\n    <string name=\"manage_accounts\">إدارة الحسابات</string>\n    <string name=\"edit_account\">تعديل الحساب</string>\n    <string name=\"links_reloaded_toast\">تم إعادة تحميل الروابط</string>\n    <string name=\"rotate_video_desc\">عرض زر تبديل لاتجاه الشاشة</string>\n    <string name=\"auto_rotate_video\">الدوران التلقائي</string>\n    <string name=\"rotate_video\">تدوير</string>\n    <string name=\"auto_rotate_video_desc\">تمكين التبديل التلقائي لاتجاه الشاشة بناءً على اتجاه الفيديو</string>\n    <string name=\"recommendations_tooltip\">إظهار التوصيات</string>\n    <string name=\"speed_setting_summary\">يضيف خيار السرعة في المُشغل</string>\n    <string name=\"test_extensions_summary\">هذا الاختبار مخصص للمطورين فقط ولا يتحقق أو ينفي عمل أي ملحق.</string>\n    <string name=\"subscribe_tooltip\">إشعار الحلقة الجديدة</string>\n    <string name=\"result_search_tooltip\">البحث في امتدادات أخرى</string>\n    <string name=\"test_extensions\">اختبار كافة الملحقات</string>\n    <string name=\"biometric_setting\">اقفل باستخدام المقاييس الحيوية</string>\n    <string name=\"biometric_unsupported\">المصادقة البيومترية غير مدعومة على هذا الجهاز</string>\n    <string name=\"biometric_setting_summary\">افتح التطبيق باستخدام بصمة الإصبع ومعرف الوجه ورقم التعريف الشخصي والنمط وكلمة المرور.</string>\n    <string name=\"biometric_authentication_title\">فتح سحابة البث</string>\n    <string name=\"password_pin_authentication_title\">مصادقة كلمة المرور/رقم التعريف الشخصي</string>\n    <string name=\"biometric_prompt_description\">بعد عدة محاولات فاشلة، سيتم إغلاق المطالبة. ما عليك سوى إعادة تشغيل التطبيق للمحاولة مرة أخرى.</string>\n    <string name=\"biometric_warning\">لقد تم الآن نسخ بيانات CloudStream احتياطيًا. على الرغم من أن احتمال حدوث ذلك منخفض جدًا، إلا أن جميع الأجهزة يمكن أن تتصرف بشكل مختلف. في الحالات النادرة، التي يتم فيها منعك من الوصول إلى التطبيق، قم بمسح بيانات التطبيق بالكامل واستعادتها من نسخة احتياطية. نحن نأسف جدًا لأي إزعاج ناتج عن هذا.</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nمتبقي</string>\n    <string name=\"favorite\">المفضلة</string>\n    <string name=\"unfavorite\">إزالة من المفضلة</string>\n    <string name=\"repo_copy_label\">اسم و عنوان المخزن</string>\n    <string name=\"clipboard_permission_error\">خطأ في الوصول الي حافظة النسخ، برجاء المحاولة مرة اخرى.</string>\n    <string name=\"toast_copied\">تم النسخ!</string>\n    <string name=\"clipboard_unknown_error\">خطأ في عملية النسخ، برجاء نسخ ال logcat و ارساله الى مسؤولين دعم التطبيق.</string>\n    <string name=\"battery_dialog_title\">تعطيل تحسين البطارية</string>\n    <string name=\"app_unrestricted_toast\">تم ضبط استخدام بطارية التطبيق بالفعل على غير مقيد</string>\n    <string name=\"app_info_intent_error\">غير قادر على فتح معلومات تطبيق CloudStream.</string>\n    <string name=\"audio_book_singular\">كتاب صوتي</string>\n    <string name=\"ok\">حسناً</string>\n    <string name=\"battery_dialog_message\">لضمان عدم انقطاع التنزيلات والإشعارات للعروض التلفزيونية التي اشتركت بها ، يحتاج CloudStream إلى إذن للتشغيل في الخلفية. بالضغط على \\\"موافق\\\"، سيظهر لك مربع حوار طلب. يُرجى الضغط على \\\"السماح\\\".\\n\\nيرجى ملاحظة أن هذا الإذن لا يعني أن CS3 سيستنزف بطاريتك. سيعمل في الخلفية فقط عند الضرورة، مثلا عند تلقي الإشعارات أو تنزيل مقاطع الفيديو من الإضافات الرسمية.</string>\n    <string name=\"music_singlar\">موسيقى</string>\n    <string name=\"custom_media_singluar\">الوسائط</string>\n    <string name=\"reset_btn\">اعادة تعيين</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">قادم خلال %s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">سيتم إصدار الحلقة %1$d من الموسم %2$d في</string>\n    <string name=\"episode_action_cast_mirror\">مرآة البث</string>\n    <string name=\"player_settings_select_cast_device\">حدد جهاز البث</string>\n    <string name=\"cs3wiki\">CloudStream ويكي</string>\n    <string name=\"pref_category_security\">إعدادات الأمان</string>\n    <string name=\"pref_category_accounts\">الحسابات</string>\n    <string name=\"qr_image\">صورة رمز الاستجابة السريعة</string>\n    <string name=\"dismiss\">تجاهَل</string>\n    <string name=\"open_downloaded_repo\">فتح المستودع</string>\n    <string name=\"device_pin_expired_message\">لقد انتهت صلاحية الرمز السري الآن!</string>\n    <string name=\"auth_locally\">تحقق محليا</string>\n    <string name=\"device_pin_url_message\">قم بزيارة <b>%s</b> على هاتفك الذكي أو جهاز الكمبيوتر وأدخل الرمز أعلاه</string>\n    <string name=\"device_pin_error_message\">لا يمكن الحصول على رمز PIN للجهاز، حاول المصادقة المحلية</string>\n    <string name=\"device_pin_counter_text\">تنتهي صلاحية الرمز خلال %1$dm %2$ds</string>\n    <string name=\"play_from_beginning_img_des\">تشغيل من البداية</string>\n    <string name=\"open_local_video\">فتح فيديو محلي</string>\n    <string name=\"test_warning\">تحذير</string>\n    <string name=\"delete_plugin\">حذف الإضافة</string>\n    <string name=\"hide_player_control_names\">إخفاء الأسم من عناصر تحكم المشغل</string>\n    <string name=\"downloads_empty\">لا يوجد حالياً اى تنزيلات.</string>\n    <string name=\"sort_release_date_new\">تاريخ الإصدار (من الأحدث إلى الأقدم)</string>\n    <string name=\"sort_release_date_old\">تاريخ الإصدار (القديم إلى الجديد)</string>\n    <string name=\"downloads_delete_select\">الرجاء تحديد العناصر للحذف</string>\n    <string name=\"select_all\">تحديد الكل</string>\n    <string name=\"delete_files\">حذف الملفات</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">هل أنت متأكد أنك تريد حذف الحلقات التالية نهائيًا في %1$s ؟\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">ستقوم أيضًا بحذف جميع الحلقات في السلسلة التالية نهائيًا:\n\\n\n\\n%s</string>\n    <string name=\"delete_format\" formatted=\"true\">حذف (%1$d | %2$s)</string>\n    <string name=\"offline_file\">متاح للمشاهدة في وضع عدم الاتصال</string>\n    <string name=\"deselect_all\">إلغاء تحديد الكل</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">هل أنت متأكد أنك تريد حذف العناصر التالية نهائيًا ؟\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">هل أنت متأكد أنك تريد حذف جميع الحلقات في السلسلة التالية نهائيًا ؟\n\\n\n\\n%s</string>\n    <string name=\"preview_seekbar\">معاينة شريط البحث</string>\n    <string name=\"preview_seekbar_desc\">تمكين معاينة الصورة المصغرة على شريط البحث</string>\n    <string name=\"no_subtitles_loaded\">لم يتم تحميل أي ترجمات بعد</string>\n    <string name=\"confirm_before_exiting_title\">تأكيد قبل الخروج</string>\n    <string name=\"confirm_before_exiting_desc\">عرض مربع الحوار قبل الخروج من التطبيق</string>\n    <string name=\"show\">أظهِر</string>\n    <string name=\"dont_show\">لا تظهر</string>\n    <string name=\"backup_path_title\">موقع مجلد النسخ الاحتياطي</string>\n    <string name=\"custom\">مخصص</string>\n    <string name=\"torrent_info\">هذا الفيديو موجود على شبكة تورنت، مما يعني ان الاستخدام يمكن تعقبه.\\nتأكد من فهم شبكات التورنت قبل الاستكمال.</string>\n    <string name=\"subs_edge_size\">حجم الحافة</string>\n    <string name=\"audio_singluar\">صوت</string>\n    <string name=\"podcast_singluar\">بودكاست</string>\n    <string name=\"encoding_error\">خطأ في التكويد</string>\n    <string name=\"unsupported_error\">خطأ في الدعم</string>\n    <string name=\"player_load_one_subtitle_online\">تحميل أول ترجمة متاحة</string>\n    <string name=\"torrent_preferred_media\">تفعيل التورنت من خلال الاعدادات/المصادر/المحتوى المفضل</string>\n    <string name=\"torrent_not_accepted\">قم بإعادة تشغيل التطبيق و قبول التنبيه الخاص بالتورنت للمتابعة.</string>\n    <string name=\"software_decoding_desc\">يمكّن فك تشفير البرمجي المشغل من تشغيل ملفات الفيديو التي لا يدعمها جهازك، ولكنه قد يتسبب في بطء أو عدم استقرار التشغيل على الدقة العالية.</string>\n    <string name=\"software_decoding\">فك الترميز البرمجي</string>\n    <string name=\"sort_episodes_rating_high_low\">تقييم (الأعلى)</string>\n    <string name=\"sort_episodes_rating_low_high\">تقييم (الأقل)</string>\n    <string name=\"sort_button_episode\">ح %s</string>\n    <string name=\"sort_button_rating\">تقييم %s</string>\n    <string name=\"sort_button_date\">تاريخ %s</string>\n    <string name=\"update_plugins\">تحديث الإضافات</string>\n    <string name=\"plugins_updated_manually\">تم تحديث %d إضافات بنجاح!</string>\n    <string name=\"no_plugins_updated_manually\">لم يتم تحديث الإضافات.</string>\n    <string name=\"update_plugins_manually\">تحديث الإضافات يدوياً</string>\n    <string name=\"sort_episodes_number_asc\">حلقة (تصاعدي)</string>\n    <string name=\"sort_episodes_number_desc\">حلقة (تنازلي)</string>\n    <string name=\"sort_episodes_date_newest\">تاريخ البث (الأحدث)</string>\n    <string name=\"sort_episodes_date_oldest\">تاريخ البث (الأقدم)</string>\n    <string name=\"starting_plugin_update_manually\">بدأ عملية تحديث الإضافات!</string>\n    <string name=\"player_notification_channel_description\">تنبيه المشغل المسؤول عن تشغيل الميديا في الخلفية</string>\n    <string name=\"player_notification_channel_name\">تنبيهات المشغل</string>\n    <string name=\"speech_recognition_unavailable\">التعرّف الصوتي غير متاح</string>\n    <string name=\"begin_speaking\">بدأ التحدث…</string>\n    <string name=\"subtitles_from_online\">اونلاين</string>\n    <string name=\"subtitles_from_embedded\">داخلياً</string>\n    <string name=\"volume_exceeded_100\">لقد تجاوز مستوى الصوت 100٪</string>\n    <string name=\"all_subtitles_bold\">جعل جميع العناوين الفرعية عريضة</string>\n    <string name=\"slide_up_again_to_exceed_100\">اسحب لأعلى مرة أخرى لتتجاوز 100%</string>\n    <string name=\"all_subtitles_italic\">جعل كل العناوين الفرعية مائلة</string>\n    <string name=\"background_radius\">نصف قطر الخلفية</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$d</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$d</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$dث</string>\n    <string name=\"show_rating\">ملصق التصنيف</string>\n    <string name=\"player_settings_always_ask\">أسال دائما</string>\n    <string name=\"download_parallel_settings_des\">عدد الأصناف المختلفة التي يمكن تنزيلها بالتوازي</string>\n    <string name=\"parallel_downloads\">تحميلات موازية</string>\n    <string name=\"concurrent_connections\">الاتصالات الجارية</string>\n    <string name=\"concurrent_connections_settings_des\">كم عدد الاتصالات المتزامنة التي يمكن أن يستخدمها كل تحميل</string>\n    <string name=\"go_to_downloads\">الذهاب إلى تحميل</string>\n    <string name=\"no_internet_connection\">لا يوجد اتصال بالإنترنت.\\n\\nيُرجى الاتصال بالإنترنت والمحاولة مرة أخرى، أو مشاهدة التنزيلات أثناء عدم الاتصال بالإنترنت.</string>\n    <string name=\"overscan_settings_des\">تغير حدود الشاشة</string>\n    <string name=\"overscan_settings\">مسح زائد</string>\n    <string name=\"poster_size_settings_des\">تغيير حجم الملصقات</string>\n    <string name=\"poster_size_settings\">حجم الملصقات</string>\n    <string name=\"speedup_title\">تبديل سرعة الضغط لفترة طويلة</string>\n    <string name=\"speedup_summary\">اضغط مع الاستمرار للحصول على سرعة 2x</string>\n    <string name=\"no_account\">لا يوجد حساب</string>\n    <string name=\"edit_profile_image_title\">تعديل صورة الملف الشخصي</string>\n    <string name=\"edit_profile_image_hint\">ادخل رابط صورة الملف الشخصي</string>\n    <string name=\"edit_profile_image_error_empty\">لم يتم العثور على الرابط</string>\n    <string name=\"edit_profile_image_error_invalid\">رابط او صورة غير صالحة للاستخدام</string>\n    <string name=\"edit_profile_image_success\">تم رفع الصورة</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">ضع علامة تمت المشاهدة لهذه الحلقة</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">ازالة علامة تمت المشاهدة لهذه الحلقة</string>\n    <string name=\"action_reload\">تم تحديث الصفحة</string>\n    <string name=\"reload_provider\">تحديث المزود</string>\n    <string name=\"episode_action_play_mirror\">تشغيل مصدر بديل</string>\"\n    <string name=\"name\">اسم</string>\n    <string name=\"resolution_and_name\">الدقة و الاسم</string>\n    <string name=\"subs_subtitle_alignment\">محاذاة الترجمة</string>\n    <string name=\"bottom_left\">أسفل اليسار</string>\n    <string name=\"bottom_center\">اسفل وسط</string>\n    <string name=\"bottom_right\">أسفل اليمين</string>\n    <string name=\"middle_left\">منتصف اليسار</string>\n    <string name=\"middle_center\">منتصف وسط</string>\n    <string name=\"middle_right\">منتصف يمين</string>\n    <string name=\"top_left\">اعلى يسار</string>\n    <string name=\"top_center\">اعلى وسط</string>\n    <string name=\"top_right\">اعلى يمين</string>\n    <string name=\"play_full_series_button\">شاهد المسلسل كاملاً</string>\n    <string name=\"extra_brightness_settings\">سطوع إضافي</string>\n    <string name=\"extra_brightness_settings_des\">تفعيل فلتر السطوع عند تجاوز سطوع الشاشة 100%</string>\n    <string name=\"extra_brightness_key\">تفعيل فلتر السطوع الإضافي</string>\n    <string name=\"search_suggestions\">اقتراحات البحث</string>\n    <string name=\"search_suggestions_des\">عرض اقتراحات البحث أثناء الكتابة</string>\n    <string name=\"clear_suggestions\">مسح الاقتراحات</string>\n    <string name=\"show_cast_in_details\">عرض لوحة البث</string>\n    <string name=\"install_prerelease\">تثبيت الإصدار التجريبي</string>\n    <string name=\"prerelease_already_installed\">تم تثبيت الإصدار التجريبي بالفعل.</string>\n    <string name=\"prerelease_install_failed\">فشل تثبيت الإصدار التجريبي.</string>\n    <string name=\"show_episode_text\">نص الحلقة</string>\n    <string name=\"video_info\">معلومات الوسائط</string>\n    <string name=\"source_name\">اسم المصدر</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ars/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"search_poster_img_des\">لافتة</string>\n    <string name=\"home_change_provider_img_des\">تغيير مزود</string>\n    <string name=\"downloading\">جارى التحميل</string>\n    <string name=\"cast_format\" formatted=\"true\">بث%s</string>\n    <string name=\"filler\" formatted=\"true\">ملء</string>\n    <string name=\"skip_loading\">تخطي التحميل</string>\n    <string name=\"loading\">تحميل…</string>\n    <string name=\"pick_subtitle\">ترجمات</string>\n    <string name=\"reload_error\">إعادة محاولة الاتصال …</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$sايبي%2$d</string>\n    <string name=\"next_episode_format\" formatted=\"true\">الحلقة%dسيتم نشرها في</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dي%2$dس%3$dد</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dس%2$dد</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dد</string>\n    <string name=\"episode_poster_img_des\">لافتة الحلقة</string>\n    <string name=\"home_main_poster_img_des\">اللافتة الاساسية</string>\n    <string name=\"go_back_img_des\">اذهب للخالف</string>\n    <string name=\"preview_background_img_des\">معاينة الخلفية</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">سرعة(%.2fx)</string>\n    <string name=\"play_with_app_name\">فتح مع كلاودستريم</string>\n    <string name=\"title_home\">الصفحة الاساسية</string>\n    <string name=\"search_hint_site\" formatted=\"true\">...%sابحث</string>\n    <string name=\"no_data\">لايوجد بيانات</string>\n    <string name=\"episode_more_options_des\">المزيد من الخيارات</string>\n    <string name=\"result_open_in_browser\">فتح في المتصفح</string>\n    <string name=\"browser\">المتصفح</string>\n    <string name=\"play_movie_button\">شاهد الفلم</string>\n    <string name=\"play_torrent_button\">دفق التورنت</string>\n    <string name=\"download_started\">بدأ التنزيل</string>\n    <string name=\"home_next_random_img_des\">عشوائي قادم</string>\n    <string name=\"play_trailer_button\">تشغيل المقطع الدعائي</string>\n    <string name=\"result_tags\">الأنواع</string>\n    <string name=\"download_paused\">توقف التنزيل</string>\n    <string name=\"type_plan_to_watch\">خطط للمشاهدة</string>\n    <string name=\"type_re_watching\">إعادة المشاهدة</string>\n    <string name=\"new_update_format\" formatted=\"true\">!تم العثور على تحديث جديد\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"rated_format\" formatted=\"true\">%.1f:قدر</string>\n    <string name=\"duration_format\" formatted=\"true\">%dاقل</string>\n    <string name=\"app_name\">كلاودستريم</string>\n    <string name=\"title_search\">بحث</string>\n    <string name=\"title_downloads\">التحميلات</string>\n    <string name=\"title_settings\">اعدادات</string>\n    <string name=\"search_hint\">...بحث</string>\n    <string name=\"next_episode\">الحلقة القادمة</string>\n    <string name=\"result_share\">شارك</string>\n    <string name=\"type_watching\">مشاهدة</string>\n    <string name=\"type_on_hold\">في التوقف</string>\n    <string name=\"type_completed\">مكتمل</string>\n    <string name=\"type_dropped\">توقف</string>\n    <string name=\"play_livestream_button\">تشغيل البث المباشر</string>\n    <string name=\"pick_source\">مصادر</string>\n    <string name=\"play_episode\">تشغيل الحلقة</string>\n    <string name=\"download_canceled\">تم إلغاء التنزيل</string>\n    <string name=\"download_done\">تم التنزيل</string>\n    <string name=\"downloaded\">تنززل</string>\n    <string name=\"download\">تحميل</string>\n    <string name=\"go_back\">عُد</string>\n    <string name=\"download_failed\">التحميل فشل</string>\n    <string name=\"use_system_brightness_settings_des\">استخدم سطوع النظام في مشغل التطبيق بدلاً من التراكب الداكن</string>\n    <string name=\"restore_success\">تم تحميل ملف النسخ الاحتياطي</string>\n    <string name=\"advanced_search\">البحث المتقدم</string>\n    <string name=\"player_size_settings_des\">إزالة الحدود السوداء</string>\n    <string name=\"player_subtitles_settings\">ترجمات</string>\n    <string name=\"double_tap_to_seek_settings\">انقر نقرا مزدوجا للبحث</string>\n    <string name=\"double_tap_to_pause_settings\">انقر نقرًا مزدوجًا للإيقاف المؤقت</string>\n    <string name=\"double_tap_to_seek_amount_settings\">اللاعب يبحث عن المبلغ (بالثواني)</string>\n    <string name=\"swipe_to_seek_settings_des\">اسحب من جانب إلى آخر للتحكم بموقعك في الفيديو</string>\n    <string name=\"autoplay_next_settings_des\">ابدأ الحلقة التالية عندما تنتهي الحلقة الحالية</string>\n    <string name=\"use_system_brightness_settings\">استخدام سطوع النظام</string>\n    <string name=\"episode_sync_settings\">تحديث مراقبة التقدم</string>\n    <string name=\"episode_sync_settings_des\">قم بمزامنة تقدم الحلقة الحالية تلقائيًا</string>\n    <string name=\"swipe_to_change_settings\">اسحب لتغيير الإعدادات</string>\n    <string name=\"restore_settings\">استعادة البيانات من النسخة الاحتياطية</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">فشل في استعادة البيانات من الملف %s</string>\n    <string name=\"double_tap_to_seek_settings_des\">انقر مرتين على الجانب الأيمن أو الأيسر للبحث للأمام أو للخلف</string>\n    <string name=\"backup_success\">البيانات المخزنة</string>\n    <string name=\"double_tap_to_pause_settings_des\">اضغط مرتين في المنتصف للتوقف مؤقتًا</string>\n    <string name=\"backup_failed\">أذونات التخزين مفقودة. حاول مرة اخرى.</string>\n    <string name=\"backup_failed_error_format\">حدث خطأ أثناء النسخ الاحتياطي %s</string>\n    <string name=\"search\">بحث</string>\n    <string name=\"library\">مكتبة</string>\n    <string name=\"settings_info\">معلومات</string>\n    <string name=\"category_updates\">التحديثات والنسخ الاحتياطي</string>\n    <string name=\"advanced_search_des\">يعطيك نتائج البحث مفصولة حسب المزود</string>\n    <string name=\"show_trailers_settings\">عرض المقطورات</string>\n    <string name=\"kitsu_settings\">عرض الملصقات من كيتسو</string>\n    <string name=\"category_account\">حسابات</string>\n    <string name=\"show_fillers_settings\">عرض حلقة حشو للأنمي</string>\n    <string name=\"pref_filter_search_quality\">إخفاء جودة الفيديو المحددة في نتائج البحث</string>\n    <string name=\"automatic_plugin_updates\">تحديثات البرنامج المساعد التلقائي</string>\n    <string name=\"updates_settings_des\">البحث تلقائيًا عن التحديثات الجديدة بعد بدء تشغيل التطبيق.</string>\n    <string name=\"automatic_plugin_download\">تنزيل المكونات الإضافية تلقائيًا</string>\n    <string name=\"redo_setup_process\">إعادة عملية الإعداد</string>\n    <string name=\"automatic_plugin_download_mode_title\">حدد الوضع لتصفية تنزيل المكونات الإضافية</string>\n    <string name=\"automatic_plugin_download_summary\">قم تلقائيًا بتثبيت جميع المكونات الإضافية التي لم يتم تثبيتها بعد من المستودعات المضافة.</string>\n    <string name=\"chromecast_subtitles_settings_des\">إعدادات ترجمات كرومكاست</string>\n    <string name=\"eigengraumode_settings\">وضع إيجينجرافي</string>\n    <string name=\"swipe_to_seek_settings\">انتقد للبحث</string>\n    <string name=\"backup_settings\">نسخ إحتياطي للبيانات</string>\n    <string name=\"updates_settings\">إظهار تحديثات التطبيق</string>\n    <string name=\"player_subtitles_settings_des\">إعدادات ترجمات المشغل</string>\n    <string name=\"chromecast_subtitles_settings\">ترجمات كرومكاست</string>\n    <string name=\"swipe_to_change_settings_des\">قم بالتمرير لأعلى أو لأسفل على الجانب الأيسر أو الأيمن لتغيير السطوع أو مستوى الصوت</string>\n    <string name=\"autoplay_next_settings\">التشغيل التلقائي للحلقة القادمة</string>\n    <string name=\"lightnovel\">تطبيق رواية خفيفة من نفس المطورين</string>\n    <string name=\"benene\">أعط بينيني للمطورين</string>\n    <string name=\"github\">جيتهب</string>\n    <string name=\"anim\">تطبيق انيمي من نفس المطورين</string>\n    <string name=\"app_language\">لغة التطبيق</string>\n    <string name=\"discord\">انضم إلى الديسكورد</string>\n    <string name=\"benene_des\">بنيني معطا</string>\n    <string name=\"apk_installer_settings_des\">بعض الهواتف لا تدعم مثبت الحزمة الجديد. جرب الخيار القديم إذا لم يتم تثبيت التحديثات.</string>\n    <string name=\"apk_installer_settings\">مثبت تتبيق</string>\n    <string name=\"test_passed\">اجتاز</string>\n    <string name=\"episodes\">الحلقات</string>\n    <string name=\"season\">موسم</string>\n    <string name=\"copy_link_toast\">تم نسخ الرابط إلى الحافظة</string>\n    <string name=\"delete\">مسح</string>\n    <string name=\"cancel\">الغي</string>\n    <string name=\"pause\">وقف</string>\n    <string name=\"update_notification_downloading\">جارٍ تنزيل تحديث التطبيق…</string>\n    <string name=\"subs_default_reset_toast\">إعادة التعيين إلى القيمة العادية</string>\n    <string name=\"season_short\">س</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"no_chromecast_support_toast\">لا يتمتع هذا المزود بدعم كرومكاست</string>\n    <string name=\"no_links_found_toast\">لم يتم العثور على أي روابط</string>\n    <string name=\"play_episode_toast\">تشغيل الحلقة</string>\n    <string name=\"season_format\">%1$s%2$d%3$s</string>\n    <string name=\"no_season\">لا يوجد موسم</string>\n    <string name=\"episode\">حلقة</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_short\">يي</string>\n    <string name=\"clear_history\">امسح التاريخ</string>\n    <string name=\"update_notification_installing\">جارٍ تثبيت تحديث التطبيق…</string>\n    <string name=\"start\">بدأ</string>\n    <string name=\"no_episodes_found\">لم يتم العثور على أي حلقات</string>\n    <string name=\"enable_skip_op_from_database_des\">إظهار تخطي النوافذ المنبثقة للفتح/الإنهاء</string>\n    <string name=\"clipboard_too_large\">الكثير من النص. غير قادر على الحفظ في الحافظة.</string>\n    <string name=\"action_mark_as_watched\">وضع علامة كما شاهدت</string>\n    <string name=\"action_remove_from_watched\">إزالة من شاهد</string>\n    <string name=\"delete_file\">حذف ملف</string>\n    <string name=\"test_failed\">فشل</string>\n    <string name=\"resume\">اكتمل</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"history\">تاريخ</string>\n    <string name=\"confirm_exit_dialog\">هل أنت متأكد أنك تريد الخروج؟</string>\n    <string name=\"yes\">نعم</string>\n    <string name=\"no\">لا</string>\n    <string name=\"update_notification_failed\">تعذر تثبيت الإصدار الجديد من التطبيق</string>\n    <string name=\"apk_installer_legacy\">إرث</string>\n    <string name=\"apk_installer_package_installer\">منزل المجموعة</string>\n    <string name=\"sort_rating_asc\">التقييم (من الأقل إلى الأعلى)</string>\n    <string name=\"sort_updated_new\">تم التحديث (من الجديد إلى القديم)</string>\n    <string name=\"sort_updated_old\">تم التحديث (القديم إلى الجديد)</string>\n    <string name=\"sort_alphabetical_a\">أبجديًا (من الألف إلى الياء)</string>\n    <string name=\"empty_library_no_accounts_message\">مكتبتك فارغة :(\n\\nقم بتسجيل الدخول إلى حساب المكتبة أو قم بإضافة العروض إلى مكتبتك المحلية.</string>\n    <string name=\"safe_mode_file\">!تم العثور على ملف الوضع الآمن\n\\n.عدم تحميل أي ملحقات عند بدء التشغيل حتى تتم إزالة الملف</string>\n    <string name=\"revert\">ارجع</string>\n    <string name=\"subscription_in_progress_notification\">تحديث العروض المشتركة</string>\n    <string name=\"set_default\">الوضع العادي</string>\n    <string name=\"edit\">حرر</string>\n    <string name=\"profiles\">ملفات تعريفية</string>\n    <string name=\"help\">مساعدة</string>\n    <string name=\"quality_profile_help\">.هنا يمكنك تغيير كيفية ترتيب المصادر. إذا كان للفيديو أولوية أعلى، فسيظهر في مكان أعلى في تحديد المصدر. مجموع أولوية المصدر وأولوية الجودة هو أولوية الفيديو\n\\n\n\\nالمصدر أ: 3\n\\nالجودة ب: 7\n\\nستكون أولوية الفيديو المدمجة .10\n\\n\n\\n!ملاحظة: إذا كان المجموع 10 أو أكثر، فسيقوم اللاعب تلقائيًا بتخطي التحميل عند تحميل هذا الرابط</string>\n    <string name=\"already_voted\">لقد صوت بالفعل</string>\n    <string name=\"sort_alphabetical_z\">أبجديًا (ياء إلى ألف)</string>\n    <string name=\"sort_by\">ترتيب حسب</string>\n    <string name=\"subscription_list_name\">مشترك</string>\n    <string name=\"delayed_update_notice\">سيتم تحديث التطبيق عند الخروج</string>\n    <string name=\"sort\">رتب</string>\n    <string name=\"sort_rating_desc\">التقييم (من الأعلى إلى الأقل)</string>\n    <string name=\"select_library\">حدد المكتبة</string>\n    <string name=\"open_with\">افتع مع</string>\n    <string name=\"empty_library_logged_in_message\">.هذه القائمة فارغة. حاول التبديل إلى واحد آخر</string>\n    <string name=\"subscription_new\">%sتم الاشتراك في</string>\n    <string name=\"subscription_deleted\">%sتم إلغاء الاشتراك من</string>\n    <string name=\"subscription_episode_released\">!%dتم إصدار الحلقة</string>\n    <string name=\"profile_background_des\">خلفية الملف الشخصي</string>\n    <string name=\"profile_number\">%dملف التعريف</string>\n    <string name=\"wifi\">واي فاي</string>\n    <string name=\"mobile_data\">بيانات الجوال</string>\n    <string name=\"use\">استخدم</string>\n    <string name=\"unable_to_inflate\">%sتعذر إنشاء واجهة المستخدم بشكل صحيح، وهذا خطأ كبير ويجب الإبلاغ عنه على الفور</string>\n    <string name=\"qualities\">الصفات</string>\n    <string name=\"subs_edge_type\">نوع الحافة</string>\n    <string name=\"home_play\">العب</string>\n    <string name=\"error_loading_links_toast\">حدث خطأ أثناء تحميل الروابط</string>\n    <string name=\"download_storage_text\">التخزين الداخلي</string>\n    <string name=\"app_subbed_text\">الترجمة</string>\n    <string name=\"popup_resume_download\">استئناف تحميل</string>\n    <string name=\"home_info\">معلومات</string>\n    <string name=\"popup_pause_download\">وقفة التحميل</string>\n    <string name=\"sort_save\">احفظ</string>\n    <string name=\"subtitles_settings\">إعدادات الترجمة</string>\n    <string name=\"subs_text_color\">لون الخط</string>\n    <string name=\"subs_outline_color\">لون المخطط التفصيلي</string>\n    <string name=\"sort_close\">اقفل</string>\n    <string name=\"sort_clear\">امسح</string>\n    <string name=\"player_speed\">سرعة اللاعب</string>\n    <string name=\"subs_background_color\">لون الخلفية</string>\n    <string name=\"subs_window_color\">لون النافذة</string>\n    <string name=\"subs_subtitle_elevation\">ارتفاع الترجمة</string>\n    <string name=\"popup_delete_file\">حذف ملف</string>\n    <string name=\"update_started\">بدأ التحديث</string>\n    <string name=\"sort_copy\">انسخ</string>\n    <string name=\"stream\">بث</string>\n    <string name=\"popup_play_file\">ملف اللعب</string>\n    <string name=\"home_more_info\">مزيد من المعلومات</string>\n    <string name=\"filter_bookmarks\">تصفية الإشارات المرجعية</string>\n    <string name=\"error_bookmarks_text\">إشارات مرجعية</string>\n    <string name=\"action_remove_from_bookmarks\">زيل</string>\n    <string name=\"action_add_to_bookmarks\">ضبط حالة المشاهدة</string>\n    <string name=\"app_dubbed_text\">مدبلجة</string>\n    <string name=\"home_expanded_hide\">اخفي</string>\n    <string name=\"sort_apply\">قدم</string>\n    <string name=\"torrent_plot\">وصف</string>\n    <string name=\"picture_in_picture_des\">يستمر التشغيل في مشغل مصغر فوق التطبيقات الأخرى</string>\n    <string name=\"delete_message\" formatted=\"true\">نهائيا %sسيؤدي هذا الى حذف\n\\nهل أنت متأكد؟</string>\n    <string name=\"subs_font\">الخط</string>\n    <string name=\"subs_font_size\">حجم الخط</string>\n    <string name=\"action_remove_watching\">زيل</string>\n    <string name=\"vpn_torrent\">هذا المزود عبارة عن تورنت، ويوصى باستخدام فيبيان</string>\n    <string name=\"provider_info_meta\">لا يتم توفير البيانات الوصفية بواسطة الموقع، وسيفشل تحميل الفيديو إذا لم يكن موجودًا في الموقع.</string>\n    <string name=\"status_ongoing\">جاري التنفيذ</string>\n    <string name=\"status_completed\">مكتمل</string>\n    <string name=\"status\">حالة</string>\n    <string name=\"subs_auto_select_language\">التحديد التلقائي للغة</string>\n    <string name=\"player_size_settings\">زر تغيير حجم المشغل</string>\n    <string name=\"continue_watching\">مواصلة المشاهدة</string>\n    <string name=\"action_open_watching\">مزيد من المعلومات</string>\n    <string name=\"search_provider_text_providers\">البحث باستخدام مقدمي الخدمات</string>\n    <string name=\"search_provider_text_types\">البحث باستخدام الأنواع</string>\n    <string name=\"benene_count_text\">بنيني الى المطورين %d تم منح</string>\n    <string name=\"benene_count_text_none\">لم يتم تقديم بنيني</string>\n    <string name=\"subs_download_languages\">تحميل اللغات</string>\n    <string name=\"subs_subtitle_languages\">لغة الترجمة</string>\n    <string name=\"subs_hold_to_reset_to_default\">اضغط لإعادة التعيين إلى الوضع الافتراضي</string>\n    <string name=\"subs_import_text\" formatted=\"true\">%s قم باستيراد الخطوط بوضعها في</string>\n    <string name=\"vpn_might_be_needed\">قد تكون هناك حاجة إلى فيبيان حتى يعمل هذا المزود بشكل صحيح</string>\n    <string name=\"normal_no_plot\">لم يتم العثور على قطعة أرض</string>\n    <string name=\"torrent_no_plot\">لم يتم العثور على وصف</string>\n    <string name=\"show_log_cat\">🐈عرض لوجكات</string>\n    <string name=\"test_log\">سجل</string>\n    <string name=\"picture_in_picture\">صور في صور</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%d\n\\nباقي</string>\n    <string name=\"video_source\">مصدر</string>\n    <string name=\"android_tv_interface_off_seek_settings\">اللاعب مخفي - ابحث عن المبلغ</string>\n    <string name=\"backup_frequency\">تكرار النسخ الاحتياطي</string>\n    <string name=\"movies_singular\">فلم</string>\n    <string name=\"torrent_singular\">توررنت</string>\n    <string name=\"no_update_found\">لا يوجد تحديث</string>\n    <string name=\"tv_series\">مسلسل تلفزيونى</string>\n    <string name=\"check_for_update\">فحص التحديثات</string>\n    <string name=\"render_error\">خطأ في العارض</string>\n    <string name=\"show_title\">عنوان</string>\n    <string name=\"download_path_pref\">مسار التحميل</string>\n    <string name=\"movies\">افلام</string>\n    <string name=\"limit_title_rez\">دقة مشغل الفيديو</string>\n    <string name=\"torrent\">توررنتس</string>\n    <string name=\"legal_notice\">تنصل</string>\n    <string name=\"show_sub\">علامة الترجمة</string>\n    <string name=\"ova_singular\">اوفياي</string>\n    <string name=\"episode_action_download_mirror\">تحميل مرآة</string>\n    <string name=\"add_site_pref\">موقع استنساخ</string>\n    <string name=\"free_storage\">مجان</string>\n    <string name=\"resize_fill\">تمتد</string>\n    <string name=\"update\">تحديث</string>\n    <string name=\"show_dub\">علامة الدبلجة</string>\n    <string name=\"year\">سنة</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"episode_action_play_in_format\">%s افتح في</string>\n    <string name=\"episode_action_download_subtitle\">تحميل ترجمات</string>\n    <string name=\"dont_show_again\">لا تظهر مرة أخرى</string>\n    <string name=\"video_buffer_clear_settings\">مسح ذاكرة التخزين المؤقت للفيديو والصور</string>\n    <string name=\"video_skip_op\">تخطي البداية</string>\n    <string name=\"documentaries\">الافلام الوثائقية</string>\n    <string name=\"cartoons\">الرسوم المتحركة</string>\n    <string name=\"no_subtitles\">لا ترجمات</string>\n    <string name=\"watch_quality_pref\">(WiFi) جودة الساعة المفضلة</string>\n    <string name=\"cartoons_singular\">فلم كرتون</string>\n    <string name=\"synopsis\">ملخص</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">يتم استخدام مبلغ البحث عندما يكون اللاعب مرئيًا</string>\n    <string name=\"other_singular\">فيديو</string>\n    <string name=\"live_singular\">بث مباشر</string>\n    <string name=\"android_tv_interface_on_seek_settings\">اللاعب المعروض - ابحث عن المبلغ</string>\n    <string name=\"display_subbed_dubbed_settings\">عرض الأنمي المدبلج/المترجم</string>\n    <string name=\"ova\">اوفياي</string>\n    <string name=\"unexpected_error\">خطأ غير متوقع من اللاعب</string>\n    <string name=\"used_storage\">مستعمل</string>\n    <string name=\"video_disk_description\">.Android TV يسبب مشاكل إذا تم ضبطه على أجهزة ذات مساحة تخزين منخفضة، مثل</string>\n    <string name=\"others\">اخرون</string>\n    <string name=\"skip_update\">تخطي هذا التحديث</string>\n    <string name=\"jsdelivr_proxy_summary\">.قد يتسبب في تأخير التحديثات لبضعة أيام .jsDelivr باستخدام GitHubيتجاوز حظر</string>\n    <string name=\"asian_drama\">الدرامات الآسيوية</string>\n    <string name=\"queued\">في قائمة الانتظار</string>\n    <string name=\"episode_action_play_in_app\">افتح في التطبيق</string>\n    <string name=\"dns_pref_summary\">مفيد لتجاوز حجب مزودي خدمة الإنترنت</string>\n    <string name=\"tv_series_singular\">مسلسل</string>\n    <string name=\"rating\">تقييم</string>\n    <string name=\"remove_site_pref\">إزالة الموقع</string>\n    <string name=\"video_aspect_ratio_resize\">تغيير الحجم</string>\n    <string name=\"show_hd\">علامة الجودة</string>\n    <string name=\"episode_action_reload_links\">إعادة تحميل الروابط</string>\n    <string name=\"add_site_summary\">مختلف URL أضف نسخة من موقع موجود بعنوان</string>\n    <string name=\"watch_quality_pref_data\">جودة الساعة المفضلة (بيانات الجوال)</string>\n    <string name=\"episode_action_auto_download\">التنزيل التلقائي</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"anime\">انيمي</string>\n    <string name=\"episode_action_chromecast_mirror\">مرآة كروم كاست</string>\n    <string name=\"poster_ui_settings\">تبديل عناصر واجهة المستخدم على الملصق</string>\n    <string name=\"resize_zoom\">تكبير</string>\n    <string name=\"resize_fit\">صالح للشاشة</string>\n    <string name=\"jsdelivr_enabled\">...jsDelivr لا يمكن الوصول إلى جيتهاب. جارٍ تشغيل وكيل</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">استخدام مبلغ البحث عندما يكون اللاعب مخفيًا</string>\n    <string name=\"video_lock\">قفل</string>\n    <string name=\"storage_error\">خطأ في التنزيل، تحقق من أذونات التخزين</string>\n    <string name=\"anime_singular\">انيمي</string>\n    <string name=\"app_storage\">برنامج</string>\n    <string name=\"action_default\">عادي</string>\n    <string name=\"remote_error\">خطأ عن بعد</string>\n    <string name=\"video_buffer_size_settings\">حجم المخزن المؤقت للفيديو</string>\n    <string name=\"video_buffer_length_settings\">طول المخزن المؤقت للفيديو</string>\n    <string name=\"episode_action_chromecast_episode\">حلقة كروم كاست</string>\n    <string name=\"livestreams\">بثات مباشرة</string>\n    <string name=\"duration\">مدة</string>\n    <string name=\"asian_drama_singular\">الدراما الآسيوية</string>\n    <string name=\"video_ram_description\">.Android TV يتسبب في حدوث أعطال إذا تم ضبطه على مستوى مرتفع جدًا على الأجهزة ذات الذاكرة المنخفضة، مثل</string>\n    <string name=\"source_error\">خطأ في المصدر</string>\n    <string name=\"video_buffer_disk_settings\">ذاكرة التخزين المؤقت للفيديو على القرص</string>\n    <string name=\"documentaries_singular\">وثائقي</string>\n    <string name=\"site\">موقع</string>\n    <string name=\"limit_title\">عنوان مشغل الفيديو بحد أقصى لعدد الأحرف</string>\n    <string name=\"dns_pref\">DNS عبر HTTPS</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+as/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"search_poster_img_des\">পোস্টাৰ</string>\n    <string name=\"episode_poster_img_des\">এপিচ\\'ড পোস্টাৰ</string>\n    <string name=\"home_main_poster_img_des\">প্ৰধান পোস্টাৰ</string>\n    <string name=\"go_back_img_des\">পাছলৈ ঘূৰক</string>\n    <string name=\"rated_format\" formatted=\"true\">ৰেটিং: %.1f</string>\n    <string name=\"title_settings\">ছেটিংছ</string>\n    <string name=\"search_hint\">সন্ধান কৰক…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">%sত সন্ধান কৰক…</string>\n    <string name=\"downloading\">ডাউনলোড হৈ আছে</string>\n    <string name=\"recommendations_tooltip\">পৰামৰ্শসমূহ প্ৰদৰ্শন কৰক</string>\n    <string name=\"player_speed\">প্লেয়াৰ গতি</string>\n    <string name=\"subs_text_color\">পাঠৰ ৰং</string>\n    <string name=\"subs_edge_type\">কোৰা প্ৰকাৰ</string>\n    <string name=\"action_remove_watching\">অপসাৰণ কৰক</string>\n    <string name=\"torrent_plot\">বিৱৰণ</string>\n    <string name=\"show_log_cat\">লগকেট প্ৰদৰ্শন কৰক 🐈</string>\n    <string name=\"test_log\">লগ</string>\n    <string name=\"backup_failed_error_format\">%s সংৰক্ষণত ত্ৰুটি</string>\n    <string name=\"search\">সন্ধান কৰক</string>\n    <string name=\"library\">পুথিভঁৰাল</string>\n    <string name=\"category_account\">একাউণ্ট আৰু সুৰক্ষা</string>\n    <string name=\"category_updates\">আপডেট আৰু ব্যাকআপ</string>\n    <string name=\"automatic_plugin_download\">স্বয়ংক্ৰিয়ভাৱে প্লাগইন ডাউনলোড কৰক</string>\n    <string name=\"automatic_plugin_download_mode_title\">প্লাগইন ডাউনলোডৰ ম\\'ড নিৰ্বাচন কৰক</string>\n    <string name=\"automatic_plugin_download_summary\">যোগ কৰা ৰিপ\\'জিটৰীৰ পৰা এতিয়ালৈকে ইনষ্টল নকৰা সকলো প্লাগইন স্বয়ংক্ৰিয়ভাৱে ইনষ্টল কৰক।</string>\n    <string name=\"cartoons\">কাৰ্টুন</string>\n    <string name=\"anime\">এনিম</string>\n    <string name=\"torrent\">ট’ৰেণ্ট</string>\n    <string name=\"ova\">ওভিএ</string>\n    <string name=\"asian_drama_singular\">এছিয়ান ড্ৰামা</string>\n    <string name=\"live_singular\">লাইভষ্ট্ৰীম</string>\n    <string name=\"nsfw_singular\">এনএছএফডব্লিউ</string>\n    <string name=\"other_singular\">ভিডিঅ\\'</string>\n    <string name=\"episode_action_play_in_app\">অ্যাপত প্লে কৰক</string>\n    <string name=\"episode_action_reload_links\">লিংকসমূহ পুনৰ ল\\'ড কৰক</string>\n    <string name=\"episode_action_download_subtitle\">সাবটাইটেল ডাউনলোড কৰক</string>\n    <string name=\"show_hd\">গুণগত মানৰ ছপা</string>\n    <string name=\"show_title\">শিৰোনাম</string>\n    <string name=\"no_update_found\">কোনো আপডেট পোৱা নগ\\'ল</string>\n    <string name=\"check_for_update\">আপডেটৰ বাবে পৰীক্ষা কৰক</string>\n    <string name=\"dont_show_again\">আৰো দেখুৱাব নালাগে</string>\n    <string name=\"limit_title\">ভিডিঅ\\' প্লেয়াৰৰ শিৰোনামৰ সৰ্বাধিক অক্ষৰ</string>\n    <string name=\"add_site_summary\">বিদ্যমান চাইটৰ ক্লোন এটা সন্নিবিষ্ট কৰক, ভিন্ন URLৰ সৈতে</string>\n    <string name=\"pref_category_links\">লিংকসমূহ</string>\n    <string name=\"category_ui\">লেআউট</string>\n    <string name=\"automatic\">স্বয়ংচালিত</string>\n    <string name=\"example_password\">password123</string>\n    <string name=\"example_username\">ব্যৱহাৰকাৰীনাম</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"logout\">লগ আউট</string>\n    <string name=\"sync_score\">ৰেটিং দিয়া</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s প্ৰমাণীকৃত</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">%s ত লগ ইন কৰিবলৈ পৰা নগ\\'ল</string>\n    <string name=\"error_invalid_data\">অবৈধ তথ্য</string>\n    <string name=\"error_invalid_url\">অবৈধ URL</string>\n    <string name=\"error\">ভুল</string>\n    <string name=\"subtitles_remove_captions\">বন্ধ কেপচনচসমূহ সাবটাইটেলৰ পৰা আঁতৰাওক</string>\n    <string name=\"referer\">ৰেফাৰাৰ (ঐচ্ছিক)</string>\n    <string name=\"next\">পৰৱৰ্তী</string>\n    <string name=\"provider_languages_tip\">এই ভাষাবোৰত ভিডিঅ\\' চাওক</string>\n    <string name=\"batch_download\">ব্যাচ ডাউনলোড</string>\n    <string name=\"setup_extensions_subtext\">আপুনি ব্যৱহাৰ কৰিব বিচৰা চাইটবোৰৰ তালিকা ডাউনলোড কৰক</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">ডাউনলোড কৰা: %d</string>\n    <string name=\"clipboard_permission_error\">ক্ৰিপবোর্ডত প্ৰবেশৰ সময়ত সমস্যা। পুনৰ চেষ্টা কৰক।</string>\n    <string name=\"sort_alphabetical_z\">বৰ্ণানুক্ৰমিক (Z ৰ পৰা A)</string>\n    <string name=\"subscription_episode_released\">অধ্যায় %d মুক্তি পালে!</string>\n    <string name=\"action_subscribe\">সদস্যতা কৰক</string>\n    <string name=\"action_unsubscribe\">সদস্যতা বাতিল কৰক</string>\n    <string name=\"profile_number\">প্ৰ\\'ফাইল %d</string>\n    <string name=\"enter_pin\">পিন সন্নিবিষ্ট কৰক</string>\n    <string name=\"edit_account\">একাউণ্ট সম্পাদনা কৰক</string>\n    <string name=\"custom_media_singluar\">মিডিয়া</string>\n    <string name=\"reset_btn\">ৰিচেট কৰক</string>\n    <string name=\"cast_format\" formatted=\"true\">Cast: %s</string>\n    <string name=\"type_watching\">দেখি আছে</string>\n    <string name=\"continue_watching\">চাবলৈ জাৰি ৰাখক</string>\n    <string name=\"player_subtitles_settings\">সাবটাইটেল</string>\n    <string name=\"use_system_brightness_settings\">পদ্ধতিৰ উজ্জ্বলতা ব্যৱহাৰ কৰক</string>\n    <string name=\"backup_failed\">সংৰক্ষণ অনুমতি অনুপস্থিত। পুনৰ চেষ্টা কৰক।</string>\n    <string name=\"min\">সৰ্বনিম্ন</string>\n    <string name=\"quality_sd\">এছ.ডি.</string>\n    <string name=\"setup_done\">সম্পূৰ্ণ</string>\n    <string name=\"view_public_repositories_button_short\">সৰ্বজনীন তালিকা</string>\n    <string name=\"stop\">বন্ধ কৰক</string>\n    <string name=\"battery_dialog_title\">বেটাৰী অপ্টিমাইজেচন নিষ্ক্ৰিয় কৰক</string>\n    <string name=\"subscription_list_name\">সদস্যতা গ্ৰহণ কৰা</string>\n    <string name=\"qualities\">গুণসমূহ</string>\n    <string name=\"duplicate_add\">যোগ কৰক</string>\n    <string name=\"duplicate_replace\">প্ৰতিস্থাপন কৰক</string>\n    <string name=\"biometric_authentication_title\">CloudStream আনলক কৰক</string>\n    <string name=\"biometric_setting\">বায়\\'মেট্ৰিক্সৰ সৈতে লক কৰক</string>\n    <string name=\"password_pin_authentication_title\">পাছৱাৰ্ড/পিন প্ৰমাণীকৰণ</string>\n    <string name=\"music_singlar\">সংগীত</string>\n    <string name=\"audio_book_singular\">অডিঅ\\' বুক</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episode %d will be released in</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Season %1$d Episode %2$d will be released in</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"result_poster_img_des\">পোস্টাৰ</string>\n    <string name=\"home_change_provider_img_des\">প্ৰদানকাৰী সলনি কৰক</string>\n    <string name=\"preview_background_img_des\">পূৰ্বদৰ্শন পটভূমি</string>\n    <string name=\"home_next_random_img_des\">পৰৱৰ্তী ৰেণ্ডম</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">গতি (%.2fx)</string>\n    <string name=\"next_episode\">পৰৱৰ্তী এপিচ\\'ড</string>\n    <string name=\"duration_format\" formatted=\"true\">%d মিনিট</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">ঘৰ</string>\n    <string name=\"no_data\">তথ্য নাই</string>\n    <string name=\"episode_more_options_des\">অধিক বিকল্পসমূহ</string>\n    <string name=\"result_share\">শ্বেয়াৰ</string>\n    <string name=\"result_open_in_browser\">ব্ৰাউজাৰত খোলক</string>\n    <string name=\"browser\">ব্ৰাউজাৰ</string>\n    <string name=\"type_plan_to_watch\">দেখাৰ পৰিকল্পনা</string>\n    <string name=\"play_torrent_button\">ট\\'ৰেণ্ট ষ্ট্ৰীম কৰক</string>\n    <string name=\"reload_error\">পুনৰ সংযোগ চেষ্টা কৰক…</string>\n    <string name=\"go_back\">পাছলৈ ঘূৰক</string>\n    <string name=\"pick_source\">উৎসসমূহ</string>\n    <string name=\"downloaded\">ডাউনলোড সম্পূৰ্ণ</string>\n    <string name=\"download_paused\">ডাউনলোড ৰখা হৈছে</string>\n    <string name=\"download_started\">ডাউনলোড আৰম্ভ হৈছে</string>\n    <string name=\"download_failed\">ডাউনলোড বিফল</string>\n    <string name=\"download_canceled\">ডাউনলোড বাতিল</string>\n    <string name=\"download_done\">ডাউনলোড সম্পন্ন</string>\n    <string name=\"update_started\">আপডেট আৰম্ভ হৈছে</string>\n    <string name=\"stream\">নেটৱাৰ্ক ষ্ট্ৰীম</string>\n    <string name=\"error_loading_links_toast\">লিংক লোডত ত্ৰুটি</string>\n    <string name=\"links_reloaded_toast\">লিংক পুনৰ লোড কৰা হ’ল</string>\n    <string name=\"download_storage_text\">অভ্যন্তৰীণ সংৰক্ষণ</string>\n    <string name=\"app_dubbed_text\">ডাব</string>\n    <string name=\"app_subbed_text\">চাব</string>\n    <string name=\"popup_delete_file\">ফাইল মচক</string>\n    <string name=\"popup_play_file\">ফাইল প্লে কৰক</string>\n    <string name=\"popup_resume_download\">ডাউনলোড পুনৰ আৰম্ভ কৰক</string>\n    <string name=\"popup_pause_download\">ডাউনলোড ৰখা</string>\n    <string name=\"home_more_info\">অধিক তথ্য</string>\n    <string name=\"home_expanded_hide\">লুকুৱাওক</string>\n    <string name=\"home_play\">প্লে কৰক</string>\n    <string name=\"home_info\">তথ্য</string>\n    <string name=\"action_remove_from_bookmarks\">অপসাৰণ কৰক</string>\n    <string name=\"action_add_to_bookmarks\">দেখাৰ অৱস্থা নিৰ্ধাৰণ কৰক</string>\n    <string name=\"filter_bookmarks\">বুকমাৰ্ক ফিল্টাৰ কৰক</string>\n    <string name=\"error_bookmarks_text\">বুকমাৰ্ক</string>\n    <string name=\"sort_copy\">কপি</string>\n    <string name=\"sort_close\">বন্ধ কৰক</string>\n    <string name=\"sort_clear\">প্ৰশস্ত কৰক</string>\n    <string name=\"sort_save\">সংৰক্ষণ কৰক</string>\n    <string name=\"repo_copy_label\">Repository নাম আৰু URL</string>\n    <string name=\"toast_copied\">কপি কৰা হ’ল!</string>\n    <string name=\"subscribe_tooltip\">নতুন এপিচ\\'ডৰ সূচনা</string>\n    <string name=\"result_search_tooltip\">অন্যান্য এক্সটেনশ্যনত সন্ধান কৰক</string>\n    <string name=\"subtitles_settings\">চাবটাইটল ছেটিংছ</string>\n    <string name=\"subs_outline_color\">বাহ্যৰেখা ৰং</string>\n    <string name=\"subs_background_color\">পটভূমি ৰং</string>\n    <string name=\"subs_window_color\">ৱিন্ড\\'ৰ ৰং</string>\n    <string name=\"subs_subtitle_elevation\">সাবটাইটেল উচুতা</string>\n    <string name=\"subs_font\">ফণ্ট</string>\n    <string name=\"subs_font_size\">ফণ্টৰ আকাৰ</string>\n    <string name=\"search_provider_text_types\">প্ৰকাৰৰ দ্বাৰা সন্ধান কৰক</string>\n    <string name=\"search_provider_text_providers\">প্ৰদানকাৰীৰে সন্ধান কৰক</string>\n    <string name=\"benene_count_text\">%d জন ডেভেলপাৰক বেঙেনা দিয়া হৈছে</string>\n    <string name=\"benene_count_text_none\">কোনো বেঙেনা দিয়া হোৱা নাই</string>\n    <string name=\"subs_auto_select_language\">স্বয়ংক্ৰিয় ভাষা নিৰ্বাচন</string>\n    <string name=\"subs_download_languages\">ভাষাসমূহ ডাউনলোড কৰক</string>\n    <string name=\"subs_subtitle_languages\">সাবটাইটেল ভাষা</string>\n    <string name=\"subs_hold_to_reset_to_default\">মূল পৰিৱেশলৈ সলনি কৰিবলৈ ধৰি ৰাখক</string>\n    <string name=\"vpn_might_be_needed\">এই প্ৰদানকাৰী ঠিকমতে কাম কৰিবৰ বাবে VPNৰ প্ৰয়োজন হ\\'ব পাৰে</string>\n    <string name=\"vpn_torrent\">এই প্ৰদানকাৰী এটা ট\\'ৰেণ্ট, VPNৰ পৰামৰ্শ দিয়া হৈছে</string>\n    <string name=\"subs_import_text\" formatted=\"true\">%s ত ফণ্টসমূহ ৰাখি সন্নিবিষ্ট কৰক</string>\n    <string name=\"action_open_watching\">অধিক তথ্য</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"provider_info_meta\">সাইটে মেটাডাটা প্ৰদান কৰা নাই, যদি সাইটত নাথাকে তেন্তে ভিডিঅ\\' মুকলি নহ\\'ব পাৰে।</string>\n    <string name=\"normal_no_plot\">কোনো কাহিনী পোৱা নগ\\'ল</string>\n    <string name=\"torrent_no_plot\">কোনো বিৱৰণ পোৱা নগ\\'ল</string>\n    <string name=\"player_size_settings\">প্লেয়াৰৰ আকাৰ পৰিবৰ্তনৰ বুটাম</string>\n    <string name=\"player_size_settings_des\">ক’লা পাৰত আঁতৰাওক</string>\n    <string name=\"picture_in_picture\">ছবি-ইন-ছবি</string>\n    <string name=\"picture_in_picture_des\">অন্য এপ্‌সমূহৰ ওপৰত এটি সৰু প্লেয়াৰত প্লেবেক চলি থাকে</string>\n    <string name=\"player_subtitles_settings_des\">প্লেয়াৰৰ সাবটাইটেল চেটিংছ</string>\n    <string name=\"chromecast_subtitles_settings\">ক্ৰ\\'মকাষ্ট সাবটাইটেল</string>\n    <string name=\"chromecast_subtitles_settings_des\">ক্ৰ\\'মকাষ্ট সাবটাইটেল চেটিংছ</string>\n    <string name=\"eigengraumode_settings\">প্লেবেক গতিবেগ</string>\n    <string name=\"speed_setting_summary\">প্লেয়াৰত গতিৰ বিকল্প যোগ কৰে</string>\n    <string name=\"swipe_to_seek_settings\">সুৱাইপ কৰি সন্ধান কৰক</string>\n    <string name=\"swipe_to_seek_settings_des\">ভিডিঅ\\'ৰ অৱস্থান নিয়ন্ত্ৰণ কৰিবলৈ কাষৰ পৰা কাষলৈ সুৱাইপ কৰক</string>\n    <string name=\"swipe_to_change_settings\">চেটিংছ সলনি কৰিবলৈ সুৱাইপ কৰক</string>\n    <string name=\"swipe_to_change_settings_des\">উজ্জ্বলতা বা শব্দ পৰিমাণ সলনি কৰিবলৈ বাওঁ বা সোঁপিনে ওপৰলৈ সুৱাইপ কৰক</string>\n    <string name=\"autoplay_next_settings\">পৰৱৰ্তী খণ্ড স্বয়ংক্ৰিয়ভাৱে চালাওক</string>\n    <string name=\"autoplay_next_settings_des\">বৰ্তমানৰ খণ্ডৰ অন্তত পৰৱৰ্তী খণ্ড আৰম্ভ কৰক</string>\n    <string name=\"double_tap_to_seek_settings\">সন্ধান কৰিবলৈ দ্বৈত টেপ কৰক</string>\n    <string name=\"double_tap_to_pause_settings\">বিৰতিৰ বাবে দ্বৈত টেপ কৰক</string>\n    <string name=\"double_tap_to_seek_amount_settings\">প্লেয়াৰ সন্ধানৰ পৰিমাণ (ছেকেণ্ড)</string>\n    <string name=\"double_tap_to_seek_settings_des\">অগ্ৰসৰ বা পশ্চাদ্দেশৰ বাবে সোঁ বা বাওঁপিনে দুবাৰ টেপ কৰক</string>\n    <string name=\"double_tap_to_pause_settings_des\">বিৰতিৰ বাবে মাজত দুবাৰ টেপ কৰক</string>\n    <string name=\"use_system_brightness_settings_des\">এপ্‌ প্লেয়াৰত অন্ধকাৰ আবৰণৰ সলনি পদ্ধতিৰ উজ্জ্বলতা ব্যৱহাৰ কৰক</string>\n    <string name=\"episode_sync_settings\">দেখাৰ প্ৰগতি আপডেট কৰক</string>\n    <string name=\"episode_sync_settings_des\">স্বয়ংক্ৰিয়ভাৱে আপোনাৰ বৰ্তমানৰ খণ্ডৰ প্ৰগতি ছিঙ্ক কৰক</string>\n    <string name=\"restore_settings\">ব্যাকআপৰ পৰা ডাটা পুনৰুদ্ধাৰ কৰক</string>\n    <string name=\"backup_settings\">ডাটা সংৰক্ষণ কৰক</string>\n    <string name=\"backup_frequency\">ব্যাকআপৰ সঁফলতা</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">%s ফাইলৰ পৰা ডাটা পুনৰুদ্ধাৰত বিফল</string>\n    <string name=\"backup_success\">ডাটা সংৰক্ষণ কৰা হৈছে</string>\n    <string name=\"settings_info\">তথ্য</string>\n    <string name=\"restore_success\">ব্যাকআপ ফাইল ল\\'ড কৰা হৈছে</string>\n    <string name=\"advanced_search\">উন্নত সন্ধান</string>\n    <string name=\"advanced_search_des\">আপোনাক প্ৰদানকাৰীৰে পৃথককৃত সন্ধান ফলাফল দিব</string>\n    <string name=\"show_fillers_settings\">এনিমেৰ ফিলাৰ খণ্ড দেখুৱাওক</string>\n    <string name=\"show_trailers_settings\">ট্ৰেইলাৰ দেখুৱাওক</string>\n    <string name=\"kitsu_settings\">কিৎসুৰ পৰা প\\'ষ্টাৰ দেখুৱাওক</string>\n    <string name=\"pref_filter_search_quality\">সন্ধান ফলাফলে নিৰ্বাচিত ভিডিঅ\\' গুণমান লুকুৱাওক</string>\n    <string name=\"automatic_plugin_updates\">স্বয়ংক্ৰিয় প্লাগইন আপডেট</string>\n    <string name=\"updates_settings\">এপ্‌ আপডেট দেখুৱাওক</string>\n    <string name=\"redo_setup_process\">পুনৰ চেটআপ প্ৰক্ৰিয়া কৰক</string>\n    <string name=\"apk_installer_settings\">APK ইনষ্টলাৰ</string>\n    <string name=\"apk_installer_settings_des\">কিছুমান ফোনে নতুন পেকেজ ইনষ্টলাৰ সমৰ্থন নকৰে। আপডেটসমূহ ইনষ্টল নকৰিলে লিগেচি বিকল্প পৰীক্ষা কৰক।</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">একেই ডেভেলপাৰৰ দ্বাৰা লাইট নভেল এপ্‌</string>\n    <string name=\"discord\">Discordত যোগদান কৰক</string>\n    <string name=\"no_links_found_toast\">লিংক পোৱা নগল</string>\n    <string name=\"benene\">ডেভেলপাৰক এখন বেঙেনা দিয়ক</string>\n    <string name=\"benene_des\">দিয়া নাম</string>\n    <string name=\"app_language\">অ্যাপ ভাষা</string>\n    <string name=\"no_chromecast_support_toast\">এই প্ৰদানকাৰীৰ ক্ৰোমকাষ্ট সমৰ্থন নাই</string>\n    <string name=\"copy_link_toast\">লিংক ক্লিপব\\'ৰ্ডত কপিকৰ কৰা হ’ল</string>\n    <string name=\"play_episode_toast\">এপিচ’ড প্লে কৰক</string>\n    <string name=\"season\">চিজন</string>\n    <string name=\"subs_default_reset_toast\">ডিফল্ট মানলৈ পুনৰছেট কৰক</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">চিজন নাই</string>\n    <string name=\"episode\">এপিচ’ড</string>\n    <string name=\"episodes\">এপিচ’ডসমূহ</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">%s ত আহি আছে</string>\n    <string name=\"season_short\">চি</string>\n    <string name=\"episode_short\">এ</string>\n    <string name=\"no_episodes_found\">এপিচ’ড পোৱা নগল</string>\n    <string name=\"delete_file\">ফাইল ডিলিট কৰক</string>\n    <string name=\"delete\">ডিলিট কৰক</string>\n    <string name=\"cancel\">বাতিল কৰক</string>\n    <string name=\"pause\">থামক</string>\n    <string name=\"start\">আৰম্ভ কৰক</string>\n    <string name=\"test_failed\">ব্যৰ্থ</string>\n    <string name=\"test_passed\">উত্তীৰ্ণ</string>\n    <string name=\"resume\">পুনৰ আৰম্ভ কৰক</string>\n    <string name=\"go_back_30\">-৩০</string>\n    <string name=\"go_forward_30\">+৩০</string>\n    <string name=\"delete_message\" formatted=\"true\">এইটো স্থায়ীভাৱে %s ডিলিট কৰিব।\n\\nআপুনি নিশ্চিত নেকি?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nবাকী</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nবাকী</string>\n    <string name=\"status_ongoing\">চলমান</string>\n    <string name=\"status_completed\">সম্পূৰ্ণ</string>\n    <string name=\"status\">স্থিতি</string>\n    <string name=\"year\">বৰ্ষ</string>\n    <string name=\"rating\">ৰেটিং</string>\n    <string name=\"duration\">সময়</string>\n    <string name=\"site\">চাইট</string>\n    <string name=\"synopsis\">সাৰাংশ</string>\n    <string name=\"queued\">পংক্তিবদ্ধ</string>\n    <string name=\"no_subtitles\">সাবটাইটেল নাই</string>\n    <string name=\"action_default\">ডিফল্ট</string>\n    <string name=\"free_storage\">ফ্ৰী</string>\n    <string name=\"used_storage\">ব্যৱহৃত</string>\n    <string name=\"app_storage\">অ্যাপ</string>\n    <string name=\"movies\">চিত্ৰপট</string>\n    <string name=\"tv_series\">টিভি ছিৰিজ</string>\n    <string name=\"documentaries\">ডকুমেণ্টাৰী</string>\n    <string name=\"asian_drama\">এছিয়ান ড্ৰামা</string>\n    <string name=\"livestreams\">লাইভষ্ট্ৰীম</string>\n    <string name=\"nsfw\">এনএছএফডব্লিউ</string>\n    <string name=\"others\">অন্যান্য</string>\n    <string name=\"movies_singular\">চিত্ৰপট</string>\n    <string name=\"tv_series_singular\">ছিৰিজ</string>\n    <string name=\"cartoons_singular\">কাৰ্টুন</string>\n    <string name=\"anime_singular\">এনিম</string>\n    <string name=\"ova_singular\">ওভিএ</string>\n    <string name=\"torrent_singular\">ট’ৰেণ্ট</string>\n    <string name=\"documentaries_singular\">ডকুমেণ্টাৰী</string>\n    <string name=\"source_error\">সোর্স ত্ৰুটি</string>\n    <string name=\"remote_error\">ৰিমোট ত্ৰুটি</string>\n    <string name=\"render_error\">ৰেণ্ডাৰ ত্ৰুটি</string>\n    <string name=\"storage_error\">ডাউনলোড ত্ৰুটি, সঞ্চয়ৰ অনুমতি চাওক</string>\n    <string name=\"unexpected_error\">অপ্ৰত্যাশিত প্লেয়াৰ ত্ৰুটি</string>\n    <string name=\"episode_action_chromecast_episode\">ক্ৰোমকাষ্ট এপিচ’ড</string>\n    <string name=\"episode_action_chromecast_mirror\">ক্ৰোমকাষ্ট মিৰৰ</string>\n    <string name=\"episode_action_cast_mirror\">কাষ্ট মিৰৰ</string>\n    <string name=\"show_dub\">ডাব ছপা</string>\n    <string name=\"episode_action_play_in_format\">প্লে %s ত</string>\n    <string name=\"episode_action_auto_download\">স্বয়ংক্ৰিয় ডাউনলোড</string>\n    <string name=\"episode_action_download_mirror\">ডাউনলোড মিৰৰ</string>\n    <string name=\"show_sub\">সাব ছপা</string>\n    <string name=\"poster_ui_settings\">প\\'ষ্টাৰত UI উপাদানসমূহ টগল কৰক</string>\n    <string name=\"video_lock\">লক কৰক</string>\n    <string name=\"video_aspect_ratio_resize\">ৰিসাইজ কৰক</string>\n    <string name=\"video_source\">উত্‍স</string>\n    <string name=\"update\">আপডেট কৰক</string>\n    <string name=\"watch_quality_pref\">পচন্দৰ ভিডিঅ\\' মান (WiFi)</string>\n    <string name=\"video_skip_op\">OP স্কিপ কৰক</string>\n    <string name=\"skip_update\">এই আপডেট স্কিপ কৰক</string>\n    <string name=\"watch_quality_pref_data\">পচন্দৰ ভিডিঅ\\' মান (ম\\'বাইল ডাটা)</string>\n    <string name=\"limit_title_rez\">ভিডিঅ\\' প্লেয়াৰৰ ৰিজল্যুশন</string>\n    <string name=\"video_buffer_size_settings\">ভিডিঅ\\' বাফাৰ আকাৰ</string>\n    <string name=\"video_buffer_length_settings\">ভিডিঅ\\' বাফাৰ দৈৰ্ঘ্য</string>\n    <string name=\"video_buffer_disk_settings\">ডিস্কত ভিডিঅ\\' কেশ</string>\n    <string name=\"video_buffer_clear_settings\">ভিডিঅ\\' আৰু ছবিৰ কেশ মচক</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">প্লেয়াৰ দেখুওৱা অৱস্থাত ব্যৱহৃত চাৰ্কৰ পৰিমাণ</string>\n    <string name=\"android_tv_interface_off_seek_settings\">প্লেয়াৰ লুকোৱা - চাৰ্কৰ পৰিমাণ</string>\n    <string name=\"android_tv_interface_on_seek_settings\">প্লেয়াৰ দেখুৱাব - চাৰ্কৰ পৰিমাণ</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">প্লেয়াৰ লুকোৱা অৱস্থাত ব্যৱহৃত চাৰ্কৰ পৰিমাণ</string>\n    <string name=\"video_disk_description\">কম সঞ্চয়স্থলৰ (যেনেঃ Android TV) সঁজুলিসমূহত সৰৱাধিক পৰিসৰত স্থাপন কৰিলে সমস্যা সৃষ্টি কৰে।</string>\n    <string name=\"dns_pref\">DNS ওপৰত HTTPS</string>\n    <string name=\"video_ram_description\">কম মেম\\'ৰীৰ (যেনেঃ Android TV) সঁজুলিসমূহত সৰৱাধিক পৰিসৰত স্থাপন কৰিলে সমস্যা সৃষ্টি কৰে।</string>\n    <string name=\"dns_pref_summary\">ISP ব্লকসমূহ বাচিবলৈ সহায়কাৰী</string>\n    <string name=\"add_site_pref\">চাইট ক্লোন কৰক</string>\n    <string name=\"jsdelivr_proxy\">GitHub প্ৰক্সি</string>\n    <string name=\"jsdelivr_enabled\">GitHub পাবলৈ সক্ষম নহ\\'ল। jsDelivr প্ৰক্সি সক্ৰিয় কৰি দিছে…</string>\n    <string name=\"jsdelivr_proxy_summary\">jsDelivr ব্যৱহাৰ কৰি কাঁচা GitHub URLসমূহৰ ব্লক আঁতৰ কৰক। ই আপডেট বিলম্বিত হোৱাৰ সম্ভাৱনা আছে।</string>\n    <string name=\"remove_site_pref\">চাইট আঁতৰাওক</string>\n    <string name=\"download_path_pref\">ডাউনলোড পথ</string>\n    <string name=\"nginx_url_pref\">NGINX ছাৰ্ভাৰ URL</string>\n    <string name=\"display_subbed_dubbed_settings\">ডাব কৰা/সাবটাইটেলযুক্ত এনিমে প্ৰদৰ্শন</string>\n    <string name=\"resize_fit\">স্ক্ৰিনত মিলাওক</string>\n    <string name=\"resize_fill\">প্ৰসাৰিত কৰক</string>\n    <string name=\"legal_notice\">দায়ৱলী</string>\n    <string name=\"pref_category_bypass\">ISP বাইপাছসমূহ</string>\n    <string name=\"resize_zoom\">জুম কৰক</string>\n    <string name=\"pref_category_app_updates\">এপ্লিকেশ্বনৰ আপডেটসমূহ</string>\n    <string name=\"pref_category_backup\">ব্যাকআপ</string>\n    <string name=\"pref_category_extensions\">এক্সটেনশ্বনসমূহ</string>\n    <string name=\"pref_category_actions\">ক্ৰিয়াসমূহ</string>\n    <string name=\"pref_category_cache\">কেশ</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"pref_category_gestures\">ইঙ্গিতসমূহ</string>\n    <string name=\"pref_category_player_features\">প্লেয়াৰৰ বৈশিষ্ট্যসমূহ</string>\n    <string name=\"pref_category_subtitles\">সাবটাইটেলসমূহ</string>\n    <string name=\"pref_category_player_layout\">বিন্যাস</string>\n    <string name=\"pref_category_defaults\">পূৰ্ব নিৰ্ধাৰণসমূহ</string>\n    <string name=\"pref_category_looks\">দেখাত</string>\n    <string name=\"pref_category_ui_features\">বৈশিষ্ট্যসমূহ</string>\n    <string name=\"category_general\">সাধাৰণ</string>\n    <string name=\"random_button_settings\">যৌগিক বুটাম</string>\n    <string name=\"random_button_settings_desc\">হোমপেজ আৰু লাইব্ৰেৰীত যৌগিক বুটাম প্ৰদৰ্শন কৰক</string>\n    <string name=\"provider_lang_settings\">এক্সটেনশ্বন ভাষাসমূহ</string>\n    <string name=\"app_layout\">এপ্লিকেশ্বন বিন্যাস</string>\n    <string name=\"preferred_media_settings\">পচন্দৰ মিডিয়া</string>\n    <string name=\"enable_nsfw_on_providers\">সমৰ্থিত এক্সটেনশ্বনত NSFW সক্ৰিয় কৰক</string>\n    <string name=\"subtitles_encoding\">সাবটাইটেল ক\\'ডিং</string>\n    <string name=\"category_providers\">প্ৰদানকাৰীসকল</string>\n    <string name=\"category_provider_test\">প্ৰদানকাৰীৰ পৰীক্ষা</string>\n    <string name=\"test_extensions\">সমস্ত এক্সটেনশ্বন পৰীক্ষা কৰক</string>\n    <string name=\"test_extensions_summary\">এই টেষ্টটি মাত্ৰ ডেভেলপাৰসকলৰ বাবে আৰু ই একো এক্সটেনচনৰ কাম কৰে নে নকৰে তাৰ পৰীক্ষা নকৰে।</string>\n    <string name=\"tv_layout\">টিভি লেআউট</string>\n    <string name=\"emulator_layout\">এমুলেটৰ লেআউট</string>\n    <string name=\"primary_color_settings\">প্ৰাথমিক ৰং</string>\n    <string name=\"app_theme_settings\">এপ থিম</string>\n    <string name=\"bottom_title_settings\">প\\'ষ্টাৰৰ শিৰোনামৰ স্থান</string>\n    <string name=\"phone_layout\">ফোন লেআউট</string>\n    <string name=\"bottom_title_settings_des\">প\\'ষ্টাৰৰ তলত শিৰোনাম ৰাখক</string>\n    <string name=\"example_site_name\">নতুন সাইটৰ নাম</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">ভাষা ক\\'ড (en)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">একাউন্ট</string>\n    <string name=\"login\">লগ ইন</string>\n    <string name=\"switch_account\">একাউন্ট সলনি কৰক</string>\n    <string name=\"add_account\">একাউন্ট যোগ কৰক</string>\n    <string name=\"create_account\">একাউন্ট সৃষ্টি কৰক</string>\n    <string name=\"add_sync\">ট্ৰেকিং যোগ কৰক</string>\n    <string name=\"none\">একো নহয়</string>\n    <string name=\"normal\">সাধাৰণ</string>\n    <string name=\"added_sync_format\" formatted=\"true\">%s যোগ কৰা হৈছে</string>\n    <string name=\"upload_sync\">সিঙ্ক</string>\n    <string name=\"disable\">বন্ধ কৰক</string>\n    <string name=\"all\">সকলো</string>\n    <string name=\"max\">সৰ্বাধিক</string>\n    <string name=\"subtitles_outline\">আউটলাইন</string>\n    <string name=\"subtitles_depressed\">ডিপ্ৰেছড</string>\n    <string name=\"subtitles_shadow\">ছাঁয়া</string>\n    <string name=\"subtitle_offset_hint\">১০০০ মি.ছে.</string>\n    <string name=\"subtitles_raised\">উঠা</string>\n    <string name=\"subtitle_offset\">সাবচিট্ৰ সিঙ্ক</string>\n    <string name=\"subtitle_offset_title\">সাবচিট্ৰৰ সময়কাল</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">%d মি.ছে. অধিক দেখুৱাবৰ বাবে ব্যৱহাৰ কৰক</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">কোনো সাবচিট্ৰৰ সময়কাল নাই</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">%d মি.ছে. অলপ পিচৰ পৰা দেখুৱাবৰ বাবে ব্যৱহাৰ কৰক</string>\n    <string name=\"subtitles_example_text\">এজন চালাক পোহা কুকুৰাই অলপ তেজী মেজাজৰ কুকুৰাৰ ওপৰেদি জাপ দিলে</string>\n    <string name=\"recommended\">পৰামৰ্শ দিয়া হৈছে</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">%s ল\\'ড হৈছে</string>\n    <string name=\"player_load_subtitles\">ফাইলৰ পৰা ল\\'ড কৰক</string>\n    <string name=\"player_load_subtitles_online\">ইণ্টাৰনেটৰ পৰা ল\\'ড কৰক</string>\n    <string name=\"actor_background\">পটভূমি</string>\n    <string name=\"downloaded_file\">ডাউনলোড কৰা ফাইল</string>\n    <string name=\"home_source\">উৎস</string>\n    <string name=\"actor_main\">মূল</string>\n    <string name=\"home_random\">যিকোনো এটা</string>\n    <string name=\"coming_soon\">অচিৰেই আহিব…</string>\n    <string name=\"actor_supporting\">সহায়ক</string>\n    <string name=\"quality_cam\">কেম</string>\n    <string name=\"quality_cam_rip\">কেম</string>\n    <string name=\"quality_cam_hd\">কেম</string>\n    <string name=\"quality_hq\">উচ্চ গুণমান</string>\n    <string name=\"quality_hd\">এইচডি</string>\n    <string name=\"quality_ts\">টি.এছ.</string>\n    <string name=\"quality_blueray\">ব্লু-ৰেই</string>\n    <string name=\"quality_workprint\">ডব্লিউ.পি.</string>\n    <string name=\"quality_tc\">টি.চি.</string>\n    <string name=\"quality_dvd\">ডি.ভি.ডি.</string>\n    <string name=\"quality_4k\">৪কে</string>\n    <string name=\"quality_uhd\">ইউএইচডি</string>\n    <string name=\"quality_hdr\">এইচডি আৰ</string>\n    <string name=\"quality_sdr\">এছডি আৰ</string>\n    <string name=\"quality_webrip\">ৱেব</string>\n    <string name=\"poster_image\">পোষ্টাৰৰ ছবি</string>\n    <string name=\"category_player\">প্লেয়াৰ</string>\n    <string name=\"resolution_and_title\">ৰিজলিউচন আৰু শিৰোনাম</string>\n    <string name=\"title\">শিৰোনাম</string>\n    <string name=\"resolution\">ৰিজলিউচন</string>\n    <string name=\"error_invalid_id\">অবৈধ আইডি</string>\n    <string name=\"subtitles_filter_lang\">পছন্দৰ মিডিয়া ভাষাৰ দ্বাৰা ফিল্টাৰ কৰক</string>\n    <string name=\"subtitles_remove_bloat\">অপ্রয়োজনীয়তাবোৰ সাবটাইটেলৰ পৰা আঁতৰাওক</string>\n    <string name=\"extras\">অতিৰিক্ত</string>\n    <string name=\"trailer\">ট্ৰেইলাৰ</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"previous\">পূৰ্বৰ</string>\n    <string name=\"skip_setup\">ছেটআপ এৰি দিয়া</string>\n    <string name=\"app_layout_subtext\">আপোনাৰ ডিভাইচৰ বাবে এপ্‌টোৰ চেহেৰাটো সলনি কৰক</string>\n    <string name=\"preferred_media_subtext\">আপুনি কি চাব বিচাৰে</string>\n    <string name=\"extensions\">বৃদ্ধিসকল</string>\n    <string name=\"add_repository\">ৰিপ\\'জিট\\'ৰি যোগ কৰক</string>\n    <string name=\"repository_name_hint\">ৰিপ\\'জিট\\'ৰিৰ নাম (বৈকল্পিক)</string>\n    <string name=\"repository_url_hint\">ৰিপ\\'জিট\\'ৰিৰ URL বা চৰ্টকোড</string>\n    <string name=\"plugin_loaded\">প্লাগইন লোড কৰা হ\\'ল</string>\n    <string name=\"plugin_downloaded\">প্লাগইন ডাউনলোড কৰা হ\\'ল</string>\n    <string name=\"plugin_deleted\">প্লাগইন ডিলিট কৰা হ\\'ল</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">%s লোড কৰিব পৰা নগ\\'ল</string>\n    <string name=\"is_adult\">১৮+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">%1$d %2$s ডাউনলোড কৰা আৰম্ভ হৈছে…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">%1$d %2$s ডাউনলোড সম্পূৰ্ণ</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">সকলো %s ইতিমধ্যে ডাউনলোড কৰা হৈছে</string>\n    <string name=\"no_plugins_found_error\">ৰিপ\\'জিট\\'ৰিত কোনো প্লাগইন পোৱা নগ\\'ল</string>\n    <string name=\"plugin_singular\">প্লাগইন</string>\n    <string name=\"plugin\">প্লাগইনসমূহ</string>\n    <string name=\"no_repository_found_error\">ৰিপ\\'জিট\\'ৰি পোৱা নগ\\'ল, URL পৰীক্ষা কৰক আৰু VPN চেষ্টা কৰক</string>\n    <string name=\"delete_repository_plugins\">এইটোয়ে সমস্ত ৰিপ\\'জিট\\'ৰি প্লাগইনসমূহও ডিলিট কৰিব</string>\n    <string name=\"delete_repository\">ৰিপ\\'জিট\\'ৰি ডিলিট কৰক</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d প্লাগইন আপডেট কৰা হ\\'ল</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">নিষ্ক্ৰিয় কৰা: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">ডাউনলোড কৰা নহয়: %d</string>\n    <string name=\"blank_repo_message\">CloudStreamত কোনো চাইট ডিফল্টভাৱে ইনষ্টল হোৱা নাই। আপুনিয়ে ৰিপ\\'জিট\\'ৰিবোৰৰ পৰা চাইটসমূহ ইনষ্টল কৰিব লাগিব।\n\\n\n\\nআমাৰ Discordত যোগদান কৰক বা অনলাইন বিচাৰক।</string>\n    <string name=\"view_public_repositories_button\">সম্প্ৰদায়ৰ ৰিপ\\'জিট\\'ৰিসমূহ চাওক</string>\n    <string name=\"uppercase_all_subtitles\">সকলো চাবটাইটল মুকলি আখৰত</string>\n    <string name=\"download_all_plugins_from_repo\">সতর্কতা: CloudStream 3 কোৱা নাই যে তৃতীয় পক্ষৰ বৃদ্ধিসমূহ ব্যৱহাৰ কৰিবলৈ আপুনি সম্পূৰ্ণ দায়িত্ব ল\\'ব আৰু কোনো সহায় নাপাব!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (নিষ্ক্ৰিয়)</string>\n    <string name=\"tracks\">ট্ৰেকসমূহ</string>\n    <string name=\"audio_tracks\">অ\\'ডিঅ\\' ট্ৰেকসমূহ</string>\n    <string name=\"video_tracks\">ভিডিঅ\\' ট্ৰেকসমূহ</string>\n    <string name=\"apply_on_restart\">এপ্‌টো পুনৰ আৰম্ভ কৰক যাতে সলনিবোৰ চাব পাৰে।</string>\n    <string name=\"restart\">পুনৰ আৰম্ভ কৰক</string>\n    <string name=\"safe_mode_title\">নিরাপদ মোড অন</string>\n    <string name=\"safe_mode_description\">এটা ক্ৰেছৰ বাবে সকলো বৃদ্ধি বন্ধ কৰা হৈছে যাতে আপুনি সমস্যা উদ্ভৱ কৰা বৃদ্ধি চাব পাৰে।</string>\n    <string name=\"safe_mode_crash_info\">ক্ৰেছৰ তথ্য চাওক</string>\n    <string name=\"extension_rating\" formatted=\"true\">ৰেটিং: %s</string>\n    <string name=\"extension_description\">বিৱৰণ</string>\n    <string name=\"extension_version\">সংস্কৰণ</string>\n    <string name=\"extension_status\">স্থিতি</string>\n    <string name=\"extension_size\">আকাৰ</string>\n    <string name=\"extension_authors\">লেখক</string>\n    <string name=\"extension_types\">সমৰ্থিত</string>\n    <string name=\"extension_language\">ভাষা</string>\n    <string name=\"extension_install_first\">আগতে বৃদ্ধি ইনষ্টল কৰক</string>\n    <string name=\"app_not_found_error\">এপ্‌টো পোৱা নগ\\'ল</string>\n    <string name=\"all_languages_preference\">সকলো ভাষা</string>\n    <string name=\"skip_type_format\" formatted=\"true\">%s এৰি দিয়া</string>\n    <string name=\"skip_type_op\">উদ্‌ঘাটনী</string>\n    <string name=\"skip_type_ed\">সমাপ্তি</string>\n    <string name=\"skip_type_recap\">সংক্ষেপ</string>\n    <string name=\"hls_playlist\">HLS প্লেলিস্ট</string>\n    <string name=\"player_pref\">পছন্দৰ ভিডিঅ\\' প্লেয়াৰ</string>\n    <string name=\"player_settings_play_in_app\">আভ্যন্তৰীণ প্লেয়াৰ</string>\n    <string name=\"player_settings_select_cast_device\">কাষ্ট ডিভাইচ চয়ন কৰক</string>\n    <string name=\"skip_type_mixed_ed\">মিশ্ৰিত সমাপ্তি</string>\n    <string name=\"skip_type_mixed_op\">মিশ্ৰিত উদ্‌ঘাটনী</string>\n    <string name=\"clear_history\">ইতিহাস পৰিস্কাৰ কৰক</string>\n    <string name=\"skip_type_creddits\">স্বীকৃতি</string>\n    <string name=\"skip_type_intro\">ভূমিকা</string>\n    <string name=\"history\">ইতিহাস</string>\n    <string name=\"enable_skip_op_from_database_des\">উদ্‌ঘাটনী/সমাপ্তিৰ বাবে এৰি দিয়াৰ পপআপ দেখুৱাওক</string>\n    <string name=\"clipboard_too_large\">অতিৰিক্ত লিখা। ক্ৰিপবোর্ডত সংৰক্ষণ কৰিব পৰা নগ\\'ল।</string>\n    <string name=\"clipboard_unknown_error\">কপি কৰাৰ সময়ত সমস্যা। লগকেট কপি কৰি এপ্‌টোৰ সহায়ক দলৰ লগত যোগাযোগ কৰক।</string>\n    <string name=\"action_mark_as_watched\">চোৱা হিচাপে চিহ্নিত কৰক</string>\n    <string name=\"action_remove_from_watched\">চোৱা হ\\'ব পৰা তালিকাৰ পৰা আঁতৰাওক</string>\n    <string name=\"yes\">হয়</string>\n    <string name=\"no\">না</string>\n    <string name=\"ok\">ঠিক আছে</string>\n    <string name=\"confirm_exit_dialog\">আপুনি নিশ্চিত যে আপুনি বাহিৰ হ\\'ব বিচাৰে?</string>\n    <string name=\"app_unrestricted_toast\">এপ্‌ৰ বেটাৰী ব্যৱহাৰ ইতিমধ্যে অবাধত সজোৱা হৈছে</string>\n    <string name=\"battery_dialog_message\">ক্লাউডষ্ট্ৰিমক পটভূমিত চলাবলৈ অনুমতিৰ প্ৰয়োজন যাতে চাবস্ক্ৰাইব কৰা টিভি শ্ব\\'সমূহৰ বাবে নিৰৱচ্ছিন্ন ডাউনলোড আৰু জাননীসমূহ নিশ্চিত কৰিব পাৰি। এটা অনুৰোধ সংলাপ প্ৰদৰ্শন কৰিবলে ঠিক আছে টিপক। তাৰ পিছত, \\'Allow\\' টিপক।\\n\\nঅনুগ্ৰহ কৰি মন কৰক, এই অনুমতিৰ অৰ্থ এইটো নহয় যে CS3 এ আপোনাৰ বেটাৰী শেষ কৰিব। ই কেৱল প্ৰয়োজনৰ সময়তহে পটভূমিত কাম কৰিব, যেনে জাননী লাভ কৰাৰ সময়ত বা অফিচিয়েল এক্সটেনচনৰ পৰা ভিডিঅ’ ডাউনলোড কৰাৰ সময়ত।</string>\n    <string name=\"app_info_intent_error\">CloudStream-ৰ App Info খুলিব পৰা নগ\\'ল।</string>\n    <string name=\"update_notification_failed\">এপ্‌ৰ নতুন সংস্কৰণ স্থাপন কৰিব পৰা নগ\\'ল</string>\n    <string name=\"update_notification_downloading\">এপ্‌ আপডেট ডাউনলোড কৰি আছে…</string>\n    <string name=\"update_notification_installing\">এপ্‌ আপডেট স্থাপন কৰি আছে…</string>\n    <string name=\"apk_installer_legacy\">প্ৰাচীন</string>\n    <string name=\"apk_installer_package_installer\">পেকেজ ইন্সটলাৰ</string>\n    <string name=\"delayed_update_notice\">এপ্‌ নিৰ্গমন কৰোতে আপডেট হ\\'ব</string>\n    <string name=\"sort_by\">শ্ৰেণী অনুসাৰে চিহ্নিত কৰক</string>\n    <string name=\"sort\">শ্ৰেণী</string>\n    <string name=\"sort_rating_desc\">ৰেটিং (উচ্চৰ পৰা নিম্নলৈ)</string>\n    <string name=\"sort_rating_asc\">ৰেটিং (নিম্নৰ পৰা উচ্চলৈ)</string>\n    <string name=\"sort_updated_new\">আপডেট (নতুনৰ পৰা পুৰণিলৈ)</string>\n    <string name=\"sort_updated_old\">আপডেট (পুৰণিলৈ নতুন)</string>\n    <string name=\"sort_alphabetical_a\">বৰ্ণানুক্ৰমিক (A ৰ পৰা Z)</string>\n    <string name=\"select_library\">পুথিভঁৰালী বাছক</string>\n    <string name=\"open_with\">ইয়াৰ সহায়ত খুলক</string>\n    <string name=\"empty_library_no_accounts_message\">আপোনাৰ পুথিভঁৰালী খালি আছে :(\n\\nএখন পুথিভঁৰালী একাউণ্টত লগ ইন কৰক বা স্থানীয় পুথিভঁৰালীত শ্ব\\'সমূহ যোগ কৰক।</string>\n    <string name=\"empty_library_logged_in_message\">এই তালিকা খালি। অন্য এটি তালিকালৈ সলনি কৰি চাওক।</string>\n    <string name=\"safe_mode_file\">নিরাপদ ম\\'ড ফাইল পোৱা গৈছে!\n\\nফাইল আঁতৰোৱা নোহোৱালৈকে কোনো এক্সটেনশ্যন আৰম্ভ নকৰা হৈছে।</string>\n    <string name=\"revert\">ঘূৰাই দিয়া</string>\n    <string name=\"subscription_in_progress_notification\">সদস্যতা গ্ৰহণ কৰা শ্ব\\'সমূহ আপডেট কৰিছে</string>\n    <string name=\"subscription_new\">%s-ত সদস্যতা গ্ৰহণ কৰা হৈছে</string>\n    <string name=\"subscription_deleted\">%s-ৰ পৰা সদস্যতা বাতিল কৰা হৈছে</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">ম\\'বাইল ডাটা</string>\n    <string name=\"set_default\">ডিফল্ট হিচাপে সজোৱা</string>\n    <string name=\"use\">ব্যৱহাৰ কৰক</string>\n    <string name=\"edit\">সম্পাদনা কৰক</string>\n    <string name=\"profiles\">প্ৰ\\'ফাইলসমূহ</string>\n    <string name=\"help\">সহায়</string>\n    <string name=\"quality_profile_help\">ইয়াত আপুনি উৎসসমূহ কেনেকৈ ক্ৰম অনুযায়ী চিহ্নিত কৰিব সেই বিষয়ে সলনি কৰিব পাৰে। যদি এখন ভিডিঅ\\'ৰ উচ্চ অগ্ৰাধিকাৰ থাকে তেন্তে সেইটো উৎস নিৰ্বাচনৰ সময়ত ওপৰত দেখা যাব। উৎস অগ্ৰাধিকাৰ আৰু গুণ অগ্ৰাধিকাৰৰ মুঠ যোগফল হৈছে ভিডিঅ\\'ৰ অগ্ৰাধিকাৰ।\n\\n\n\\nউৎস A: 3\n\\nগুণ B: 7\n\\nসৰহযোগে ভিডিঅ\\'ৰ অগ্ৰাধিকাৰ হ\\'ব 10।\n\\n\n\\nদ্ৰষ্টব্য: যদি যোগফল 10 বা তাৰ ওপৰত থাকে তেন্তে প্লেয়াৰটো নিজেই লিংক ল\\'ড কৰাৰ সময়ত ল\\'ডিং এড়াই যাব!</string>\n    <string name=\"profile_background_des\">প্ৰ\\'ফাইলৰ পটভূমি</string>\n    <string name=\"unable_to_inflate\">UI সঠিকভাৱে সৃষ্টি কৰিব পৰা নগ\\'ল, ই এটা গুৰুত্বপূৰ্ণ সমস্যা আৰু তাক অবিলম্বে জনোৱা উচিত %s</string>\n    <string name=\"already_voted\">আপুনি ইতিমধ্যে ভোট দিছে</string>\n    <string name=\"favorites_list_name\">প্ৰিয় তালিকা</string>\n    <string name=\"favorite_added\">%s প্ৰিয় তালিকাত যোগ কৰা হৈছে</string>\n    <string name=\"favorite_removed\">%s প্ৰিয় তালিকাৰ পৰা আঁতৰ কৰা হৈছে</string>\n    <string name=\"action_add_to_favorites\">প্ৰিয় তালিকালৈ যোগ কৰক</string>\n    <string name=\"action_remove_from_favorites\">প্ৰিয় তালিকাৰ পৰা আঁতৰ কৰক</string>\n    <string name=\"duplicate_title\">সম্ভাৱ্য নকল বস্ত্ত পোৱা গৈছে</string>\n    <string name=\"duplicate_replace_all\">সকলো প্ৰতিস্থাপন কৰক</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">আপোনাৰ পুথিভঁৰালীতে সম্ভাৱ্য নকল বস্তু পোৱা গৈছে: \\'%s.\\'\n\\n\n\\nআপুনি এই বস্তু যিকোনো হ\\'লে যোগ কৰিব বিচাৰেনে, বিদ্যমান বস্তু প্ৰতিস্থাপন কৰিব, বা কাৰ্য বাতিল কৰিব বিচাৰেনে?</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">আপোনাৰ পুথিভঁৰালীতে সম্ভাৱ্য নকল বস্তুসমূহ পোৱা গৈছে:\n\\n\n\\n%s\n\\n\n\\nআপুনি এই বস্তু যিকোনো হ\\'লে যোগ কৰিব বিচাৰেনে, বিদ্যমানবোৰ প্ৰতিস্থাপন কৰিব, বা কাৰ্য বাতিল কৰিব বিচাৰেনে?</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">%s ৰ বাবে পিন সন্নিবিষ্ট কৰক</string>\n    <string name=\"enter_current_pin\">বৰ্তমান পিন সন্নিবিষ্ট কৰক</string>\n    <string name=\"lock_profile\">প্ৰফাইল লক কৰক</string>\n    <string name=\"pin\">পিন</string>\n    <string name=\"pin_error_incorrect\">ভুল পিন। অনুগ্ৰহ কৰি পুনৰ চেষ্টা কৰক।</string>\n    <string name=\"pin_error_length\">পিন ৪ অক্ষৰৰ হ\\'ব লাগিব</string>\n    <string name=\"select_an_account\">এটা একাউণ্ট বাচনি কৰক</string>\n    <string name=\"manage_accounts\">একাউণ্টসমূহ পৰিচালনা কৰক</string>\n    <string name=\"skip_startup_account_select_pref\">স্টাৰ্টআপত একাউণ্ট বাচনি কৰা এড়াই যোৱাঁ</string>\n    <string name=\"use_default_account\">ডিফল্ট একাউণ্ট ব্যৱহাৰ কৰক</string>\n    <string name=\"rotate_video\">ঘূৰাওক</string>\n    <string name=\"logged_account\" formatted=\"true\">%s হিচাপে লগ ইন কৰা হৈছে</string>\n    <string name=\"rotate_video_desc\">স্ক্ৰীণৰ অভিমুখৰ বাবে টগল বুটাম প্ৰদৰ্শন কৰক</string>\n    <string name=\"auto_rotate_video_desc\">ভিডিঅ\\'ৰ অভিমুখৰ ওপৰত আধাৰিত স্ক্ৰীণৰ অভিমুখ স্বয়ংক্ৰিয়ভাৱে পৰিবৰ্তন কৰক</string>\n    <string name=\"auto_rotate_video\">স্বয়ংক্ৰিয় ঘূৰাওক</string>\n    <string name=\"unfavorite\">প্ৰিয় নকৰা</string>\n    <string name=\"biometric_unsupported\">এই ডিভাইচত বায়\\'মেট্ৰিক প্ৰমাণীকৰণ সমৰ্থিত নহয়</string>\n    <string name=\"biometric_setting_summary\">আঙুলি চিহ্ন, মুখৰ আইডি, পিন, পেটাৰ্ণ আৰু পাছৱাৰ্ডৰ সৈতে এপ্লিকেচন আনলক কৰক।</string>\n    <string name=\"favorite\">প্ৰিয়</string>\n    <string name=\"biometric_prompt_description\">কেইবাটাও ভুল চেষ্টা কৰাৰ পিছত, প্ৰম্প্ট বন্ধ হ\\'ব। পুনৰ চেষ্টা কৰিবলৈ মাত্ৰ এপ্পটো পুনৰ আৰম্ভ কৰক।</string>\n    <string name=\"biometric_warning\">আপোনাৰ CloudStream ডেটা এতিয়া সংৰক্ষণ কৰা হৈছে। এইৰ সম্ভাৱনা অত্যন্ত কম, কিন্তু সকলো ডিভাইচৰ ব্যৱহাৰ ভিন্ন হ\\'ব পাৰে। যদি এপ্লিকেচনটোত প্রবেশ কৰিব নোৱাৰা অৱস্থাত পৰাৰ কম সম্ভাৱনাৰ ঘটনা ঘটে, তেন্তে সম্পূৰ্ণভাবে এপ্প ডেটা মচি দিয়ক আৰু সংৰক্ষণৰ পৰা পুনৰুদ্ধাৰ কৰক। কোনো অশান্তিৰ বাবে আমাৰ দুখিত হওক।</string>\n    <string name=\"download\">ডাউনলোড</string>\n    <string name=\"updates_settings_des\">এপ্‌ আৰম্ভণিৰ পিছত নতুন আপডেটৰ সন্ধান কৰক।</string>\n    <string name=\"anim\">একেই ডেভেলপাৰৰ দ্বাৰা এনিম এপ্‌</string>\n    <string name=\"new_update_format\" formatted=\"true\">নতুন আপডেট পোৱা গ’ল!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">ফিলাৰ</string>\n    <string name=\"play_with_app_name\">CloudStreamৰে প্লে কৰক</string>\n    <string name=\"title_search\">সন্ধান</string>\n    <string name=\"title_downloads\">ডাউনলোড</string>\n    <string name=\"result_tags\">শ্ৰেণীসমূহ</string>\n    <string name=\"skip_loading\">লোডিং এড়াওক</string>\n    <string name=\"loading\">লোড হৈ আছে…</string>\n    <string name=\"type_on_hold\">স্থগিত</string>\n    <string name=\"type_completed\">সম্পূৰ্ণ</string>\n    <string name=\"type_dropped\">এৰি দিয়া</string>\n    <string name=\"type_re_watching\">পুনৰাবলোকন</string>\n    <string name=\"play_movie_button\">চলচ্চিত্ৰ প্লে কৰক</string>\n    <string name=\"play_trailer_button\">ট্ৰেইলাৰ প্লে কৰক</string>\n    <string name=\"play_livestream_button\">লাইভ ষ্ট্ৰীম প্লে কৰক</string>\n    <string name=\"pick_subtitle\">চাবটাইটলসমূহ</string>\n    <string name=\"play_episode\">এপিচ\\'ড প্লে কৰক</string>\n    <string name=\"sort_apply\">প্ৰয়োগ কৰক</string>\n    <string name=\"delete_files\">ফাইলসমূহ ডিলিট কৰক</string>\n    <string name=\"delete_format\" formatted=\"true\">ডিলিট (%1$d | %2$s)</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">আপুনি স্থায়ীভাৱে তলত দিয়া আইটেমসমূহ ডিলিট কৰিবলৈ নিশ্চিত নেকি?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">%1$s ত তলত দিয়া এপিচ’ডসমূহ স্থায়ীভাৱে ডিলিট কৰিব নেকি?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">আপুনি দিয়া ছিৰিজৰ সকলো এপিচ’ড স্থায়ীভাৱে ডিলিট কৰিব:\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">আপুনি দিয়া ছিৰিজৰ সকলো এপিচ’ড স্থায়ীভাৱে ডিলিট কৰিবলৈ নিশ্চিত নেকি?\n\\n\n\\n%s</string>\n    <string name=\"sort_release_date_old\">মুক্তিৰ তাৰিখ (পুৰণাৰ পৰা নতুন)</string>\n    <string name=\"test_warning\">সতৰ্কবাৰ্তা</string>\n    <string name=\"auth_locally\">স্থানীয়ভাৱে প্ৰমাণীকৰণ কৰক</string>\n    <string name=\"downloads_empty\">বৰ্তমান কোনো ডাউনলোড নাই।</string>\n    <string name=\"open_local_video\">স্থানীয় ভিডিঅ’ খোলক</string>\n    <string name=\"pref_category_accounts\">একাউণ্টসমূহ</string>\n    <string name=\"qr_image\">কিউ আৰ কোডৰ ছবি</string>\n    <string name=\"delete_plugin\">প্লাগইন ডিলিট কৰক</string>\n    <string name=\"cs3wiki\">CloudStream ৱিকি</string>\n    <string name=\"pref_category_security\">সুৰক্ষা</string>\n    <string name=\"device_pin_url_message\">আপোনাৰ স্মাৰ্টফোন বা কম্পিউটাৰত <b>%s</b> লগ কৰক আৰু ওপৰৰ ক\\'ডটো প্ৰৱিষ্ট কৰক</string>\n    <string name=\"device_pin_error_message\">ডিভাইচ পিন ক\\'ড পোৱা নাই, স্থানীয় প্ৰমাণীকৰণ চেষ্টা কৰক</string>\n    <string name=\"device_pin_expired_message\">পিন ক\\'ডৰ মেয়াদ শেষ হৈছে!</string>\n    <string name=\"device_pin_counter_text\">ক\\'ড মেয়াদ শেষ হব %1$dm %2$ds</string>\n    <string name=\"preview_seekbar\">সীকবৰ প্ৰিভিউ</string>\n    <string name=\"preview_seekbar_desc\">সীকবৰত প্ৰিভিউ থাম্বনেইল সক্ৰিয় কৰক</string>\n    <string name=\"play_from_beginning_img_des\">আৰম্ভৰ পৰা প্লে কৰক</string>\n    <string name=\"dismiss\">এৰি দিয়া</string>\n    <string name=\"open_downloaded_repo\">ডাউনলোড কৰা ৰিপ\\'জিট\\'ৰি খোলক</string>\n    <string name=\"hide_player_control_names\">প্লেয়াৰৰ নিয়ন্ত্ৰণসমূহৰ নাম লুকাওক</string>\n    <string name=\"downloads_delete_select\">মুছিবলৈ আইটেমসমূহ নিৰ্ব্বাচন কৰক</string>\n    <string name=\"offline_file\">অফলাইনতে চাবলৈ উপলব্ধ</string>\n    <string name=\"select_all\">সকলো বাছক</string>\n    <string name=\"deselect_all\">সকলো বাদ দিয়ক</string>\n    <string name=\"sort_release_date_new\">মুক্তিৰ তাৰিখ (নতুনৰ পৰা পুৰণা)</string>\n    <string name=\"no_subtitles_loaded\">এতিয়ালৈকে কোনো চাবটাইটেল লোড কৰা হোৱা নাই</string>\n    <string name=\"custom\">কাষ্টম</string>\n    <string name=\"dont_show\">নেদেখুৱাওক</string>\n    <string name=\"confirm_before_exiting_desc\">এপ্‌ট পৰা উলাই যোৱা আগতে বাৰ্তা দেখুৱাওক</string>\n    <string name=\"confirm_before_exiting_title\">উলাই যোৱা আগতে নিশ্চিত কৰক</string>\n    <string name=\"backup_path_title\">ব্যাকআপ ফ\\'ল্ডাৰ স্থান</string>\n    <string name=\"show\">দেখুৱাওক</string>\n    <string name=\"torrent_info\">এই ভিডিওটো টৰেন্ট। এই অৰ্থ হৈছে যে আপোনাৰ ভিডিও কাৰ্যকলাপ ট্ৰেক কৰা হ\\'ব পাৰে।\\nআগবঢ়িবলৈ আগতে টৰেণ্টিং বুজি পোৱা নিশ্চিত কৰক।</string>\n    <string name=\"subs_edge_size\">চুকৰ মাপ</string>\n    <string name=\"player_load_one_subtitle_online\">প্ৰথম উপলব্ধটো লোড কৰক</string>\n    <string name=\"audio_singluar\">অডিঅ\\'</string>\n    <string name=\"podcast_singluar\">প’ডকাষ্ট</string>\n    <string name=\"encoding_error\">এনকোডিং ত্ৰুটি</string>\n    <string name=\"unsupported_error\">সমৰ্থিত ত্ৰুটি</string>\n    <string name=\"torrent_not_accepted\">গ্ৰহণ কৰা হোৱা নাই টৰেণ্ট</string>\n    <string name=\"torrent_preferred_media\">সংহতিসমূহ/প্ৰদানকাৰী/পছন্দৰ মাধ্যমত টৰেণ্ট সামৰ্থবান কৰক</string>\n    <string name=\"software_decoding\">চফ্টৱেৰ ডিকোডিং</string>\n    <string name=\"software_decoding_desc\">চফ্টৱেৰ ডিকোডিঙে প্লেয়াৰক আপোনাৰ ফোন দ্বাৰা সমৰ্থিত নোহোৱা ভিডিঅ\\' ফাইলসমূহ চলাবলৈ সামৰ্থবান কৰে, কিন্তু উচ্চ ৰিজ\\'লিউচনত লেগি বা অস্থিৰ প্লেবেকৰ সৃষ্টি কৰিব পাৰে</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+az/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"cast_format\" formatted=\"true\">Oyunçu heyəti: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Bölüm %d bu tarixdə yayımlanacaq</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dg%2$ds%3$dd</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dd</string>\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"home_main_poster_img_des\">Əsas Afişa</string>\n    <string name=\"episode_poster_img_des\">Bölüm Afişası</string>\n    <string name=\"home_next_random_img_des\">Sonrakı Təsadüfi</string>\n    <string name=\"go_back_img_des\">Geri get</string>\n    <string name=\"play_from_beginning_img_des\">Əvvəldən oynat</string>\n    <string name=\"home_change_provider_img_des\">Provayderi dəyişdir</string>\n    <string name=\"preview_background_img_des\">Arxaplana ilkin baxış keçir</string>\n    <string name=\"rated_format\" formatted=\"true\">Xal: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Yeniləmə mövcuddur!\\n%1$s -&gt; %2$s</string>\n    <string name=\"title_home\">Ana səhifə</string>\n    <string name=\"title_search\">Axtar</string>\n    <string name=\"title_downloads\">Yükləmələr</string>\n    <string name=\"no_data\">Məlumat yoxdur</string>\n    <string name=\"episode_more_options_des\">Daha çox seçimlər</string>\n    <string name=\"next_episode\">Sonrakı bölüm</string>\n    <string name=\"result_tags\">Janrlar</string>\n    <string name=\"result_share\">Paylaş</string>\n    <string name=\"result_open_in_browser\">Brauzerdə aç</string>\n    <string name=\"browser\">Brauzer</string>\n    <string name=\"skip_loading\">Yükləməni keç</string>\n    <string name=\"loading\">Yüklənir…</string>\n    <string name=\"type_watching\">İzlənir</string>\n    <string name=\"type_on_hold\">Gözləmədə</string>\n    <string name=\"type_dropped\">Yarıda dayandırıldı</string>\n    <string name=\"type_plan_to_watch\">İzləməyə planlandı</string>\n    <string name=\"type_re_watching\">Yenidən izlənilir</string>\n    <string name=\"play_movie_button\">Filmi oynat</string>\n    <string name=\"play_trailer_button\">Fraqmanı Oynat</string>\n    <string name=\"play_livestream_button\">Canlı Yayını oynat</string>\n    <string name=\"pick_source\">Mənbələr</string>\n    <string name=\"pick_subtitle\">Altyazılar</string>\n    <string name=\"reload_error\">Yenidən bağlanmaya cəhd edin…</string>\n    <string name=\"go_back\">Geri dön</string>\n    <string name=\"play_episode\">Bölümü oynat</string>\n    <string name=\"downloaded\">Yükləndi</string>\n    <string name=\"download_paused\">Yükləmə dayandırıldı</string>\n    <string name=\"download_started\">Yükləmə başladıldı</string>\n    <string name=\"download_failed\">Yükləmə uğursuz oldu</string>\n    <string name=\"download_canceled\">Yükləmə ləğv edildi</string>\n    <string name=\"downloads_delete_select\">Silinəcək faylları seçin</string>\n    <string name=\"downloads_empty\">Hal-hazırda heç bir yükləmə yoxdur.</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Böl. %2$d</string>\n    <string name=\"duration_format\" formatted=\"true\">%d dəqiqə</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$ds %2$dd</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Sezon %1$d Bölüm %2$d bu tarixdə yayımlanacaq</string>\n    <string name=\"search_poster_img_des\">Afişa</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Sürət (%.2fx)</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">CloudStream ilə oynat</string>\n    <string name=\"type_completed\">Tamamlandı</string>\n    <string name=\"title_settings\">Parametrlər</string>\n    <string name=\"search_hint\">Axtar…</string>\n    <string name=\"download\">Yüklə</string>\n    <string name=\"downloading\">Yüklənir</string>\n    <string name=\"download_done\">Yükləmə bitdi</string>\n    <string name=\"torrent_plot\">Açıqlama</string>\n    <string name=\"player_size_settings_des\">Qara sərhədləri, kənarları sil</string>\n    <string name=\"torrent_no_plot\">Açıqlama Tapılmadı</string>\n    <string name=\"picture_in_picture\">Şəkil içində şəkil</string>\n    <string name=\"player_size_settings\">Pleyeri yenidən ölçüləndirmə düyməsini</string>\n    <string name=\"player_subtitles_settings\">Subtitrlər</string>\n    <string name=\"player_subtitles_settings_des\">Pleyerin subtitr parametrləri</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast Subtitrləri</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast subtitr parametrləri</string>\n    <string name=\"eigengraumode_settings\">Pleyer oynadılma sürəti</string>\n    <string name=\"settings_info\">Məlumat</string>\n    <string name=\"category_updates\">Yeniləmələr və Ehtiyat Nüsxələmə</string>\n    <string name=\"pref_filter_search_quality\">Seçilmiş video keyfiyyətini axtarış nəticələrində gizlət</string>\n    <string name=\"double_tap_to_pause_settings_des\">Dayandırma üçün videonun ortasına iki dəfə toxunun</string>\n    <string name=\"use_system_brightness_settings\">Sistem parlaqlığından istifadə et</string>\n    <string name=\"restore_settings\">Ehtiyat nüsxədən məlumatları bərpa et</string>\n    <string name=\"backup_settings\">Məlumatları ehtiyata nüsxələ</string>\n    <string name=\"backup_frequency\">Ehtiyat nüsxələmə sıxlığı</string>\n    <string name=\"restore_success\">Ehtiyat nüsxələmə faylı yükləndi</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">%s faylından məlumatları bərpa etmək mümkün olmadı</string>\n    <string name=\"backup_success\">Məlumat ehtiyata nüsxələndi</string>\n    <string name=\"backup_failed\">Yaddaş icazəsi yoxdur. Zəhmət olmasa, yenidən yoxlayın.</string>\n    <string name=\"backup_failed_error_format\">%s ehtiyata nüsxələnirkən xəta baş verdi</string>\n    <string name=\"search\">Axtar</string>\n    <string name=\"library\">Kitabxana</string>\n    <string name=\"category_account\">Hesablar və Təhlükəsizlik</string>\n    <string name=\"advanced_search\">Təkmilləşdirilmiş Axtarış</string>\n    <string name=\"show_trailers_settings\">Treylerləri göstər</string>\n    <string name=\"kitsu_settings\">Kitsu afişalarını, posterlərini göstər</string>\n    <string name=\"copy_link_toast\">Link mübadilə buferinə nüsxələndi</string>\n    <string name=\"subs_default_reset_toast\">Standart dəyərlərə sıfırla</string>\n    <string name=\"season\">Sezon</string>\n    <string name=\"pause\">Dayandır</string>\n    <string name=\"start\">Başlat</string>\n    <string name=\"test_failed\">Uğursuz oldu</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Aşağıdakı faylları həmişəlik silmək istədiyinizə əminsinizmi?\\n\\n%s</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"no_episodes_found\">Bölümlər tapılmadı</string>\n    <string name=\"delete\">Sil</string>\n    <string name=\"delete_file\">Faylı sil</string>\n    <string name=\"delete_files\">Faylları sil</string>\n    <string name=\"delete_format\" formatted=\"true\">Sil (%1$d | %2$s)</string>\n    <string name=\"cancel\">Ləğv et</string>\n    <string name=\"test_passed\">Uğurlu oldu</string>\n    <string name=\"test_warning\">Xəbərdarlıq</string>\n    <string name=\"resume\">Davam et</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">%s həmişəlik silinəcək\\nƏminsiniz?</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">%1$s içindəki aşağıdakı bölümləri həmişəlik silmək istədiyinizdən əminsinizmi?\\n\\n%2$s</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d%2$s</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"documentaries\">Sənədli filmlər</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Sənədli film</string>\n    <string name=\"storage_error\">Yükləmə xətası, yaddaş icazələrini yoxlayın</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"encoding_error\">Kodlama xətası</string>\n    <string name=\"cartoons\">Cizgi filmləri</string>\n    <string name=\"anime\">Anime-lər</string>\n    <string name=\"torrent\">Torrent-lər</string>\n    <string name=\"asian_drama\">Asiya serialları (dramalar)</string>\n    <string name=\"livestreams\">Canlı yayımlar</string>\n    <string name=\"nsfw\">+18 məzmun</string>\n    <string name=\"others\">Digərləri</string>\n    <string name=\"tv_series_singular\">Seriallar</string>\n    <string name=\"cartoons_singular\">Cizgi filmi</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"asian_drama_singular\">Asiya serialı (drama)</string>\n    <string name=\"live_singular\">Canlı yayım</string>\n    <string name=\"nsfw_singular\">+18 məzmun</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"music_singlar\">Musiqi</string>\n    <string name=\"audio_book_singular\">Səsli Kitab</string>\n    <string name=\"audio_singluar\">Səs</string>\n    <string name=\"podcast_singluar\">Podkast</string>\n    <string name=\"source_error\">Mənbə xətası</string>\n    <string name=\"remote_error\">Server xətası</string>\n    <string name=\"unsupported_error\">Dəstəklənməyən xəta</string>\n    <string name=\"unexpected_error\">Gözlənilməyən oynadıcı xətası</string>\n    <string name=\"episode_action_cast_mirror\">Ekran yansıtma</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+bg/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string formatted=\"true\" name=\"app_dub_sub_episode_text_format\">%1$s еп. %2$d</string>\n    <string formatted=\"true\" name=\"cast_format\">Актьори: %s</string>\n    <string formatted=\"true\" name=\"next_episode_format\">Епизод %d ще бъде пуснат след</string>\n    <string formatted=\"true\" name=\"next_episode_time_day_format\">%1$dd %2$dh %3$dm</string>\n    <string formatted=\"true\" name=\"next_episode_time_hour_format\">%1$dh %2$dm</string>\n    <string formatted=\"true\" name=\"next_episode_time_min_format\">%dm</string>\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"episode_poster_img_des\">Episode Poster</string>\n    <string name=\"home_main_poster_img_des\">Main Poster</string>\n    <string name=\"home_next_random_img_des\">Следващ произволен</string>\n    <string name=\"go_back_img_des\">Върни се</string>\n    <string name=\"home_change_provider_img_des\">Смяна на доставчика</string>\n    <string name=\"preview_background_img_des\">Визуализация на фона</string>\n    <string formatted=\"true\" name=\"player_speed_text_format\">Скорост (%.2fx)</string>\n    <string formatted=\"true\" name=\"rated_format\">Оценка: %.1f</string>\n    <string formatted=\"true\" name=\"new_update_format\">Намерена е нова актуализация!\n\\n%1$s -&gt; %2$s</string>\n    <string formatted=\"true\" name=\"filler\">Шаблон</string>\n    <string formatted=\"true\" name=\"duration_format\">%d мин</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Пусни с CloudStream</string>\n    <string name=\"title_home\">Начало</string>\n    <string name=\"title_search\">Търсене</string>\n    <string name=\"title_downloads\">Изтегляния</string>\n    <string name=\"title_settings\">Настройки</string>\n    <string name=\"search_hint\">Търсене…</string>\n    <string formatted=\"true\" name=\"search_hint_site\">Търси %s…</string>\n    <string name=\"no_data\">Няма данни</string>\n    <string name=\"episode_more_options_des\">Още опции</string>\n    <string name=\"next_episode\">Следващ епизод</string>\n    <string name=\"result_tags\">Жанрове</string>\n    <string name=\"result_share\">Сподели</string>\n    <string name=\"result_open_in_browser\">Отвори в браузъра</string>\n    <string name=\"skip_loading\">Пропусни зареждането</string>\n    <string name=\"loading\">Зареждане…</string>\n    <string name=\"type_watching\">Гледане</string>\n    <string name=\"type_on_hold\">На изчакване</string>\n    <string name=\"type_completed\">Завършено</string>\n    <string name=\"type_dropped\">Изпуснат</string>\n    <string name=\"type_plan_to_watch\">План за гледане</string>\n    <string name=\"type_re_watching\">Повторно гледане</string>\n    <string name=\"play_movie_button\">Пускане на филм</string>\n    <string name=\"play_livestream_button\">Възпроизвеждане на живо</string>\n    <string name=\"play_torrent_button\">Поточно предаване на торент</string>\n    <string name=\"pick_source\">Източници</string>\n    <string name=\"pick_subtitle\">субтитри</string>\n    <string name=\"reload_error\">Повторен опит за свързване…</string>\n    <string name=\"go_back\">Върни се</string>\n    <string name=\"play_episode\">Пусни епизод</string>\n    <string name=\"download\">Изтегли</string>\n    <string name=\"downloaded\">Изтеглено</string>\n    <string name=\"downloading\">Изтегля се</string>\n    <string name=\"download_paused\">Изтеглянето е на пауза</string>\n    <string name=\"download_started\">Изтеглянето започна</string>\n    <string name=\"download_failed\">Изтеглянето се провали</string>\n    <string name=\"download_canceled\">Изтеглянето е отменено</string>\n    <string name=\"download_done\">Изтеглянето е завършено</string>\n    <string name=\"stream\">Поток на данни</string>\n    <string name=\"error_loading_links_toast\">Грешка при зареждане на връзки</string>\n    <string name=\"download_storage_text\">Вътрешна памет</string>\n    <string name=\"app_dubbed_text\">Дублаж</string>\n    <string name=\"app_subbed_text\">Субтитри</string>\n    <string name=\"popup_delete_file\">Изтрий файла</string>\n    <string name=\"popup_play_file\">Възпроизвеждане на файл</string>\n    <string name=\"popup_resume_download\">Възобновете изтеглянето</string>\n    <string name=\"popup_pause_download\">Пауза на изтеглянето</string>\n    <string name=\"home_more_info\">Повече информация</string>\n    <string name=\"home_expanded_hide\">Скрий</string>\n    <string name=\"home_play\">Пусни</string>\n    <string name=\"home_info\">Информация</string>\n    <string name=\"filter_bookmarks\">Филтриране на отметки</string>\n    <string name=\"error_bookmarks_text\">Отметки</string>\n    <string name=\"action_remove_from_bookmarks\">Премахване</string>\n    <string name=\"action_add_to_bookmarks\">Задайте статус на гледане</string>\n    <string name=\"sort_apply\">Приложи</string>\n    <string name=\"sort_copy\">Копирай</string>\n    <string name=\"sort_close\">Затвори</string>\n    <string name=\"sort_clear\">Изчисти</string>\n    <string name=\"sort_save\">Запазване</string>\n    <string name=\"player_speed\">Скорост на възпроизвеждане</string>\n    <string name=\"subtitles_settings\">Настройки на субтитрите</string>\n    <string name=\"subs_text_color\">Цвят на текста</string>\n    <string name=\"subs_outline_color\">Цвят на контура</string>\n    <string name=\"subs_background_color\">Цвят на фона</string>\n    <string name=\"subs_window_color\">Цвят на прозореца</string>\n    <string name=\"subs_edge_type\">Тип ръб</string>\n    <string name=\"subs_subtitle_elevation\">Височина на субтитрите</string>\n    <string name=\"subs_font\">Шрифт</string>\n    <string name=\"subs_font_size\">Размер на шрифта</string>\n    <string name=\"search_provider_text_providers\">Търсене чрез доставчици</string>\n    <string name=\"search_provider_text_types\">Търсене с помощта на типове</string>\n    <string name=\"benene_count_text\">%d Банан/а даден/и на разработчиците</string>\n    <string name=\"benene_count_text_none\">Не е/са даден/и Банан/и</string>\n    <string name=\"subs_auto_select_language\">Автоматичен избор на език</string>\n    <string name=\"subs_download_languages\">Изтегляне на езици</string>\n    <string name=\"subs_subtitle_languages\">Език на субтитрите</string>\n    <string name=\"subs_hold_to_reset_to_default\">Задръжте, за да нулирате по подразбиране</string>\n    <string formatted=\"true\" name=\"subs_import_text\">Импортирайте шрифтове, като ги поставите в %s</string>\n    <string name=\"continue_watching\">Продължете да гледате</string>\n    <string name=\"action_remove_watching\">Премахване</string>\n    <string name=\"action_open_watching\">Повече информация</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Може да е необходим VPN, за да работи правилно този доставчик</string>\n    <string name=\"vpn_torrent\">Този доставчик е торент, препоръчва се VPN</string>\n    <string name=\"provider_info_meta\">Метаданните не се предоставят от сайта, зареждането на видео ще бъде неуспешно, ако не съществува на сайта.</string>\n    <string name=\"torrent_plot\">Описание</string>\n    <string name=\"normal_no_plot\">Няма намерен съдържание</string>\n    <string name=\"torrent_no_plot\">Няма намерено описание</string>\n    <string name=\"show_log_cat\">Покажи Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Картина в картина</string>\n    <string name=\"picture_in_picture_des\">Продължава възпроизвеждането в миниатюрен плейър върху други приложения</string>\n    <string name=\"player_size_settings\">Бутон за преоразмеряване на плейъра</string>\n    <string name=\"player_size_settings_des\">Премахнете черните граници</string>\n    <string name=\"player_subtitles_settings\">Субтитри</string>\n    <string name=\"player_subtitles_settings_des\">Настройки на субтитрите на плейъра</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast субтитри</string>\n    <string name=\"chromecast_subtitles_settings_des\">Настройки за субтитри на Chromecast</string>\n    <string name=\"eigengraumode_settings\">Промяна на скорост</string>\n    <string name=\"swipe_to_seek_settings\">Плъзнете за преместване</string>\n    <string name=\"swipe_to_seek_settings_des\">Плъзнете пръст от една страна на друга, за да контролирате позицията си във видеоклип</string>\n    <string name=\"swipe_to_change_settings\">Плъзнете, за да промените настройките</string>\n    <string name=\"swipe_to_change_settings_des\">Плъзнете нагоре или надолу от лявата или дясната страна, за да промените яркостта или силата на звука</string>\n    <string name=\"autoplay_next_settings\">Автоматично пускане на следващ епизод</string>\n    <string name=\"autoplay_next_settings_des\">Започнете следващия епизод, когато текущият приключи</string>\n    <string name=\"double_tap_to_seek_settings\">Докоснете двукратно за превъртане</string>\n    <string name=\"double_tap_to_pause_settings\">Докоснете два пъти за пауза</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Размер на превъртане (секунди)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Докоснете два пъти от дясната или лявата страна, за да превъртите напред или назад</string>\n    <string name=\"double_tap_to_pause_settings_des\">Докоснете два пъти в средата, за да поставите на пауза</string>\n    <string name=\"use_system_brightness_settings\">Използвайте яркостта на системата</string>\n    <string name=\"use_system_brightness_settings_des\">Използвайте системна яркост в плейъра на приложението вместо тъмно наслагване</string>\n    <string name=\"episode_sync_settings\">Актуализирайте прогреса на гледане</string>\n    <string name=\"episode_sync_settings_des\">Автоматично синхронизирайте прогреса на текущия си епизод</string>\n    <string name=\"restore_settings\">Възстановете данните от архив</string>\n    <string name=\"backup_settings\">Архивиране на данни</string>\n    <string name=\"restore_success\">Зареден архивен файл</string>\n    <string formatted=\"true\" name=\"restore_failed_format\">Неуспешно възстановяване на данни от файл %s</string>\n    <string name=\"backup_success\">Съхранени данни</string>\n    <string name=\"backup_failed\">Липсват разрешения за съхранение. Моля, опитайте отново.</string>\n    <string name=\"backup_failed_error_format\">Грешка при архивирането на %s</string>\n    <string name=\"search\">Търсене</string>\n    <string name=\"category_account\">Акаунти и сигурност</string>\n    <string name=\"category_updates\">Актуализации и архивиране</string>\n    <string name=\"settings_info\">Информация</string>\n    <string name=\"advanced_search\">Подробно търсене</string>\n    <string name=\"advanced_search_des\">Дава ви резултатите от търсенето, разделени по доставчик</string>\n    <string name=\"show_fillers_settings\">Показване заместващ епизод за аниме</string>\n    <string name=\"show_trailers_settings\">Показване на трейлъри</string>\n    <string name=\"kitsu_settings\">Покажете плакати от Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Скрий избраното видео качество в резултатите от търсенето</string>\n    <string name=\"automatic_plugin_updates\">Автоматични актуализации на плъгини</string>\n    <string name=\"updates_settings\">Показвай актуализации на приложението</string>\n    <string name=\"updates_settings_des\">Автоматично търси нови актуализации при стартиране на приложението.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Light novel - приложение от същите разработчици</string>\n    <string name=\"anim\">Приложение за аниме от същите разработчици</string>\n    <string name=\"discord\">Присъединете се към Discord</string>\n    <string name=\"benene\">Дайте банан/и разработчиците</string>\n    <string name=\"benene_des\">Даден/и банан/и</string>\n    <string name=\"app_language\">Език на приложението</string>\n    <string name=\"no_chromecast_support_toast\">Този доставчик няма поддръжка за Chromecast</string>\n    <string name=\"no_links_found_toast\">Няма намерени връзки</string>\n    <string name=\"copy_link_toast\">Връзката е копирана в клипборда</string>\n    <string name=\"play_episode_toast\">Пусни епизода</string>\n    <string name=\"subs_default_reset_toast\">Възстановяване на стойността по подразбиране</string>\n    <string name=\"season\">Сезон</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Без сезон</string>\n    <string name=\"episode\">Епизод</string>\n    <string name=\"episodes\">Епизоди</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string formatted=\"true\" name=\"episode_format\">%1$d %2$s</string>\n    <string name=\"season_short\">С</string>\n    <string name=\"episode_short\">Е</string>\n    <string name=\"no_episodes_found\">Няма намерени епизоди</string>\n    <string name=\"delete_file\">Изтрий файла</string>\n    <string name=\"delete\">Изтрий</string>\n    <string name=\"cancel\">Отказ</string>\n    <string name=\"pause\">Пауза</string>\n    <string name=\"resume\">Продължи</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">30</string>\n    <string formatted=\"true\" name=\"delete_message\">Това ще изтрие за постоянно %s\n\\nСигурни ли сте?</string>\n    <string formatted=\"true\" name=\"resume_time_left\">%dm\n\\nостава</string>\n    <string name=\"status_ongoing\">Продължава</string>\n    <string name=\"status_completed\">Завършен</string>\n    <string name=\"status\">Статус</string>\n    <string name=\"year\">Година</string>\n    <string name=\"rating\">Рейтинг</string>\n    <string name=\"duration\">Продължителност</string>\n    <string name=\"site\">Уебсайт</string>\n    <string name=\"synopsis\">Синопсис</string>\n    <string name=\"queued\">На опашката</string>\n    <string name=\"no_subtitles\">Без субтитри</string>\n    <string name=\"action_default\">По подразбиране</string>\n    <string name=\"free_storage\">Безплатно</string>\n    <string name=\"used_storage\">Използвано</string>\n    <string name=\"app_storage\">Приложения</string>\n    <string name=\"movies\">Филми</string>\n    <string name=\"tv_series\">Телевизионен сериал</string>\n    <string name=\"cartoons\">Анимационни филми</string>\n    <string name=\"anime\">Аниме</string>\n    <string name=\"torrent\">Торенти</string>\n    <string name=\"documentaries\">Документални</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Азиатски драми</string>\n    <string name=\"livestreams\">На живо</string>\n    <string name=\"nsfw\">Разпоретини</string>\n    <string name=\"others\">други</string>\n    <string name=\"movies_singular\">Филм</string>\n    <string name=\"tv_series_singular\">Серия</string>\n    <string name=\"cartoons_singular\">Анимационен филм</string>\n    <string name=\"anime_singular\">Аниме</string>\n    <string name=\"ova_singular\">ОВА</string>\n    <string name=\"torrent_singular\">Торент</string>\n    <string name=\"documentaries_singular\">Документален филм</string>\n    <string name=\"asian_drama_singular\">Азиатска драма</string>\n    <string name=\"live_singular\">Поток на живо</string>\n    <string name=\"nsfw_singular\">Разпоретинa</string>\n    <string name=\"other_singular\">Видео</string>\n    <string name=\"source_error\">Грешка в източника</string>\n    <string name=\"remote_error\">Дистанционна грешка</string>\n    <string name=\"render_error\">Грешка в рендъра</string>\n    <string name=\"unexpected_error\">Неочаквана грешка на плеъра</string>\n    <string name=\"storage_error\">Грешка при изтегляне, проверете разрешенията за съхранение</string>\n    <string name=\"episode_action_chromecast_episode\">Епизод за Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast огледало</string>\n    <string name=\"episode_action_play_in_app\">Пусни в приложението</string>\n    <string name=\"episode_action_play_in_format\">Пусни в %s</string>\n    <string name=\"episode_action_auto_download\">Автоматично изтегляне</string>\n    <string name=\"episode_action_download_mirror\">Изтегляне на огледало</string>\n    <string name=\"episode_action_reload_links\">Презареждане на връзки</string>\n    <string name=\"episode_action_download_subtitle\">Изтегляне на субтитри</string>\n    <string name=\"show_hd\">покажи качество</string>\n    <string name=\"show_dub\">Покажи дублаж</string>\n    <string name=\"show_sub\">Покажи субтитри</string>\n    <string name=\"show_title\">Заглавие</string>\n    <string name=\"poster_ui_settings\">Превключване на елементите на потребителския интерфейс на плаката</string>\n    <string name=\"no_update_found\">Няма намерена актуализация</string>\n    <string name=\"check_for_update\">Проверка за актуализация</string>\n    <string name=\"video_lock\">Заключен</string>\n    <string name=\"video_aspect_ratio_resize\">Преоразмеряване</string>\n    <string name=\"video_source\">Източник</string>\n    <string name=\"video_skip_op\">Пропусни</string>\n    <string name=\"dont_show_again\">Не показвай отново</string>\n    <string name=\"skip_update\">Пропуснете тази актуализация</string>\n    <string name=\"update\">Актуализация</string>\n    <string name=\"watch_quality_pref\">Предпочитано качество за гледане (през WiFi)</string>\n    <string name=\"limit_title\">Максимален брой знаци за заглавие във видеоплейъра</string>\n    <string name=\"limit_title_rez\">Разделителна способност на видео плейъра</string>\n    <string name=\"video_buffer_size_settings\">Размер на видео буфера</string>\n    <string name=\"video_buffer_length_settings\">Дължина на видео буфера</string>\n    <string name=\"video_buffer_disk_settings\">Видео кеш на диск</string>\n    <string name=\"video_buffer_clear_settings\">Изчистете кеша за видео и изображения</string>\n    <string name=\"video_ram_description\">Причинява сривове, ако е зададено твърде високо на устройства с малко памет, като Android TV.</string>\n    <string name=\"video_disk_description\">Причинява проблеми, ако е зададено твърде високо на устройства с малко място за съхранение, като Android TV.</string>\n    <string name=\"dns_pref\">DNS през HTTPS</string>\n    <string name=\"dns_pref_summary\">Полезно за заобикаляне на блокирания от ISP доставчик</string>\n    <string name=\"add_site_pref\">Сайт за клониране</string>\n    <string name=\"remove_site_pref\">Премахване на сайта</string>\n    <string name=\"add_site_summary\">Добавяне на клонинг на съществуващ сайт с различен URL</string>\n    <string name=\"download_path_pref\">Път за изтегляне</string>\n    <string name=\"nginx_url_pref\">URL адрес на сървър NGINX</string>\n    <string name=\"display_subbed_dubbed_settings\">Показване на дублирани/субирани аниме</string>\n    <string name=\"resize_fit\">Побиране в екрана</string>\n    <string name=\"resize_fill\">Разтягане</string>\n    <string name=\"resize_zoom\">Мащабиране</string>\n    <string name=\"legal_notice\">Опровержение</string>\n    <string name=\"category_general\">Общ</string>\n    <string name=\"random_button_settings\">Случаен бутон</string>\n    <string name=\"random_button_settings_desc\">Показване на произволен бутон на началната страница и библиотека</string>\n    <string name=\"provider_lang_settings\">Езици на доставчика</string>\n    <string name=\"app_layout\">Оформление на приложението</string>\n    <string name=\"preferred_media_settings\">Предпочитана медия</string>\n    <string name=\"enable_nsfw_on_providers\">Активирайте разпоретините на поддържани доставчици</string>\n    <string name=\"subtitles_encoding\">Кодиране на субтитрите</string>\n    <string name=\"category_providers\">Доставчици</string>\n    <string name=\"category_ui\">Оформление</string>\n    <string name=\"automatic\">Автоматично</string>\n    <string name=\"tv_layout\">ТВ оформление</string>\n    <string name=\"phone_layout\">Оформление като телефон</string>\n    <string name=\"emulator_layout\">Оформление като емулатор</string>\n    <string name=\"primary_color_settings\">Основен цвят</string>\n    <string name=\"app_theme_settings\">Тема на приложението</string>\n    <string name=\"bottom_title_settings\">Местоположение на заглавието на плаката</string>\n    <string name=\"bottom_title_settings_des\">Поставете заглавието под плаката</string>\n    <string name=\"example_password\">парола123</string>\n    <string name=\"example_username\">Потребителско име</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">НовоИмеНаСайт</string>\n    <string name=\"example_site_url\">example.com</string>\n    <string name=\"example_lang_name\">Езиков код (en)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">Акаунт</string>\n    <string name=\"logout\">Излизане</string>\n    <string name=\"login\">Влизане</string>\n    <string name=\"switch_account\">Превключване на акаунт</string>\n    <string name=\"add_account\">Добавяне на акаунт</string>\n    <string name=\"create_account\">Създай акаунт</string>\n    <string name=\"add_sync\">Добавете проследяване</string>\n    <string formatted=\"true\" name=\"added_sync_format\">Добавен %s</string>\n    <string name=\"upload_sync\">Синхронизиране</string>\n    <string name=\"sync_score\">Оценен</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string formatted=\"true\" name=\"authenticated_user\">%s удостоверен</string>\n    <string formatted=\"true\" name=\"authenticated_user_fail\">Не можах да вляза в %s</string>\n    <string name=\"none\">Нито един</string>\n    <string name=\"normal\">Нормално</string>\n    <string name=\"all\">Всичко</string>\n    <string name=\"max\">Макс</string>\n    <string name=\"min\">Мин</string>\n    <string name=\"subtitles_outline\">Контур</string>\n    <string name=\"subtitles_depressed\">Удвоени</string>\n    <string name=\"subtitles_shadow\">Сянка</string>\n    <string name=\"subtitles_raised\">Повдигнати</string>\n    <string name=\"subtitle_offset\">Синхронизиране на суб</string>\n    <string name=\"subtitle_offset_hint\">1000.ms</string>\n    <string name=\"subtitle_offset_title\">Забавяне на субтитрите</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Използвайте това, ако субтитрите се показват %d ms твърде рано</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Използвайте това, ако субтитрите се показват %d ms твърде късно</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Без забавяне на субтитрите</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">Бързата кафява лисица прескача мързеливото куче</string>\n    <string name=\"recommended\">Препоръчва се</string>\n    <string formatted=\"true\" name=\"player_loaded_subtitles\">Заредено %s</string>\n    <string name=\"player_load_subtitles\">Зареди от файл</string>\n    <string name=\"player_load_subtitles_online\">Зареди от Интернет</string>\n    <string name=\"downloaded_file\">Изтеглен файл</string>\n    <string name=\"actor_main\">Главен</string>\n    <string name=\"actor_supporting\">Поддържащ</string>\n    <string name=\"actor_background\">Заден план</string>\n    <string name=\"home_source\">Източник</string>\n    <string name=\"home_random\">Случаен</string>\n    <string name=\"coming_soon\">Очаквайте скоро…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Снимка на плакат</string>\n    <string name=\"category_player\">Плеър</string>\n    <string name=\"resolution_and_title\">Резолюция и заглавие</string>\n    <string name=\"title\">Заглавие</string>\n    <string name=\"resolution\">Резолюция</string>\n    <string name=\"error_invalid_id\">Невалиден ID</string>\n    <string name=\"error_invalid_data\">Невалидни данни</string>\n    <string name=\"error_invalid_url\">Невалиден URL</string>\n    <string name=\"error\">Грешка</string>\n    <string name=\"subtitles_remove_captions\">Премахнете затворените надписи от субтитрите</string>\n    <string name=\"subtitles_remove_bloat\">Премахнете рекламирането в субтитрите</string>\n    <string name=\"subtitles_filter_lang\">Филтриране по предпочитан медиен език</string>\n    <string name=\"extras\">Екстри</string>\n    <string name=\"trailer\">Трейлър</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"referer\">Обратно към</string>\n    <string name=\"next\">Следващ</string>\n    <string name=\"provider_languages_tip\">Гледайте видеоклипове на тези езици</string>\n    <string name=\"previous\">Предишен</string>\n    <string name=\"skip_setup\">Пропуснете настройката</string>\n    <string name=\"app_layout_subtext\">Променете външния вид на приложението, за да отговаря на вашето устройство</string>\n    <string name=\"preferred_media_subtext\">Какво искате да видите</string>\n    <string name=\"setup_done\">Край</string>\n    <string name=\"extensions\">Разширения</string>\n    <string name=\"add_repository\">Добавяне на хранилище</string>\n    <string name=\"repository_name_hint\">Име на хранилището (по избор)</string>\n    <string name=\"repository_url_hint\">URL адрес на хранилището или кратък код</string>\n    <string name=\"plugin_loaded\">Приставката е заредена</string>\n    <string name=\"plugin_deleted\">Приставката е изтрита</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Не може да зареди %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Започна да изтегля %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Изтеглено %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Всички %s вече са изтеглени</string>\n    <string name=\"batch_download\">Пакетно изтегляне</string>\n    <string name=\"plugin_singular\">Плъгин</string>\n    <string name=\"plugin\">Плъгини</string>\n    <string name=\"delete_repository_plugins\">Това също ще изтрие всички хранилища за плъгини</string>\n    <string name=\"delete_repository\">Изтриване на хранилище</string>\n    <string name=\"setup_extensions_subtext\">Изтеглете списъка със сайтове, които искате да използвате</string>\n    <string formatted=\"true\" name=\"plugins_downloaded\">Изтеглено: %d</string>\n    <string formatted=\"true\" name=\"plugins_disabled\">Деактивирано: %d</string>\n    <string formatted=\"true\" name=\"plugins_not_downloaded\">Не е изтеглено: %d</string>\n    <string formatted=\"true\" name=\"plugins_updated\">Актуализирани %d плъгини</string>\n    <string name=\"blank_repo_message\">CloudStream няма инсталирани сайтове по подразбиране. Трябва да инсталирате сайтовете от хранилища.\n\\n\n\\nПрисъединете се към нашия Дискорд или потърсете онлайн.</string>\n    <string name=\"view_public_repositories_button\">Вижте хранилищата на общността</string>\n    <string name=\"view_public_repositories_button_short\">Публичен списък</string>\n    <string name=\"uppercase_all_subtitles\">Всички субтитри с главни букви</string>\n    <string name=\"download_all_plugins_from_repo\">Предупреждение: CloudStream 3 не носи отговорност за използването на трети страни разширения и не предоставя поддръжка за тях!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Деактивиран)</string>\n    <string name=\"tracks\">Потоци</string>\n    <string name=\"audio_tracks\">Аудио потоци</string>\n    <string name=\"video_tracks\">Видео потоци</string>\n    <string name=\"apply_on_restart\">Приложете при рестартиране.</string>\n    <string name=\"safe_mode_title\">Безопасен режим включен</string>\n    <string name=\"safe_mode_description\">Всички разширения бяха изключени поради срив, за да ви помогне да намерите това, което създава проблеми.</string>\n    <string name=\"safe_mode_crash_info\">Вижте информация за срива</string>\n    <string formatted=\"true\" name=\"extension_rating\">Оценка: %s</string>\n    <string name=\"extension_description\">Описание</string>\n    <string name=\"extension_version\">Версия</string>\n    <string name=\"extension_status\">Статус</string>\n    <string name=\"extension_size\">Размер</string>\n    <string name=\"extension_authors\">Автори</string>\n    <string name=\"extension_types\">Поддържани</string>\n    <string name=\"extension_language\">език</string>\n    <string name=\"extension_install_first\">Първо инсталирайте разширението</string>\n    <string name=\"hls_playlist\">HLS плейлист</string>\n    <string name=\"player_pref\">Предпочитан видео плеър</string>\n    <string name=\"player_settings_play_in_app\">Вътрешен плеър</string>\n    <string name=\"app_not_found_error\">Приложението не е намерено</string>\n    <string name=\"automatic_plugin_download\">Автоматично изтегли добавки</string>\n    <string name=\"all_languages_preference\">Всички езици</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Пропусни %s</string>\n    <string name=\"skip_type_op\">Отваряне</string>\n    <string name=\"skip_type_ed\">Затваряне</string>\n    <string name=\"skip_type_recap\">Резюме</string>\n    <string name=\"history\">История</string>\n    <string name=\"clipboard_too_large\">Твърде много текст. Не може да се запази в клипборда.</string>\n    <string name=\"action_mark_as_watched\">Маркирай като гледано</string>\n    <string name=\"confirm_exit_dialog\">Сигурни ли сте, че искате да излезете?</string>\n    <string name=\"yes\">Да</string>\n    <string name=\"no\">Не</string>\n    <string name=\"update_notification_installing\">Инсталиране на актуализация на приложението…</string>\n    <string name=\"update_notification_failed\">Не можа да се инсталира новата версия на приложението</string>\n    <string name=\"enable_skip_op_from_database_des\">Покажи изскачащи прозорци при отваряне/затваряне</string>\n    <string name=\"update_notification_downloading\">Изтегля се актуализация на приложението…</string>\n    <string name=\"skip_type_mixed_op\">Смесено отваряне</string>\n    <string name=\"skip_type_mixed_ed\">Смесено затваряне</string>\n    <string name=\"skip_type_creddits\">Кредити</string>\n    <string name=\"skip_type_intro\">въведение</string>\n    <string name=\"clear_history\">Изчистване на историята</string>\n    <string name=\"automatic_plugin_download_summary\">Автоматично инсталиране на всички все още неинсталирани добавки от добавени хранилища.</string>\n    <string name=\"apk_installer_settings\">APK Инсталатор</string>\n    <string name=\"apk_installer_settings_des\">Някои телефони не поддържат новия пакет за инсталиране. Опитайте предпоследената опция, ако актуализациите не се инсталират.</string>\n    <string name=\"play_trailer_button\">Пусни трейлър</string>\n    <string name=\"pref_category_links\">Връзки</string>\n    <string name=\"pref_category_app_updates\">Актуализации на приложението</string>\n    <string name=\"pref_category_extensions\">Разширения</string>\n    <string name=\"pref_category_actions\">Действия</string>\n    <string name=\"apk_installer_legacy\">Предишна версия</string>\n    <string name=\"apk_installer_package_installer\">Пакетен инсталатор</string>\n    <string name=\"pref_category_player_features\">Възможности на плеъра</string>\n    <string name=\"pref_category_defaults\">По подразбиране</string>\n    <string name=\"pref_category_looks\">Изгледи</string>\n    <string name=\"pref_category_subtitles\">Субтитри</string>\n    <string name=\"pref_category_ui_features\">Възможности</string>\n    <string name=\"redo_setup_process\">Повторете процеса на настройка</string>\n    <string name=\"pref_category_backup\">Архивиране</string>\n    <string name=\"pref_category_cache\">Кеш</string>\n    <string name=\"pref_category_gestures\">Жестове</string>\n    <string name=\"pref_category_player_layout\">Шаблон</string>\n    <string name=\"plugin_downloaded\">Приставката е изтеглена</string>\n    <string name=\"delayed_update_notice\">Приложението ще се актуализира при изход от него</string>\n    <string name=\"update_started\">Започна Актуализация</string>\n    <string name=\"action_remove_from_watched\">Премахване от гледани</string>\n    <string name=\"search_poster_img_des\">Постер</string>\n    <string name=\"browser\">Браузър</string>\n    <string name=\"test_log\">Регистър</string>\n    <string name=\"test_passed\">Преминато</string>\n    <string name=\"test_failed\">Неуспешен</string>\n    <string name=\"library\">Библиотека</string>\n    <string name=\"watch_quality_pref_data\">Предпочитано качество за гледане (Мобилни данни)</string>\n    <string name=\"start\">Старт</string>\n    <string name=\"automatic_plugin_download_mode_title\">Избери режим, да филтрира изтегляне на добавки</string>\n    <string name=\"jsdelivr_proxy\">raw.githubusercontent.com прокси</string>\n    <string name=\"jsdelivr_enabled\">Неуспешно свързване с GitHub. Включване на jsDelivr прокси…</string>\n    <string name=\"jsdelivr_proxy_summary\">Заобикали блокирането на GitHub адреси с помощта на jsDelivr. Може да доведе до забавяне на актуализациите с няколко дни.</string>\n    <string name=\"category_provider_test\">Тест на доставчик</string>\n    <string name=\"disable\">Деактивиране</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"pref_category_bypass\">Заобикаляне на интернет доставчик</string>\n    <string name=\"no_plugins_found_error\">Няма намерени добавки в този архив</string>\n    <string name=\"no_repository_found_error\">Архивът не е намерен, проверете уеб-адреса и пробвайте с VPN</string>\n    <string name=\"sort_rating_desc\">Оценка (От висока до ниска)</string>\n    <string name=\"sort_by\">Сортирай по</string>\n    <string name=\"stop\">Стоп</string>\n    <string name=\"restart\">Рестартиране</string>\n    <string name=\"sort\">Сортиране</string>\n    <string name=\"sort_rating_asc\">Оценка (от ниска до висока)</string>\n    <string name=\"subscription_new\">Абонирани сте за %s</string>\n    <string name=\"subscription_in_progress_notification\">Обновяване на абонирани сериали</string>\n    <string name=\"mobile_data\">Мобилни данни</string>\n    <string name=\"subscription_list_name\">Абонаменти</string>\n    <string name=\"revert\">Връщане</string>\n    <string name=\"select_library\">Избиране на библиотека</string>\n    <string name=\"subscription_deleted\">Отписахте се от %s</string>\n    <string name=\"profiles\">Профили</string>\n    <string name=\"sort_alphabetical_z\">По азбучен ред (Z до A)</string>\n    <string name=\"unable_to_inflate\">Създаването на потребителският интерфейс е неуспешно, това е ГОЛЯМ БЪГ и трябва да бъде докладван незабавно %s</string>\n    <string name=\"edit\">Редактиране</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"help\">Помощ</string>\n    <string name=\"empty_library_logged_in_message\">Списъкът е празен. Опитайте да превключите на друг.</string>\n    <string name=\"profile_number\">Профил %d</string>\n    <string name=\"sort_alphabetical_a\">По азбучен ред (A до Z)</string>\n    <string name=\"open_with\">Отваряне с</string>\n    <string name=\"empty_library_no_accounts_message\">Вашата библиотека е празна :(\n\\nВпишете се в акаунт с библиотеки или добавете сериали в локалната Ви библиотека.</string>\n    <string name=\"use\">Използване</string>\n    <string name=\"subscription_episode_released\">Епизод %d е публикуван!</string>\n    <string name=\"safe_mode_file\">Намерен е файл за безопасен режим!\n\\nНяма да се зареждат никакви разширения при стартиране, докато файлът не бъде премахнат.</string>\n    <string name=\"already_voted\">Вече сте гласували</string>\n    <string name=\"set_default\">Задаване по подразбиране</string>\n    <string name=\"pin_error_length\">ПИН трябва да е 4 символа</string>\n    <string name=\"sort_updated_old\">Актуализирано (от старо към ново)</string>\n    <string name=\"profile_background_des\">Фон на профила</string>\n    <string name=\"favorites_list_name\">Любими</string>\n    <string name=\"favorite_removed\">%s премахнати от любими</string>\n    <string name=\"action_add_to_favorites\">Добави в любими</string>\n    <string name=\"action_remove_from_favorites\">Премахване от любими</string>\n    <string name=\"enter_pin\">Въведи ПИН код</string>\n    <string name=\"pin\">ПИН</string>\n    <string name=\"pin_error_incorrect\">Неверен ПИН. Моля опитайте отново.</string>\n    <string name=\"select_an_account\">Избери профил</string>\n    <string name=\"logged_account\" formatted=\"true\">Вписан като %s</string>\n    <string name=\"skip_startup_account_select_pref\">Пропуснете избора на акаунт при стартиране</string>\n    <string name=\"links_reloaded_toast\">Презаредени Линкове</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Вкарай ПИН за %s</string>\n    <string name=\"action_subscribe\">Абонирай се</string>\n    <string name=\"action_unsubscribe\">Отписване</string>\n    <string name=\"duplicate_title\">Открит е Потенциален дубликат</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Показан играч - сума за търсене</string>\n    <string name=\"qualities\">Качества</string>\n    <string name=\"rotate_video\">Завърти</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Скрит играч - сума за търсене</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Сумата за търсене, използвана, когато играчът е скрит</string>\n    <string name=\"sort_updated_new\">Актуализирано (от ново към старо)</string>\n    <string name=\"quality_profile_help\">Тук можете да промените начина на подреждане на източниците. Ако даден видеоклип има по-висок приоритет, той ще се показва по-високо в избора на източник. Сборът от приоритета на източника и приоритета на качеството е приоритетът на видеото.\n\\n\n\\nИзточник A: 3\n\\nКачество B: 7\n\\nЩе има комбиниран видео приоритет от 10.\n\\n\n\\nЗАБЕЛЕЖКА: Ако сумата е 10 или повече, играчът автоматично ще пропусне зареждането, когато тази връзка се зареди!</string>\n    <string name=\"duplicate_replace\">Замени</string>\n    <string name=\"duplicate_replace_all\">Замени Всички</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Изглежда, че потенциално дублиран елемент вече съществува във вашата библиотека: „%s“.\n\\n\n\\nИскате ли все пак да добавите този елемент, да замените съществуващия или да отмените действието?</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Във вашата библиотека са намерени потенциални дублиращи се елементи:\n\\n\n\\n%s\n\\n\n\\nИскате ли все пак да добавите този елемент, да замените съществуващите или да отмените действието?</string>\n    <string name=\"lock_profile\">Заключи Профил</string>\n    <string name=\"enter_current_pin\">Вкарай Сегашен ПИН</string>\n    <string name=\"manage_accounts\">Управлявай Профили</string>\n    <string name=\"edit_account\">Редактирай профил</string>\n    <string name=\"use_default_account\">Използвай Акаунт по Подразбиране</string>\n    <string name=\"rotate_video_desc\">Показване на бутон за превключване за ориентация на екрана</string>\n    <string name=\"backup_frequency\">Честота на запазване</string>\n    <string name=\"favorite_added\">%s добавени в любими</string>\n    <string name=\"duplicate_add\">Добави</string>\n    <string name=\"auto_rotate_video_desc\">Разрешете автоматичното превключване на ориентацията на екрана въз основа на ориентацията на видеото</string>\n    <string name=\"auto_rotate_video\">Автоматично завъртане</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Използваният размер на превъртане, когато плеърът е видим</string>\n    <string name=\"test_extensions\">Тествай всички добавки</string>\n    <string name=\"subscribe_tooltip\">Известие за нов епизод</string>\n    <string name=\"result_search_tooltip\">Търси в други екстеншъни</string>\n    <string name=\"recommendations_tooltip\">Покажи предложения</string>\n    <string name=\"speed_setting_summary\">Добавя опция за промяна на скоростта в плеъра</string>\n    <string name=\"test_extensions_summary\">Този тест е направен за програмисти и не проверява работата на никакви добавки.</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Предстоящо в %s</string>\n    <string name=\"repo_copy_label\">Име на хранилището и URL адрес</string>\n    <string name=\"toast_copied\">копирани!</string>\n    <string name=\"delete_format\" formatted=\"true\">Изтриване (%1$d | %2$s)</string>\n    <string name=\"delete_files\">Изтриване на файлове</string>\n    <string name=\"play_from_beginning_img_des\">Пусни от самото начало</string>\n    <string name=\"open_local_video\">Отваряне на местно видео</string>\n    <string name=\"downloads_empty\">В момента няма изтегляния.</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Сезон %1$d Епизод %2$d ще бъде пуснат на</string>\n    <string name=\"downloads_delete_select\">Изберете елементите за изтриване</string>\n    <string name=\"offline_file\">Наличен за гледане офлайн</string>\n    <string name=\"select_all\">Изберете всички</string>\n    <string name=\"deselect_all\">Премахване на избора на всички</string>\n    <string name=\"test_warning\">Предупреждение</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Сигурни ли сте, че искате да изтриете трайно следните елементи?\\n\\n %s</string>\n    <string name=\"encoding_error\">Проблем с кодирането</string>\n    <string name=\"unsupported_error\">Неподдържана грешка</string>\n    <string name=\"subtitles_from_online\">Онлайн</string>\n    <string name=\"volume_exceeded_100\">Обемът надвиши 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Плъзнете нагоре отново, за да преминете над 100%</string>\n    <string name=\"player_notification_channel_description\">Известие на плейъра за контролиране на възпроизвеждането от фона</string>\n    <string name=\"subtitles_from_embedded\">Вграден</string>\n    <string name=\"all_subtitles_bold\">Направете всички субтитри удебелени</string>\n    <string name=\"background_radius\">Радиус на фона</string>\n    <string name=\"preview_seekbar\">Преглед на лентата за търсене</string>\n    <string name=\"sort_episodes_number_asc\">Епизод (възходящо)</string>\n    <string name=\"sort_episodes_rating_low_high\">Оценка (най-ниска)</string>\n    <string name=\"sort_button_episode\">Епизод %s</string>\n    <string name=\"backup_path_title\">Местоположение на папката за архивиране</string>\n    <string name=\"confirm_before_exiting_title\">Потвърдете преди да излезете</string>\n    <string name=\"subs_edge_size\">Размер на ръба</string>\n    <string name=\"software_decoding\">Софтуерно декодиране</string>\n    <string name=\"confirm_before_exiting_desc\">Покажи диалог преди да затвориш приложението</string>\n    <string name=\"show\">Покажи</string>\n    <string name=\"dont_show\">Не показвай</string>\n    <string name=\"update_plugins\">Актуализирай плъгини</string>\n    <string name=\"update_plugins_manually\">Актуализирайте плъгините ръчно</string>\n    <string name=\"sort_release_date_new\">Дата на издаване (от нова към стара)</string>\n    <string name=\"hide_player_control_names\">Скрий имената на контролните елементи на играча</string>\n    <string name=\"sort_episodes_rating_high_low\">Оценка (най-висока)</string>\n    <string name=\"sort_episodes_date_newest\">Дата на излъчване (най-нова)</string>\n    <string name=\"sort_button_rating\">Оценка %s</string>\n    <string name=\"preview_seekbar_desc\">Активирай миниатюра за преглед на лентата за търсене</string>\n    <string name=\"custom\">По избор</string>\n    <string name=\"sort_release_date_old\">Дата на издаване (от стара към нова)</string>\n    <string name=\"torrent_preferred_media\">Активирай торент в Настройки/Доставчици/Предпочитани медии</string>\n    <string name=\"plugins_updated_manually\">Успешно актуализиран/и %d плъгин/а!</string>\n    <string name=\"all_subtitles_italic\">Направете всички субтитри наклонени</string>\n    <string name=\"sort_episodes_date_oldest\">Дата на излъчване (най-стара)</string>\n    <string name=\"sort_button_date\">Дата %s</string>\n    <string name=\"no_plugins_updated_manually\">Няма актуализирани плъгини.</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Are you sure you wСигурни ли сте, че искате трайно да изтриете всички епизоди от тази поредица?\\n\\n%s</string>\n    <string name=\"torrent_not_accepted\">Рестартирайте приложението и приемете изскачащото съобщение за Stream Torrent, за да продължите.</string>\n    <string name=\"software_decoding_desc\">Софтуерното декодиране позволява на плейъра да възпроизвежда видео файлове, които не се поддържат от телефона ви, но може да причини забавяне или нестабилно възпроизвеждане при висока резолюция</string>\n    <string name=\"player_notification_channel_name\">Известия на плейъра</string>\n    <string name=\"sort_episodes_number_desc\">Епизод (низходящо)</string>\n    <string name=\"starting_plugin_update_manually\">Започва процесът на актуализация на плъгините!</string>\n    <string name=\"player_load_one_subtitle_online\">Зареди първия наличен</string>\n    <string name=\"no_subtitles_loaded\">Няма заредени субтитри още</string>\n    <string name=\"audio_singluar\">Звук</string>\n    <string name=\"podcast_singluar\">Подкаст</string>\n    <string name=\"auth_locally\">Автентикация локално</string>\n    <string name=\"biometric_setting\">Заключване с биометрия</string>\n    <string name=\"open_downloaded_repo\">Отвори хранилище</string>\n    <string name=\"reset_btn\">Нулиране</string>\n    <string name=\"device_pin_expired_message\">PIN кодът е изтекъл !</string>\n    <string name=\"cs3wiki\">CloudStream Уики</string>\n    <string name=\"password_pin_authentication_title\">Удостоверяване с парола/PIN</string>\n    <string name=\"custom_media_singluar\">Медия</string>\n    <string name=\"audio_book_singular\">Аудиокнига</string>\n    <string name=\"dismiss\">Отхвърли</string>\n    <string name=\"biometric_setting_summary\">Отключете приложението с отпечатък, Face ID, PIN, шаблон или парола.</string>\n    <string name=\"delete_plugin\">Изтриване на плъгин</string>\n    <string name=\"biometric_prompt_description\">След няколко неуспешни опита, прозорецът ще се затвори. Просто рестартирайте приложението, за да опитате отново.</string>\n    <string name=\"biometric_warning\">Вашите данни от CloudStream бяха архивирани. Въпреки че възможността за това е много малка, всички устройства могат да се държат по различен начин. В редките случаи, когато бъдете блокирани от достъпа до приложението, изчистете напълно данните на приложението и възстановете от архив. Извиняваме се за всяко неудобство, което може да възникне от това.</string>\n    <string name=\"device_pin_error_message\">Не може да се получи PIN кода на устройството, опитайте локално удостоверяване</string>\n    <string name=\"torrent_info\">Това видео е торент, което означава, че вашата видео дейност може да бъде проследена.\\nУверете се, че разбирате принципите на торентирането, преди да продължите.</string>\n    <string name=\"pref_category_security\">Сигурност</string>\n    <string name=\"ok\">Добре</string>\n    <string name=\"app_unrestricted_toast\">Използването на батерия от приложението вече е настроено като неограничено</string>\n    <string name=\"app_info_intent_error\">Не може да се отвори информацията за приложението CloudStream.</string>\n    <string name=\"battery_dialog_title\">Изключи оптимизация на батерията</string>\n    <string name=\"biometric_authentication_title\">Отключи CloudStream</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\nоставащи</string>\n    <string name=\"clipboard_permission_error\">Грешка при достъп до клипборда, моля опитайте отново.</string>\n    <string name=\"speech_recognition_unavailable\">Разпознаването на реч не е налично</string>\n    <string name=\"begin_speaking\">Започнете да говорите…</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Сигурни ли сте, че искате да изтриете завинаги следните епизоди в %1$s?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Също така ще изтриете завинаги всички епизоди от следните серии:\\n\\n%s</string>\n    <string name=\"episode_action_cast_mirror\">Огледално излъчването</string>\n    <string name=\"pref_category_accounts\">Акаунти</string>\n    <string name=\"clipboard_unknown_error\">Грешка при копиране, моля копирайте logcat и се свържете с поддръжката на приложението.</string>\n    <string name=\"biometric_unsupported\">Биометричното удостоверяване не се поддържа на това устройство</string>\n    <string name=\"device_pin_url_message\">Посетете <b>%s</b> на вашия смартфон или компютър и въведете горния код</string>\n    <string name=\"device_pin_counter_text\">Кодът изтича след %1$dm %2$ds</string>\n    <string name=\"player_settings_select_cast_device\">Изберете устройство за излъчване</string>\n    <string name=\"music_singlar\">Музика</string>\n    <string name=\"favorite\">Любим</string>\n    <string name=\"battery_dialog_message\">За да гарантираме непрекъснати изтегляния и известия за абонирани телевизионни шоута, CloudStream се нуждае от разрешение да работи в фонов режим. Като натиснете ДОБРЕ, ще видите диалогов прозорец с искане. Моля, натиснете \\\"Позволи\\\".\\n\\nМоля, имайте предвид, че това разрешение не означава, че CS3 ще изтощава батерията ви. То ще работи във фонов режим само когато е необходимо, като например при получаване на известия или изтегляне на видеоклипове от официални разширения.</string>\n    <string name=\"qr_image\">Изображение на QR код</string>\n    <string name=\"unfavorite\">Премахни от любими</string>\n    <string name=\"download_parallel_settings_des\">Колко различни елемента могат да бъдат изтеглени паралелно</string>\n    <string name=\"parallel_downloads\">Паралелни изтегляния</string>\n    <string name=\"concurrent_connections\">Едновременни връзки</string>\n    <string name=\"concurrent_connections_settings_des\">Колко едновременни връзки може да използва всяко изтегляне по време на самото изтегляне</string>\n    <string name=\"go_to_downloads\">Сваляния</string>\n    <string name=\"no_internet_connection\">Няма интернет връзка.\\n\\nМоля, свържете се с интернет и опитайте отново, или гледайте вашите изтегляния, докато сте офлайн.</string>\n    <string name=\"overscan_settings_des\">Променя границите на екрана</string>\n    <string name=\"overscan_settings\">Overscan</string>\n    <string name=\"poster_size_settings_des\">Променя размера на плакатите</string>\n    <string name=\"poster_size_settings\">Размер на плаката</string>\n    <string name=\"player_settings_always_ask\">Винаги изпращай запитване</string>\n    <string name=\"speedup_summary\">Задръжте, за да удвоите скоростта</string>\n    <string name=\"speedup_title\">Дълго задържане за смяна на скоростта</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+bn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"result_poster_img_des\">পোস্টার</string>\n    <string name=\"play_with_app_name\">ক্লাউডস্ট্রিম দিয়ে চালান</string>\n    <string name=\"title_home\">হোম</string>\n    <string name=\"cast_format\" formatted=\"true\">অভিনয়েঃ %s</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dদিন %2$dঘন্টা %3$dমিনিট</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dঘন্টা %2$dমিনিট</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d মিনিট</string>\n    <string name=\"episode_poster_img_des\">পর্বের পোস্টার</string>\n    <string name=\"home_main_poster_img_des\">মূল পোস্টার</string>\n    <string name=\"home_next_random_img_des\">পরবর্তী র‍্যান্ডম</string>\n    <string name=\"go_back_img_des\">ফিরে যান</string>\n    <string name=\"home_change_provider_img_des\">প্রোভাইডার পরিবর্তন করুন</string>\n    <string name=\"preview_background_img_des\">ব্যাকগ্রাউন্ড দেখান</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">গতি (%.2f গুণ)</string>\n    <string name=\"rated_format\" formatted=\"true\">মূল্যায়নঃ %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">নতুন আপডেট এসেছে!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">ফিলার</string>\n    <string name=\"duration_format\" formatted=\"true\">%d মিনিট</string>\n    <string name=\"app_name\">ক্লাউডস্ট্রিম</string>\n    <string name=\"title_search\">খুঁজুন</string>\n    <string name=\"title_downloads\">ডাউনলোডসমূহ</string>\n    <string name=\"title_settings\">সেটিংস</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s এপি %2$d</string>\n    <string name=\"next_episode_format\" formatted=\"true\">পর্ব %d মুক্তির তারিখ</string>\n    <string name=\"result_share\">শেয়ার</string>\n    <string name=\"result_open_in_browser\">ব্রাউজারে খুলুন</string>\n    <string name=\"result_tags\">জনরা</string>\n    <string name=\"search_hint\">খুঁজুন…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">খুঁজুন %s…</string>\n    <string name=\"play_movie_button\">মুভি চালান</string>\n    <string name=\"play_livestream_button\">স্ট্রিম চালান</string>\n    <string name=\"go_back\">পিছনে যান</string>\n    <string name=\"no_data\">কোন তথ্য নেই</string>\n    <string name=\"episode_more_options_des\">আরো অপশন</string>\n    <string name=\"next_episode\">পরবর্তী পর্ব</string>\n    <string name=\"skip_loading\">লোডিং বাদ দিন</string>\n    <string name=\"loading\">লোডিং…</string>\n    <string name=\"type_watching\">দেখা হচ্ছে</string>\n    <string name=\"type_on_hold\">স্থগিত</string>\n    <string name=\"type_completed\">শেষ</string>\n    <string name=\"type_dropped\">বাদ</string>\n    <string name=\"type_plan_to_watch\">দেখার ইচ্ছায়</string>\n    <string name=\"type_re_watching\">পুনরায় দেখা হচ্ছে</string>\n    <string name=\"play_torrent_button\">টরেন্ট স্ট্রিম করুন</string>\n    <string name=\"pick_source\">উৎসসমূহ</string>\n    <string name=\"pick_subtitle\">সাবটাইটেলসমূহ</string>\n    <string name=\"reload_error\">আবার সংযোগ দেওয়ার চেষ্টা করুন…</string>\n    <string name=\"play_episode\">পর্ব চালান</string>\n    <string name=\"download\">ডাউনলোড</string>\n    <string name=\"downloaded\">ডাউনলোড হয়েছে</string>\n    <string name=\"downloading\">ডাউনলোড চলছে</string>\n    <string name=\"download_paused\">ডাউনলোড স্থগিত</string>\n    <string name=\"download_started\">ডাউনলোড শুরু</string>\n    <string name=\"download_canceled\">ডাউনলোড বাদ</string>\n    <string name=\"download_done\">ডাউনলোড শেষ</string>\n    <string name=\"stream\">নেটওয়ার্ক স্ট্রিম</string>\n    <string name=\"error_loading_links_toast\">লিংক লোডিং ব্যর্থ</string>\n    <string name=\"app_dubbed_text\">ডাব</string>\n    <string name=\"app_subbed_text\">সাব</string>\n    <string name=\"popup_play_file\">ফাইল চালান</string>\n    <string name=\"popup_pause_download\">ডাউনলোড থামান</string>\n    <string name=\"home_more_info\">আরো তথ্য</string>\n    <string name=\"home_expanded_hide\">বন্ধ করুন</string>\n    <string name=\"home_play\">চালান</string>\n    <string name=\"home_info\">তথ্য</string>\n    <string name=\"error_bookmarks_text\">বুকমার্কসমূহ</string>\n    <string name=\"action_remove_from_bookmarks\">বাদ দিন</string>\n    <string name=\"action_add_to_bookmarks\">বুকমার্ক করুন</string>\n    <string name=\"sort_apply\">প্রয়োগ করুন</string>\n    <string name=\"sort_copy\">কপি করুন</string>\n    <string name=\"sort_close\">বন্ধ করুন</string>\n    <string name=\"sort_clear\">মুছুন</string>\n    <string name=\"sort_save\">সংরক্ষণ করুন</string>\n    <string name=\"player_speed\">ভিডিও এর গতি</string>\n    <string name=\"subs_outline_color\">ফন্ট আউটলাইন কালার</string>\n    <string name=\"subs_edge_type\">সাবটাইটেল এজের ধরণ</string>\n    <string name=\"subs_subtitle_elevation\">সাবটাইটেল এর উচ্চতা</string>\n    <string name=\"search_provider_text_providers\">প্রভাইডার অনুযায়ি খুঁজুন</string>\n    <string name=\"search_provider_text_types\">ধরণ অনুযায়ি খুঁজুন</string>\n    <string name=\"benene_count_text\">%d টা বেনেনা ডেভদের দেয়া হয়েছে</string>\n    <string name=\"benene_count_text_none\">কোন বেনেনা দেয়া হয়নি</string>\n    <string name=\"subs_download_languages\">ভাষা ডাউনলোড</string>\n    <string name=\"subs_subtitle_languages\">সাবটাইটেল ভাষা</string>\n    <string name=\"subs_hold_to_reset_to_default\">প্রাথমিক সেটিংসে নিতে চেপে রাখুন</string>\n    <string name=\"continue_watching\">দেখতে থাকুন</string>\n    <string name=\"action_remove_watching\">মুছুন</string>\n    <string name=\"action_open_watching\">আরো তথ্য</string>\n    <string name=\"torrent_plot\">বিবরণ</string>\n    <string name=\"normal_no_plot\">কোন প্লট পাওয়া যায়নি</string>\n    <string name=\"torrent_no_plot\">কোন বিবরণ পাওয়া যায়নি</string>\n    <string name=\"picture_in_picture\">পিকচার ইন পিকচার</string>\n    <string name=\"picture_in_picture_des\">অন্য অ্যাপ এর উপর ভিডিও চালাতে থাকুন</string>\n    <string name=\"player_size_settings\">প্লেয়ারের সাইজ পরিবর্তন বাটন</string>\n    <string name=\"download_failed\">ডাউনলোড ব্যর্থ</string>\n    <string name=\"download_storage_text\">ইন্টারনাল স্টোরেজ</string>\n    <string name=\"filter_bookmarks\">বুকমার্ক ফিল্টার করুন</string>\n    <string name=\"popup_delete_file\">ফাইল মুছুন</string>\n    <string name=\"popup_resume_download\">ডাউনলোড চালু করুন</string>\n    <string name=\"subtitles_settings\">সাবটাইটেল সেটিংস</string>\n    <string name=\"subs_background_color\">সাবটাইটেল ব্যাকগ্রাউন্ড কালার</string>\n    <string name=\"subs_text_color\">লেখার রং</string>\n    <string name=\"vpn_torrent\">এটা একটি টরেন্ট প্রভাইডার, ভিপিএন ব্যবহার করা উচিৎ</string>\n    <string name=\"subs_window_color\">উইন্ডো কালার</string>\n    <string name=\"subs_font_size\">ফন্টের সাইজ</string>\n    <string name=\"subs_font\">ফন্ট</string>\n    <string name=\"subs_auto_select_language\">স্বয়ংক্রিয় ভাষা</string>\n    <string name=\"subs_import_text\" formatted=\"true\">সাবটাইটেল ফন্ট যোগ করতে এখানে ফাইলটি রাখুন %s</string>\n    <string name=\"show_log_cat\">লগক্যাট দেখান 🐈</string>\n    <string name=\"vpn_might_be_needed\">এই প্রভাইডার ঠিকভাবে চালাতে ভিপিএন লাগতে পারে</string>\n    <string name=\"provider_info_meta\">প্রভাইডার থেকে মেটাডেটা পাওয়া যায়নি, যদি সম্পূর্ন সাইটে না পাওয়া যায় তাইলে ভিডিও লোড হবে না।</string>\n    <string name=\"history\">ইতিহাস</string>\n    <string name=\"player_subtitles_settings\">সাবটাইটেল</string>\n    <string name=\"player_subtitles_settings_des\">প্লেয়ার এর সাবটাইটেলসমূহের সেটিংস</string>\n    <string name=\"chromecast_subtitles_settings\">ক্রোমক্যাস্ট এ সাবটাইটেলসমূহ</string>\n    <string name=\"chromecast_subtitles_settings_des\">ক্রোমক্যাস্ট এ সাবটাইটেল সমূহের সেটিংস</string>\n    <string name=\"player_size_settings_des\">কালো প্রান্ত অপসারণ করুন</string>\n    <string name=\"search\">অনুসন্ধান করুন</string>\n    <string name=\"category_account\">অ্যাকাউন্টসমূহ এবং নিরাপত্তা</string>\n    <string name=\"double_tap_to_pause_settings_des\">বিরতি দিতে মাঝে দুইবার চাপুন</string>\n    <string name=\"use_system_brightness_settings\">সিস্টেম এর উজ্জ্বলতা ব্যবহার করুন</string>\n    <string name=\"play_trailer_button\">ট্রেইলার চালু করুন</string>\n    <string name=\"swipe_to_seek_settings_des\">ভিডিওর সময় নিয়ন্ত্রণ করতে, ডানে অথবা বামে সোয়াইপ করুন</string>\n    <string name=\"swipe_to_change_settings\">সেটিংস পরিবর্তন করতে সোয়াইপ করুন</string>\n    <string name=\"swipe_to_change_settings_des\">উজ্জ্বলতা বা ভলিউম পরিবর্তন করতে বাম বা ডান দিকে উপরে বা নিচে স্লাইড করুন</string>\n    <string name=\"autoplay_next_settings\">স্বয়ংক্রিয়ভাবে পরবর্তী পর্ব চালান</string>\n    <string name=\"autoplay_next_settings_des\">বর্তমান পর্বটি শেষ হলে পরের পর্বটি চালান</string>\n    <string name=\"double_tap_to_pause_settings\">থামতে দুইবার চাপুন</string>\n    <string name=\"backup_success\">ডাটা জমা হয়েছে</string>\n    <string name=\"backup_failed\">স্টোরেজ এর অনুমতি অনুপস্থিত। দয়া করে আবার চেষ্টা করুন।</string>\n    <string name=\"settings_info\">তথ্য</string>\n    <string name=\"show_trailers_settings\">ট্রেইলার প্রদর্শন করুন</string>\n    <string name=\"kitsu_settings\">কিটসু হতে পোস্টারসমূহ প্রদর্শন করুন</string>\n    <string name=\"automatic_plugin_updates\">স্বয়ংক্রিয়ভাবে প্লাগিন এর হালনাগাদ</string>\n    <string name=\"automatic_plugin_download\">স্বয়ংক্রিয়ভাবে প্লাগিনসমুহের ডাউনলোড</string>\n    <string name=\"category_updates\">হালনাগাদ ও ব্যাকআপ</string>\n    <string name=\"updates_settings\">অ্যাপ এর হালনাগাদ দেখান</string>\n    <string name=\"swipe_to_seek_settings\">খুঁজতে সোয়াইপ করুন</string>\n    <string name=\"search_poster_img_des\">পোস্টার</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"double_tap_to_seek_settings\">আগাতে ডবল ট্যাপ করুন</string>\n    <string name=\"eigengraumode_settings\">প্লেব্যাক এর গতি</string>\n    <string name=\"update_started\">আপডেট শুরু হয়েছে</string>\n    <string name=\"browser\">ব্রাউজার</string>\n    <string name=\"test_log\">লগ</string>\n    <string name=\"double_tap_to_seek_amount_settings\">প্লেয়ারে এগিয়ে যাওয়ার পরিমাণ (সেকেন্ডে)</string>\n    <string name=\"double_tap_to_seek_settings_des\">সামনে বা পিছনের দিকে যেতে ডান বা বাম দিকে দুবার আলতো চাপুন</string>\n    <string name=\"delete_file\">ফাইল ডিলিট</string>\n    <string name=\"subs_default_reset_toast\">মান ডিফল্ট এ রিসেট করুন</string>\n    <string name=\"updates_settings_des\">স্টার্টআপে নতুন আপডেটের জন্য স্বয়ংক্রিয়ভাবে অনুসন্ধান করুন</string>\n    <string name=\"movies_singular\">সিনেমা</string>\n    <string name=\"show_fillers_settings\">এনিমে এর ফিলার পর্ব দেখায়</string>\n    <string name=\"tv_series\">টিভি সিরিজ</string>\n    <string name=\"no_links_found_toast\">লিংক পাওয়া যায়নি</string>\n    <string name=\"benene_des\">চা খাওয়ানো হয়েছে</string>\n    <string name=\"go_forward_30\">+৩০</string>\n    <string name=\"movies\">সিনেমা</string>\n    <string name=\"discord\">ডিসকর্ডে যোগ দিন</string>\n    <string name=\"torrent\">টরেন্টস</string>\n    <string name=\"delete_message\" formatted=\"true\">এটি স্থায়ীভাবে মুছে ফেলা হবে %s\n\\nআপনি কি নিশ্চিত?</string>\n    <string name=\"pause\">থামুন</string>\n    <string name=\"go_back_30\">-৩০</string>\n    <string name=\"github\">গিটহাব</string>\n    <string name=\"free_storage\">ফ্রি</string>\n    <string name=\"backup_settings\">ডেটা ব্যাকআপ করুন</string>\n    <string name=\"restore_success\">ব্যাকআপ ফাইল লোড হয়েছে</string>\n    <string name=\"year\">বছর</string>\n    <string name=\"no_season\">কোন সিজন নেই</string>\n    <string name=\"play_episode_toast\">এপিসোড পরলে করুন</string>\n    <string name=\"resume\">শুরু করুন</string>\n    <string name=\"documentaries\">তথ্যচিত্র</string>\n    <string name=\"automatic_plugin_download_summary\">যোগ করা রিপোজিটরি থেকে এখনও ইনস্টল করা হয়নি এমন সব প্লাগইন স্বয়ংক্রিয়ভাবে ইনস্টল করুন।</string>\n    <string name=\"delete\">ডিলিট</string>\n    <string name=\"start\">শুরু</string>\n    <string name=\"cartoons\">কার্টুন</string>\n    <string name=\"apk_installer_settings_des\">কিছু ফোন নতুন প্যাকেজ ইনস্টলার সাপোর্ট করে না। যদি আপডেটগুলি ইনস্টল না হয় তবে পুরোনো পদ্ধতি ব্যবহার করে দেখুন।</string>\n    <string name=\"no_subtitles\">সাবটাইটেল নেই</string>\n    <string name=\"no_chromecast_support_toast\">এই প্রোভাইডার ক্রোমকাস্ট সাপোর্ট করে না</string>\n    <string name=\"advanced_search\">উন্নত অনুসন্ধান</string>\n    <string name=\"synopsis\">সারমর্ম</string>\n    <string name=\"used_storage\">ব্যবহৃত</string>\n    <string name=\"library\">লাইব্রেরী</string>\n    <string name=\"lightnovel\">আমাদের তৈরি ছোট উপন্যাস পড়ার অ্যাপ্লিকেশন</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%d মি\n\\nবাকি</string>\n    <string name=\"others\">অন্যান্য</string>\n    <string name=\"status_ongoing\">চলমান</string>\n    <string name=\"asian_drama\">এশিয়ান নাটক</string>\n    <string name=\"queued\">অপেক্ষা করছে</string>\n    <string name=\"episode\">পর্ব</string>\n    <string name=\"status\">অবস্থা</string>\n    <string name=\"use_system_brightness_settings_des\">অ্যাপের প্লেয়ারে অন্ধকার ওভারলে এর পরিবর্তে সিস্টেম ব্রাইটনেস ব্যবহার করুন</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">%s ফাইল থেকে ডেটা পুনরুদ্ধার করা ব্যর্থ হয়েছে</string>\n    <string name=\"no_episodes_found\">কোনো এপিসোড পাওয়া যায়নি</string>\n    <string name=\"test_failed\">ব্যর্থ হয়েছে</string>\n    <string name=\"advanced_search_des\">প্রোভাইডার অনুযায়ী আপনাকে পৃথক অনুসন্ধান ফলাফল দেয়</string>\n    <string name=\"tv_series_singular\">সিরিজ</string>\n    <string name=\"rating\">রেটিং</string>\n    <string name=\"redo_setup_process\">সেটআপ প্রক্রিয়া পুনরায় করুন</string>\n    <string name=\"benene\">ভাই এক কাপ চা খাওয়াও ☕</string>\n    <string name=\"restore_settings\">ব্যাকআপ থেকে ডেটা পুনরুদ্ধার করুন</string>\n    <string name=\"copy_link_toast\">ক্লিপবোর্ডে লিঙ্ক কপি করা হয়েছে</string>\n    <string name=\"status_completed\">দেখা শেষ</string>\n    <string name=\"anim\">আমাদের তৈরি Anime দেখার অ্যাপ্লিকেশন</string>\n    <string name=\"nsfw\">18+</string>\n    <string name=\"anime\">এনিমে</string>\n    <string name=\"pref_filter_search_quality\">অনুসন্ধান ফলাফলে নির্বাচিত ভিডিও কুয়ালিটি লুকান</string>\n    <string name=\"app_storage\">অ্যাপ</string>\n    <string name=\"livestreams\">লাইভস্ট্রিম</string>\n    <string name=\"apk_installer_settings\">APK ইনস্টলার</string>\n    <string name=\"duration\">সময়কাল</string>\n    <string name=\"app_language\">অ্যাপের ভাষা</string>\n    <string name=\"test_passed\">পাস করেছে</string>\n    <string name=\"episodes\">পর্ব</string>\n    <string name=\"backup_failed_error_format\">%s ব্যাক আপ করতে সমস্যা হয়েছে</string>\n    <string name=\"site\">সাইট</string>\n    <string name=\"season\">সিজন</string>\n    <string name=\"backup_frequency\">ব্যাকআপ ফ্রিকোয়েন্সি</string>\n    <string name=\"episode_sync_settings\">দেখার অগ্রগতি আপডেট করুন</string>\n    <string name=\"episode_sync_settings_des\">আপনার বর্তমান পর্বের অগ্রগতি স্বয়ংক্রিয়ভাবে সিঙ্ক করুন</string>\n    <string name=\"automatic_plugin_download_mode_title\">প্লাগইন ডাউনলোড ফিল্টার করতে মোড নির্বাচন করুন</string>\n    <string name=\"links_reloaded_toast\">লিঙ্ক পুনরায় লোড হয়েছে</string>\n    <string name=\"switch_account\">সুইচ অ্যাকাউন্ট</string>\n    <string name=\"legal_notice\">দাবিত্যাগ</string>\n    <string name=\"asian_drama_singular\">এশিয়ান ড্রামা</string>\n    <string name=\"video_source\">সোর্স</string>\n    <string name=\"pref_category_extensions\">এক্সটেনশন</string>\n    <string name=\"pref_category_links\">লিংকস</string>\n    <string name=\"nsfw_singular\">এনএসএফডব্লিউ</string>\n    <string name=\"episode_action_download_mirror\">ডাউনলোড মিরর</string>\n    <string name=\"unexpected_error\">অপ্রত্যাশিত প্লেয়ার এর সমস্যা</string>\n    <string name=\"episode_action_download_subtitle\">সাবটাইটেল ডাউনলোড করুন</string>\n    <string name=\"repo_copy_label\">রিপোজিটরির নাম এবং ইউ আর এল</string>\n    <string name=\"toast_copied\">কপি করা হয়েছে!</string>\n    <string name=\"video_disk_description\">অ্যান্ড্রয়েড টিভির মতো, কম মেমরির ডিভাইসে খুব বেশি সেট করা হলে সমস্যা করবে।</string>\n    <string name=\"add_site_pref\">ক্লোন সাইট</string>\n    <string name=\"pref_category_player_features\">প্লেয়ারের ফিচার</string>\n    <string name=\"app_theme_settings\">অ্যাপ থিম</string>\n    <string name=\"recommendations_tooltip\">রিকমেন্ডেশনগুলো দেখাও</string>\n    <string name=\"speed_setting_summary\">প্লেয়ারে গতির বিকল্প যোগ কর</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"cartoons_singular\">কার্টুন</string>\n    <string name=\"anime_singular\">এনিমে</string>\n    <string name=\"poster_ui_settings\">পোস্টারে ইউ আই উপাদান টগল করুন</string>\n    <string name=\"check_for_update\">আপডেট চেক করুন</string>\n    <string name=\"video_aspect_ratio_resize\">রিসাইজ</string>\n    <string name=\"video_skip_op\">ওপেনিং স্কিপ করুন</string>\n    <string name=\"video_buffer_disk_settings\">ডিক্সের ভিডিও ক্যাশ</string>\n    <string name=\"video_buffer_clear_settings\">ভিডিও এবং ইমেজ ক্যাশ পরিস্কার করুন</string>\n    <string name=\"video_ram_description\">অ্যান্ড্রয়েড টিভির মতো, কম মেমরির ডিভাইসে খুব বেশি সেট করা হলে ক্র্যাশ করবে</string>\n    <string name=\"dns_pref\">ডিএনএস ওভার এইচটিটিপিএস</string>\n    <string name=\"add_site_summary\">একটি ভিন্ন URL সহ একটি বিদ্যমান সাইটের, একটি ক্লোন যোগ করুন</string>\n    <string name=\"resize_fit\">স্ক্রিনে ফিট করুন</string>\n    <string name=\"pref_category_cache\">ক্যাশ</string>\n    <string name=\"pref_category_player_layout\">লেআউট</string>\n    <string name=\"tv_layout\">টিভি লেআউট</string>\n    <string name=\"example_username\">ব্যবহারকারীর নাম</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"example_site_name\">NewSiteName</string>\n    <string name=\"action_default\">ডিফল্ট</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"ova_singular\">ওভিয়ে</string>\n    <string name=\"torrent_singular\">টরেন্ট</string>\n    <string name=\"episode_action_chromecast_episode\">এপিসোড ক্রোমকাস্ট করুন</string>\n    <string name=\"episode_action_play_in_format\">প্লে হচ্ছে %s সময়ের মধ্যে</string>\n    <string name=\"episode_action_auto_download\">স্বয়ংক্রিয় ডাউনলোড</string>\n    <string name=\"show_title\">টাইটেল</string>\n    <string name=\"android_tv_interface_off_seek_settings\">প্লেয়ার দেখা যাচ্ছে - সিকের পরিমাণ</string>\n    <string name=\"remove_site_pref\">রিমুভ সাইট</string>\n    <string name=\"nginx_url_pref\">NGINX সার্ভারের ইউআরএল</string>\n    <string name=\"pref_category_bypass\">আইএসপি বাইপাস</string>\n    <string name=\"pref_category_android_tv\">অ্যান্ড্রয়েড টিভি</string>\n    <string name=\"enable_nsfw_on_providers\">সমর্থিত এক্সটেনশনগুলিতে NSFW সক্ষম করুন</string>\n    <string name=\"subtitles_encoding\">সাবটাইটেল এনকোডিং</string>\n    <string name=\"pref_category_looks\">দেখার ধরন</string>\n    <string name=\"pref_category_ui_features\">ফিচার সমূহ</string>\n    <string name=\"random_button_settings_desc\">হোমপেজ এবং লাইব্রেরিতে এলোমেলো বোতাম দেখান</string>\n    <string name=\"category_providers\">প্রদানকারী</string>\n    <string name=\"category_provider_test\">প্রদানকারী পরীক্ষা</string>\n    <string name=\"automatic\">স্বয়ংক্রিয়</string>\n    <string name=\"phone_layout\">ফোন লেআউট</string>\n    <string name=\"bottom_title_settings\">পোস্টার শিরোনামের অবস্থান</string>\n    <string name=\"bottom_title_settings_des\">পোস্টারের নীচে শিরোনাম রাখুন</string>\n    <string name=\"login\">প্রবেশ করুন</string>\n    <string name=\"create_account\">অ্যাকাউন্ট তৈরি করা</string>\n    <string name=\"add_account\">একাউন্ট যোগ করা</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">যখন প্লেয়ার হিডেন থাকবে তখন সিকের পরিমান</string>\n    <string name=\"episode_action_chromecast_mirror\">ক্রোমকাস্ট মিরর</string>\n    <string name=\"provider_lang_settings\">এক্সটেনশন ভাষা</string>\n    <string name=\"category_ui\">লেআউট</string>\n    <string name=\"pref_category_subtitles\">সাবটাইটেল</string>\n    <string name=\"pref_category_actions\">অ্যাকশন</string>\n    <string name=\"limit_title\">ভিডিও প্লেয়ারের টাইটেল এ সর্বোচ্চ ক্যারেক্টার</string>\n    <string name=\"documentaries_singular\">ডকুমেন্টারি</string>\n    <string name=\"app_layout\">অ্যাপ লেআউট</string>\n    <string name=\"other_singular\">ভিডিও</string>\n    <string name=\"pref_category_backup\">বেকাপ</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"subscribe_tooltip\">নতুন এপিসোডের নোটিফিকেশন</string>\n    <string name=\"result_search_tooltip\">অন্য এক্সটেনশনের মধ্যে খুঁজুন</string>\n    <string name=\"no_update_found\">কোন আপডেট পাওয়া যায়নি</string>\n    <string name=\"example_password\">password123</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">আসছে %s সময়ের মধ্যে</string>\n    <string name=\"cancel\">বাতিল করুন</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nঅবশিষ্ট</string>\n    <string name=\"live_singular\">লাইভ স্ট্রিম</string>\n    <string name=\"source_error\">সোর্স সমস্যা</string>\n    <string name=\"remote_error\">রিমোট সমস্যা</string>\n    <string name=\"render_error\">রেন্ডারের সমস্যা</string>\n    <string name=\"storage_error\">ডাউনলোডের সমস্যা, স্ট্রোরেজদের পারমিশন চেক করুন</string>\n    <string name=\"episode_action_play_in_app\">অ্যাপ এ প্লে করুন</string>\n    <string name=\"episode_action_reload_links\">লিংক রিলোড করুন</string>\n    <string name=\"show_hd\">কোয়ালিটি লেবেল</string>\n    <string name=\"show_sub\">সাব লেবেল</string>\n    <string name=\"show_dub\">ডাব লেবেল</string>\n    <string name=\"video_lock\">লক</string>\n    <string name=\"dont_show_again\">আর দেখাবেন না</string>\n    <string name=\"skip_update\">এই আপডেট স্কিপ করুন</string>\n    <string name=\"update\">আপডেট</string>\n    <string name=\"watch_quality_pref\">ওয়াইফাই তে যে কোয়ালিটিতে দেখতে চান</string>\n    <string name=\"watch_quality_pref_data\">মোবাইল ডাটায় যে কোয়ালিটিতে দেখতে চান</string>\n    <string name=\"limit_title_rez\">ভিডিও প্লেয়ারে রেজুলেশন</string>\n    <string name=\"video_buffer_size_settings\">ভিডিও বাফার সাইজ</string>\n    <string name=\"video_buffer_length_settings\">ভিডিও বাফার লেনথ</string>\n    <string name=\"dns_pref_summary\">যখন আইএসপি ব্লক করবে তখন কার্যকরী</string>\n    <string name=\"jsdelivr_proxy\">গিডহাব প্রক্সি</string>\n    <string name=\"download_path_pref\">ডাউনলোডের পথ</string>\n    <string name=\"display_subbed_dubbed_settings\">ডাব/সাব এনিমে দেখান</string>\n    <string name=\"resize_fill\">স্ট্রেচ</string>\n    <string name=\"resize_zoom\">বড় করুন</string>\n    <string name=\"pref_category_app_updates\">অ্যাপ আপডেট</string>\n    <string name=\"pref_category_gestures\">গ্যাসচার</string>\n    <string name=\"pref_category_defaults\">ডিফল্ট</string>\n    <string name=\"category_general\">সাধারণ</string>\n    <string name=\"random_button_settings\">এলোমেলো বোতাম</string>\n    <string name=\"preferred_media_settings\">পছন্দের মিডিয়া</string>\n    <string name=\"test_extensions\">সমস্ত এক্সটেনশন পরীক্ষা করুন</string>\n    <string name=\"test_extensions_summary\">এই পরীক্ষাটি শুধুমাত্র ডেভেলপারদের জন্য এবং কোন এক্সটেনশনের কাজ যাচাই বা অস্বীকার করে না।</string>\n    <string name=\"emulator_layout\">এমুলেটর লেআউট</string>\n    <string name=\"primary_color_settings\">প্রাইমারি রং</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_lang_name\">Language code (en)</string>\n    <string name=\"account\">অ্যাকাউন্ট</string>\n    <string name=\"logout\">প্রস্থান</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d%2$s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">সিজন %1$d পর্ব %2$d প্রকাশিত হবে</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dঘন্টা %2$dমিনিট %3$dসেকেন্ড</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dমিনিট %2$dসেকেন্ড</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$dসেকেন্ড</string>\n    <string name=\"play_from_beginning_img_des\">শুরু থেকে চালু করুন</string>\n    <string name=\"speech_recognition_unavailable\">স্পিচ রিকগনিশন উপলব্ধ নেই</string>\n    <string name=\"begin_speaking\">কথা বলা শুরু করুন…</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ckb/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$sئەڵقەى%2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">تیم:%s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">ئەڵقەی %d لە</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">وەرزی %1$d ئەڵقەی %2$d لە</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"search_poster_img_des\">پۆستەر</string>\n    <string name=\"episode_poster_img_des\">پۆستەری ئەڵقە</string>\n    <string name=\"home_main_poster_img_des\">پۆستەری سەرەکی</string>\n    <string name=\"home_next_random_img_des\">داهاتوو بە هەڕەمەکی</string>\n    <string name=\"go_back_img_des\">گەڕانەوە</string>\n    <string name=\"play_from_beginning_img_des\">لە سەرەتاوە دەست پێ بکە</string>\n    <string name=\"home_change_provider_img_des\">گۆڕینی دابینکەر</string>\n    <string name=\"preview_background_img_des\">پێشبینی پاشبنەما</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">خێرای(x%.2f)</string>\n    <string name=\"rated_format\" formatted=\"true\">هەڵسەنگاندن:%.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">نوێکاری نوێ دۆزرایەوە!\\n%1$s-&gt;%2$s</string>\n    <string name=\"filler\" formatted=\"true\">فیلەر</string>\n    <string name=\"duration_format\" formatted=\"true\">min%d</string>\n    <string name=\"app_name\">کلاود ستریم</string>\n    <string name=\"title_home\">سەرەکی</string>\n    <string name=\"title_search\">گەڕان</string>\n    <string name=\"title_downloads\">داونڵۆد</string>\n    <string name=\"title_settings\">ڕێکخستن</string>\n    <string name=\"search_hint\">گەڕان…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">بگەڕێ بۆ%s…</string>\n    <string name=\"speech_recognition_unavailable\">ناسینەوەی قسەکردن بەردەست نییە</string>\n    <string name=\"begin_speaking\">دەست بکە بە قسەکردن…</string>\n    <string name=\"no_data\">هیچ داتایەک نییە</string>\n    <string name=\"episode_more_options_des\">هەڵبژاردنی زیاتر</string>\n    <string name=\"next_episode\">ئەڵقەی داهاتوو</string>\n    <string name=\"result_tags\">ژانرەکان</string>\n    <string name=\"result_share\">شەیر</string>\n    <string name=\"result_open_in_browser\">بکەرەوە لە براوزەر</string>\n    <string name=\"browser\">براوزەر</string>\n    <string name=\"type_watching\">تەماشاکردن</string>\n    <string name=\"type_completed\">تەواو بووە</string>\n    <string name=\"type_dropped\">دابەزیووە</string>\n    <string name=\"type_plan_to_watch\">پلان بۆ سەیرکردن</string>\n    <string name=\"type_re_watching\">دووبارە سەیرکردنەوە</string>\n    <string name=\"play_torrent_button\">تۆرێنت ستریم بکە</string>\n    <string name=\"torrent_info\">ئەم ڤیدیۆیە تۆرێنتە، ئەمەش مانای ئەوەیە کە دەتوانرێت شوێنپێی چالاکیی ڤیدیۆکەت بگرێت.\\nپێش ئەوەی بەردەوام بیت دڵنیابە لە تۆرێنتینگ تێدەگەیت.</string>\n    <string name=\"pick_source\">سەرچاوەکان</string>\n    <string name=\"pick_subtitle\">ژێرنووسەکان</string>\n    <string name=\"reload_error\">دووبارە هەوڵبدە پەیوەندی…</string>\n    <string name=\"go_back\">گەڕانەوە بۆ دواوە</string>\n    <string name=\"result_poster_img_des\">پۆستەر</string>\n    <string name=\"download\">داونلۆد</string>\n    <string name=\"downloaded\">دابەزێنراوە</string>\n    <string name=\"downloading\">دادەبەزێندرێت</string>\n    <string name=\"download_paused\">دابەزاندن وەستاوە</string>\n    <string name=\"download_started\">داگرتن دەستی پێکرد</string>\n    <string name=\"download_failed\">داونلۆدکردن شکستی هێنا</string>\n    <string name=\"download_canceled\">داونلۆد هەڵوەشایەوە</string>\n    <string name=\"download_done\">داونلۆد تەواو بووە</string>\n    <string name=\"downloads_delete_select\">ئەو شتانە هەڵبژێرە کە دەتەوێت بیسڕیتەوە</string>\n    <string name=\"downloads_empty\">لە ئێستادا هیچ داونلۆدێک نییە.</string>\n    <string name=\"offline_file\">بەردەستە بۆ سەیرکردنی ئۆفلاین</string>\n    <string name=\"select_all\">هەموو هەڵبژێرە</string>\n    <string name=\"deselect_all\">هەمووی لابدە</string>\n    <string name=\"update_started\">نوێکردنەوە دەستی پێکرد</string>\n    <string name=\"open_local_video\">ڤیدیۆی ناوخۆیی بکەرەوە</string>\n    <string name=\"download_storage_text\">کۆگای ناوخۆیی</string>\n    <string name=\"app_dubbed_text\">دۆبلاژ</string>\n    <string name=\"app_subbed_text\">ژێرنووس</string>\n    <string name=\"popup_delete_file\">سڕینەوەی فایل</string>\n    <string name=\"popup_resume_download\">دووبارە دەستپێکردنەوەی دابەزاندن</string>\n    <string name=\"popup_pause_download\">وەستاندنی دابەزاندن</string>\n    <string name=\"home_more_info\">زانیاری زیاتر</string>\n    <string name=\"home_expanded_hide\">شاردنەوە</string>\n    <string name=\"home_info\">زانیاری</string>\n    <string name=\"filter_bookmarks\">فلتەرکردنی ئاماژەکان</string>\n    <string name=\"error_bookmarks_text\">ئاماژەکان</string>\n    <string name=\"action_remove_from_bookmarks\">لابردن</string>\n    <string name=\"action_add_to_bookmarks\">دۆخی تەماشاکردن دابنێ</string>\n    <string name=\"sort_apply\">جێبەجێکردن</string>\n    <string name=\"sort_copy\">کۆپی</string>\n    <string name=\"sort_close\">داخستن</string>\n    <string name=\"sort_save\">سەیڤ</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+cs/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- KEYS DON'T TRANSLATE -->\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Hrají: %s</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Plakát</string>\n    <string name=\"search_poster_img_des\">Plakát</string>\n    <string name=\"episode_poster_img_des\">Plakát epizody</string>\n    <string name=\"home_main_poster_img_des\">Hlavní plakát</string>\n    <string name=\"home_next_random_img_des\">Další náhodný</string>\n    <string name=\"go_back_img_des\">Přejít zpět</string>\n    <string name=\"home_change_provider_img_des\">Změnit poskytovatele</string>\n    <string name=\"preview_background_img_des\">Náhled pozadí</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Rychlost (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Hodnocení: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Nalezena nová aktualizace!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Výplň</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Domů</string>\n    <string name=\"title_search\">Hledat</string>\n    <string name=\"title_downloads\">Stahování</string>\n    <string name=\"title_settings\">Nastavení</string>\n    <string name=\"search_hint\">Hledat…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Hledat %s…</string>\n    <string name=\"no_data\">Žádná data</string>\n    <string name=\"episode_more_options_des\">Další možnosti</string>\n    <string name=\"next_episode\">Další epizoda</string>\n    <string name=\"result_tags\">Žánry</string>\n    <string name=\"result_share\">Sdílet</string>\n    <string name=\"result_open_in_browser\">Otevřít v prohlížeči</string>\n    <string name=\"skip_loading\">Přeskočit načítání</string>\n    <string name=\"loading\">Načítání…</string>\n    <string name=\"type_watching\">Sledování</string>\n    <string name=\"type_on_hold\">Pozastaveno</string>\n    <string name=\"type_completed\">Dokončeno</string>\n    <string name=\"type_dropped\">Zahozeno</string>\n    <string name=\"type_plan_to_watch\">Plánuji sledovat</string>\n    <string name=\"type_re_watching\">Opětovné sledování</string>\n    <string name=\"play_movie_button\">Přehrát film</string>\n    <string name=\"play_torrent_button\">Streamovat torrent</string>\n    <string name=\"pick_source\">Zdroje</string>\n    <string name=\"pick_subtitle\">Titulky</string>\n    <string name=\"reload_error\">Opakovat připojení…</string>\n    <string name=\"go_back\">Návrat zpět</string>\n    <string name=\"play_episode\">Přehrát epizodu</string>\n    <!--<string name=\"need_storage\">Umožnit stahování epizod</string>-->\n    <string name=\"download\">Stáhnout</string>\n    <string name=\"downloaded\">Stáhnuto</string>\n    <string name=\"downloading\">Stahování</string>\n    <string name=\"download_paused\">Stahování pozastaveno</string>\n    <string name=\"download_started\">Stahování spuštěno</string>\n    <string name=\"download_failed\">Stahování selhalo</string>\n    <string name=\"download_canceled\">Stahování zrušeno</string>\n    <string name=\"download_done\">Stahování dokončeno</string>\n    <string name=\"error_loading_links_toast\">Chyba při načítání odkazů</string>\n    <string name=\"download_storage_text\">Interní úložiště</string>\n    <string name=\"app_dubbed_text\">Dab</string>\n    <string name=\"app_subbed_text\">Tit</string>\n    <string name=\"popup_delete_file\">Smazat soubor</string>\n    <string name=\"popup_play_file\">Přehrát soubor</string>\n    <string name=\"popup_resume_download\">Pokračovat ve stahování</string>\n    <string name=\"popup_pause_download\">Pozastavit stahování</string>\n    <string name=\"home_more_info\">Více informací</string>\n    <string name=\"home_expanded_hide\">Skrýt</string>\n    <string name=\"home_play\">Přehrát</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"filter_bookmarks\">Filtrovat záložky</string>\n    <string name=\"error_bookmarks_text\">Záložky</string>\n    <string name=\"action_remove_from_bookmarks\">Odebrat</string>\n    <string name=\"action_add_to_bookmarks\">Nastavit stav sledování</string>\n    <string name=\"sort_apply\">Použít</string>\n    <string name=\"sort_copy\">Kopírovat</string>\n    <string name=\"sort_close\">Zavřít</string>\n    <string name=\"sort_clear\">Vymazat</string>\n    <string name=\"sort_save\">Uložit</string>\n    <string name=\"player_speed\">Rychlost přehrávání</string>\n    <string name=\"subtitles_settings\">Nastavení titulků</string>\n    <string name=\"subs_text_color\">Barva texta</string>\n    <string name=\"subs_outline_color\">Barva ohraničení</string>\n    <string name=\"subs_background_color\">Barva pozadí</string>\n    <string name=\"subs_window_color\">Barva okna</string>\n    <string name=\"subs_edge_type\">Typ hran</string>\n    <string name=\"subs_subtitle_elevation\">Zvýšení titulků</string>\n    <string name=\"subs_font\">Písmo</string>\n    <string name=\"subs_font_size\">Velikost písma</string>\n    <string name=\"search_provider_text_providers\">Hledat pomocí poskytovatelů</string>\n    <string name=\"search_provider_text_types\">Hledat pomocí typů</string>\n    <string name=\"benene_count_text\">%d benénů darováno vývojářům</string>\n    <string name=\"benene_count_text_none\">Nedarovali jste žádné benény</string>\n    <string name=\"subs_auto_select_language\">Automaticky vybrat jazyk</string>\n    <string name=\"subs_download_languages\">Stáhnout jazyky</string>\n    <string name=\"subs_subtitle_languages\">Jazyk titulků</string>\n    <string name=\"subs_hold_to_reset_to_default\">Podržte pro obnovení na výchozí</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importovat písma umístěním jich do %s</string>\n    <string name=\"continue_watching\">Pokračovat ve sledování</string>\n    <string name=\"action_remove_watching\">Odebrat</string>\n    <string name=\"action_open_watching\">Další informace</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Aby tento poskytovatel fungoval správně, budete možná potřebovat VPN</string>\n    <string name=\"vpn_torrent\">Tento poskytovatel je torrent, je doporučená VPN</string>\n    <string name=\"provider_info_meta\">Web neposkytnul žádná metadata, načítání videa selže, pokud na webu neexistuje.</string>\n    <string name=\"torrent_plot\">Popis</string>\n    <string name=\"normal_no_plot\">Příběh nenalezen</string>\n    <string name=\"torrent_no_plot\">Popis nenalezen</string>\n    <string name=\"show_log_cat\">Zobrazit Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Obraz v obraze</string>\n    <string name=\"picture_in_picture_des\">Přehrávání bude pokračovat v miniaturním přehrávači na vrchu ostatních aplikací</string>\n    <string name=\"player_size_settings\">Tlačítko pro změnu velikosti přehrávače</string>\n    <string name=\"player_size_settings_des\">Odebrat černá ohraničení</string>\n    <string name=\"player_subtitles_settings\">Titulky</string>\n    <string name=\"player_subtitles_settings_des\">Nastavení titulků přehrávače</string>\n    <string name=\"chromecast_subtitles_settings\">Titulky Chromecastu</string>\n    <string name=\"chromecast_subtitles_settings_des\">Natavení titulků Chromecastu</string>\n    <string name=\"eigengraumode_settings\">Rychlost přehrávání</string>\n    <string name=\"swipe_to_seek_settings\">Přejet pro posun</string>\n    <string name=\"swipe_to_seek_settings_des\">Přejeďte prstem ze strany na stranu pro ovládání své pozice ve videu</string>\n    <string name=\"swipe_to_change_settings\">Přejet pro změnu nastavení</string>\n    <string name=\"swipe_to_change_settings_des\">Přejeďte prstem nahoru nebo dolů na levé nebo pravé straně pro změnu jasu nebo hlasitosti</string>\n    <string name=\"double_tap_to_seek_settings\">Dvojité klepnutí pro posun</string>\n    <string name=\"double_tap_to_pause_settings\">Dvojité klepnutí pro pozastavení</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Množství času k posunu (sekundy)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Klepněte dvakrát vpravo nebo vlevo pro posun vpřed nebo vzad</string>\n    <string name=\"double_tap_to_pause_settings_des\">Klepněte dvakrát doprostřed pro pozastavení</string>\n    <string name=\"use_system_brightness_settings\">Použít systémový jas</string>\n    <string name=\"use_system_brightness_settings_des\">V přehrávači použít systémový jas namísto tmavého překrytí</string>\n    <string name=\"episode_sync_settings\">Aktualizovat postup sledování</string>\n    <string name=\"episode_sync_settings_des\">Automaticky synchronizovat postup sledování současné epizody</string>\n    <string name=\"restore_settings\">Obnovit data ze zálohy</string>\n    <string name=\"backup_settings\">Zálohovat data</string>\n    <string name=\"restore_success\">Načten soubor zálohy</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Nepodařilo se obnovit data ze soubory %s</string>\n    <string name=\"backup_success\">Data uložena</string>\n    <string name=\"backup_failed\">Chybí oprávnění k úložišti. Zkuste to prosím znovu.</string>\n    <string name=\"backup_failed_error_format\">Chyba při zálohování %s</string>\n    <string name=\"search\">Search</string>\n    <string name=\"category_account\">Účty a zabezpečení</string>\n    <string name=\"category_updates\">Aktualizace a záloha</string>\n    <string name=\"settings_info\">Informace</string>\n    <string name=\"advanced_search\">Pokročilé hledání</string>\n    <string name=\"advanced_search_des\">Zobrazí vám výsledky hledání oddělené poskytovatelem</string>\n    <string name=\"show_fillers_settings\">Zobrazit výplňové epizody u anime</string>\n    <string name=\"updates_settings\">Zobrazit aktualizace aplikace</string>\n    <string name=\"updates_settings_des\">Při spuštění aplikace automaticky zkontrolovat nové aktualizace.</string>\n    <string name=\"github\">GitHub</string>\n    <string name=\"lightnovel\">Nenáročná aplikace pro romány od stejných vývojářů</string>\n    <string name=\"anim\">Anime aplikace od stejných vývojářů</string>\n    <string name=\"discord\">Připojte se na Discord</string>\n    <string name=\"benene\">Darujte benén vývojářům</string>\n    <string name=\"benene_des\">Benén darován</string>\n    <string name=\"app_language\">Jazyk aplikace</string>\n    <string name=\"no_chromecast_support_toast\">Tento poskytovatel nemá podporu pro Chromecast</string>\n    <string name=\"no_links_found_toast\">Nenalezeny žádné odkazy</string>\n    <string name=\"copy_link_toast\">Odkaz zkopírován do schránky</string>\n    <string name=\"play_episode_toast\">Přehrát epizodu</string>\n    <string name=\"subs_default_reset_toast\">Obnovit na výchozí hodnoty</string>\n    <string name=\"season\">Sezóna</string>\n    <string name=\"no_season\">Žádná sezóna</string>\n    <string name=\"episode\">Epizoda</string>\n    <string name=\"episodes\">Epizody</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Nenalezeny žádné epizody</string>\n    <string name=\"delete_file\">Smazat soubor</string>\n    <string name=\"delete\">Smazat</string>\n    <string name=\"cancel\">Zrušit</string>\n    <string name=\"pause\">Pozastavit</string>\n    <string name=\"resume\">Pokračovat</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Toto nevratně smaže %s\n\\nJste si jisti?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nzbývá</string>\n    <string name=\"status_ongoing\">Probíhající</string>\n    <string name=\"status_completed\">Dokončena</string>\n    <string name=\"status\">Stav</string>\n    <string name=\"year\">Rok</string>\n    <string name=\"rating\">Hodnocení</string>\n    <string name=\"duration\">Trvání</string>\n    <string name=\"site\">Místo</string>\n    <string name=\"synopsis\">Synopse</string>\n    <string name=\"queued\">ve frontě</string>\n    <string name=\"no_subtitles\">Žádné titulky</string>\n    <string name=\"action_default\">Výchozí</string>\n    <string name=\"free_storage\">Volné</string>\n    <string name=\"used_storage\">Použito</string>\n    <string name=\"app_storage\">Aplikace</string>\n    <!--plural-->\n    <string name=\"movies\">Filmy</string>\n    <string name=\"tv_series\">Seriály</string>\n    <string name=\"cartoons\">Animované</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrenty</string>\n    <string name=\"documentaries\">Dokumenty</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Asijská dramata</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Seriál</string>\n    <string name=\"cartoons_singular\">Animovaný</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Dokument</string>\n    <string name=\"asian_drama_singular\">Asijské drama</string>\n    <string name=\"source_error\">Chyba zdroje</string>\n    <string name=\"remote_error\">Chyba vzdáleného zdroje</string>\n    <string name=\"render_error\">Chyba vykreslování</string>\n    <string name=\"unexpected_error\">Neočekávaná chyba přehrávače</string>\n    <string name=\"storage_error\">Chyba stahování, zkontrolujte oprávnění úložiště</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecastovat epizodu</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast jako zrcadlo</string>\n    <string name=\"episode_action_play_in_app\">Přehrát v aplikace</string>\n    <string name=\"episode_action_play_in_format\">Přehrát ve %s</string>\n    <string name=\"episode_action_auto_download\">Automaticky stáhnout</string>\n    <string name=\"episode_action_download_mirror\">Zrcadlo stahování</string>\n    <string name=\"episode_action_reload_links\">Obnovit odkazy</string>\n    <string name=\"episode_action_download_subtitle\">Stáhnout titulky</string>\n    <string name=\"show_hd\">Štítek s kvalitou</string>\n    <string name=\"show_dub\">Štítek dabingu</string>\n    <string name=\"show_sub\">Štítek titulků</string>\n    <string name=\"show_title\">Název</string>\n    <string name=\"poster_ui_settings\">Přepnout prvky UI na plakátu</string>\n    <string name=\"no_update_found\">Nenalezeny žádné aktualizace</string>\n    <string name=\"check_for_update\">Zkontrolovat aktualizace</string>\n    <string name=\"video_lock\">Uzamknout</string>\n    <string name=\"video_aspect_ratio_resize\">Změnit velikost</string>\n    <string name=\"video_source\">Zdroj</string>\n    <string name=\"video_skip_op\">Přeskočit OP</string>\n    <string name=\"dont_show_again\">Již nezobrazovat</string>\n    <string name=\"skip_update\">Přeskočit tuto aktualizace</string>\n    <string name=\"update\">Aktualizovat</string>\n    <string name=\"watch_quality_pref\">Upřednostněná kvalita sledování (WiFi)</string>\n    <string name=\"limit_title\">Maximální počet znaků v názvu přehrávače</string>\n    <string name=\"limit_title_rez\">Zobrazit informace o přehrávači</string>\n    <string name=\"video_buffer_size_settings\">Velikost vyrovnávací paměti videa</string>\n    <string name=\"video_buffer_length_settings\">Délka vyrovnávací paměti videa</string>\n    <string name=\"video_buffer_disk_settings\">Mezipaměť videa na disku</string>\n    <string name=\"video_buffer_clear_settings\">Vymazat mezipamět videí a obrázků</string>\n    <string name=\"video_ram_description\">Při nastavení příliš vysoké hodnoty na zařízeních s malou pamětí, jako je například Android TV, může způsobit pády.</string>\n    <string name=\"video_disk_description\">Při nastavení příliš vysoké hodnoty na zařízeních s malým dostupným úložištěm, jako je například Android TV, může způsobit pády.</string>\n    <string name=\"dns_pref\">DNS přes HTTPS</string>\n    <string name=\"dns_pref_summary\">Užitečné pro obcházení blokací ISP</string>\n    <string name=\"download_path_pref\">Cesta stahování</string>\n    <string name=\"nginx_url_pref\">URL serveru NGINX</string>\n    <string name=\"display_subbed_dubbed_settings\">Zobrazit dabované anime/anime s titulky</string>\n    <string name=\"resize_fit\">Vyplnit na obrazovku</string>\n    <string name=\"resize_fill\">Roztáhnout</string>\n    <string name=\"resize_zoom\">Přiblížit</string>\n    <string name=\"legal_notice\">Odmítnutí odpovědnosti</string>\n    <string name=\"category_general\">Obecné</string>\n    <string name=\"random_button_settings\">Náhodné tlačítko</string>\n    <string name=\"random_button_settings_desc\">Zobrazit na domovské stránce a v knihovně náhodné tlačítko</string>\n    <string name=\"provider_lang_settings\">Jazyky rozšíření</string>\n    <string name=\"app_layout\">Rozložení aplikace</string>\n    <string name=\"preferred_media_settings\">Preferovaná média</string>\n    <string name=\"subtitles_encoding\">Kódování titulků</string>\n    <string name=\"category_ui\">Rozložení</string>\n    <string name=\"automatic\">Automaticky</string>\n    <string name=\"tv_layout\">TV rozložení</string>\n    <string name=\"phone_layout\">Mobilní rozložení</string>\n    <string name=\"emulator_layout\">Rozložení emulátoru</string>\n    <string name=\"primary_color_settings\">Primární barva</string>\n    <string name=\"app_theme_settings\">Motiv aplikace</string>\n    <string name=\"bottom_title_settings\">Umístění názvu plakátu</string>\n    <string name=\"bottom_title_settings_des\">Umístit název pod plakát</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">heslo123</string>\n    <string name=\"example_username\">Uživatelské jméno</string>\n    <string name=\"example_email\">ahoj@svete.cz</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">účet</string>\n    <string name=\"logout\">Odhlásit se</string>\n    <string name=\"login\">Přihlásit se</string>\n    <string name=\"switch_account\">Přepnout účet</string>\n    <string name=\"add_account\">Přidat účet</string>\n    <string name=\"create_account\">Vytvořit účet</string>\n    <string name=\"add_sync\">Sledování aplikace</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Přidáno %s</string>\n    <string name=\"upload_sync\">Synchronizovat</string>\n    <string name=\"sync_score\">Hodnoceno</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">Přihlášeno k %s</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Nepodařilo se přihlásit k %s</string>\n    <!-- ============ -->\n    <string name=\"none\">Žádné</string>\n    <string name=\"normal\">Normální</string>\n    <string name=\"all\">Vše</string>\n    <string name=\"max\">Max</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Ohraničení</string>\n    <string name=\"subtitles_depressed\">Potlačené</string>\n    <string name=\"subtitles_shadow\">Stín</string>\n    <string name=\"subtitles_raised\">Vyvýšené</string>\n    <string name=\"subtitle_offset\">Synch. titulky</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Zpoždění titulků</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Toto použijte, pokud jsou titulky zobrazeny o %d ms dříve</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Toto použijte, pokud jsou titulky zobrazeny o %d ms později</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Žádné zpoždění titulků</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">Příliš žluťoučký kůň úpěl ďábelské ódy</string>\n    <string name=\"recommended\">Doporučeno</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Načteno %s</string>\n    <string name=\"player_load_subtitles\">Načíst ze souboru</string>\n    <string name=\"player_load_subtitles_online\">Načíst z internetu</string>\n    <string name=\"downloaded_file\">Stažen soubor</string>\n    <string name=\"actor_main\">Hlavní</string>\n    <string name=\"actor_supporting\">Podpora</string>\n    <string name=\"actor_background\">Pozadí</string>\n    <string name=\"home_source\">Zdroj</string>\n    <string name=\"home_random\">Náhodný</string>\n    <string name=\"coming_soon\">Již brzy…</string>\n    <string name=\"quality_cam\">Kam</string>\n    <string name=\"quality_cam_rip\">Kam</string>\n    <string name=\"quality_cam_hd\">Kam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Obrázek plakátu</string>\n    <string name=\"category_player\">Přehrávač</string>\n    <string name=\"resolution_and_title\">Rozlišení a název</string>\n    <string name=\"title\">Název</string>\n    <string name=\"resolution\">Rozlišení</string>\n    <string name=\"error_invalid_id\">Neplatné ID</string>\n    <string name=\"subtitles_remove_captions\">Odstranit skryté titulky z titulků</string>\n    <string name=\"subtitles_remove_bloat\">Odstranit nadbytečné titulky</string>\n    <string name=\"extras\">Extra</string>\n    <string name=\"action_mark_as_watched\">Označit jako zhlédnuté</string>\n    <string name=\"history\">Historie</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"play_with_app_name\">Přehrát s CloudStream</string>\n    <string name=\"autoplay_next_settings_des\">Přehrát další epizodu po skončení aktuální</string>\n    <string name=\"show_trailers_settings\">Zobrazit trailery</string>\n    <string name=\"pref_filter_search_quality\">Skrýt vybranou kvalitu videa ve výsledcích vyhledávání</string>\n    <string name=\"automatic_plugin_updates\">Automatické aktualizace doplňků</string>\n    <string name=\"remove_site_pref\">Odebrat web</string>\n    <string name=\"error_invalid_data\">Neplatné údaje</string>\n    <string name=\"error\">Chyba</string>\n    <string name=\"repository_name_hint\">Název repozitáře (volitelné)</string>\n    <string name=\"plugin_loaded\">Doplněk načten</string>\n    <string name=\"setup_extensions_subtext\">Stáhněte si seznam webů, které chcete používat</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Staženo: %d</string>\n    <string name=\"audio_tracks\">Zvukové stopy</string>\n    <string name=\"video_tracks\">Videostopy</string>\n    <string name=\"apply_on_restart\">Restartujte aplikaci pro použití změn.</string>\n    <string name=\"safe_mode_title\">Bezpečný režim povolen</string>\n    <string name=\"extension_size\">Velikost</string>\n    <string name=\"extension_authors\">Autoři</string>\n    <string name=\"repository_url_hint\">Adresa URL nebo krátký kód repozitáře</string>\n    <string name=\"error_invalid_url\">Neplatná adresa URL</string>\n    <string name=\"automatic_plugin_download_summary\">Automaticky instalovat všechny dosud nenainstalované doplňky z přidaných repozitářů.</string>\n    <string name=\"others\">Ostatní</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"network_adress_example\">https://example.com/priklad.mp4</string>\n    <string name=\"skip_setup\">Přeskočit nastavení</string>\n    <string name=\"add_repository\">Přidat repozitář</string>\n    <string name=\"plugin_deleted\">Doplněk odstraněn</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Nepodařilo se načíst %s</string>\n    <string name=\"view_public_repositories_button_short\">Veřejný seznam</string>\n    <string name=\"uppercase_all_subtitles\">Velká písmena u všech titulků</string>\n    <string name=\"hls_playlist\">Playlist HLS</string>\n    <string name=\"app_not_found_error\">Aplikace nenalezena</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Přeskočit %s</string>\n    <string name=\"skip_type_op\">Úvod</string>\n    <string name=\"skip_type_ed\">Konec</string>\n    <string name=\"clipboard_too_large\">Příliš mnoho textu. Nepodařilo se uložit do schránky.</string>\n    <string name=\"yes\">Ano</string>\n    <string name=\"browser\">Prohlížeč</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"library\">Knihovna</string>\n    <string name=\"kitsu_settings\">Zobrazit plakáty z Kitsu</string>\n    <string name=\"automatic_plugin_download\">Automaticky stahovat doplňky</string>\n    <string name=\"redo_setup_process\">Znovu provést proces nastavení</string>\n    <string name=\"apk_installer_settings\">Instalátor APK</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"apk_installer_settings_des\">Některá zařízení nepodporují nový instalátor balíčků. Pokud se aktualizace nenainstalují, zkuste použít starší možnost.</string>\n    <string name=\"pref_category_cache\">Mezipaměť</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Epizoda %d bude vydána za</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"play_livestream_button\">Přehrát přímý přenos</string>\n    <string name=\"pref_category_extensions\">Rozšíření</string>\n    <string name=\"pref_category_actions\">Akce</string>\n    <string name=\"pref_category_looks\">Vzhled</string>\n    <string name=\"pref_category_links\">Odkazy</string>\n    <string name=\"pref_category_ui_features\">Funkce</string>\n    <string name=\"example_site_name\">NovýNázevWebu</string>\n    <string name=\"enable_nsfw_on_providers\">Povolit NSFW u podporovaných rozšíření</string>\n    <string name=\"category_providers\">Poskytovatelé</string>\n    <string name=\"previous\">Předchozí</string>\n    <string name=\"app_layout_subtext\">Změnit vzhled aplikace tak, aby vám vyhovoval</string>\n    <string name=\"preferred_media_subtext\">Co chcete vidět</string>\n    <string name=\"plugin_downloaded\">Doplněk stažen</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Spuštěno stahování %1$d %2$s…</string>\n    <string name=\"blank_repo_message\">CloudStream nemá ve výchozím nastavení nainstalované žádné zdroje. Je třeba je nainstalovat z repozitářů.\n\\n\n\\nPřipojte se na náš Discord nebo hledejte na internetu.</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Zakázáno: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Aktualizováno %d doplňků</string>\n    <string name=\"safe_mode_crash_info\">Zobrazit informace o pádu</string>\n    <string name=\"extension_rating\" formatted=\"true\">Hodnocení: %s</string>\n    <string name=\"action_remove_from_watched\">Odebrat ze zhlédnutých</string>\n    <string name=\"update_notification_installing\">Instalace aktualizace aplikace…</string>\n    <string name=\"safe_mode_description\">Všechna rozšíření byla vypnuta z důvodu pádu, abyste mohli najít to, které způsobuje potíže.</string>\n    <string name=\"extension_version\">Verze</string>\n    <string name=\"player_pref\">Preferovaný přehrávač videí</string>\n    <string name=\"extension_description\">Popis</string>\n    <string name=\"extension_status\">Stav</string>\n    <string name=\"extension_install_first\">Nejprve nainstalujte rozšíření</string>\n    <string name=\"skip_type_mixed_ed\">Smíšený konec</string>\n    <string name=\"extension_language\">Jazyk</string>\n    <string name=\"player_settings_play_in_app\">Interní přehrávač</string>\n    <string name=\"skip_type_recap\">Rekapitulace</string>\n    <string name=\"clear_history\">Vymazat historii</string>\n    <string name=\"all_languages_preference\">Všechny jazyky</string>\n    <string name=\"skip_type_mixed_op\">Smíšený úvod</string>\n    <string name=\"skip_type_creddits\">Poděkování</string>\n    <string name=\"skip_type_intro\">Znělka</string>\n    <string name=\"enable_skip_op_from_database_des\">Zobrazit vyskakovací okna pro přeskočení úvodu/konce</string>\n    <string name=\"update_notification_downloading\">Stahování aktualizace aplikace…</string>\n    <string name=\"confirm_exit_dialog\">Opravdu chcete opustit aplikaci?</string>\n    <string name=\"update_notification_failed\">Nepodařilo se nainstalovat novou verzi aplikace</string>\n    <string name=\"apk_installer_legacy\">Původní</string>\n    <string name=\"delayed_update_notice\">Aplikace bude po ukončení aktualizována</string>\n    <string name=\"empty_library_no_accounts_message\">Vaše knihovna je prázdná :(\n\\nPřihlaste se k účtu v knihovně nebo přidejte pořady do místní knihovny.</string>\n    <string name=\"select_library\">Vybrat knihovnu</string>\n    <string name=\"sort_rating_desc\">Hodnocení (od nejvyššího)</string>\n    <string name=\"sort_rating_asc\">Hodnocení (od nejnižšího)</string>\n    <string name=\"sort_alphabetical_z\">Abecedně (od Z do A)</string>\n    <string name=\"sort_by\">Seřadit podle</string>\n    <string name=\"sort\">Řazení</string>\n    <string name=\"empty_library_logged_in_message\">Tento seznam je prázdný. Zkuste přepnout na jiný.</string>\n    <string name=\"safe_mode_file\">Nalezen soubor bezpečného režimu!\n\\nDo odebrání souboru nebudeme načítat žádná rozšíření.</string>\n    <string name=\"sort_updated_new\">Aktualizováno (od nejnovějšího)</string>\n    <string name=\"sort_updated_old\">Aktualizováno (od nejstaršího)</string>\n    <string name=\"sort_alphabetical_a\">Abecedně (od A do Z)</string>\n    <string name=\"open_with\">Otevřít pomocí</string>\n    <string name=\"pref_category_backup\">Záloha</string>\n    <string name=\"pref_category_gestures\">Gesta</string>\n    <string name=\"add_site_pref\">Klonovat web</string>\n    <string name=\"add_site_summary\">Přidat klon existujícího webu s jinou adresou URL</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">Kód jazyka (cs)</string>\n    <string name=\"download_all_plugins_from_repo\">Varování: CloudStream nenese žádnou zodpovědnost za používání rozšíření třetích stran a neposkytuje pro ně žádnou podporu!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (zakázáno)</string>\n    <string name=\"tracks\">Stopy</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"pref_category_player_features\">Funkce přehrávače</string>\n    <string name=\"pref_category_subtitles\">Titulky</string>\n    <string name=\"pref_category_player_layout\">Rozložení</string>\n    <string name=\"pref_category_defaults\">Výchozí hodnoty</string>\n    <string name=\"apk_installer_package_installer\">Instalátor balíčků</string>\n    <string name=\"pref_category_app_updates\">Aktualizace aplikace</string>\n    <string name=\"setup_done\">Hotovo</string>\n    <string name=\"extension_types\">Podporováno</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"live_singular\">Živý přenos</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"extensions\">Rozšíření</string>\n    <string name=\"play_trailer_button\">Přehrát trailer</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"view_public_repositories_button\">Zobrazit komunitní repozitáře</string>\n    <string name=\"update_started\">Aktualizace zahájena</string>\n    <string name=\"stream\">Síťový stream</string>\n    <string name=\"autoplay_next_settings\">Automaticky přehrát další epizodu</string>\n    <string name=\"livestreams\">Živé přenosy</string>\n    <string name=\"subtitles_filter_lang\">Filtrování podle preferovaného jazyka médií</string>\n    <string name=\"referer\">Referent (volitelný)</string>\n    <string name=\"next\">Další</string>\n    <string name=\"provider_languages_tip\">Sledovat videa v těchto jazycích</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Staženo %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Všechny %s jsou již staženy</string>\n    <string name=\"batch_download\">Hromadné stahování</string>\n    <string name=\"plugin_singular\">doplněk</string>\n    <string name=\"plugin\">doplňků</string>\n    <string name=\"delete_repository_plugins\">Tímto také odstraníte všechny doplňky repozitářů</string>\n    <string name=\"delete_repository\">Odstranit repozitář</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Nestaženo: %d</string>\n    <string name=\"no\">Ne</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Skrytý přehrávač - doba hledání</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Množství vyhledávané doby při skrytém přehrávači</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Zobrazený přehrávač - doba hledání</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Množství vyhledávané doby při zobrazeném přehrávači</string>\n    <string name=\"test_log\">Protokol</string>\n    <string name=\"category_provider_test\">Test poskytovatele</string>\n    <string name=\"test_failed\">Neúspěšné</string>\n    <string name=\"test_passed\">Úspěšné</string>\n    <string name=\"restart\">Restart</string>\n    <string name=\"start\">Spustit</string>\n    <string name=\"stop\">Zastavit</string>\n    <string name=\"subscription_in_progress_notification\">Aktualizace odebíraných pořadů</string>\n    <string name=\"subscription_new\">Přihlášeno k odběru %s</string>\n    <string name=\"subscription_deleted\">Odhlášen odběr od %s</string>\n    <string name=\"subscription_episode_released\">Byla vydána epizoda %d!</string>\n    <string name=\"subscription_list_name\">Odebíráno</string>\n    <string name=\"jsdelivr_proxy\">Proxy GitHub</string>\n    <string name=\"jsdelivr_enabled\">Nelze se připojit k serveru GitHub. Zapínání proxy jsDelivr…</string>\n    <string name=\"watch_quality_pref_data\">Upřednostněná kvalita sledování (mobilní data)</string>\n    <string name=\"revert\">Vrátit zpět</string>\n    <string name=\"jsdelivr_proxy_summary\">Obejít blokování přímých adres GitHub pomocí jsDelivr. Může způsobit zpoždění aktualizací o několik dní.</string>\n    <string name=\"pref_category_bypass\">Obcházení ISP</string>\n    <string name=\"profile_number\">Profil %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Mobilní data</string>\n    <string name=\"set_default\">Nastavit jako výchozí</string>\n    <string name=\"use\">Použít</string>\n    <string name=\"edit\">Upravit</string>\n    <string name=\"profiles\">Profily</string>\n    <string name=\"help\">Nápověda</string>\n    <string name=\"qualities\">Kvality</string>\n    <string name=\"profile_background_des\">Pozadí profilu</string>\n    <string name=\"quality_profile_help\">Zde můžete změnit pořadí zdrojů. Pokud má video vyšší prioritu, objeví se ve výběru zdrojů výše. Součet priority zdroje a priority kvality je priorita videa.\n\\n\n\\nZdroj A: 3\n\\nKvalita B: 7\n\\nBudou mít celkovou prioritu videa 10.\n\\n\n\\nPOZNÁMKA: Pokud je součet 10 nebo vyšší, přehrávač automaticky přeskočí načítání při načtení daného odkazu!</string>\n    <string name=\"unable_to_inflate\">Nepodařilo se správně vytvořit rozhraní. Toto je VÁŽNÁ CHYBA, kterou je potřeba ihned nahlásit %s</string>\n    <string name=\"disable\">Vypnout</string>\n    <string name=\"automatic_plugin_download_mode_title\">Výběr režimu pro filtrování stahování doplňků</string>\n    <string name=\"no_plugins_found_error\">V repozitáři nebyly nalezeny žádné doplňky</string>\n    <string name=\"no_repository_found_error\">Repozitář nenalezen, zkontrolujte adresu URL a zkuste použít VPN</string>\n    <string name=\"already_voted\">Již jste hlasovali</string>\n    <string name=\"favorite_removed\">%s odebráno z oblíbených</string>\n    <string name=\"favorites_list_name\">Oblíbené</string>\n    <string name=\"favorite_added\">%s přidáno do oblíbených</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Ve vaší knihovně byl nalezen potenciální duplikát:\n\\n\n\\n%s\n\\n\n\\nChcete přesto přidat tuto položku, nahradit existující nebo zrušit akci?</string>\n    <string name=\"backup_frequency\">Frekvence záloh</string>\n    <string name=\"duplicate_title\">Nalezena potenciální duplicita</string>\n    <string name=\"lock_profile\">Zamknout profil</string>\n    <string name=\"action_add_to_favorites\">Přidat do oblíbených</string>\n    <string name=\"duplicate_replace_all\">Nahradit vše</string>\n    <string name=\"pin_error_incorrect\">Nesprávný PIN. Zkuste to prosím znovu.</string>\n    <string name=\"action_unsubscribe\">Zrušit odběr</string>\n    <string name=\"pin_error_length\">PIN musí obsahovat 4 znaky</string>\n    <string name=\"duplicate_replace\">Nahradit</string>\n    <string name=\"duplicate_add\">Přidat</string>\n    <string name=\"action_subscribe\">Odebírat</string>\n    <string name=\"action_remove_from_favorites\">Odebrat z oblíbených</string>\n    <string name=\"select_an_account\">Vyberte účet</string>\n    <string name=\"duplicate_message_single\">Vypadá to, že ve vaší knihovně již existuje potenciální duplikát: „%s“.\n\\n\n\\nChcete přesto přidat tuto položku, nahradit existující nebo zrušit akci?</string>\n    <string name=\"enter_pin\">Zadejte PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">Zadejte současný PIN</string>\n    <string name=\"logged_account\" formatted=\"true\">Přihlášeni jako %s</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Zadejte PIN pro %s</string>\n    <string name=\"use_default_account\">Použít výchozí účet</string>\n    <string name=\"skip_startup_account_select_pref\">Přeskočit výběr účtu při spuštění</string>\n    <string name=\"manage_accounts\">Správce účtů</string>\n    <string name=\"edit_account\">Upravit účet</string>\n    <string name=\"links_reloaded_toast\">Odkazy znovu načteny</string>\n    <string name=\"rotate_video_desc\">Zobrazit tlačítko pro přepnutí otočení obrazovky</string>\n    <string name=\"auto_rotate_video\">Automatické otáčení</string>\n    <string name=\"rotate_video\">Otočení</string>\n    <string name=\"auto_rotate_video_desc\">Zapnout automatické otáčení obrazovky v závislosti na orientaci videa</string>\n    <string name=\"test_extensions\">Otestovat všechna rozšíření</string>\n    <string name=\"test_extensions_summary\">Tento test slouží pouze pro vývojáře a neověřuje funkčnost jakéhokoli rozšíření.</string>\n    <string name=\"result_search_tooltip\">Hledat v ostatních rozšířeních</string>\n    <string name=\"subscribe_tooltip\">Oznámení o nové epizodě</string>\n    <string name=\"recommendations_tooltip\">Zobrazit doporučené</string>\n    <string name=\"speed_setting_summary\">Přidá nastavení rychlosti do přehrávače</string>\n    <string name=\"biometric_authentication_title\">Odemknout CloudStream</string>\n    <string name=\"biometric_setting\">Zamknout biometrikou</string>\n    <string name=\"password_pin_authentication_title\">Ověření heslem/PINem</string>\n    <string name=\"biometric_unsupported\">Biometrické ověření není na tomto zařízení podporováno</string>\n    <string name=\"biometric_setting_summary\">Odemkněte aplikaci otiskem prstu, obličejem, PINem, gestem nebo heslem.</string>\n    <string name=\"biometric_prompt_description\">Po několika nezdařilých pokusech se okno zavře. Pro opětovný pokus restartujte aplikaci.</string>\n    <string name=\"biometric_warning\">Vaše data z aplikace CloudStream byla nyní zálohována. Ačkoli je tato možnost velmi malá, různá zařízení se mohou chovat různě. Ve výjimečném případě, že se vám přístup k aplikaci zablokuje, data aplikace zcela vymažte a obnovte je ze zálohy. Velmi se omlouváme za případné nepříjemnosti z toho plynoucí.</string>\n    <string name=\"unfavorite\">Odebrat z oblíbených</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nzbývá</string>\n    <string name=\"favorite\">Přidat do oblíbených</string>\n    <string name=\"repo_copy_label\">Název a adresa repozitáře</string>\n    <string name=\"clipboard_unknown_error\">Chyba při kopírování, zkopírujte prosím protokol a kontaktujte podporu aplikace.</string>\n    <string name=\"toast_copied\">Zkopírováno!</string>\n    <string name=\"clipboard_permission_error\">Chyba při přístupu ke schránce, zkuste to prosím znovu.</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"app_unrestricted_toast\">Využití baterie aplikací je již nastaveno na neomezené</string>\n    <string name=\"app_info_intent_error\">Nepodařilo se otevřít informace o aplikaci CloudStream.</string>\n    <string name=\"music_singlar\">Hudba</string>\n    <string name=\"custom_media_singluar\">Média</string>\n    <string name=\"battery_dialog_title\">Zakažte optimalizace baterie</string>\n    <string name=\"battery_dialog_message\">Aby bylo zajištěno nepřetržité stahování a upozornění na odebírané seriály, potřebuje aplikace CloudStream povolení ke spuštění na pozadí. Po stisknutí tlačítka OK se vám zobrazí dialog se žádostí. Stiskněte prosím „Povolit“.\\n\\nUpozorňujeme, že toto oprávnění neznamená, že CS3 bude vybíjet baterii. Na pozadí bude pracovat pouze v případě potřeby, například při přijímání oznámení nebo stahování videí z oficiálních rozšíření.</string>\n    <string name=\"audio_book_singular\">Audiokniha</string>\n    <string name=\"reset_btn\">Resetovat</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Vychází %s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Epizoda %2$d ze série %1$d bude vydána za</string>\n    <string name=\"episode_action_cast_mirror\">Vysílat zrcadlení</string>\n    <string name=\"player_settings_select_cast_device\">Vyberte zařízení k vysílání</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"pref_category_security\">Zabezpečení</string>\n    <string name=\"qr_image\">Obrázek QR kódu</string>\n    <string name=\"dismiss\">Zavřít</string>\n    <string name=\"open_downloaded_repo\">Otevřít repozitář</string>\n    <string name=\"device_pin_url_message\">Navštivte <b>%s</b> na vašem zařízení nebo počítači a zadejte kód výše</string>\n    <string name=\"device_pin_error_message\">Nepodařilo se získat PIN kód, zkuste místní ověření</string>\n    <string name=\"device_pin_counter_text\">Kód vyprší za %1$dm %2$ds</string>\n    <string name=\"pref_category_accounts\">Účty</string>\n    <string name=\"auth_locally\">Lokální ověření</string>\n    <string name=\"device_pin_expired_message\">PIN kód vypršel!</string>\n    <string name=\"play_from_beginning_img_des\">Přehrát od začátku</string>\n    <string name=\"downloads_empty\">Aktuálně neprobíhají žádná stahování.</string>\n    <string name=\"open_local_video\">Otevřít místní video</string>\n    <string name=\"delete_plugin\">Odstranit doplněk</string>\n    <string name=\"hide_player_control_names\">Skrýt názvy ovládání přehrávače</string>\n    <string name=\"test_warning\">Varování</string>\n    <string name=\"sort_release_date_new\">Datum vydání (od nových)</string>\n    <string name=\"sort_release_date_old\">Datum vydání (od starých)</string>\n    <string name=\"downloads_delete_select\">Zvolte položky k odstranění</string>\n    <string name=\"offline_file\">Dostupné pro sledování offline</string>\n    <string name=\"select_all\">Vybrat vše</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Opravdu chcete trvale odstranit následující položky?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Opravdu chcete trvale odstranit následující epizody v %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Opravdu chcete trvale odstranit všechny epizody v následujících sériích?\n\\n\n\\n%s</string>\n    <string name=\"deselect_all\">Zrušit výběr všeho</string>\n    <string name=\"delete_files\">Odstranit soubory</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Také trvale odstraníte všechny epizody v následujících sériích:\n\\n\n\\n%s</string>\n    <string name=\"delete_format\" formatted=\"true\">Odstranit (%1$d | %2$s)</string>\n    <string name=\"preview_seekbar\">Náhled v liště přehrávače</string>\n    <string name=\"preview_seekbar_desc\">Povolit náhled miniatur na liště přehrávače</string>\n    <string name=\"no_subtitles_loaded\">Zatím nenačteny žádné titulky</string>\n    <string name=\"confirm_before_exiting_title\">Potvrdit před ukončením</string>\n    <string name=\"confirm_before_exiting_desc\">Zobrazit dialog před ukončením aplikace</string>\n    <string name=\"show\">Zobrazit</string>\n    <string name=\"dont_show\">Nezobrazovat</string>\n    <string name=\"backup_path_title\">Umístění složky záloh</string>\n    <string name=\"custom\">Vlastní</string>\n    <string name=\"torrent_info\">Toto video je torrent, což znamená, že lze sledovat vaší aktivitu v něm.\\nPřed pokračováním se ujistěte, že chápete, co to je torrentování.</string>\n    <string name=\"subs_edge_size\">Velikost okraje</string>\n    <string name=\"audio_singluar\">Zvuk</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"encoding_error\">Chyba kódování</string>\n    <string name=\"unsupported_error\">Nepodporovaná chyba</string>\n    <string name=\"player_load_one_subtitle_online\">Načíst první dostupné</string>\n    <string name=\"torrent_not_accepted\">Pro pokračování restartujte aplikaci a potvrďte dialog o streamování torrentu.</string>\n    <string name=\"torrent_preferred_media\">Povolte torrent v Nastavení/Poskytovatelé/Preferovaná média</string>\n    <string name=\"software_decoding\">Softwarové dekódování</string>\n    <string name=\"software_decoding_desc\">Softwarové dekódování umožňuje přehrávači přehrávat video soubory, které vaše zařízení nepodporuje, ale může způsobit zpoždění nebo nestabilní přehrávání ve vysokém rozlišení.</string>\n    <string name=\"sort_episodes_rating_high_low\">Hodnocení (nejvyšší)</string>\n    <string name=\"sort_episodes_date_newest\">Datum vysílání (nejnovější)</string>\n    <string name=\"sort_episodes_date_oldest\">Datum vysílání (nejstarší)</string>\n    <string name=\"sort_button_rating\">Hodnocení %s</string>\n    <string name=\"sort_button_date\">Datum %s</string>\n    <string name=\"update_plugins\">Aktualizovat doplňky</string>\n    <string name=\"starting_plugin_update_manually\">Spouštím proces aktualizace doplňků!</string>\n    <string name=\"no_plugins_updated_manually\">Nebyly aktualizovány žádné doplňky.</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"plugins_updated_manually\">Úspěšně aktualizováno %d doplňků!</string>\n    <string name=\"sort_episodes_number_desc\">Epizoda (sestupně)</string>\n    <string name=\"sort_episodes_rating_low_high\">Hodnocení (nejnižší)</string>\n    <string name=\"update_plugins_manually\">Ručně aktualizovat doplňky</string>\n    <string name=\"sort_episodes_number_asc\">Epizoda (vzestupně)</string>\n    <string name=\"player_notification_channel_name\">Oznámení přehrávače</string>\n    <string name=\"player_notification_channel_description\">Oznámení přehrávače pro ovládání přehrávání na pozadí</string>\n    <string name=\"speech_recognition_unavailable\">Rozpoznávání řeči není k dispozici</string>\n    <string name=\"begin_speaking\">Začněte mluvit…</string>\n    <string name=\"subtitles_from_embedded\">Vložené</string>\n    <string name=\"subtitles_from_online\">Online</string>\n    <string name=\"all_subtitles_bold\">Vykreslit všechny titulky tučně</string>\n    <string name=\"all_subtitles_italic\">Vykreslit všechny titulky kurzívou</string>\n    <string name=\"background_radius\">Poloměr pozadí</string>\n    <string name=\"slide_up_again_to_exceed_100\">Přejeďte opět nahoru pro pokračování nad 100 %</string>\n    <string name=\"volume_exceeded_100\">Hlasitost překročila 100 %</string>\n    <string name=\"download_parallel_settings_des\">Počet různých položek, které lze stahovat v jednu chvíli</string>\n    <string name=\"poster_size_settings_des\">Změní velikost plakátů</string>\n    <string name=\"no_internet_connection\">Žádné připojení k internetu. \\n\\nPřipojte se prosím k internetu a zkuste to znovu, nebo sledujte stažené, zatímco jste offline.</string>\n    <string name=\"poster_size_settings\">Velikost plakátů</string>\n    <string name=\"overscan_settings_des\">Změní hranice obrazovky</string>\n    <string name=\"overscan_settings\">Oříznutí</string>\n    <string name=\"parallel_downloads\">Paralelní stahování</string>\n    <string name=\"concurrent_connections\">Souběžná připojení</string>\n    <string name=\"concurrent_connections_settings_des\">Kolik souběžných připojení může každé stahování použít</string>\n    <string name=\"go_to_downloads\">Přejít na stažené</string>\n    <string name=\"player_settings_always_ask\">Vždy se zeptat</string>\n    <string name=\"speedup_title\">Přepínač rychlosti při podržení</string>\n    <string name=\"speedup_summary\">Podržte pro 2x rychlost</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dmin %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dmin %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"show_rating\">Štítek hodnocení</string>\n    <string name=\"no_account\">Žádný účet</string>\n    <string name=\"edit_profile_image_title\">Upravit profilový obrázek</string>\n    <string name=\"edit_profile_image_hint\">Zadejte adresu profilového obrázku</string>\n    <string name=\"edit_profile_image_error_empty\">Adresa nenalezena</string>\n    <string name=\"edit_profile_image_error_invalid\">Neplatná adresa nebo obrázek</string>\n    <string name=\"edit_profile_image_success\">Obrázek úspěšně upraven</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Označit jako zhlédnuté po tuto epizodu</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Odebrat zhlédnutí po tuto epizodu</string>\n    <string name=\"action_reload\">Znovu načteno</string>\n    <string name=\"reload_provider\">Znovu načíst poskytovatele</string>\n    <string name=\"episode_action_play_mirror\">Přehrát ze zrcadla</string>\"\n    <string name=\"name\">Název</string>\n    <string name=\"resolution_and_name\">Rozlišení a název</string>\n    <string name=\"subs_subtitle_alignment\">Zarovnání titulků</string>\n    <string name=\"bottom_left\">Vlevo dole</string>\n    <string name=\"bottom_center\">Uprostřed dole</string>\n    <string name=\"bottom_right\">Vpravo dole</string>\n    <string name=\"middle_left\">Vlevo uprostřed</string>\n    <string name=\"middle_center\">Uprostřed</string>\n    <string name=\"middle_right\">Vpravo uprostřed</string>\n    <string name=\"top_left\">Vlevo nahoře</string>\n    <string name=\"top_center\">Uprostřed nahoře</string>\n    <string name=\"top_right\">Vpravo nahoře</string>\n    <string name=\"play_full_series_button\">Přehrát celý seriál</string>\n    <string name=\"install_prerelease\">Nainstalovat předběžnou verzi</string>\n    <string name=\"prerelease_already_installed\">Předběžné vydání je již nainstalováno.</string>\n    <string name=\"prerelease_install_failed\">Nepodařilo se nainstalovat předběžné vydání.</string>\n    <string name=\"show_episode_text\">Text epizody</string>\n    <string name=\"search_suggestions\">Návrhy vyhledávání</string>\n    <string name=\"search_suggestions_des\">Zobrazit návrhy vyhledávání během psaní</string>\n    <string name=\"clear_suggestions\">Vymazat návrhy</string>\n    <string name=\"show_cast_in_details\">Zobrazit panel vysílání</string>\n    <string name=\"extra_brightness_settings\">Extra jas</string>\n    <string name=\"extra_brightness_settings_des\">Povolit filtr jasu při překročení 100 % jasu obrazovky</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"video_info\">Informace o médiu</string>\n    <string name=\"source_name\">Název zdroje</string>\n    <string name=\"download_queue\">Fronta stahování</string>\n    <string name=\"queue_empty_message\">Momentálně nemáte žádná stahování ve frontě.</string>\n    <string name=\"download_all\">Stáhnout vše</string>\n    <string name=\"cancel_all\">Zrušit vše</string>\n    <string name=\"download_episode_range\">Chcete stáhnout epizodu %s?</string>\n    <string name=\"cancel_queue_message\">Chcete zrušit všechna stahování ve frontě?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d aktivní stahování</item>\n        <item quantity=\"few\">%d aktivní stahování</item>\n        <item quantity=\"many\">%d aktivních stahování</item>\n        <item quantity=\"other\">%d aktivních stahování</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d stahování uloženo do fronty</item>\n        <item quantity=\"few\">%d stahování uložena do fronty</item>\n        <item quantity=\"many\">%d stahování uloženo do fronty</item>\n        <item quantity=\"other\">%d stahování uloženo do fronty</item>\n    </plurals>\n    <string name=\"source_priority\">Priorita zdrojů</string>\n    <string name=\"source_priority_help\">Rozhodněte, jak mají být řazeny zdroje videí v přehrávači</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Besetzung: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episode %d wird veröffentlicht in</string>\n    <string name=\"result_poster_img_des\">Vorschaubild</string>\n    <string name=\"search_poster_img_des\">Vorschaubild</string>\n    <string name=\"subs_hold_to_reset_to_default\">Halten, um auf Standardeinstellungen zurückzusetzen</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Wiederherstellung der Daten aus der Datei %s fehlgeschlagen</string>\n    <string name=\"backup_success\">Daten erfolgreich gesichert</string>\n    <string name=\"backup_failed_error_format\">Fehler beim Sichern von %s</string>\n    <string name=\"no_chromecast_support_toast\">Dieser Anbieter hat keine Chromecast-Unterstützung</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast-Mirror</string>\n    <string name=\"episode_action_play_in_app\">In App wiedergeben</string>\n    <string name=\"skip_type_mixed_op\">Gemischte Openings</string>\n    <string name=\"skip_type_creddits\">Abspann</string>\n    <string name=\"skip_type_intro\">Intro</string>\n    <string name=\"clear_history\">Verlauf löschen</string>\n    <string name=\"history\">Verlauf</string>\n    <string name=\"enable_skip_op_from_database_des\">Button zum Überspringen für Openings/Endings anzeigen</string>\n    <string name=\"clipboard_too_large\">Zu viel Text. Kann nicht in der Zwischenablage gespeichert werden.</string>\n    <string name=\"episode_poster_img_des\">Episodenvorschaubild</string>\n    <string name=\"home_main_poster_img_des\">Medienvorschaubild</string>\n    <string name=\"home_next_random_img_des\">Nächstes zufällig</string>\n    <string name=\"go_back_img_des\">Zurück</string>\n    <string name=\"home_change_provider_img_des\">Anbieter wechseln</string>\n    <string name=\"preview_background_img_des\">Hintergrundbildvorschau</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Geschwindigkeit (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Bewertung: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Neues Update gefunden!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Füller</string>\n    <string name=\"duration_format\" formatted=\"true\">%d Min</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Mit CloudStream abspielen</string>\n    <string name=\"title_home\">Startseite</string>\n    <string name=\"title_search\">Suche</string>\n    <string name=\"title_downloads\">Downloads</string>\n    <string name=\"title_settings\">Einstellungen</string>\n    <string name=\"search_hint\">Suchen…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Suche %s…</string>\n    <string name=\"no_data\">Keine Daten vorhanden</string>\n    <string name=\"episode_more_options_des\">Mehr Optionen</string>\n    <string name=\"next_episode\">Nächste Episode</string>\n    <string name=\"result_tags\">Genres</string>\n    <string name=\"result_share\">Teilen</string>\n    <string name=\"result_open_in_browser\">Im Browser öffnen</string>\n    <string name=\"skip_loading\">Laden überspringen</string>\n    <string name=\"loading\">Lädt…</string>\n    <string name=\"type_watching\">Am schauen</string>\n    <string name=\"type_on_hold\">Pausiert</string>\n    <string name=\"type_completed\">Abgeschlossen</string>\n    <string name=\"type_dropped\">Abgebrochen</string>\n    <string name=\"type_plan_to_watch\">Geplant</string>\n    <string name=\"type_re_watching\">Erneut schauen</string>\n    <string name=\"play_movie_button\">Film abspielen</string>\n    <string name=\"play_livestream_button\">Livestream abspielen</string>\n    <string name=\"play_torrent_button\">Torrent streamen</string>\n    <string name=\"pick_source\">Quellen</string>\n    <string name=\"pick_subtitle\">Untertitel</string>\n    <string name=\"reload_error\">Erneuter Verbindungsaufbau…</string>\n    <string name=\"go_back\">Zurück</string>\n    <string name=\"play_episode\">Episode abspielen</string>\n    <string name=\"download\">Herunterladen</string>\n    <string name=\"downloaded\">Heruntergeladen</string>\n    <string name=\"downloading\">Lädt herunter</string>\n    <string name=\"download_paused\">Download pausiert</string>\n    <string name=\"download_started\">Download gestartet</string>\n    <string name=\"download_failed\">Download fehlgeschlagen</string>\n    <string name=\"download_canceled\">Download abgebrochen</string>\n    <string name=\"download_done\">Download abgeschlossen</string>\n    <string name=\"stream\">Netzwerk-Stream</string>\n    <string name=\"error_loading_links_toast\">Fehler beim Laden von Links</string>\n    <string name=\"download_storage_text\">Interner Speicher</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Datei löschen</string>\n    <string name=\"popup_play_file\">Datei abspielen</string>\n    <string name=\"popup_resume_download\">Download fortsetzen</string>\n    <string name=\"popup_pause_download\">Download pausieren</string>\n    <string name=\"home_more_info\">Mehr Infos</string>\n    <string name=\"home_expanded_hide\">Verstecken</string>\n    <string name=\"home_play\">Abspielen</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"filter_bookmarks\">Lesezeichen filtern</string>\n    <string name=\"error_bookmarks_text\">Lesezeichen</string>\n    <string name=\"action_remove_from_bookmarks\">Entfernen</string>\n    <string name=\"action_add_to_bookmarks\">Status setzen</string>\n    <string name=\"sort_apply\">Anwenden</string>\n    <string name=\"sort_copy\">Kopieren</string>\n    <string name=\"sort_close\">Schließen</string>\n    <string name=\"sort_clear\">Leeren</string>\n    <string name=\"sort_save\">Speichern</string>\n    <string name=\"player_speed\">Player-Geschwindigkeit</string>\n    <string name=\"subtitles_settings\">Untertiteleinstellungen</string>\n    <string name=\"subs_text_color\">Textfarbe</string>\n    <string name=\"subs_outline_color\">Konturfarbe</string>\n    <string name=\"subs_background_color\">Hintergrundfarbe</string>\n    <string name=\"subs_window_color\">Fensterfarbe</string>\n    <string name=\"subs_edge_type\">Kantentyp</string>\n    <string name=\"subs_subtitle_elevation\">Untertitelhöhe</string>\n    <string name=\"subs_font\">Schriftart</string>\n    <string name=\"subs_font_size\">Schriftgröße</string>\n    <string name=\"search_provider_text_providers\">Suche anhand Anbietern</string>\n    <string name=\"search_provider_text_types\">Suche anhand Typen</string>\n    <string name=\"benene_count_text\">%d Benenes an die Devs geschenkt</string>\n    <string name=\"benene_count_text_none\">Noch keine Benenes verschenkt</string>\n    <string name=\"subs_auto_select_language\">Sprache automatisch wählen</string>\n    <string name=\"subs_download_languages\">Sprachen herunterladen</string>\n    <string name=\"subs_subtitle_languages\">Untertitelsprache</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Fonts in %s importieren</string>\n    <string name=\"continue_watching\">Weiterschauen</string>\n    <string name=\"action_remove_watching\">Entfernen</string>\n    <string name=\"action_open_watching\">Mehr Infos</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Damit dieser Anbieter korrekt funktioniert, ist möglicherweise ein VPN erforderlich</string>\n    <string name=\"vpn_torrent\">Dieser Anbieter bietet Torrents an, ein VPN wird deswegen dringend empfohlen</string>\n    <string name=\"provider_info_meta\">Metadaten werden nicht von der Website bereitgestellt, das Laden des Videos schlägt fehl, wenn sie nicht auf der Website vorhanden sind.</string>\n    <string name=\"torrent_plot\">Beschreibung</string>\n    <string name=\"normal_no_plot\">Keine Handlung gefunden</string>\n    <string name=\"torrent_no_plot\">Keine Beschreibung gefunden</string>\n    <string name=\"show_log_cat\">Logcat anzeigen 🐈</string>\n    <string name=\"picture_in_picture\">Bild-in-Bild</string>\n    <string name=\"picture_in_picture_des\">Setzt die Wiedergabe in einem kleinen Fenster über anderen Anwendungen fort</string>\n    <string name=\"player_size_settings\">Player-Skalierung anpassen</string>\n    <string name=\"player_size_settings_des\">Entfernt schwarze Ränder</string>\n    <string name=\"player_subtitles_settings\">Untertitel</string>\n    <string name=\"player_subtitles_settings_des\">Player-Untertiteleinstellungen</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast-Untertitel</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast-Untertiteleinstellungen</string>\n    <string name=\"eigengraumode_settings\">Wiedergabegeschwindigkeit</string>\n    <string name=\"swipe_to_seek_settings\">Wischen zum vor- und zurückspulen</string>\n    <string name=\"swipe_to_seek_settings_des\">Nach links oder rechts wischen, um die Zeit im Videoplayer zu steuern</string>\n    <string name=\"swipe_to_change_settings\">Wischen, um Einstellungen zu ändern</string>\n    <string name=\"swipe_to_change_settings_des\">Links oder rechts nach oben oder unten wischen, um die Helligkeit oder Lautstärke zu ändern</string>\n    <string name=\"autoplay_next_settings\">Nächste Episode automatisch abspielen</string>\n    <string name=\"autoplay_next_settings_des\">Nächste Episode wird gestartet, sobald die aktuelle Episode endet</string>\n    <string name=\"double_tap_to_seek_settings\">Doppeltippen zum vor- und zurückspulen</string>\n    <string name=\"double_tap_to_pause_settings\">Doppeltippen zum Pausieren</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Zeit für vor- und zurückspulen im Player (Sekunden)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Zweimal auf die rechte oder linke Seite tippen, um vor- oder zurückzuspulen</string>\n    <string name=\"double_tap_to_pause_settings_des\">Zweimal in die Mitte tippen, um zu pausieren</string>\n    <string name=\"use_system_brightness_settings\">Systemhelligkeit verwenden</string>\n    <string name=\"use_system_brightness_settings_des\">Systemhelligkeit anstelle eines dunklen Overlay im Player verwenden</string>\n    <string name=\"episode_sync_settings\">Episodenfortschritt aktualisieren</string>\n    <string name=\"episode_sync_settings_des\">Automatisches synchronisieren des aktuellen Episodenfortschritts</string>\n    <string name=\"restore_settings\">Daten aus Sicherung wiederherstellen</string>\n    <string name=\"backup_settings\">Daten sichern</string>\n    <string name=\"restore_success\">Sicherungsdatei geladen</string>\n    <string name=\"backup_failed\">Speicherberechtigungen fehlen. Bitte erneut versuchen.</string>\n    <string name=\"search\">Suche</string>\n    <string name=\"category_account\">Konten und Sicherheit</string>\n    <string name=\"category_updates\">Aktualisierungen und Datensicherung</string>\n    <string name=\"settings_info\">Info</string>\n    <string name=\"advanced_search\">Erweiterte Suche</string>\n    <string name=\"advanced_search_des\">Liefert die Suchergebnisse getrennt nach Anbietern</string>\n    <string name=\"show_fillers_settings\">Füller-Episoden für Animes anzeigen</string>\n    <string name=\"show_trailers_settings\">Trailer anzeigen</string>\n    <string name=\"kitsu_settings\">Vorschaubilder von Kitsu anzeigen</string>\n    <string name=\"pref_filter_search_quality\">Ausgewählte Videoqualität in den Suchergebnissen ausblenden</string>\n    <string name=\"automatic_plugin_updates\">Automatische Plugin-Updates</string>\n    <string name=\"updates_settings\">App-Updates anzeigen</string>\n    <string name=\"updates_settings_des\">Automatisches Suchen nach neuen Updates nach dem Start.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Light Novel App von denselben Entwicklern</string>\n    <string name=\"anim\">Anime App von denselben Entwicklern</string>\n    <string name=\"discord\">Trete dem Discord Server bei</string>\n    <string name=\"benene\">Eine Benene an die Devs schenken</string>\n    <string name=\"benene_des\">Geschenkte Benenes</string>\n    <string name=\"app_language\">App-Sprache</string>\n    <string name=\"no_links_found_toast\">Keine Links gefunden</string>\n    <string name=\"copy_link_toast\">Link in die Zwischenablage kopiert</string>\n    <string name=\"play_episode_toast\">Episode abspielen</string>\n    <string name=\"subs_default_reset_toast\">Auf Standardwert zurücksetzen</string>\n    <string name=\"season\">Staffel</string>\n    <string name=\"no_season\">Keine Staffel</string>\n    <string name=\"episode\">Episode</string>\n    <string name=\"episodes\">Episoden</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"delete_file\">Datei löschen</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Keine Episoden gefunden</string>\n    <string name=\"delete\">Löschen</string>\n    <string name=\"cancel\">Abbrechen</string>\n    <string name=\"pause\">Pause</string>\n    <string name=\"resume\">Fortsetzen</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Dadurch wird %s permanent gelöscht\n\\nBist du dir sicher?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nverbleibend</string>\n    <string name=\"status_ongoing\">Laufend</string>\n    <string name=\"status_completed\">Abgeschlossen</string>\n    <string name=\"status\">Status</string>\n    <string name=\"year\">Jahr</string>\n    <string name=\"rating\">Bewertung</string>\n    <string name=\"duration\">Länge</string>\n    <string name=\"site\">Website</string>\n    <string name=\"synopsis\">Zusammenfassung</string>\n    <string name=\"queued\">In Warteschlange eingereiht</string>\n    <string name=\"no_subtitles\">Keine Untertitel</string>\n    <string name=\"action_default\">Standard</string>\n    <string name=\"free_storage\">Frei</string>\n    <string name=\"used_storage\">Belegt</string>\n    <string name=\"app_storage\">App</string>\n    <string name=\"movies\">Filme</string>\n    <string name=\"tv_series\">TV-Serien</string>\n    <string name=\"cartoons\">Trickfilme</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"documentaries\">Dokumentationen</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Asiatische Dramen</string>\n    <string name=\"livestreams\">Livestreams</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Andere</string>\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Serie</string>\n    <string name=\"cartoons_singular\">Trickfilm</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Dokumentation</string>\n    <string name=\"asian_drama_singular\">Asiatisches Drama</string>\n    <string name=\"live_singular\">Livestream</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"source_error\">Quellenfehler</string>\n    <string name=\"remote_error\">Remote-Fehler</string>\n    <string name=\"render_error\">Renderfehler</string>\n    <string name=\"unexpected_error\">Unerwarteter Playerfehler</string>\n    <string name=\"storage_error\">Downloadfehler, bitte überprüfen sie die Speicherberechtigungen</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast-Episode</string>\n    <string name=\"episode_action_play_in_format\">In %s wiedergeben</string>\n    <string name=\"episode_action_auto_download\">Auto-Download</string>\n    <string name=\"episode_action_download_mirror\">Alternativer Download</string>\n    <string name=\"episode_action_reload_links\">Links neu laden</string>\n    <string name=\"episode_action_download_subtitle\">Untertitel herunterladen</string>\n    <string name=\"show_hd\">Qualitätsanzeige</string>\n    <string name=\"show_dub\">Dub-Label</string>\n    <string name=\"show_sub\">Sub-Label</string>\n    <string name=\"show_title\">Titel</string>\n    <string name=\"poster_ui_settings\">UI-Elemente auf Vorschaubild umschalten</string>\n    <string name=\"no_update_found\">Kein Update gefunden</string>\n    <string name=\"check_for_update\">Auf Updates prüfen</string>\n    <string name=\"video_lock\">Sperren</string>\n    <string name=\"video_aspect_ratio_resize\">Skalieren</string>\n    <string name=\"video_source\">Quelle</string>\n    <string name=\"video_skip_op\">Intro überspringen</string>\n    <string name=\"dont_show_again\">Nicht mehr anzeigen</string>\n    <string name=\"skip_update\">Update ignorieren</string>\n    <string name=\"update\">Update</string>\n    <string name=\"watch_quality_pref\">Bevorzugte Videoqualität (WLAN)</string>\n    <string name=\"limit_title\">Videoplayertitel max. Zeichen</string>\n    <string name=\"limit_title_rez\">Playerinformationen anzeigen</string>\n    <string name=\"video_buffer_size_settings\">Videopuffergröße</string>\n    <string name=\"video_buffer_length_settings\">Videopufferlänge</string>\n    <string name=\"video_buffer_disk_settings\">Video-Cache in Speicher</string>\n    <string name=\"video_buffer_clear_settings\">Video- und Bild-Cache leeren</string>\n    <string name=\"video_ram_description\">Verursacht Abstürze, wenn zu hoch eingestellt. Nicht ändern, wenn wenig Arbeitsspeicher verfügbar ist, wie z.B. auf einem Android TV oder auf einem alten Smartphone.</string>\n    <string name=\"video_disk_description\">Kann auf Systemen mit geringem Speicherplatz, wie z. B. auf Android TV-Geräten, zu Problemen führen, wenn der Wert zu hoch eingestellt ist.</string>\n    <string name=\"dns_pref\">DNS über HTTPS</string>\n    <string name=\"dns_pref_summary\">Nützlich zur Umgehung von ISP-Sperren</string>\n    <string name=\"add_site_pref\">Website klonen</string>\n    <string name=\"remove_site_pref\">Website entfernen</string>\n    <string name=\"add_site_summary\">Einen Klon einer bestehenden Website mit einer anderen URL hinzufügen</string>\n    <string name=\"download_path_pref\">Downloadpfad</string>\n    <string name=\"nginx_url_pref\">Nginx-Server-URL</string>\n    <string name=\"display_subbed_dubbed_settings\">Dubbed/Subbed Anime anzeigen</string>\n    <string name=\"resize_fit\">An Bildschirm anpassen</string>\n    <string name=\"resize_fill\">Strecken</string>\n    <string name=\"resize_zoom\">Vergrößern</string>\n    <string name=\"legal_notice\">Haftungsausschluss</string>\n    <string name=\"category_general\">Allgemein</string>\n    <string name=\"random_button_settings\">Zufalls-Button</string>\n    <string name=\"random_button_settings_desc\">Zeige Knopf mit Zufallsgenerator auf Startseite und Bibliothek</string>\n    <string name=\"provider_lang_settings\">Erweiterungssprachen</string>\n    <string name=\"app_layout\">App-Layout</string>\n    <string name=\"preferred_media_settings\">Bevorzugte Medien</string>\n    <string name=\"enable_nsfw_on_providers\">NSFW bei unterstützten Erweiterungen aktivieren</string>\n    <string name=\"subtitles_encoding\">Untertitel-Kodierung</string>\n    <string name=\"category_providers\">Anbieter</string>\n    <string name=\"category_ui\">Layout</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"tv_layout\">TV-Layout</string>\n    <string name=\"phone_layout\">Telefon-Layout</string>\n    <string name=\"emulator_layout\">Emulator-Layout</string>\n    <string name=\"primary_color_settings\">Grundfarbe</string>\n    <string name=\"app_theme_settings\">App-Thema</string>\n    <string name=\"bottom_title_settings\">Vorschaubildtitel Platzierung</string>\n    <string name=\"bottom_title_settings_des\">Titel unter Vorschaubild platzieren</string>\n    <string name=\"example_password\">passwort123</string>\n    <string name=\"example_username\">Benutzername</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NeuerSeitenNamen</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">Sprachencode (en)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">Account</string>\n    <string name=\"logout\">Ausloggen</string>\n    <string name=\"login\">Einloggen</string>\n    <string name=\"switch_account\">Account wechseln</string>\n    <string name=\"add_account\">Account hinzufügen</string>\n    <string name=\"create_account\">Account erstellen</string>\n    <string name=\"add_sync\">Synchronisation hinzufügen</string>\n    <string name=\"added_sync_format\" formatted=\"true\">%s hinzugefügt</string>\n    <string name=\"upload_sync\">Sync</string>\n    <string name=\"sync_score\">Bewertung</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s authentifiziert</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Die Authentifizierung bei %s ist fehlgeschlagen</string>\n    <string name=\"none\">Keine</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">Alle</string>\n    <string name=\"max\">Max</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Umrandung</string>\n    <string name=\"subtitles_depressed\">Gesenkt</string>\n    <string name=\"subtitles_shadow\">Schatten</string>\n    <string name=\"subtitles_raised\">Erhöht</string>\n    <string name=\"subtitle_offset\">Untertitel synchronisieren</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Untertitelverzögerung</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Verwenden, wenn die Untertitel %d ms zu früh angezeigt werden</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Verwenden, wenn die Untertitel %d ms zu spät angezeigt werden</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Keine Untertitelverzögerung</string>\n    <string name=\"subtitles_example_text\">Vogel Quax zwickt Johnys Pferd Bim</string>\n    <string name=\"recommended\">Empfohlen</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">%s geladen</string>\n    <string name=\"player_load_subtitles\">Aus Datei laden</string>\n    <string name=\"player_load_subtitles_online\">Aus Internet laden</string>\n    <string name=\"downloaded_file\">Heruntergeladene Datei</string>\n    <string name=\"actor_main\">Hauptdarsteller</string>\n    <string name=\"actor_supporting\">Nebendarsteller</string>\n    <string name=\"actor_background\">Hintergrunddarsteller</string>\n    <string name=\"home_source\">Quelle</string>\n    <string name=\"home_random\">Zufällig</string>\n    <string name=\"coming_soon\">Demnächst…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blue-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Vorschaubild</string>\n    <string name=\"category_player\">Player</string>\n    <string name=\"resolution_and_title\">Auflösung und Titel</string>\n    <string name=\"title\">Titel</string>\n    <string name=\"resolution\">Auflösung</string>\n    <string name=\"error_invalid_id\">Ungültige ID</string>\n    <string name=\"error_invalid_data\">Ungültige Daten</string>\n    <string name=\"error_invalid_url\">Ungültige URL</string>\n    <string name=\"error\">Fehler</string>\n    <string name=\"subtitles_remove_captions\">Softsubs aus Untertiteln entfernen</string>\n    <string name=\"subtitles_remove_bloat\">Entfernt Schrott aus Untertiteln (z.B. Werbung)</string>\n    <string name=\"subtitles_filter_lang\">Nach bevorzugter Mediensprache filtern</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"referer\">Referent (optional)</string>\n    <string name=\"next\">Weiter</string>\n    <string name=\"provider_languages_tip\">Videos in diesen Sprachen ansehen</string>\n    <string name=\"previous\">Vorherige</string>\n    <string name=\"skip_setup\">Einrichtung überspringen</string>\n    <string name=\"app_layout_subtext\">Aussehen der App passend zu dem des Geräts ändern</string>\n    <string name=\"preferred_media_subtext\">Was möchten Sie sehen</string>\n    <string name=\"setup_done\">Fertig</string>\n    <string name=\"extensions\">Erweiterungen</string>\n    <string name=\"add_repository\">Repository hinzufügen</string>\n    <string name=\"repository_name_hint\">Repository Name (Optional)</string>\n    <string name=\"repository_url_hint\">Repository-URL oder Kurz Code</string>\n    <string name=\"plugin_loaded\">Plugin geladen</string>\n    <string name=\"plugin_deleted\">Plugin gelöscht</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Fehler beim Laden von %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Herunterladen von %1$d %2$s gestartet…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">%1$d %2$s heruntergeladen</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Alle %s bereits heruntergeladen</string>\n    <string name=\"batch_download\">Batch-Download</string>\n    <string name=\"plugin_singular\">Plugin</string>\n    <string name=\"plugin\">Plugins</string>\n    <string name=\"delete_repository_plugins\">Dadurch werden auch alle Repository-Plugins gelöscht</string>\n    <string name=\"delete_repository\">Repository löschen</string>\n    <string name=\"setup_extensions_subtext\">Lade eine Liste der Websites herunter, welche du verwenden möchtest</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Heruntergeladen: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Deaktiviert: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Nicht heruntergeladen: %d</string>\n    <string name=\"blank_repo_message\">CloudStream hat standardmäßig keine Websites installiert. Websites müssen aus Repositories installiert werden.\n\\n\n\\nTrete unserem Discord Server bei oder suche online.</string>\n    <string name=\"view_public_repositories_button\">Community-Repositories anzeigen</string>\n    <string name=\"view_public_repositories_button_short\">Öffentliche Liste</string>\n    <string name=\"uppercase_all_subtitles\">Alle Untertitel in Großbuchstaben</string>\n    <string name=\"download_all_plugins_from_repo\">Warnung: CloudStream übernimmt keine Verantwortung für das nutzen von Dritt-Anbieter-Erweiterungen und leistet für sie keine Unterstützung!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Deaktiviert)</string>\n    <string name=\"tracks\">Spuren</string>\n    <string name=\"audio_tracks\">Audiospuren</string>\n    <string name=\"video_tracks\">Videospuren</string>\n    <string name=\"apply_on_restart\">Starte die App neu, um die Änderungen zu sehen.</string>\n    <string name=\"safe_mode_title\">Abgesicherter Modus aktiviert</string>\n    <string name=\"safe_mode_description\">Alle Erweiterungen wurden aufgrund eines Absturzes deaktiviert, damit die fehlerhafte Erweiterung ausfindig gemacht werden kann.</string>\n    <string name=\"safe_mode_crash_info\">Absturzinfo ansehen</string>\n    <string name=\"extension_rating\" formatted=\"true\">Bewertung: %s</string>\n    <string name=\"extension_description\">Beschreibung</string>\n    <string name=\"extension_version\">Version</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"extension_size\">Größe</string>\n    <string name=\"extension_authors\">Autoren</string>\n    <string name=\"extension_types\">Unterstützt</string>\n    <string name=\"extension_language\">Sprache</string>\n    <string name=\"extension_install_first\">Zuerst muss die Erweiterung installiert werden</string>\n    <string name=\"hls_playlist\">HLS-Playlist</string>\n    <string name=\"player_pref\">Bevorzugter Videoplayer</string>\n    <string name=\"player_settings_play_in_app\">Interner Player</string>\n    <string name=\"app_not_found_error\">App nicht gefunden</string>\n    <string name=\"all_languages_preference\">Alle Sprachen</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Überspringen %s</string>\n    <string name=\"skip_type_op\">Opening</string>\n    <string name=\"skip_type_ed\">Ending</string>\n    <string name=\"skip_type_recap\">Zusammenfassung</string>\n    <string name=\"skip_type_mixed_ed\">Vermischte Endings</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"play_trailer_button\">Trailer abspielen</string>\n    <string name=\"automatic_plugin_download\">Automatisches Herunterladen von Plugins</string>\n    <string name=\"automatic_plugin_download_summary\">Automatische Installation aller noch nicht installierten Plugins aus hinzugefügten Repositories.</string>\n    <string name=\"redo_setup_process\">Einrichtungsvorgang wiederholen</string>\n    <string name=\"apk_installer_settings\">APK-Installer</string>\n    <string name=\"apk_installer_settings_des\">Einige Geräte unterstützen den neuen Package-Installer nicht. Benutze die Legacy-Option, wenn sich die Updates nicht installieren lassen.</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"pref_category_links\">Links</string>\n    <string name=\"pref_category_app_updates\">App-Updates</string>\n    <string name=\"pref_category_backup\">Sicherung</string>\n    <string name=\"pref_category_extensions\">Erweiterungen</string>\n    <string name=\"pref_category_actions\">Wartung</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_gestures\">Gesten</string>\n    <string name=\"pref_category_player_features\">Player-Funktionen</string>\n    <string name=\"pref_category_subtitles\">Untertitel</string>\n    <string name=\"pref_category_player_layout\">Layout</string>\n    <string name=\"pref_category_defaults\">Voreinstellungen</string>\n    <string name=\"pref_category_looks\">Aussehen</string>\n    <string name=\"pref_category_ui_features\">Funktionen</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d Plugins aktualisiert</string>\n    <string name=\"action_mark_as_watched\">Als gesehen markieren</string>\n    <string name=\"confirm_exit_dialog\">Sicher, dass die App beendet werden soll?</string>\n    <string name=\"yes\">Ja</string>\n    <string name=\"no\">Nein</string>\n    <string name=\"update_notification_downloading\">App-Update wird heruntergeladen…</string>\n    <string name=\"update_notification_installing\">App-Update wird installiert…</string>\n    <string name=\"update_notification_failed\">Die neue Version der App konnte nicht installieren werden</string>\n    <string name=\"apk_installer_legacy\">Legacy</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"update_started\">Aktualisierung gestartet</string>\n    <string name=\"delayed_update_notice\">Die Anwendung wird beim Beenden aktualisiert</string>\n    <string name=\"plugin_downloaded\">Das Plugin wurde heruntergeladen</string>\n    <string name=\"action_remove_from_watched\">Von geschaut entfernen</string>\n    <string name=\"library\">Bibliothek</string>\n    <string name=\"browser\">Browser</string>\n    <string name=\"sort_by\">Sortieren nach</string>\n    <string name=\"sort\">Sortieren</string>\n    <string name=\"sort_rating_desc\">Bewertung (gut zu schlecht)</string>\n    <string name=\"sort_rating_asc\">Bewertung (schlecht zu gut)</string>\n    <string name=\"sort_updated_new\">Aktualisiert (neu zu alt)</string>\n    <string name=\"sort_updated_old\">Aktualisiert (alt zu neu)</string>\n    <string name=\"sort_alphabetical_a\">Alphabetisch (A zu Z)</string>\n    <string name=\"sort_alphabetical_z\">Alphabetisch (Z zu A)</string>\n    <string name=\"select_library\">Bibliothek auswählen</string>\n    <string name=\"open_with\">Öffnen mit</string>\n    <string name=\"empty_library_no_accounts_message\">Deine Bibliothek ist leer :(\n\\nMelde dich mit einem Bibliothekskonto an oder füge Titel zu deiner lokalen Bibliothek hinzu.</string>\n    <string name=\"empty_library_logged_in_message\">Diese Liste ist leer. Versuch zu einer anderen Liste zu wechseln.</string>\n    <string name=\"safe_mode_file\">Datei für den abgesicherten Modus gefunden!\n\\nBeim Start werden keine Erweiterungen geladen, bis die Datei entfernt wird.</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Player ausgeblendet - Betrag zum vor- und zurückspulen</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Der Betrag, welcher verwendet wird, wenn der Player eingeblendet ist</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Der Betrag, welcher verwendet wird, wenn der Player ausgeblendet ist</string>\n    <string name=\"pref_category_android_tv\">Android-TV</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Player eingeblendet - Betrag zum vor- und zurückspulen</string>\n    <string name=\"test_failed\">Fehlgeschlagen</string>\n    <string name=\"test_passed\">Erfolgreich</string>\n    <string name=\"category_provider_test\">Anbieter-Test</string>\n    <string name=\"stop\">Stopp</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"start\">Start</string>\n    <string name=\"restart\">Neustarten</string>\n    <string name=\"watch_quality_pref_data\">Bevorzugte Videoqualität (mobile Daten)</string>\n    <string name=\"jsdelivr_proxy_summary\">Umgehung der Sperre von GitHub-URLs mit jsdelivr. Kann zu einigen Tagen Verzögerung bei Updates führen.</string>\n    <string name=\"subscription_new\">%s abonniert</string>\n    <string name=\"subscription_deleted\">%s deabonniert</string>\n    <string name=\"subscription_episode_released\">Episode %d erschienen!</string>\n    <string name=\"jsdelivr_proxy\">GitHub Proxy</string>\n    <string name=\"jsdelivr_enabled\">GitHub konnte nicht erreicht werden. Der jsDelivr-Proxy wird aktiviert …</string>\n    <string name=\"subscription_in_progress_notification\">Abonnierte Serien werden aktualisiert</string>\n    <string name=\"revert\">Rückgängig</string>\n    <string name=\"subscription_list_name\">Abonniert</string>\n    <string name=\"pref_category_bypass\">ISP-Umgehungen</string>\n    <string name=\"profile_number\">Profil %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Mobile Daten</string>\n    <string name=\"set_default\">Standard festlegen</string>\n    <string name=\"use\">Verwenden</string>\n    <string name=\"edit\">Bearbeiten</string>\n    <string name=\"profiles\">Profile</string>\n    <string name=\"help\">Hilfe</string>\n    <string name=\"qualities\">Qualitäten</string>\n    <string name=\"profile_background_des\">Profil-Hintergrund</string>\n    <string name=\"quality_profile_help\">Hier kannst du verändern, wie die Quellen geordnet werden. Wenn ein Video eine höhere Priorität hat, wird es höher in der Quellenauswahl erscheinen. Die Summe der Quellenpriorität und der Qualitätspriorität ist die Videopriorität.\n\\n\n\\nQuelle A: 3\n\\nQualität B: 7\n\\nWerden eine kombinierte Videopriorität von 10 haben.\n\\n\n\\nHINWEIS: Wenn die Summe 10 oder mehr beträgt, überspringt der Player automatisch das Laden, wenn der Link geladen wird!</string>\n    <string name=\"automatic_plugin_download_mode_title\">Filtermodus für Plugin-Downloads auswählen</string>\n    <string name=\"already_voted\">Es wurde bereits abgestimmt</string>\n    <string name=\"no_plugins_found_error\">Keine Plugins im Repository gefunden</string>\n    <string name=\"no_repository_found_error\">Repository nicht gefunden, überprüf die URL und versuch ein VPN</string>\n    <string name=\"unable_to_inflate\">Die Benutzeroberfläche konnte nicht korrekt erstellt werden. Dies ist ein SCHWERWIEGENDER FEHLER und sollte sofort gemeldet werden. %s</string>\n    <string name=\"disable\">Deaktivieren</string>\n    <string name=\"favorite_removed\">%s von Favoriten entfernt</string>\n    <string name=\"favorites_list_name\">Favoriten</string>\n    <string name=\"favorite_added\">%s zu Favoriten hinzugefügt</string>\n    <string name=\"backup_frequency\">Sicherungshäufigkeit</string>\n    <string name=\"duplicate_title\">Potentielles Duplikat gefunden</string>\n    <string name=\"lock_profile\">Profil sperren</string>\n    <string name=\"action_add_to_favorites\">Zu Favoriten hinzufügen</string>\n    <string name=\"duplicate_replace_all\">Alle ersetzen</string>\n    <string name=\"pin_error_incorrect\">Falsche PIN. Bitte versuche es erneut.</string>\n    <string name=\"action_unsubscribe\">Deabonnieren</string>\n    <string name=\"pin_error_length\">PIN muss 4 Zeichen sein</string>\n    <string name=\"duplicate_replace\">Ersetzen</string>\n    <string name=\"duplicate_add\">Hinzufügen</string>\n    <string name=\"action_subscribe\">Abonnieren</string>\n    <string name=\"action_remove_from_favorites\">Von Favoriten entfernen</string>\n    <string name=\"select_an_account\">Ein Konto auswählen</string>\n    <string name=\"enter_pin\">PIN eingeben</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">Aktuelle PIN eingeben</string>\n    <string name=\"logged_account\" formatted=\"true\">Angemeldet als %s</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">PIN für %s eingeben</string>\n    <string name=\"use_default_account\">Standard-Konto verwenden</string>\n    <string name=\"skip_startup_account_select_pref\">Kontoauswahl beim Starten überspringen</string>\n    <string name=\"manage_accounts\">Konten verwalten</string>\n    <string name=\"edit_account\">Konto bearbeiten</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Es wurden potentielle Duplikate in deiner Bibliothek gefunden:\n\\n\n\\n%s\n\\n\n\\nMöchtest du dieses Element dennoch hinzufügen, das existierende ersetzen oder diese Aktion abbrechen?</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Deine Bibliothek enthält möglicherweise schon ein Duplikat dieses Elements: \\'%s\\'\n\\n\n\\nMöchtest du dieses Element dennoch hinzufügen, das existierende ersetzen oder diese Aktion abbrechen?</string>\n    <string name=\"links_reloaded_toast\">Links wurden neu geladen</string>\n    <string name=\"rotate_video\">Drehen</string>\n    <string name=\"rotate_video_desc\">Zeige einen Umschalter für Bildschirmorientierung an</string>\n    <string name=\"auto_rotate_video\">Automatisch drehen</string>\n    <string name=\"result_search_tooltip\">In anderen Erweiterungen suchen</string>\n    <string name=\"recommendations_tooltip\">Empfehlungen anzeigen</string>\n    <string name=\"speed_setting_summary\">Fügt dem Player eine Geschwindigkeitsoption hinzu</string>\n    <string name=\"subscribe_tooltip\">Benachrichtigung für neue Episoden</string>\n    <string name=\"auto_rotate_video_desc\">Automatisches Umschalten der Bildschirmausrichtung basierend auf der Videoausrichtung aktivieren</string>\n    <string name=\"test_extensions\">Teste alle Erweiterungen</string>\n    <string name=\"test_extensions_summary\">Dieser Test ist nur für Entwickler gedacht und bestimmt nicht die Funktionsfähigkeit einer Erweiterung.</string>\n    <string name=\"biometric_authentication_title\">Entsperre CloudStream</string>\n    <string name=\"biometric_setting\">Sperre mit Biometric</string>\n    <string name=\"password_pin_authentication_title\">Passwort/PIN Authentifizierung</string>\n    <string name=\"biometric_unsupported\">Biometrische Authentifizierung wird auf diesem Gerät nicht unterstützt</string>\n    <string name=\"biometric_setting_summary\">Entsperre die App via Fingerabdruck, FaceID, PIN, Muster und Passwort.</string>\n    <string name=\"unfavorite\">kein Favorit</string>\n    <string name=\"biometric_prompt_description\">Dieser Bildschirm wurde nach einigen Fehlversuchen geschlossen. Starte die App neu.</string>\n    <string name=\"biometric_warning\">Ihre CloudStream-Daten wurden gesichert. Obwohl die Wahrscheinlichkeit dieses seltenen Falles sehr gering ist, verhalten sich alle Geräte unterschiedlich. Falls Sie im schlimmsten Fall den Zugriff zur App verlieren, löschen Sie die App-Daten vollständig und stellen Sie die Sicherung wieder her. Jegliche Unannehmlichkeiten, die Ihnen dadurch entstehen, bedauern wir sehr.</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nausstehend</string>\n    <string name=\"favorite\">Favorit</string>\n    <string name=\"toast_copied\">Kopiert!</string>\n    <string name=\"clipboard_unknown_error\">Beim kopieren ist ein Fehler aufgetreten, bitte kopieren sie logical und wenden sich an den Support.</string>\n    <string name=\"clipboard_permission_error\">Fehler beim zugriff auf die Zwischenablage, bitte erneut versuchen.</string>\n    <string name=\"repo_copy_label\">Repository Name und URL</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"battery_dialog_title\">Akku-Optimierung deaktivieren</string>\n    <string name=\"music_singlar\">Musik</string>\n    <string name=\"audio_book_singular\">Hörbuch</string>\n    <string name=\"custom_media_singluar\">Medien</string>\n    <string name=\"reset_btn\">Zurücksetzen</string>\n    <string name=\"app_unrestricted_toast\">Akkuverbrauch der App ist bereits auf unbeschränkt eingestellt</string>\n    <string name=\"app_info_intent_error\">CloudStreams App-Info kann nicht geöffnet werden.</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Staffel %1$d Episode %2$d wird veröffentlicht in</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Wird veröffentlicht in %s</string>\n    <string name=\"pref_category_security\">Sicherheit</string>\n    <string name=\"pref_category_accounts\">Konten</string>\n    <string name=\"open_downloaded_repo\">Repository öffnen</string>\n    <string name=\"device_pin_url_message\">Besuche<b>%s</b> auf dem Smartphone oder Computer und gebe den obenstehenden Code ein</string>\n    <string name=\"device_pin_error_message\">PIN-Code vom Gerät nicht abrufbar, versuche lokale Authentifizierung</string>\n    <string name=\"downloads_empty\">Zur Zeit sind keine Downloads verfügbar.</string>\n    <string name=\"open_local_video\">Lokales Video öffnen</string>\n    <string name=\"auth_locally\">Lokale Auth</string>\n    <string name=\"dismiss\">Verwerfen</string>\n    <string name=\"qr_image\">QR-Code Bild</string>\n    <string name=\"player_settings_select_cast_device\">Cast-Gerät auswählen</string>\n    <string name=\"delete_plugin\">Plugin löschen</string>\n    <string name=\"device_pin_expired_message\">PIN-Code ist jetzt abgelaufen!</string>\n    <string name=\"hide_player_control_names\">Namen von Player-Steuerelementen ausblenden</string>\n    <string name=\"episode_action_cast_mirror\">Cast-Mirror</string>\n    <string name=\"test_warning\">Warnung</string>\n    <string name=\"device_pin_counter_text\">Code läuft ab in %1$dm %2$ds</string>\n    <string name=\"cs3wiki\">CloudStream-Wiki</string>\n    <string name=\"battery_dialog_message\">Um einen unterbrechungsfreien Download zu gewährleisten und Benachrichtigungen für abonnierte TV-Shows anzuzeigen, benötigt Cloudstream die Berechtigung, im Hintergrund ausgeführt zu werden. Beim drücken auf 𝙊𝙆 wird ein Dialog angezeigt. Bitte drücke ‚Erlauben‘.\\n\\nBitte beachte, dass dies nicht dazu führt, dass CS3 den Akku dauerhaft entlädt. Es läuft nur im Hintergrund, wenn es nötig ist, beispielsweise zum Empfang von Benachrichtigungen oder dem Download von Videos aus offiziellen Erweiterungen.</string>\n    <string name=\"delete_files\">Dateien löschen</string>\n    <string name=\"delete_format\" formatted=\"true\">Löschen (%1$d | %2$s)</string>\n    <string name=\"select_all\">Alle auswählen</string>\n    <string name=\"deselect_all\">Alle abwählen</string>\n    <string name=\"play_from_beginning_img_des\">Vom Beginn an spielen</string>\n    <string name=\"downloads_delete_select\">Elemente zum Löschen auswählen</string>\n    <string name=\"offline_file\">Zum Offline-Ansehen verfügbar</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Bist du dir sicher, dass du die folgenden Elemente permanent löschen willst?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Bist du dir sicher, dass du die folgenden Episoden in %1$s permanent löschen willst?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Du wirst ebenfalls alle Episoden der folgenden Serien permanent löschen:\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Bist du dir sicher, dass du alle Episoden der folgenden Serien permanent löschen willst?\n\\n\n\\n%s</string>\n    <string name=\"sort_release_date_new\">Veröffentlichungsdatum (von neu nach alt)</string>\n    <string name=\"sort_release_date_old\">Veröffentlichungsdatum (von alt nach neu)</string>\n    <string name=\"preview_seekbar\">Suchleisten Vorschau</string>\n    <string name=\"preview_seekbar_desc\">Vorschau Bilder in der Suchleiste einschalten</string>\n    <string name=\"no_subtitles_loaded\">Keine Untertitel geladen</string>\n    <string name=\"backup_path_title\">Backup-Speicherort</string>\n    <string name=\"confirm_before_exiting_title\">Bestätigung zum Verlassen</string>\n    <string name=\"custom\">Benutzerdefiniert</string>\n    <string name=\"confirm_before_exiting_desc\">Vor dem Verlassen der App einen Dialog anzeigen</string>\n    <string name=\"show\">Anzeigen</string>\n    <string name=\"dont_show\">Nicht anzeigen</string>\n    <string name=\"subs_edge_size\">Kantengröße</string>\n    <string name=\"torrent_info\">Dieses Video ist ein Torrent, das bedeutet, dass Ihre Videoaktivitäten nachverfolgt werden könen.\\nStellen Sie sicher, dass Sie die Grundlagen von Torrents verstehen, bevor Sie fortfahren.</string>\n    <string name=\"audio_singluar\">Ton</string>\n    <string name=\"sort_episodes_number_desc\">Episode (Absteigend)</string>\n    <string name=\"sort_episodes_rating_high_low\">Bewertung (Höchste)</string>\n    <string name=\"sort_episodes_rating_low_high\">Bewertung (Niedrigste)</string>\n    <string name=\"sort_episodes_date_newest\">Ausstrahlungsdatum (Letztes)</string>\n    <string name=\"sort_episodes_number_asc\">Episode (Steigend)</string>\n    <string name=\"sort_episodes_date_oldest\">Ausstrahlungsdatum (Erstes)</string>\n    <string name=\"sort_button_date\">Datum %s</string>\n    <string name=\"torrent_preferred_media\">Torrent in Eintellungen/Anbieter/Bevorzugte Medien aktivieren</string>\n    <string name=\"software_decoding_desc\">Softwaredekodierung ermöglicht es dem Player, Videodateien abzuspielen, die von deinem Gerät nicht unterstützt werden, könnte jedoch bei hoher Auflösung zu ruckelnder oder instabiler Wiedergabe führen.</string>\n    <string name=\"torrent_not_accepted\">App neu starten und Stream Torrent Pop-Up akzeptieren, um fortzufahren.</string>\n    <string name=\"update_plugins\">Plugins aktualisieren</string>\n    <string name=\"plugins_updated_manually\">%d Plugin(s) erfolgreich aktualisiert!</string>\n    <string name=\"update_plugins_manually\">Plugins manuell aktualisieren</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"unsupported_error\">Nicht unterstützter Fehler</string>\n    <string name=\"encoding_error\">Kodierungsfehler</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_rating\">Bewertung %s</string>\n    <string name=\"no_plugins_updated_manually\">Keine Plugins wurden aktualisiert.</string>\n    <string name=\"software_decoding\">Softwaredekodierung</string>\n    <string name=\"starting_plugin_update_manually\">Plugin-Updateprozess wird gestartet!</string>\n    <string name=\"player_load_one_subtitle_online\">Erste verfügbare laden</string>\n    <string name=\"subtitles_from_embedded\">Eingebettet</string>\n    <string name=\"subtitles_from_online\">Online</string>\n    <string name=\"player_notification_channel_description\">Player-Benachrichtigung zur Steuerung der Hintergrundwiedergabe</string>\n    <string name=\"speech_recognition_unavailable\">Spracherkennung ist nicht verfügbar</string>\n    <string name=\"begin_speaking\">Beginne zu sprechen…</string>\n    <string name=\"player_notification_channel_name\">Player-Benachrichtigung</string>\n    <string name=\"all_subtitles_bold\">Alle Untertitel fett machen</string>\n    <string name=\"all_subtitles_italic\">Alle Untertitel kursiv machen</string>\n    <string name=\"background_radius\">Hintergrundsradius</string>\n    <string name=\"volume_exceeded_100\">Lautstärke hat 100% überschritten</string>\n    <string name=\"slide_up_again_to_exceed_100\">Noch einmal nach oben wischen, um 100% zu überschreiten</string>\n    <string name=\"player_settings_always_ask\">Immer fragen</string>\n    <string name=\"download_parallel_settings_des\">Wie viele verschiedene Elemente können parallel heruntergeladen werden</string>\n    <string name=\"parallel_downloads\">Parallele Downloads</string>\n    <string name=\"concurrent_connections\">Gleichzeitige Verbindungen</string>\n    <string name=\"concurrent_connections_settings_des\">Wie viele gleichzeitige Verbindungen jeder Download während des Downloads verwenden kann</string>\n    <string name=\"go_to_downloads\">Zu den Downloads</string>\n    <string name=\"no_internet_connection\">Keine Internetverbindung.\\n\\nBitte verbinden Sie sich mit dem Internet und versuchen Sie es erneut, oder schauen Sie sich Ihre Downloads an, während Sie offline sind.</string>\n    <string name=\"overscan_settings_des\">Ändert die Grenzen des Bildschirms</string>\n    <string name=\"overscan_settings\">Überscannen</string>\n    <string name=\"poster_size_settings_des\">Ändert die Größe von Postern</string>\n    <string name=\"poster_size_settings\">Größe des Posters</string>\n    <string name=\"speedup_title\">LongPress Geschwindigkeitsschalter</string>\n    <string name=\"speedup_summary\">Halten Sie gedrückt, um die 2x Geschwindigkeit zu erhalten</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dstd%2$dm%3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm%2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"show_rating\">Bewerungslabel</string>\n    <string name=\"no_account\">Kein Konto</string>\n    <string name=\"edit_profile_image_title\">Profilbild ändern</string>\n    <string name=\"edit_profile_image_hint\">Profilbild URL eingeben</string>\n    <string name=\"edit_profile_image_error_empty\">Keine URL gefunden</string>\n    <string name=\"edit_profile_image_error_invalid\">Ungültige URL oder ungültiges Bild</string>\n    <string name=\"edit_profile_image_success\">Profilbild erfolgreich geändert</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Označi kao gledano do ove epizode</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Ukloni epizodu koju sam gledao do sada</string>\n    <string name=\"action_reload\">Ponovo učitano</string>\n    <string name=\"name\">Name</string>\n    <string name=\"resolution_and_name\">Auflösung und Name</string>\n    <string name=\"reload_provider\">Anbieter erneut laden</string>\n    <string name=\"subs_subtitle_alignment\">Untertitelausrichtung</string>\n    <string name=\"bottom_left\">Unten links</string>\n    <string name=\"bottom_center\">Unten Mitte</string>\n    <string name=\"bottom_right\">Unten rechts</string>\n    <string name=\"middle_left\">Mitte links</string>\n    <string name=\"middle_center\">Mitte</string>\n    <string name=\"middle_right\">Mitte rechts</string>\n    <string name=\"top_left\">Oben links</string>\n    <string name=\"top_center\">Oben mitte</string>\n    <string name=\"top_right\">Oben rechts</string>\n    <string name=\"play_full_series_button\">Gesamte Serie abspielen</string>\n    <string name=\"install_prerelease\">Vorabversion installieren</string>\n    <string name=\"prerelease_already_installed\">Vorabversion ist bereits installiert.</string>\n    <string name=\"prerelease_install_failed\">Die Installation der Vorabversion ist fehlgeschlagen.</string>\n    <string name=\"episode_action_play_mirror\">Spiel Mirror ab</string>\"\n    <string name=\"show_episode_text\">Episodentext</string>\n    <string name=\"search_suggestions\">Empfehlungen suchen</string>\n    <string name=\"search_suggestions_des\">Beim Tippen Suchempfehlungen anzeigen</string>\n    <string name=\"clear_suggestions\">Empfehlungen löschen</string>\n    <string name=\"extra_brightness_settings\">Zusätzliche Helligkeit</string>\n    <string name=\"extra_brightness_settings_des\">Aktiviere Helligkeitsfilter, wenn 100% Bildschirmhelligkeit überschritten ist</string>\n    <string name=\"extra_brightness_key\">Erhöhte Helligkeit aktiviert</string>\n    <string name=\"show_cast_in_details\">Cast-Panel zeigen</string>\n    <string name=\"video_info\">Medieninfo</string>\n    <string name=\"source_name\">Quellname</string>\n    <string name=\"download_all\">Alle herunterladen</string>\n    <string name=\"download_episode_range\">Möchtest du Episode %s herunter laden?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d aktiver Download</item>\n        <item quantity=\"other\">%d aktive Downloads</item>\n    </plurals>\n    <string name=\"cancel_queue_message\">Möchtest du alle Downloads in der Warteschlange abbrechen?</string>\n    <string name=\"cancel_all\">Alles abbrechen</string>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d Download in Warteschlange</item>\n        <item quantity=\"other\">%d Downloads in Warteschlange</item>\n    </plurals>\n    <string name=\"download_queue\">Download in Warteschlange</string>\n    <string name=\"queue_empty_message\">Es befinden sich keine Downloads in der Warteschlange.</string>\n    <string name=\"source_priority\">Quellpriorität</string>\n    <string name=\"source_priority_help\">Entscheide, wie Videoquellen im Player sortiert werden sollen</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+el/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Αρχική</string>\n    <string name=\"title_search\">Αναζήτηση</string>\n    <string name=\"title_downloads\">Λήψεις</string>\n    <string name=\"title_settings\">Ρυθμίσεις</string>\n    <string name=\"play_with_app_name\">Άνοιγμα με CloudStream</string>\n    <string name=\"search_hint\">Αναζήτηση…</string>\n    <string name=\"search_poster_img_des\">Αφίσα</string>\n    <string name=\"no_data\">Χωρίς δεδομένα</string>\n    <string name=\"episode_more_options_des\">Περισσότερες Επιλογές</string>\n    <string name=\"go_back_img_des\">Πίσω</string>\n    <string name=\"next_episode\">Επόμενο Επεισόδιο</string>\n    <string name=\"result_poster_img_des\">Αφίσα</string>\n    <string name=\"result_tags\">Κατηγορίες</string>\n    <string name=\"result_share\">Κοινοποίηση</string>\n    <string name=\"result_open_in_browser\">Άνοιγμα στον περιηγητή</string>\n    <string name=\"skip_loading\">Παράλειψη φόρτωσης</string>\n    <string name=\"loading\">Φόρτωση…</string>\n    <string name=\"type_watching\">Παρακολούθηση</string>\n    <string name=\"type_on_hold\">Σε αναμονή</string>\n    <string name=\"type_completed\">Ολοκληρώθηκε</string>\n    <string name=\"type_dropped\">Διακόπηκε</string>\n    <string name=\"type_plan_to_watch\">Για παρακολούθηση</string>\n    <string name=\"play_movie_button\">Αναπαραγωγή ταινίας</string>\n    <string name=\"play_torrent_button\">Μετάδοση Torrent</string>\n    <string name=\"pick_source\">Πηγές</string>\n    <string name=\"pick_subtitle\">Υπότιτλοι</string>\n    <string name=\"reload_error\">Προσπάθεια επανασύνδεσης…</string>\n    <string name=\"go_back\">Πίσω</string>\n    <string name=\"episode_poster_img_des\">Αφίσα επεισοδίου</string>\n    <string name=\"play_episode\">Αναπαραγωγή επεισοδίου</string>\n    <!--<string name=\"need_storage\">Απαιτείται άδεια για την λήψη επεισοδίου</string>-->\n    <string name=\"download\">Λήψη</string>\n    <string name=\"error_loading_links_toast\">Σφάλμα φόρτωσης συνδέσμων</string>\n    <string name=\"download_storage_text\">Εσωτερικός χώρος αποθήκευσης</string>\n    <!--<string name=\"options\">Επιλογές</string>-->\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Διαγραφή Αρχείου</string>\n    <string name=\"popup_play_file\">Αναπαραγωγή αρχείου</string>\n    <string name=\"popup_resume_download\">Συνέχιση λήψης</string>\n    <string name=\"popup_pause_download\">Παύση λήψης</string>\n    <string name=\"show_log_cat\">Εμφάνιση Logcat 🐈</string>\n    <string name=\"home_more_info\">Περαιτέρω πληροφορίες</string>\n    <string name=\"home_expanded_hide\">Απόκρυψη</string>\n    <string name=\"home_main_poster_img_des\">Κύρια αφίσα</string>\n    <string name=\"home_play\">Αναπαραγωγή</string>\n    <string name=\"home_info\">Πληροφορίες</string>\n    <string name=\"home_next_random_img_des\">Next Random</string>\n    <string name=\"home_change_provider_img_des\">Αλλαγή Παρόχου</string>\n    <string name=\"filter_bookmarks\">Φιλτράρισμα Σελιδοδεικτών</string>\n    <string name=\"error_bookmarks_text\">Σελιδοδείκτες</string>\n    <string name=\"action_remove_from_bookmarks\">Αφαίρεση</string>\n    <string name=\"play_episode_toast\">Αναπαραγωγή επεισοδίου</string>\n    <string name=\"sort_apply\">Υποβολή</string>\n    <string name=\"player_speed\">Ταχύτητα αναπαραγωγής</string>\n    <string name=\"subtitles_settings\">Ρυθμίσεις υπότιτλων</string>\n    <string name=\"subs_text_color\">Χρώμα κειμένου</string>\n    <string name=\"subs_outline_color\">Χρώμα περιγράμματος</string>\n    <string name=\"subs_background_color\">Χρώμα φόντου</string>\n    <string name=\"subs_window_color\">Χρώμα παραθύρου</string>\n    <string name=\"subs_edge_type\">Τύπος άκρων</string>\n    <string name=\"subs_subtitle_elevation\">Ύψωση υπότιτλων</string>\n    <string name=\"subs_default_reset_toast\">Επαναφορά στις προεπιλεγμένες τιμές</string>\n    <string name=\"preview_background_img_des\">Προεπισκόπηση φόντου</string>\n    <string name=\"subs_font\">Γραμματοσειρά</string>\n    <string name=\"search_provider_text_providers\">Αναζήτηση βάσει παρόχων</string>\n    <string name=\"search_provider_text_types\">Αναζήτηση βάσει τύπων</string>\n    <string name=\"benene_count_text\">%d μπανάνες δόθηκαν στους προγραμματιστές</string>\n    <string name=\"benene_count_text_none\">Καμία μπανάνα δεν δόθηκε</string>\n    <string name=\"subs_auto_select_language\">Αυτόματη επιλογή γλώσσας</string>\n    <string name=\"subs_download_languages\">Λήψη γλωσσών</string>\n    <string name=\"subs_hold_to_reset_to_default\">Κρατήστε πατημένο για επαναφορά στις προεπιλεγμένες τιμές</string>\n    <string name=\"continue_watching\">Συνέχεια παρακολούθησης</string>\n    <string name=\"action_remove_watching\">Αφαίρεση</string>\n    <string name=\"action_open_watching\">Περαιτέρω πληροφορίες</string>\n    <string name=\"vpn_might_be_needed\">Η χρήση ενός VPN ίσως χρειαστεί για την ομαλή λειτουργία του τρέχοντος παρόχου</string>\n    <string name=\"vpn_torrent\">Ο πάροχος αυτός πρόκειται για torrent, η χρήση ενός VPN συνιστάται</string>\n    <string name=\"torrent_plot\">Περιγραφή</string>\n    <string name=\"normal_no_plot\">Δεν βρέθηκε περιγραφή</string>\n    <string name=\"torrent_no_plot\">Δεν βρέθηκε περιγραφή</string>\n    <string name=\"picture_in_picture\">Εικόνα-εντός-Εικόνας</string>\n    <string name=\"picture_in_picture_des\">Συνεχίζει την αναπαραγωγή σε ένα μίνι παράθυρο πάνω από άλλες εφαρμογές</string>\n    <string name=\"player_size_settings\">Αλλαγή μεγέθους παραθύρου</string>\n    <string name=\"player_size_settings_des\">Αφαίρεση μαύρων περιγραμμάτων</string>\n    <string name=\"player_subtitles_settings\">Υπότιτλοι</string>\n    <string name=\"player_subtitles_settings_des\">Ρυθμίσεις υποτίτλων του προγράμματος αναπαραγωγής</string>\n    <string name=\"chromecast_subtitles_settings\">Υπότιτλοι για Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Ρυθμίσεις υποτίτλων για Chromecast</string>\n    <string name=\"eigengraumode_settings\">Ταχύτητα Προβολής</string>\n    <string name=\"swipe_to_seek_settings\">Σύρετε για αναζήτηση</string>\n    <string name=\"swipe_to_seek_settings_des\">Σύρετε από πλευρά σε πλευρά για να ελέγξετε το σημείο του βίντεο στο οποίο βρίσκεστε</string>\n    <string name=\"swipe_to_change_settings\">Σύρετε για να αλλάξετε ρυθμίσεις</string>\n    <string name=\"swipe_to_change_settings_des\">Σύρετε πάνω ή κάτω στην αριστερή ή στη δεξιά μεριά της οθόνης για να αλλάξετε τη φωτεινότητα ή την ένταση</string>\n    <string name=\"double_tap_to_seek_settings\">Διπλό πάτημα για αναζήτηση</string>\n    <string name=\"double_tap_to_seek_settings_des\">Διπλό πάτημα στα αριστερά ή δεξιά για αναζήτηση προς τα μπροστά ή πίσω</string>\n    <string name=\"search\">Αναζήτηση</string>\n    <string name=\"settings_info\">Πληροφορίες</string>\n    <string name=\"advanced_search\">Προχωρημένη Αναζήτηση</string>\n    <string name=\"advanced_search_des\">Δίνει τα αποτελέσματα αναζήτησης ταξινομημένα ανά πάροχο</string>\n    <string name=\"updates_settings\">Εμφάνιση ενημερώσεων</string>\n    <string name=\"updates_settings_des\">Αυτόματη αναζήτηση νέων ενημερώσεων κατά την εκκίνηση της εφαρμογής.</string>\n    <string name=\"github\">GitHub</string>\n    <string name=\"lightnovel\">Εφαρμογή βιβλίων από τους ίδιους προγραμματιστές</string>\n    <string name=\"anim\">Εφαρμογή άνιμε από τους ίδιους προγραμματιστές</string>\n    <string name=\"discord\">Βρείτε μας στο Discord</string>\n    <string name=\"benene\">Δώστε μία μπανάνα στους προγραμματιστές</string>\n    <string name=\"benene_des\">Μπανάνα δόθηκε</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Ταχύτητα (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Βαθμολογία: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Νέα διαθέσιμη ενημέρωση!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"double_tap_to_pause_settings_des\">Πατήστε δύο φορές στη μέση για παύση</string>\n    <string name=\"use_system_brightness_settings\">Χρήση φωτεινότητας συστήματος</string>\n    <string name=\"use_system_brightness_settings_des\">Χρήση φωτεινότητας συστήματος στο ενσωματωμένο πρόγραμμα αναπαραγωγής, αντί εφαρμογής προεπιλεγμένου σκούρου επικαλύμματος</string>\n    <string name=\"episode_sync_settings\">Ενημέρωση προόδου παρακολούθησης</string>\n    <string name=\"episode_sync_settings_des\">Αυτόματος συγχρονισμός της προόδου του τρέχοντος επεισοδίου</string>\n    <string name=\"restore_settings\">Επαναφορά δεδομένων από αντίγραφο ασφαλείας</string>\n    <string name=\"backup_settings\">Αντίγραφα ασφαλείας</string>\n    <string name=\"restore_success\">Τα αντίγραφα ασφαλείας φορτώθηκαν</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Η επαναφορά αντιγράφων ασφαλείας απέτυχε από το αρχείο %s</string>\n    <string name=\"backup_success\">Τα δεδομένα αποθηκεύτηκαν</string>\n    <string name=\"backup_failed\">Δεν έχει δοθεί άδεια για πρόσβαση στον αποθηκευτικό χώρο. Παρακαλώ προσπαθήστε ξανά.</string>\n    <string name=\"backup_failed_error_format\">Σφάλμα δημιουργίας αντιγράφων ασφαλείας %s</string>\n    <string name=\"category_account\">Λογαριασμοί και Ασφάλεια</string>\n    <string name=\"category_updates\">Ενημερώσεις και αντίγραφα ασφαλείας</string>\n    <string name=\"show_fillers_settings\">Εμφάνιση filler επεισοδίου για άνιμε</string>\n    <string name=\"show_trailers_settings\">Εμφάνιση trailer</string>\n    <string name=\"kitsu_settings\">Εμφάνιση αφισών από Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Απόκρυψη επιλεγμένης ποιότητας βίντεο στα αποτελέσματα αναζήτησης</string>\n    <string name=\"app_language\">Γλώσσα εφαρμογής</string>\n    <string name=\"no_chromecast_support_toast\">Αυτός ο πάροχος δεν έχει υποστήριξη για Chromecast</string>\n    <string name=\"no_links_found_toast\">Δεν βρέθηκαν διαθέσιμοι σύνδεσμοι</string>\n    <string name=\"copy_link_toast\">Ο σύνδεσμος αντιγράφηκε στο πρόχειρο</string>\n    <string name=\"season\">Κύκλος</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Κανένας κύκλος</string>\n    <string name=\"episode\">Επεισόδιο</string>\n    <string name=\"episodes\">Επεισόδια</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">Σ</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Δεν βρέθηκαν επεισόδια</string>\n    <string name=\"delete_file\">Διαγραφή αρχείου</string>\n    <string name=\"delete\">Διαγραφή</string>\n    <string name=\"cancel\">Ακύρωση</string>\n    <string name=\"pause\">Παύση</string>\n    <string name=\"resume\">Συνέχιση</string>\n    <string name=\"delete_message\" formatted=\"true\">Αυτό θα διαγράψει μόνιμα το %s\n\\nΕίστε σίγουροι πως θέλετε να προχωρήσετε;</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nαπομένουν</string>\n    <string name=\"status_ongoing\">Σε εξέλιξη</string>\n    <string name=\"status\">Κατάσταση</string>\n    <string name=\"year\">Έτος</string>\n    <string name=\"duration\">Διάρκεια</string>\n    <string name=\"site\">Ιστότοπος</string>\n    <string name=\"synopsis\">Περίληψη</string>\n    <string name=\"queued\">προστέθηκε στην ουρά</string>\n    <string name=\"no_subtitles\">Δεν υπάρχουν διαθέσιμοι υπότιτλοι</string>\n    <string name=\"action_default\">Προεπιλεγμένοι υπότιτλοι</string>\n    <string name=\"free_storage\">Ελεύθερος</string>\n    <string name=\"used_storage\">Σε χρήση</string>\n    <string name=\"app_storage\">Εφαρμογή</string>\n    <string name=\"movies\">Ταινίες</string>\n    <string name=\"tv_series\">Τηλεοπτικές σειρές</string>\n    <string name=\"cartoons\">Κινούμενα σχέδια</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"documentaries\">Ντοκιμαντέρ</string>\n    <string name=\"asian_drama\">Ασιατικά Δράματα</string>\n    <string name=\"livestreams\">Ζωντανές Μεταδόσεις</string>\n    <string name=\"others\">Άλλα</string>\n    <string name=\"movies_singular\">Ταινία</string>\n    <string name=\"tv_series_singular\">Σειρά</string>\n    <string name=\"cartoons_singular\">Κινούμενα Σχέδια</string>\n    <string name=\"documentaries_singular\">Ντοκιμαντέρ</string>\n    <string name=\"asian_drama_singular\">Ασιατικό Δράμα</string>\n    <string name=\"live_singular\">Ζωντανή Μετάδοση</string>\n    <string name=\"other_singular\">Άλλο</string>\n    <string name=\"source_error\">Σφάλμα πηγής</string>\n    <string name=\"remote_error\">Απομακρυσμένο σφάλμα</string>\n    <string name=\"render_error\">Σφάλμα απόδοσης</string>\n    <string name=\"unexpected_error\">Απρόσμενο σφάλμα αναπαραγωγής</string>\n    <string name=\"storage_error\">Σφάλμα λήψης, επιβεβαιώστε ότι η άδεια αποθήκευσης είναι ενεργοποιημένη</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast επεισόδιο</string>\n    <string name=\"episode_action_play_in_app\">Αναπαραγωγή εντός της εφαρμογής</string>\n    <string name=\"episode_action_play_in_format\">Αναπαραγωγή σε %s</string>\n    <string name=\"episode_action_auto_download\">Αυτόματη λήψη</string>\n    <string name=\"episode_action_download_mirror\">Λήψη mirror</string>\n    <string name=\"episode_action_reload_links\">Επαναφόρτωση συνδέσμων</string>\n    <string name=\"episode_action_download_subtitle\">Λήψη υποτίτλων</string>\n    <string name=\"show_hd\">Ποιότητα</string>\n    <string name=\"show_dub\">Ετικέτα Dub</string>\n    <string name=\"show_sub\">Sub</string>\n    <string name=\"show_title\">Τίτλος</string>\n    <string name=\"poster_ui_settings\">Εναλλαγή γραφικών στοιχείων στην αφίσα</string>\n    <string name=\"video_lock\">Κλείδωμα</string>\n    <string name=\"video_aspect_ratio_resize\">Αλλαγή μεγέθους</string>\n    <string name=\"video_source\">Πηγή</string>\n    <string name=\"video_skip_op\">Παράλειψη OP</string>\n    <string name=\"dont_show_again\">Να μην εμφανιστεί ξανά</string>\n    <string name=\"skip_update\">Παράλειψη της τρέχουσας ενημέρωσης</string>\n    <string name=\"update\">Ενημέρωση</string>\n    <string name=\"watch_quality_pref\">Προτιμώμενη ποιότητας παρακολούθησης (WiFi)</string>\n    <string name=\"limit_title\">Μέγιστος αριθμός χαρακτήρων τίτλου</string>\n    <string name=\"limit_title_rez\">Ανάλυση προγράμματος αναπαραγωγής βίντεο</string>\n    <string name=\"video_buffer_size_settings\">Μέγεθος buffer για βίντεο</string>\n    <string name=\"video_buffer_length_settings\">Μήκος buffer για βίντεο</string>\n    <string name=\"video_buffer_disk_settings\">Μέγεθος προσωρινής μνήμης βίντεο στον δίσκο</string>\n    <string name=\"video_buffer_clear_settings\">Εκκαθάριση προσωρινής μνήμης βίντεο και εικόνων</string>\n    <string name=\"video_ram_description\">Προκαλεί καταρρεύσεις εάν οριστεί πολύ ψηλά. Μην το αλλάξετε εάν έχετε χαμηλή ποσότητα μνήμης RAM, όπως σε Android TV ή παλιά συσκευή.</string>\n    <string name=\"video_disk_description\">Προκαλεί προβλήματα σε συστήματα με χαμηλό αποθηκευτικό χώρο, όπως σε συσκευές Android TV.</string>\n    <string name=\"dns_pref_summary\">Χρήσιμο για παράκαμψη μπλοκαρισμάτων από ISP</string>\n    <string name=\"add_site_pref\">Αντίγραφο ιστοτόπου</string>\n    <string name=\"remove_site_pref\">Αφαίρεση ιστοτόπου</string>\n    <string name=\"add_site_summary\">Προσθήκη αντιγράφου ενός υπάρχοντος ιστοτόπου, με έναν διαφορετικό σύνδεσμο</string>\n    <string name=\"download_path_pref\">Διαδρομή λήψης</string>\n    <string name=\"display_subbed_dubbed_settings\">Εμφάνιση Dubbed/Subbed Άνιμε</string>\n    <string name=\"resize_fit\">Προσαρμογή στην οθόνη</string>\n    <string name=\"resize_fill\">Τέντωμα</string>\n    <string name=\"resize_zoom\">Μεγέθυνση</string>\n    <string name=\"legal_notice\">Αποποίηση ευθυνών</string>\n    <string name=\"category_general\">Γενικά</string>\n    <string name=\"random_button_settings\">Κουμπί τυχαίας δράσης</string>\n    <string name=\"random_button_settings_desc\">Εμφάνιση κουμπιού τυχαίας προβολής στην Αρχική Οθόνη</string>\n    <string name=\"provider_lang_settings\">Γλώσσες παρόχων</string>\n    <string name=\"app_layout\">Διάταξη εφαρμογής</string>\n    <string name=\"preferred_media_settings\">Προτιμώμενα μέσα</string>\n    <string name=\"enable_nsfw_on_providers\">Ενεργοποίηση ακατάλληλου περιεχομένου σε υποστηριζόμενους παρόχους</string>\n    <string name=\"subtitles_encoding\">Κωδικοποίηση υποτίτλων</string>\n    <string name=\"category_providers\">Πάροχοι</string>\n    <string name=\"category_ui\">Διάταξη</string>\n    <string name=\"automatic\">Αυτόματο</string>\n    <string name=\"tv_layout\">Διάταξη TV</string>\n    <string name=\"phone_layout\">Διάταξη τηλεφώνου</string>\n    <string name=\"emulator_layout\">Διάταξη emulator</string>\n    <string name=\"primary_color_settings\">Πρωτεύον χρώμα</string>\n    <string name=\"app_theme_settings\">Θέμα εφαρμογής</string>\n    <string name=\"bottom_title_settings\">Τοποθεσία τίτλου Poster</string>\n    <string name=\"bottom_title_settings_des\">Τοποθετήστε τον τίτλο κάτω από το poster</string>\n    <string name=\"example_lang_name\">Κωδικός γλώσσας (el)</string>\n    <string name=\"account\">Λογαριασμός</string>\n    <string name=\"logout\">Αποσύνδεση</string>\n    <string name=\"login\">Σύνδεση</string>\n    <string name=\"switch_account\">Εναλλαγή λογαριασμού</string>\n    <string name=\"add_account\">Προσθήκη λογαριασμού</string>\n    <string name=\"create_account\">Δημιουργία λογαριασμού</string>\n    <string name=\"add_sync\">Προσθήκη παρακολούθησης</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Προστέθηκε %s</string>\n    <string name=\"upload_sync\">Συγχρονισμός</string>\n    <string name=\"sync_score\">Βαθμολογήθηκε</string>\n    <string name=\"authenticated_user\" formatted=\"true\">Πιστοποιήθηκε %s</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Αποτυχία σύνδεσης στο %s</string>\n    <string name=\"none\">Τίποτα</string>\n    <string name=\"normal\">Κανονικά</string>\n    <string name=\"all\">Όλα</string>\n    <string name=\"max\">Μέγιστο</string>\n    <string name=\"min\">Ελάχιστο</string>\n    <string name=\"subtitles_outline\">Περίγραμμα</string>\n    <string name=\"subtitles_depressed\">Σε κατάθλιψη</string>\n    <string name=\"subtitles_shadow\">Σκιά</string>\n    <string name=\"subtitles_raised\">Ανεβασμένοι</string>\n    <string name=\"subtitle_offset\">Συγχρονισμός υποτίτλων</string>\n    <string name=\"subtitle_offset_hint\">1000ms</string>\n    <string name=\"subtitle_offset_title\">Καθυστέρηση υποτίτλων</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Χρησιμοποιήστε αυτό αν οι υπότιτλοι εμφανίζονται %dms πολύ νωρίς</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Χρησιμοποιήστε αυτό αν οι υπότιτλοι εμφανίζονται %dms πολύ αργά</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Καμία καθυστέρηση υποτίτλων</string>\n    <string name=\"recommended\">Συνιστώμενο</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Φόρτωση %s</string>\n    <string name=\"player_load_subtitles\">Φόρτωση από αρχείο</string>\n    <string name=\"player_load_subtitles_online\">Φόρτωση από το Ίντερνετ</string>\n    <string name=\"downloaded_file\">Λήψη αρχείου</string>\n    <string name=\"actor_main\">Κύριο</string>\n    <string name=\"actor_supporting\">Υποστηρίζεται</string>\n    <string name=\"actor_background\">Φόντο</string>\n    <string name=\"home_source\">Πηγή</string>\n    <string name=\"home_random\">Τυχαίο</string>\n    <string name=\"coming_soon\">Έρχεται σύντομα…</string>\n    <string name=\"poster_image\">Εικόνα Poster</string>\n    <string name=\"category_player\">Πρόγραμμα αναπαραγωγής</string>\n    <string name=\"resolution_and_title\">Ανάλυση και τίτλος</string>\n    <string name=\"title\">Τίτλος</string>\n    <string name=\"resolution\">Ανάλυση</string>\n    <string name=\"error_invalid_id\">Μη έγκυρο ID</string>\n    <string name=\"error_invalid_data\">Μη έγκυρα δεδομένα</string>\n    <string name=\"error_invalid_url\">Μη έγκυρος σύνδεσμος</string>\n    <string name=\"error\">Σφάλμα</string>\n    <string name=\"subtitles_remove_captions\">Αφαίρεση closed captions (για άτομα με προβλήματα ακοής) από τους υπότιτλους</string>\n    <string name=\"subtitles_remove_bloat\">Αφαίρεση bloat από τους υπότιτλους</string>\n    <string name=\"subtitles_filter_lang\">Φιλτράρισμα ανά την προτεινόμενη γλώσσα του μέσου</string>\n    <string name=\"extras\">Έξτρα</string>\n    <string name=\"trailer\">Τρέιλερ</string>\n    <string name=\"network_adress_example\">Https://Παράδειγμα.com/Παράδειγμα.mp4</string>\n    <string name=\"referer\">Παραπομπή (προαιρετική)</string>\n    <string name=\"next\">Επόμενο</string>\n    <string name=\"provider_languages_tip\">Παρακολούθηση βίντεο σε αυτή την γλώσσα</string>\n    <string name=\"previous\">Προηγούμενο</string>\n    <string name=\"skip_setup\">Παράλειψη διαμόρφωσης της εφαρμογής</string>\n    <string name=\"app_layout_subtext\">Αλλαγή της εμφάνισης της συσκευής για να ταιριάζει με την συσκευή σας</string>\n    <string name=\"preferred_media_subtext\">Τι θα θέλατε να δείτε</string>\n    <string name=\"setup_done\">Έγινε</string>\n    <string name=\"extensions\">Extensions</string>\n    <string name=\"add_repository\">Προσθήκη αποθετηρίου</string>\n    <string name=\"repository_name_hint\">Όνομα αποθετηρίου(προαιρετικό)</string>\n    <string name=\"repository_url_hint\">Σύνδεσμος αποθετηρίου ή σύντομος κωδικός αποθετηρίου</string>\n    <string name=\"plugin_loaded\">Το πρόσθετο φορτώθηκε</string>\n    <string name=\"plugin_deleted\">Το πρόσθετο διαγράφηκε</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Αποτυχία φόρτωσης του %s</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Ξεκίνησε η λήψη %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Κατέβηκε το %1$d %2$s επιτυχώς</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Όλα τα %s έχουν ήδη κατέβει</string>\n    <string name=\"batch_download\">Μαζική λήψη</string>\n    <string name=\"plugin_singular\">Πρόσθετο</string>\n    <string name=\"plugin\">Πρόσθετα</string>\n    <string name=\"delete_repository_plugins\">Αυτό θα διαγράψει όλα τα πρόσθετα του αποθετηρίου</string>\n    <string name=\"delete_repository\">Διαγραφή αποθετηρίου</string>\n    <string name=\"setup_extensions_subtext\">Κατεβάστε την λίστα των ιστότοπων που θέλετε να χρησιμοποιήσετε</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Κατέβηκε: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Απενεργοποιήθηκε: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Δεν κατέβηκε: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Ενημερώθηκαν %d πρόσθετα</string>\n    <string name=\"blank_repo_message\">Το CloudStream δεν έχει προεγκατεστημένους ιστότοπους. Πρέπει να εγκαταστήσετε ιστότοπους μέσω ορισμένων αποθετηρίων.\n\\n\n\\nΒρείτε μας στο Discord ή ψάξτε στο διαδίκτυο.</string>\n    <string name=\"view_public_repositories_button\">Προβολή αποθετηρίων κοινότητας</string>\n    <string name=\"view_public_repositories_button_short\">Δημόσια λίστα</string>\n    <string name=\"uppercase_all_subtitles\">Κεφαλοποίηση υποτίτλων</string>\n    <string name=\"download_all_plugins_from_repo\">Προειδοποίηση: Το CloudStream 3 δεν αναλαμβάνει καμία ευθύνη για τη χρήση επεκτάσεων τρίτων και δεν παρέχει καμία υποστήριξη για αυτές!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Απενεργοποιήθηκε)</string>\n    <string name=\"tracks\">Κομμάτια</string>\n    <string name=\"audio_tracks\">Ηχητικά κομμάτια</string>\n    <string name=\"video_tracks\">Κομμάτια βίντεο</string>\n    <string name=\"apply_on_restart\">Κάντε επανεκκίνηση της εφαρμογής για να δείτε τις αλλαγές.</string>\n    <string name=\"safe_mode_title\">Η ασφαλής λειτουργία ενεργοποιήθηκε</string>\n    <string name=\"safe_mode_description\">Όλα τα extensions απενεργοποιήθηκαν , ώστε να μπορέσετε να διαπιστώσετε ποιο από αυτά προκάλεσε τη κατάρρευση.</string>\n    <string name=\"safe_mode_crash_info\">Προβολή πληροφορίας κατάρρευσης</string>\n    <string name=\"extension_rating\" formatted=\"true\">Βαθμολογία: %s</string>\n    <string name=\"extension_description\">Περιγραφή</string>\n    <string name=\"extension_version\">Έκδοση</string>\n    <string name=\"extension_status\">Κατάσταση</string>\n    <string name=\"extension_size\">Μέγεθος</string>\n    <string name=\"extension_authors\">Συγγραφείς</string>\n    <string name=\"extension_types\">Υποστηρίζονται</string>\n    <string name=\"extension_language\">Γλώσσα</string>\n    <string name=\"extension_install_first\">Εγκατάσταση προσθέτου πρώτα</string>\n    <string name=\"hls_playlist\">HLS Playlist</string>\n    <string name=\"player_pref\">Προτεινόμενο πρόγραμμα αναπαραγωγής</string>\n    <string name=\"player_settings_play_in_app\">Ενσωματωμένο πρόγραμμα αναπαραγωγής</string>\n    <string name=\"app_not_found_error\">Η εφαρμογή δεν βρέθηκε</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Επ %2$d</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Το επεισόδιο %d θα κυκλοφορήσει σε</string>\n    <string name=\"filler\" formatted=\"true\">Φίλτρο</string>\n    <string name=\"duration_format\" formatted=\"true\">%d λεπτά</string>\n    <string name=\"cast_format\" formatted=\"true\">Ηθοποιοί: %s</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dμ %2$dω %3$dλ</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dω %2$dλ</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dλ</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Αναζήτηση %s…</string>\n    <string name=\"play_livestream_button\">Αναπαραγωγή ζωντανής μετάδοσης</string>\n    <string name=\"downloaded\">Ληφθέν</string>\n    <string name=\"download_canceled\">Η λήψη ακυρώθηκε</string>\n    <string name=\"download_failed\">Η λήψη απέτυχε</string>\n    <string name=\"download_started\">Η λήψη ξεκίνησε</string>\n    <string name=\"download_paused\">Η λήψη παύθηκε</string>\n    <string name=\"downloading\">Κατεβαίνει</string>\n    <string name=\"sort_close\">Κλείσιμο</string>\n    <string name=\"sort_clear\">Εκκαθάριση</string>\n    <string name=\"subs_subtitle_languages\">Γλώσσα υποτίτλων</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"provider_info_meta\">Δεν έχουν παρασχεθεί μεταδεδομένα από τον ιστότοπο, η φόρτωση του βίντεο θα αποτύχει αν δεν υπάρχει στον ιστότοπο.</string>\n    <string name=\"double_tap_to_pause_settings\">Διπλό πάτημα για παύση</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Μέγεθος αναζήτησης στο πρόγραμμα αναπαραγωγής (σε δευτερόλεπτα)</string>\n    <string name=\"automatic_plugin_updates\">Αυτόματη ενημέρωση plugin</string>\n    <string name=\"automatic_plugin_download\">Αυτόματη λήψη plugin</string>\n    <string name=\"dns_pref\">DNS μέσω HTTPS</string>\n    <string name=\"example_site_url\">https://παράδειγμα.com</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"skip_type_mixed_op\">Ανάμεικτοι τίτλοι αρχής</string>\n    <string name=\"skip_type_creddits\">Εύσημα</string>\n    <string name=\"skip_type_intro\">Εισαγωγή</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"status_completed\">Ολοκληρώθηκε</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast mirror</string>\n    <string name=\"nginx_url_pref\">Σύνδεσμος NGINX σέρβερ</string>\n    <string name=\"example_site_name\">ΝεοΟνομαΙστοτοπου</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"clear_history\">Εκκαθάριση ιστορικού</string>\n    <string name=\"history\">Ιστορικό</string>\n    <string name=\"enable_skip_op_from_database_des\">Εμφάνιση pop-up για παράλειψη τίτλων αρχής και τέλους</string>\n    <string name=\"clipboard_too_large\">Υπερβολικά μεγάλο μέγεθος κειμένου. Αδύνατη η αποθήκευση στο πρόχειρο.</string>\n    <string name=\"yes\">Ναι</string>\n    <string name=\"no\">Όχι</string>\n    <string name=\"update_notification_downloading\">Λήψη ενημέρωσης εφαρμογής…</string>\n    <string name=\"update_notification_installing\">Εγκατάσταση ενημέρωσης εφαρμογής…</string>\n    <string name=\"update_notification_failed\">Αδύνατη η εγκατάσταση της νέας έκδοσης της εφαρμογής</string>\n    <string name=\"type_re_watching\">Ξαναβλέπει</string>\n    <string name=\"stream\">Μετάδοση</string>\n    <string name=\"download_done\">Η λήψη ολοκληρώθηκε</string>\n    <string name=\"autoplay_next_settings\">Αυτόματη αναπαραγωγή επόμενου επεισοδίου</string>\n    <string name=\"automatic_plugin_download_summary\">Αυτόματη εγκατάσταση όλων των μη-εγκατεστημένων plugin από τους προστιθεμένους παρόχους.</string>\n    <string name=\"anime\">Άνιμε</string>\n    <string name=\"no_update_found\">Δεν βρέθηκε ενημέρωση</string>\n    <string name=\"check_for_update\">Έλεγχος για ενημέρωση</string>\n    <string name=\"example_password\">κωδικός123</string>\n    <string name=\"example_username\">ΤοΚουλΟνομαΜου</string>\n    <string name=\"example_email\">γειασου@κόσμε.com</string>\n    <string name=\"subtitles_example_text\">Η γρήγορη, καφέ αλεπού πηδάει πάνω από τον τεμπέλη σκύλο / The quick brown fox jumps over the lazy dog</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"skip_type_op\">Τίτλοι αρχής</string>\n    <string name=\"skip_type_ed\">Τίτλοι τέλους</string>\n    <string name=\"skip_type_recap\">Ανακεφαλαίωση</string>\n    <string name=\"skip_type_mixed_ed\">Ανάμεικτοι τίτλοι τέλους</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"rating\">Κριτική</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"pref_category_app_updates\">Ενημερώσεις εφαρμογής</string>\n    <string name=\"pref_category_backup\">Αντίγραφο ασφαλείας</string>\n    <string name=\"pref_category_extensions\">Extensions</string>\n    <string name=\"pref_category_actions\">Δράσεις</string>\n    <string name=\"pref_category_cache\">Προσωρινή μνήμη</string>\n    <string name=\"pref_category_player_features\">Χαρακτηριστικά προγράμματος αναπαραγωγής</string>\n    <string name=\"pref_category_subtitles\">Υπότιτλοι</string>\n    <string name=\"pref_category_player_layout\">Δομή</string>\n    <string name=\"pref_category_defaults\">Προεπιλεγμένα</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"subs_font_size\">Μέγεθος γραμματοσειράς</string>\n    <string name=\"anime_singular\">Άνιμε</string>\n    <string name=\"pref_category_links\">Σύνδεσμοι</string>\n    <string name=\"pref_category_looks\">Εμφάνιση</string>\n    <string name=\"pref_category_ui_features\">Χαρακτηριστικά</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"all_languages_preference\">Όλες οι γλώσσες</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Παράλειψη %s</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"apk_installer_legacy\">Legacy</string>\n    <string name=\"play_trailer_button\">Αναπαραγωγή τρέιλερ</string>\n    <string name=\"action_add_to_bookmarks\">Ορισμός κατάστασης θέασης</string>\n    <string name=\"sort_copy\">Αντιγραφή</string>\n    <string name=\"sort_save\">Αποθήκευση</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Εισάγετε γραμματοσειρές τοποθετώντας \\'τες στο %s</string>\n    <string name=\"autoplay_next_settings_des\">Αναπαραγωγή του επόμενου επεισοδίου με το τέλος του τρέχοντος</string>\n    <string name=\"apk_installer_settings\">Εγκαταστάτης APK</string>\n    <string name=\"apk_installer_settings_des\">Ορισμένες συσκευές δεν υποστηρίζουν τον νέο εγκαταστάτη πακέτων. Δοκιμάστε την επιλογή Legacy εάν δεν εγκαθίστανται οι ενημερώσεις.</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"pref_category_gestures\">Χειρονομίες</string>\n    <string name=\"action_mark_as_watched\">Σημείωσε το ως πλήρως παρακολουθημένο</string>\n    <string name=\"confirm_exit_dialog\">Είστε σίγουροι πως θέλετε να βγείτε;</string>\n    <string name=\"redo_setup_process\">Επανάληψη διαδικασίας διαμόρφωσης της εφαρμογής</string>\n    <string name=\"plugin_downloaded\">Το πρόσθετο κατέβει</string>\n    <string name=\"update_started\">Ενημέρωση ξεκίνησε</string>\n    <string name=\"delayed_update_notice\">Η εφαρμογή θα ενημερωθεί κατά την έξοδο</string>\n    <string name=\"sort_alphabetical_z\">Αλφαβητικά (Ω προς Α)</string>\n    <string name=\"sort\">Ταξινόμηση</string>\n    <string name=\"sort_rating_asc\">Κριτική (Χαμηλή προς Υψηλή)</string>\n    <string name=\"sort_updated_new\">Ενημερωμένο (Καινούριο προς παλιό)</string>\n    <string name=\"sort_updated_old\">Ενημερωμένο (Παλιό προς Καινούργιο)</string>\n    <string name=\"library\">Βιβλιοθήκη</string>\n    <string name=\"sort_rating_desc\">Κριτική (Υψηλή προς χαμηλή)</string>\n    <string name=\"sort_by\">Ταξινόμηση με βάση</string>\n    <string name=\"sort_alphabetical_a\">Αλφαβητικά (Α προς Ω)</string>\n    <string name=\"select_library\">Διάλεξε βιβλιοθήκη</string>\n    <string name=\"empty_library_logged_in_message\">Αυτή η λίστα είναι άδεια. Δοκιμάστε μια άλλη.</string>\n    <string name=\"action_remove_from_watched\">Αφαίρεση από παρακολουθημένα</string>\n    <string name=\"browser\">Περιηγητής</string>\n    <string name=\"open_with\">Άνοιγμα με</string>\n    <string name=\"empty_library_no_accounts_message\">Η βιβλιοθήκη σας είναι άδεια :(\n\\nΣυνδεθείτε με έναν λογαριασμό βιβλιοθήκης ή προσθέστε σειρές στην τοπική βιβλιοθήκη σας.</string>\n    <string name=\"safe_mode_file\">Βρέθηκε αρχείο Ασφαλούς Λειτουργίας!\n\\nΔεν πρόκειται να φορτωθούν extensions κατά το ξεκίνημα μέχρι να διαγραφεί το αρχείο.</string>\n    <string name=\"test_log\">Αρχείο Καταγραφής</string>\n    <string name=\"test_failed\">Απέτυχε</string>\n    <string name=\"test_passed\">Πέτυχε</string>\n    <string name=\"start\">Εκκίνηση</string>\n    <string name=\"no_plugins_found_error\">Δε βρέθηκαν επεκτάσεις στο αποθετήριο</string>\n    <string name=\"no_repository_found_error\">Δε βρέθηκε αποθετήριο, ελέγξτε την URL και δοκιμάστε VPN</string>\n    <string name=\"quality_profile_help\">Από εδώ μπορείτε να αλλάξετε τον τρόπο σειράς των πηγών. Εάν ένα βίντεο έχει υψηλότερη προτεραιότητα, θα εμφανίζεται ψηλότερα στην επιλογή πηγής. Το άθροισμα της προτεραιότητας πηγής και της ποιότητας, είναι η προτεραιότητα του βίντεο.\n\\n\n\\nΠηγή Α: 3\n\\nΠοιότητα Β: 7\n\\nΘα έχει συνδυασμένη προτεραιότητα βίντεο 10.\n\\n\n\\nΣΗΜΕΙΩΣΗ: Εάν το άθροισμα είναι 10 ή περισσότερο, η συσκευή αναπαραγωγής θα παραλείψει αυτόματα τη φόρτωση όταν φορτωθεί αυτός ο σύνδεσμος!</string>\n    <string name=\"category_provider_test\">Δοκιμή παρόχου</string>\n    <string name=\"watch_quality_pref_data\">Προτιμώμενη ποιότητας παρακολούθησης (Δεδομένα τηλεφώνου)</string>\n    <string name=\"jsdelivr_proxy\">Διακομιστής μεσολάβησης GitHub</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"subscription_in_progress_notification\">Ενημέρωση εγγεγραμμένων εκπομπών</string>\n    <string name=\"subscription_new\">Έγινε εγγραφή σε %s</string>\n    <string name=\"revert\">Επαναφορά</string>\n    <string name=\"subscription_episode_released\">Δημοσιεύθηκε το επεισόδιο %d!</string>\n    <string name=\"help\">Βοήθεια</string>\n    <string name=\"qualities\">Ποιότητες</string>\n    <string name=\"profile_background_des\">Φόντο προφίλ</string>\n    <string name=\"restart\">Επανεκκίνηση</string>\n    <string name=\"jsdelivr_enabled\">Το GitHub δεν είναι προσβάσιμο. Ενεργοποίηση διακομιστή μεσολάβησης jsDelivr…</string>\n    <string name=\"pref_category_bypass\">Παράκαμψη ISP</string>\n    <string name=\"subscription_deleted\">Αφαιρέθηκε η εγγραφή από %s</string>\n    <string name=\"subscription_list_name\">Εγγεγραμμένος</string>\n    <string name=\"profile_number\">Προφίλ %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Δεδομένα τηλεφώνου</string>\n    <string name=\"set_default\">Ορισμός προεπιλογής</string>\n    <string name=\"use\">Χρήση</string>\n    <string name=\"edit\">Επεξεργασία</string>\n    <string name=\"profiles\">Προφίλ</string>\n    <string name=\"unable_to_inflate\">Το UI δεν ήταν σε θέση να δημιουργηθεί σωστά, είναι ένα σφάλμα και θα πρέπει να αναφερθεί αμέσως %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Επιλέξτε κατάσταση για φιλτράρισμα επεκτάσεων για λήψη</string>\n    <string name=\"disable\">Απενεργοποιημένο</string>\n    <string name=\"stop\">Τέλος</string>\n    <string name=\"backup_frequency\">Συχνότητα δημιουργίας αντιγράφων ασφαλείας</string>\n    <string name=\"links_reloaded_toast\">Οι σύνδεσμοι επαναφορτώθηκαν</string>\n    <string name=\"toast_copied\">αντιγράφηκε!</string>\n    <string name=\"result_search_tooltip\">Αναζήτηση σε άλλες επεκτάσεις</string>\n    <string name=\"subscribe_tooltip\">Ειδοποίηση για νέο επεισόδιο</string>\n    <string name=\"enter_pin\">Εισαγωγή Κωδικού</string>\n    <string name=\"repo_copy_label\">Όνομα \\\"αποθήκης\\\" και λινκ</string>\n    <string name=\"recommendations_tooltip\">Εμφάνιση προτάσεων</string>\n    <string name=\"action_add_to_favorites\">Προσθήκη στα Αγαπημένα</string>\n    <string name=\"action_subscribe\">Εγγραφή</string>\n    <string name=\"duplicate_replace_all\">Αντικατάσταση Όλων</string>\n    <string name=\"use_default_account\">Χρησιμοποίηση Βασικού λογαριασμού</string>\n    <string name=\"action_remove_from_favorites\">Αφαίρεση από τα Αγαπημένα</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Κρυμμένο Πλέιερ - Δευτερόλεπτα Σκιπ</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Δευτερόλεπτα Σκιπ όταν ο αναπαραγωγέας είναι κρυφός</string>\n    <string name=\"ok\">Εντάξει</string>\n    <string name=\"battery_dialog_title\">Απενεργοποιήση της εξοικονόμησης της μπαταρίας</string>\n    <string name=\"already_voted\">Έχετε ήδη ψηφίσει</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Φαίνεται πως ένα πιθανό αντίγραφο βρίσκεται στη βιβλιοθήκη σας: \\'%s.\\'\n\\n\n\\nΘα επιθυμούσατε να το προσθέσετε, να το αντικαταστήσετε, ή να ακυρώσετε την ενέργεια;</string>\n    <string name=\"enter_current_pin\">Εισαγωγή Τρέχον Κωδικού</string>\n    <string name=\"lock_profile\">Κλείδωμα Προφίλ</string>\n    <string name=\"biometric_authentication_title\">Ξεκλείδωμα Cloudstream</string>\n    <string name=\"password_pin_authentication_title\">ΚωδικόςPIN Αυθεντικότητας</string>\n    <string name=\"speed_setting_summary\">Προσθέτει επιλογή ταχύτητας στον αναπαραγωγέα</string>\n    <string name=\"logged_account\" formatted=\"true\">Σύνδεση ως %s</string>\n    <string name=\"rotate_video\">Περιστροφή</string>\n    <string name=\"action_unsubscribe\">Απεγγραφή</string>\n    <string name=\"manage_accounts\">Διαχείριση λογαριασμών</string>\n    <string name=\"auto_rotate_video_desc\">Ενεργοποίηση αυτόματης περιστροφής οθόνης αναλόγως του βίντεο</string>\n    <string name=\"auto_rotate_video\">Αυτόματη περιστροφή</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Σεζόν %1$dΕπεισόδιο%2$d θα κυκλοφορήσει</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Δευτερόλεπτα Σκιπ όταν φαίνεται ο αναπαραγωγέας (πλειερ)</string>\n    <string name=\"test_extensions\">Δοκιμή όλων των παροχών</string>\n    <string name=\"test_extensions_summary\">Αυτό το τεστ προορίζεται μόνο για τους προγραμματιστές και δε επαληθείει ούτε απορρίπτει την λειτουργία οποιουδήποτε παρόχου.</string>\n    <string name=\"player_settings_select_cast_device\">Επιλογή συσκευής για αναμετάδοση</string>\n    <string name=\"clipboard_permission_error\">Πρόβλημα στην πρόσβαση στο Clipboard, Παρακαλώ προσπαθήστε ξανά.</string>\n    <string name=\"clipboard_unknown_error\">Πρόβλημα στην αντιγραφή , Παρακαλούμε αντιγράψτε το logcat και επικοινωνήστε με την υποστήριξη.</string>\n    <string name=\"app_unrestricted_toast\">Η χρήση μπαταρίας έχει ήδη τεθεί χωρίς περιορισμό</string>\n    <string name=\"app_info_intent_error\">Αδύνατο άνοιγμα των στοιχείων της εφαρμογής Cloudstream.</string>\n    <string name=\"favorites_list_name\">Αγαπημένα</string>\n    <string name=\"favorite_added\">%s προστέθηκε στα αγαπημένα</string>\n    <string name=\"favorite_removed\">%s αφαιρέθηκε από τα αγαπημένα</string>\n    <string name=\"duplicate_title\">Πιθανό αντίγραφο βρέθηκε</string>\n    <string name=\"duplicate_add\">Προσθήκη</string>\n    <string name=\"duplicate_replace\">Αντικατάσταση</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Πιθανά διπλά αρχεία βρέθηκαν στην βιβλιοθήκη:\n\\n\n\\n%s\n\\n\n\\nΘα επιθυμούσατε να προσθέσετε αυτό το αρχείο ούτως η άλλως, να αντικαταστήσετε τα ήδη υπάρχοντα, ή να ακυρώσετε την ενέργεια?</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Εισαγωγή Κωδικού για %s</string>\n    <string name=\"pin\">Κωδικός</string>\n    <string name=\"pin_error_incorrect\">Εσφαλμένος Κωδικός. Προσπαθήστε ξανά.</string>\n    <string name=\"pin_error_length\">Ο κωδικός να περιέχει 4 χαρακτήρες</string>\n    <string name=\"select_an_account\">Επιλογή λογαριασμού</string>\n    <string name=\"unfavorite\">Αφαίρεση από αγαπημένα</string>\n    <string name=\"biometric_setting\">Κλείδωμα με βιομετρικά</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Έρχεται σε %s</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Εμφάνιση Πλέιερ - Δευτερόλεπτα Σκιπ</string>\n    <string name=\"jsdelivr_proxy_summary\">Παράκαμψη απαγόρευσης από raw github URLs χρησιμοποιώντας jsDelivr. Μπορεί να καθυστερήσει τις ενημερώσεις για μερικές μέρες.</string>\n    <string name=\"rotate_video_desc\">Εμφάνιση κουμπιού για περιστροφή οθόνης</string>\n    <string name=\"favorite\">Αγαπημένο</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nαπομένουν</string>\n    <string name=\"biometric_unsupported\">Βιομετρική αυθεντικοποίηση δεν υποστηρίζεται από τη συσκευή</string>\n    <string name=\"episode_action_cast_mirror\">Καστ ταινίας</string>\n    <string name=\"battery_dialog_message\">Για να εξασφαλιστούν αδιάκοπες λήψεις και ειδοποιήσεις για αναγραφόμενες τηλεοπτικές εκπομπές, το CloudStream χρειάζεται άδεια για να τρέξει στο παρασκήνιο. Πατώντας OK, θα εμφανιστεί ένας διάλογος αιτήματος. Παρακαλώ πατήστε \\\\\\\"Επιτρέπω\\\\\\\".\\n\\nΠαρακαλώ σημειώστε, αυτή η άδεια δεν σημαίνει ότι το CS3 θα αποστραγγίσει την μπαταρία σας. Θα λειτουργεί στο παρασκήνιο μόνο όταν είναι απαραίτητο, όπως κατά τη λήψη ειδοποιήσεων ή τη λήψη βίντεο από επίσημες επεκτάσεις.</string>\n    <string name=\"biometric_setting_summary\">Ξεκλείδωμα εφαρμογής με δακτυλικό αποτύπωμα, Face ID, PIN, Μοτίβο και Κωδικό.</string>\n    <string name=\"biometric_prompt_description\">Μετά από μερικές αποτυχημένες προσπάθειες, η άμεση θα κλείσει. Απλά επανεκκινήστε την εφαρμογή για να δοκιμάσετε ξανά.</string>\n    <string name=\"edit_account\">Επεξεργασία λογαριασμού</string>\n    <string name=\"skip_startup_account_select_pref\">Παράλειψη επιλογής λογαριασμού στην εκκίνηση της εφαρμογής</string>\n    <string name=\"music_singlar\">Μουσική</string>\n    <string name=\"audio_book_singular\">Ακουστικό Βιβλίο</string>\n    <string name=\"custom_media_singluar\">Μέσα</string>\n    <string name=\"reset_btn\">Επαναφορά</string>\n    <string name=\"biometric_warning\">Τα δεδομένα σας στο CloudStream έχουν κάνει back up. Αν και η πιθανότητα είναι πολύ χαμηλή, όλες οι συσκευές συμπεριφέρονται διαφορετικά. Στη σπάνια περίπτωση, που απαγορευτεί η πρόσβασή σας από την εφαρμογή, διαγράψτε τα δεδομένα εφαρμογής και επαναφέρετέ τα από ένα ήδη υπάρχον backup. Συγνώμη για οποιαδήποτε ταλαιπωρία.</string>\n    <string name=\"pref_category_accounts\">Λογαριασμοί</string>\n    <string name=\"pref_category_security\">Ασφάλεια</string>\n    <string name=\"dismiss\">Απόρριψη</string>\n    <string name=\"subtitles_from_embedded\">Ενσωματωμένο</string>\n    <string name=\"subtitles_from_online\">Συνδεμένοι</string>\n    <string name=\"downloads_empty\">Δεν υπάρχουν προς το παρόν λήψεις.</string>\n    <string name=\"subs_edge_size\">Μέγεθος άκρων</string>\n    <string name=\"sort_episodes_rating_low_high\">Βαθμολογία (Χαμηλότερη)</string>\n    <string name=\"sort_button_episode\">Επ %s</string>\n    <string name=\"sort_episodes_number_asc\">Επεισόδιο (αύξουσα σειρά)</string>\n    <string name=\"sort_episodes_number_desc\">Επεισόδιο (φθίνουσα σειρά)</string>\n    <string name=\"sort_episodes_rating_high_low\">Βαθμολογία (υψηλότερη)</string>\n    <string name=\"sort_button_rating\">Βαθμολογία %s</string>\n    <string name=\"update_plugins\">Ενημέρωση προσθέτων</string>\n    <string name=\"update_plugins_manually\">Ενημέρωση πρόσθετων χειροκίνητα</string>\n    <string name=\"device_pin_error_message\">Δεν μπορείτε να λάβετε τον κωδικό PIN της συσκευής, δοκιμάστε τοπική αυθεντικοποίηση</string>\n    <string name=\"device_pin_expired_message\">Ο κωδικός PIN έχει λήξει !</string>\n    <string name=\"player_notification_channel_name\">Ειδοποίησεις αναπαραγωγής</string>\n    <string name=\"player_notification_channel_description\">Η ειδοποίηση παίκτη για τον έλεγχο του playback από το φόντο</string>\n    <string name=\"delete_files\">Διαγραφή Αρχείων</string>\n    <string name=\"delete_format\" formatted=\"true\">Διαγραφή (%1$d | %2$s)</string>\n    <string name=\"sort_release_date_new\">Ημερομηνία κυκλοφορίας (από νέο σε παλιό)</string>\n    <string name=\"preview_seekbar\">Προεπισκόπηση Γραμμή αναζήτησης</string>\n    <string name=\"play_from_beginning_img_des\">Παίξε από την αρχή</string>\n    <string name=\"cs3wiki\">Το Wiki του CloudStream</string>\n    <string name=\"hide_player_control_names\">Απόκρυψη των ονομάτων των χειρισμών του παίκτη</string>\n    <string name=\"auth_locally\">Τοπική εξουσιοδότηση</string>\n    <string name=\"speech_recognition_unavailable\">Αναγνώριση ομιλίας μη διαθέσιμη</string>\n    <string name=\"begin_speaking\">Αρχίστε να μιλάτε…</string>\n    <string name=\"downloads_delete_select\">Επιλέξτε στοιχεία για Διαγραφή</string>\n    <string name=\"select_all\">Επιλογή όλων</string>\n    <string name=\"deselect_all\">Αποεπιλογή Όλων</string>\n    <string name=\"test_warning\">Προειδοποίηση</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Είστε σίγουροι ότι θέλετε να διαγράψετε μόνιμα τα ακόλουθα στοιχεία;\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Είστε σίγουροι ότι θέλετε να διαγράψετε μόνιμα τα ακόλουθα επεισόδια στο %1$s;\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Θα διαγράψετε επίσης μόνιμα όλα τα επεισόδια της ακόλουθης σειράς:\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Είστε σίγουροι ότι θέλετε να διαγράψετε μόνιμα όλα τα επεισόδια της ακόλουθης σειράς;\\n\\n%s</string>\n    <string name=\"sort_button_date\">Ημερομηνία %s</string>\n    <string name=\"device_pin_counter_text\">Ο Κωδικός λήγει σε %1$dm %2$ds</string>\n    <string name=\"sort_release_date_old\">Ημερομηνία κυκλοφορίας (από παλαιό σε νέο)</string>\n    <string name=\"preview_seekbar_desc\">Ενεργοποίηση προεπισκόπησης μικρογραφίας στη γραμμή αναζήτησης</string>\n    <string name=\"no_subtitles_loaded\">Δεν έχουν φορτωθεί υπότιτλοι ακόμη</string>\n    <string name=\"confirm_before_exiting_title\">Επιβεβαίωση πριν από την έξοδο</string>\n    <string name=\"confirm_before_exiting_desc\">Εμφάνιση διαλόγου πριν την έξοδο από την εφαρμογή</string>\n    <string name=\"dont_show\">Μην εμφανίσεις</string>\n    <string name=\"custom\">Προσαρμοργή</string>\n    <string name=\"torrent_not_accepted\">Επανεκκινήστε την εφαρμογή και δεχτείτε το αναδυόμενο Stream Torrent για να συνεχίσετε.</string>\n    <string name=\"software_decoding\">Λογισμικό αποκωδικοποίησης</string>\n    <string name=\"torrent_preferred_media\">Ενεργοποίησε torrent στις Ρυθμίσεις/Providers/Preferred media</string>\n    <string name=\"software_decoding_desc\">Η αποκωδικοποίηση λογισμικού επιτρέπει στον παίκτη να παίξει αρχεία βίντεο που δεν υποστηρίζονται από το τηλέφωνό σας, αλλά μπορεί να προκαλέσει κολλήματα ή ασταθή αναπαραγωγή σε υψηλή ανάλυση</string>\n    <string name=\"starting_plugin_update_manually\">Έναρξη διαδικασίας ενημέρωσης πρόσθετων!</string>\n    <string name=\"plugins_updated_manually\">Επιτυχής ενημέρωση του πρόσθετου(τών) %d!</string>\n    <string name=\"qr_image\">Εικόνα κωδικού QR</string>\n    <string name=\"open_downloaded_repo\">Ανοίξε αποθετήριο</string>\n    <string name=\"torrent_info\">Αυτό το βίντεο είναι ένα Torrent, αυτό σημαίνει ότι η δραστηριότητα του βίντεο μπορεί να παρακολουθείται.\\nΒεβαιωθείτε ότι έχετε κατανοήσει το Torrenting πριν συνεχίσετε.</string>\n    <string name=\"offline_file\">Διαθέσιμο για παρακολούθηση χωρίς σύνδεση</string>\n    <string name=\"device_pin_url_message\">Επισκεφθείτε το <b>%s</b> στο κινητό ή τον υπολογιστή σας και πληκτρολογήστε τον παραπάνω κωδικό</string>\n    <string name=\"delete_plugin\">Διαγραφή πρόσθετου</string>\n    <string name=\"show\">Εμφάνισε</string>\n    <string name=\"open_local_video\">Άνοιγμα τοπικού βίντεο</string>\n    <string name=\"no_plugins_updated_manually\">Κανένα πρόσθετο δεν ενημερώθηκε.</string>\n    <string name=\"backup_path_title\">Τοποθεσία φακέλου αντιγράφων</string>\n    <string name=\"audio_singluar\">Ήχος</string>\n    <string name=\"podcast_singluar\">Ποντκάστ</string>\n    <string name=\"encoding_error\">Σφάλμα κωδικοποίησης</string>\n    <string name=\"unsupported_error\">Σφάλμα που δεν υποστηρίζεται</string>\n    <string name=\"player_load_one_subtitle_online\">Φορτώστε το πρώτο διαθέσιμο</string>\n    <string name=\"sort_episodes_date_newest\">Ημερομηνία εκπομπής (Νεότερη)</string>\n    <string name=\"sort_episodes_date_oldest\">Ημερομηνία εκπομπής (Παλαιότερη)</string>\n    <string name=\"volume_exceeded_100\">Ο ήχος έχει ξεπεράσει το 100%</string>\n    <string name=\"all_subtitles_bold\">Κάντε όλους τους υπότιτλους έντονους</string>\n    <string name=\"all_subtitles_italic\">Κάντε όλους τους υπότιτλους πλάγιους</string>\n    <string name=\"background_radius\">Ακτίνα φόντου</string>\n    <string name=\"slide_up_again_to_exceed_100\">Σύρετε ξανά προς τα πάνω για να υπερβείτε το 100%</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"go_back_img_des\">Reen</string>\n    <string name=\"title_home\">Hejmo</string>\n    <string name=\"title_downloads\">Elŝutoj</string>\n    <string name=\"go_back\">Reen</string>\n    <string name=\"pick_source\">Fontoj</string>\n    <string name=\"sort_apply\">Efektivigi</string>\n    <string name=\"sort_save\">Konservi</string>\n    <string name=\"subs_font_size\">Tipara grando</string>\n    <string name=\"action_remove_watching\">Forigi</string>\n    <string name=\"episodes\">Epizodoj</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"year\">Jaro</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"extension_language\">Lingvo</string>\n    <string name=\"extension_size\">Grando</string>\n    <string name=\"extension_authors\">Aŭtoroj</string>\n    <string name=\"extension_description\">Priskribo</string>\n    <string name=\"extension_version\">Versio</string>\n    <string name=\"extension_status\">Stato</string>\n    <string name=\"sort_clear\">Forviŝi</string>\n    <string name=\"yes\">Jes</string>\n    <string name=\"no\">Ne</string>\n    <string name=\"history\">Historio</string>\n    <string name=\"title_search\">Serĉi</string>\n    <string name=\"result_poster_img_des\">Afiŝo</string>\n    <string name=\"play_movie_button\">Spekti filmon</string>\n    <string name=\"home_play\">Spekti</string>\n    <string name=\"home_info\">Informoj</string>\n    <string name=\"sort_copy\">Kopii</string>\n    <string name=\"sort_close\">Fermi</string>\n    <string name=\"subs_font\">Tiparo</string>\n    <string name=\"subs_download_languages\">Elŝuti lingvojn</string>\n    <string name=\"subs_auto_select_language\">Aŭtomate elekti lingvon</string>\n    <string name=\"subs_text_color\">Teksta koloro</string>\n    <string name=\"action_remove_from_bookmarks\">Forigi</string>\n    <string name=\"settings_info\">Informoj</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"status\">Stato</string>\n    <string name=\"source_error\">Fonta eraro</string>\n    <string name=\"login\">Saluti</string>\n    <string name=\"account\">konto</string>\n    <string name=\"subs_window_color\">Fenestra koloro</string>\n    <string name=\"title_settings\">Agordoj</string>\n    <string name=\"result_tags\">Ĝenroj</string>\n    <string name=\"all_languages_preference\">Ĉiuj lingvoj</string>\n    <string name=\"search\">Serĉi</string>\n    <string name=\"category_account\">Kontoj</string>\n    <string name=\"github\">GitHub</string>\n    <string name=\"season\">Sezono</string>\n    <string name=\"episode\">Epizodo</string>\n    <string name=\"asian_drama_singular\">Azia dramo</string>\n    <string name=\"asian_drama\">Aziaj dramoj</string>\n    <string name=\"tv_series_singular\">Serio</string>\n    <string name=\"tv_series\">Televidaj serioj</string>\n    <string name=\"go_back_30\">−30</string>\n    <string name=\"movies_singular\">Filmo</string>\n    <string name=\"movies\">Filmoj</string>\n    <string name=\"others\">Aliaj</string>\n    <string name=\"quality_blueray\">Blu-radia</string>\n    <string name=\"title\">Titolo</string>\n    <string name=\"none\">Nenio</string>\n    <string name=\"logout\">Adiaŭi</string>\n    <string name=\"show_title\">Titolo</string>\n    <string name=\"video_source\">Fonto</string>\n    <string name=\"example_lang_name\">Lingvokodo (eo)</string>\n    <string name=\"example_password\">pasvorto123</string>\n    <string name=\"example_username\">MiaSalutNomo</string>\n    <string name=\"example_email\">saluton@mondo.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">MiaRetejo</string>\n    <string name=\"example_site_url\">ekzemplo.com</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Rapido (%.2fx)</string>\n    <string name=\"search_hint\">Serĉi…</string>\n    <string name=\"download\">Elŝuti</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Rolantaro: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Epizodo %d estos publikigita en</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dt %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"new_update_format\" formatted=\"true\">Nova ĝisdatigo trovita!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Speciala epizodo</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"download_started\">Elŝuto Komencite</string>\n    <string name=\"reload_error\">Reprovi konekton…</string>\n    <string name=\"stream\">Elsendfluo</string>\n    <string name=\"home_next_random_img_des\">Sekva Hazarda</string>\n    <string name=\"download_canceled\">Elŝuto Nuligite</string>\n    <string name=\"episode_more_options_des\">Pli da Opcioj</string>\n    <string name=\"next_episode\">Sekva epizodo</string>\n    <string name=\"search_poster_img_des\">Afiŝo</string>\n    <string name=\"play_episode\">Ludi Epizodon</string>\n    <string name=\"preview_background_img_des\">Antaŭrigardi Fono</string>\n    <string name=\"home_change_provider_img_des\">Ŝanĝi Provizanton</string>\n    <string name=\"rated_format\" formatted=\"true\">Rangita: %.1f</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Serĉi %s…</string>\n    <string name=\"no_data\">Neniuj Datumoj</string>\n    <string name=\"type_watching\">Spektante</string>\n    <string name=\"type_on_hold\">En paŭzo</string>\n    <string name=\"type_completed\">Kompletigita</string>\n    <string name=\"type_re_watching\">Re-spektante</string>\n    <string name=\"play_torrent_button\">Elsendflui Torenton</string>\n    <string name=\"download_done\">Elŝuto Farite</string>\n    <string name=\"update_started\">Ĝisdatigo Komencite</string>\n    <string name=\"error_loading_links_toast\">Eraro okazis dum la Ŝarĝado de Ligiloj</string>\n    <string name=\"type_dropped\">Forlasita</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"play_with_app_name\">Ludi per CloudStream</string>\n    <string name=\"result_share\">Kunhavigi</string>\n    <string name=\"play_livestream_button\">Ludi tuj-elsendfluon</string>\n    <string name=\"download_paused\">Elŝuto Paŭzite</string>\n    <string name=\"pick_subtitle\">Subtekstoj</string>\n    <string name=\"skip_loading\">Preterpasi la ŝarĝado</string>\n    <string name=\"browser\">Retumilo</string>\n    <string name=\"loading\">Ŝarĝante…</string>\n    <string name=\"type_plan_to_watch\">Plani Spekti</string>\n    <string name=\"play_trailer_button\">Ludi Antaŭfilmon</string>\n    <string name=\"episode_poster_img_des\">Epizoda Afiŝo</string>\n    <string name=\"home_main_poster_img_des\">Ĉefa Afiŝo</string>\n    <string name=\"result_open_in_browser\">Malfermi en Retumilo</string>\n    <string name=\"downloaded\">Elŝutite</string>\n    <string name=\"downloading\">Elŝutante</string>\n    <string name=\"download_failed\">Elŝuto Malsukcesite</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+es/array.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <array name=\"cast_mini_controller_control_buttons\">\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_play_pause_toggle</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n    <array name=\"cast_expanded_controller_control_buttons\">\n        <!-- Fake sources button -->\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n        <!-- Actually fake to make the skip op button the same style -->\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n\n    <array name=\"title_info_pref_names\">\n        <item>@string/source_name</item>\n        <item>@string/resolution</item>\n        <item>@string/video_info</item>\n    </array>\n\n    <array name=\"title_info_pref_values\">\n        <item>@string/show_name_key</item>\n        <item>@string/show_resolution_key</item>\n        <item>@string/show_media_info_key</item>\n    </array>\n\n\n    <array name=\"limit_title_pref_names\">\n        <item>@string/none</item>\n        <item>16 caracteres</item>\n        <item>32 caracteres</item>\n        <item>64 caracteres</item>\n        <item>128 caracteres</item>\n        <item>Ocultar título</item>\n    </array>\n    <array name=\"limit_title_pref_values\">\n        <item>0</item>\n        <item>16</item>\n        <item>32</item>\n        <item>64</item>\n        <item>128</item>\n        <item>-1</item>\n    </array>\n\n    <array name=\"skip_sec_values\">\n        <item>5</item>\n        <item>10</item>\n        <item>15</item>\n        <item>20</item>\n        <item>25</item>\n        <item>30</item>\n    </array>\n\n    <array name=\"video_buffer_length_names\">\n        <item>@string/automatic</item>\n        <item>1 minuto</item>\n        <item>1 minuto con 30 segundos</item>\n        <item>2 minutos</item>\n        <item>2 minutos con 30 segundos</item>\n        <item>3 minutos</item>\n        <item>3 minutos con 30 segundos</item>\n        <item>4 minutos</item>\n        <item>5 minutos</item>\n        <item>6 minutos</item>\n        <item>7 minutos</item>\n        <item>8 minutos</item>\n        <item>9 minutos</item>\n        <item>10 minutos</item>\n        <item>15 minutos</item>\n        <item>20 minutos</item>\n        <item>30 minutos</item>\n    </array>\n\n    <array name=\"video_buffer_length_values\">\n        <item>0</item>\n        <item>60</item>\n        <item>90</item>\n        <item>120</item>\n        <item>150</item>\n        <item>180</item>\n        <item>210</item>\n        <item>240</item>\n        <item>300</item>\n        <item>360</item>\n        <item>420</item>\n        <item>480</item>\n        <item>540</item>\n        <item>600</item>\n        <item>900</item>\n        <item>1200</item>\n        <item>1800</item>\n    </array>\n\n    <array name=\"video_buffer_size_names\">\n        <item>@string/automatic</item>\n        <item>10 megas</item>\n        <item>20 megas</item>\n        <item>30 megas</item>\n        <item>40 megas</item>\n        <item>50 megas</item>\n        <item>60 megas</item>\n        <item>70 megas</item>\n        <item>80 megas</item>\n        <item>90 megas</item>\n        <item>100 megas</item>\n        <item>150 megas</item>\n        <item>200 megas</item>\n        <item>250 megas</item>\n        <item>300 megas</item>\n        <item>350 megas</item>\n        <item>400 megas</item>\n        <item>450 megas</item>\n        <item>500 megas</item>\n    </array>\n\n    <array name=\"video_buffer_size_values\">\n        <item>0</item>\n        <item>10</item>\n        <item>20</item>\n        <item>30</item>\n        <item>40</item>\n        <item>50</item>\n        <item>60</item>\n        <item>70</item>\n        <item>80</item>\n        <item>90</item>\n        <item>100</item>\n        <item>150</item>\n        <item>200</item>\n        <item>250</item>\n        <item>300</item>\n        <item>350</item>\n        <item>400</item>\n        <item>450</item>\n        <item>500</item>\n    </array>\n\n    <array name=\"poster_ui_options\">\n        <item>@string/show_hd</item>\n        <item>@string/show_dub</item>\n        <item>@string/show_sub</item>\n        <item>@string/show_rating</item>\n        <item>@string/show_title</item>\n        <item>@string/show_episode_text</item>\n    </array>\n\n    <array name=\"poster_ui_options_values\">\n        <item>@string/show_hd_key</item>\n        <item>@string/show_dub_key</item>\n        <item>@string/show_sub_key</item>\n        <item>@string/show_rating_key</item>\n        <item>@string/show_title_key</item>\n        <item>@string/show_episode_text_key</item>\n    </array>\n\n    <array name=\"app_layout\">\n        <item>@string/automatic</item>\n        <item>@string/phone_layout</item>\n        <item>@string/tv_layout</item>\n        <item>@string/emulator_layout</item>\n    </array>\n\n    <array name=\"app_layout_values\">\n        <item>-1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n    </array>\n\n    <string-array name=\"themes_overlay_names\">\n        <item>Normal</item>\n        <item>Diente de león amarilla</item>\n        <item>Rosa clavel</item>\n        <item>Naranja</item>\n        <item>Verde oscuro</item>\n        <item>Vino</item>\n        <item>Azul marino</item>\n        <item>Gris</item>\n        <item>Blanco</item>\n        <item>Azul fresco</item>\n        <item>Marrón</item>\n        <item>Fresco</item>\n        <item>Fuego</item>\n        <item>Burbuja</item>\n        <item>Verde</item>\n        <item>Manzana</item>\n        <item>Banana</item>\n        <item>Fiesta</item>\n        <item>Dolor rosa</item>\n        <item>Lavanda</item>\n        <item>Material You</item>\n        <item>Material You (Secondary)</item>\n    </string-array>\n    <string-array name=\"themes_overlay_names_values\">\n        <item>Normal</item>\n        <item>DandelionYellow</item>\n        <item>CarnationPink</item>\n        <item>Orange</item>\n        <item>DarkGreen</item>\n        <item>Maroon</item>\n        <item>NavyBlue</item>\n        <item>Grey</item>\n        <item>White</item>\n        <item>CoolBlue</item>\n        <item>Brown</item>\n        <item>Blue</item>\n        <item>Red</item>\n        <item>Purple</item>\n        <item>Green</item>\n        <item>GreenApple</item>\n        <item>Banana</item>\n        <item>Party</item>\n        <item>Pink</item>\n        <item>Lavender</item>\n        <item>Monet</item>\n        <item>Monet2</item>\n    </string-array>\n\n\n    <string-array name=\"themes_names\">\n        <item>Oscuro</item>\n        <item>Gris</item>\n        <item>Amoled</item>\n        <item>Destello</item>\n        <item>Sistema</item>\n        <item>Material You</item>\n        <item>Dracula</item>\n        <item>Sueños De Lavanda</item>\n        <item>Azul Silencioso</item>\n    </string-array>\n    <string-array name=\"themes_names_values\">\n        <item>AmoledLight</item>\n        <item>Black</item>\n        <item>Amoled</item>\n        <item>Light</item>\n        <item>System</item>\n        <item>Monet</item>\n        <item>Dracula</item>\n        <item>Lavender</item>\n        <item>SilentBlue</item>\n    </string-array>\n\n    <!--https://github.com/videolan/vlc-android/blob/72ccfb93db027b49855760001d1a930fa657c5a8/application/resources/src/main/res/values/arrays.xml#L266-->\n    <string-array name=\"subtitles_encoding_list\" tools:ignore=\"TypographyDashes\">\n        <item>@string/automatic</item>\n        <item>Universal (UTF-8)</item>\n        <item>Universal (UTF-16)</item>\n        <item>Universal (endian grande UTF-16)</item>\n        <item>Universal (endian pequeño UTF-16)</item>\n        <item>Universal, chino (GB18030)</item>\n        <item>Europeo occidental (Latin-9)</item>\n        <item>Europeo occidental (Windows-1252)</item>\n        <item>Europeo occidental (IBM 00850)</item>\n        <item>Europeo oriental (Latin-2)</item>\n        <item>Europeo oriental (Windows-1250)</item>\n        <item>Esperanto (Latin-3)</item>\n        <item>Nórdico (Latin-6)</item>\n        <item>Cirílico (Windows-1251)</item>\n        <item>Ruso (KOI8-R)</item>\n        <item>Ucraniano (KOI8-U)</item>\n        <item>Árabe (ISO 8859-6)</item>\n        <item>Árabe (Windows-1256)</item>\n        <item>Griego (ISO 8859-7)</item>\n        <item>Griego (Windows-1253)</item>\n        <item>Hebreo (ISO 8859-8)</item>\n        <item>Hebreo (Windows-1255)</item>\n        <item>Turco (ISO 8859-9)</item>\n        <item>Turco (Windows-1254)</item>\n        <item>Tailandés (TIS 620-2533/ISO 8859-11)</item>\n        <item>Tailandés (Windows-874)</item>\n        <item>Báltico (Latin-7)</item>\n        <item>Báltico (Windows-1257)</item>\n        <item>Céltico (Latin-8)</item>\n        <item>Europeo del sudeste (Latin-10)</item>\n        <item>Chino simplificado (ISO-2022-CN-EXT)</item>\n        <item>Chino simplificado Unix (EUC-CN)</item>\n        <item>Japonés (7-bits JIS/ISO-2022-JP-2)</item>\n        <item>Japonés Unix (EUC-JP)</item>\n        <item>Japonés (Shift JIS)</item>\n        <item>Coreano (EUC-KR/CP949)</item>\n        <item>Coreano (ISO-2022-KR)</item>\n        <item>Chino tradicional (Big5)</item>\n        <item>Chino tradicional Unix (EUC-TW)</item>\n        <item>Complemento de Hong Kong (HKSCS)</item>\n        <item>Vietnamita (VISCII)</item>\n        <item>Vietnamita (Windows-1258)</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pref_category_extensions\">Extensiones</string>\n    <string name=\"setup_extensions_subtext\">Descargue la lista de sitios que quiera utilizar</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Descargado:%d</string>\n    <string name=\"downloaded\">Descargado</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Descargado %1$d %2$s</string>\n    <string name=\"delete_repository\">Borrar repositorio</string>\n    <string name=\"next_episode_format\" formatted=\"true\">El episodio %d se lanzará en</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$d h %2$d m</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d m</string>\n    <string name=\"result_poster_img_des\">Póster</string>\n    <string name=\"extensions\">Extensiones</string>\n    <string name=\"downloaded_file\">Archivo descargado</string>\n    <string name=\"safe_mode_description\">Todas las extensiones se desactivaron debido a un fallo para ayudarlo a encontrar la que está causando problemas.</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Todo %s ha sido descargado</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">No descargado:%d</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Desactivado)</string>\n    <string name=\"repository_url_hint\">URL o código corto del repositorio</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Desactivado:%d</string>\n    <string name=\"add_repository\">Agregar repositorio</string>\n    <string name=\"repository_name_hint\">Nombre del repositorio (opcional)</string>\n    <string name=\"delete_repository_plugins\">Esto también eliminará todos los plugins del repositorio</string>\n    <string name=\"pref_filter_search_quality\">Ocultar la calidad de video en los resultados de búsqueda</string>\n    <string name=\"pref_category_player_layout\">Diseño</string>\n    <string name=\"category_ui\">Diseño</string>\n    <string name=\"watch_quality_pref\">Calidad de visualización preferida (WiFi)</string>\n    <string name=\"player_pref\">Reproductor de video preferido</string>\n    <string name=\"emulator_layout\">Diseño para emulador</string>\n    <string name=\"app_layout\">Diseño de la aplicación</string>\n    <string name=\"tv_layout\">Diseño de TV</string>\n    <string name=\"phone_layout\">Diseño para teléfonos</string>\n    <string name=\"player_subtitles_settings\">Subtítulos</string>\n    <string name=\"subtitles_encoding\">Codificación de subtítulos</string>\n    <string name=\"app_layout_subtext\">Cambiar el aspecto de la aplicación para que se adapte a tu dispositivo</string>\n    <string name=\"subtitles_settings\">Configurar Subtítulos</string>\n    <string name=\"player_subtitles_settings_des\">Configuración de subtítulos del reproductor</string>\n    <string name=\"subtitles_shadow\">Sombra</string>\n    <string name=\"chromecast_subtitles_settings\">Subtítulos de Chomecast</string>\n    <string name=\"episode_action_download_subtitle\">Descargar subtítulos</string>\n    <string name=\"pref_category_subtitles\">Subtítulos</string>\n    <string name=\"subtitles_depressed\">Deprimido</string>\n    <string name=\"subtitles_example_text\">El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío; añoraba a su querido cachorro</string>\n    <string name=\"player_load_subtitles\">Cargar desde archivo</string>\n    <string name=\"player_load_subtitles_online\">Cargar desde Internet</string>\n    <string name=\"autoplay_next_settings\">Reproducir automáticamente episodio siguiente</string>\n    <string name=\"chromecast_subtitles_settings_des\">Configuración de subtítulos de Chromecast</string>\n    <string name=\"action_default\">Predeterminado</string>\n    <string name=\"subtitles_outline\">Contorno</string>\n    <string name=\"no_subtitles\">Sin Subtítulos</string>\n    <string name=\"subtitles_raised\">Elevado</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Use esto si los subtítulos se muestran %d ms muy pronto</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Use esto si los subtítulos se muestran %d ms tarde</string>\n    <string name=\"swipe_to_seek_settings_des\">Desliza el dedo de lado a lado para controlar la posición en un video</string>\n    <string name=\"subtitles_filter_lang\">Filtrar por idioma preferido</string>\n    <string name=\"subtitles_remove_captions\">Eliminar Closed Captions (CC) de los subtítulos</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Cantidad de búsquedas del reproductor (segundos)</string>\n    <string name=\"use_system_brightness_settings_des\">Use el brillo del sistema en el reproductor de la app en lugar de una superposición oscura</string>\n    <string name=\"limit_title_rez\">Mostrar la información del reproductor de video</string>\n    <string name=\"category_player\">Reproductor</string>\n    <string name=\"autoplay_next_settings_des\">Iniciar el siguiente episodio cuando el actual termine</string>\n    <string name=\"video_skip_op\">Omitir Intro</string>\n    <string name=\"skip_type_op\">Apertura</string>\n    <string name=\"skip_update\">Omitir esta actualización</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Omitir %s</string>\n    <string name=\"skip_type_ed\">Final</string>\n    <string name=\"skip_type_mixed_op\">Apertura mixta</string>\n    <string name=\"skip_type_recap\">Resumen</string>\n    <string name=\"skip_type_creddits\">Créditos</string>\n    <string name=\"skip_type_mixed_ed\">Final mixto</string>\n    <string name=\"episode_poster_img_des\">Póster del episodio</string>\n    <string name=\"next_episode\">Siguiente episodio</string>\n    <string name=\"episode_more_options_des\">Más opciones</string>\n    <string name=\"episode_sync_settings\">Actualizar progreso de lo visto</string>\n    <string name=\"episode_action_chromecast_mirror\">Duplicar en Chromecast</string>\n    <string name=\"no_episodes_found\">No se encontraron Episodios</string>\n    <string name=\"episode_action_play_in_format\">Reproducir en %s</string>\n    <string name=\"episode_action_auto_download\">Descarga automática</string>\n    <string name=\"episode_action_download_mirror\">Descargar desde servidor alternativo</string>\n    <string name=\"episode_action_reload_links\">Recargar enlaces</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"delete_message\" formatted=\"true\">Esto eliminará %s permanentemente\n\\nEstá seguro?</string>\n    <string name=\"confirm_exit_dialog\">¿Seguro que quieres salir?</string>\n    <string name=\"popup_resume_download\">Continuar Descarga</string>\n    <string name=\"example_lang_name\">Código de idioma (es_ES)</string>\n    <string name=\"home_main_poster_img_des\">Póster principal</string>\n    <string name=\"app_language\">Idioma de la aplicación</string>\n    <string name=\"provider_languages_tip\">Ver videos en estos idiomas</string>\n    <string name=\"search_poster_img_des\">Póster</string>\n    <string name=\"home_next_random_img_des\">Siguiente al azar</string>\n    <string name=\"all_languages_preference\">Todos los Idiomas</string>\n    <string name=\"go_back_img_des\">Regresar</string>\n    <string name=\"home_change_provider_img_des\">Cambiar proveedor</string>\n    <string name=\"preview_background_img_des\">Previsualizar fondo</string>\n    <string name=\"rated_format\" formatted=\"true\">Nota:%.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Se encontró una actualización nueva:\\n%1$s → %2$s</string>\n    <string name=\"download\">Descargar</string>\n    <string name=\"popup_pause_download\">Pausar Descarga</string>\n    <string name=\"subs_font\">Formato de fuente</string>\n    <string name=\"subs_background_color\">Color de Fondo</string>\n    <string name=\"subs_font_size\">Tamaño de Fuente</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Velocidad (%.2f×)</string>\n    <string name=\"skip_loading\">Omitir carga</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep. %2$d</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d d %2$d h %3$d m</string>\n    <string name=\"cast_format\" formatted=\"true\">Reparto: %s</string>\n    <string name=\"filler\" formatted=\"true\">Relleno</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Reproducir con Cloudstream</string>\n    <string name=\"title_home\">Inicio</string>\n    <string name=\"title_search\">Buscar</string>\n    <string name=\"title_downloads\">Descargas</string>\n    <string name=\"title_settings\">Ajustes</string>\n    <string name=\"search_hint\">Buscar…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Buscar en %s…</string>\n    <string name=\"no_data\">Sin datos</string>\n    <string name=\"result_tags\">Géneros</string>\n    <string name=\"result_share\">Compartir</string>\n    <string name=\"result_open_in_browser\">Abrir en navegador</string>\n    <string name=\"loading\">Cargando…</string>\n    <string name=\"home_expanded_hide\">Ocultar</string>\n    <string name=\"sort_apply\">Aplicar</string>\n    <string name=\"pick_subtitle\">Subtítulos</string>\n    <string name=\"player_speed\">Velocidad del reproductor</string>\n    <string name=\"play_episode\">Reproducir Episodio</string>\n    <string name=\"type_watching\">Mirando</string>\n    <string name=\"type_on_hold\">En espera</string>\n    <string name=\"type_completed\">Completado</string>\n    <string name=\"type_dropped\">Descartado</string>\n    <string name=\"type_plan_to_watch\">Planeando ver</string>\n    <string name=\"type_re_watching\">Volviendo a mirar</string>\n    <string name=\"play_movie_button\">Reproducir película</string>\n    <string name=\"play_trailer_button\">Reproducir tráiler</string>\n    <string name=\"play_livestream_button\">Reproducir transmisión en vivo (livestream)</string>\n    <string name=\"play_torrent_button\">Transmitir Torrent</string>\n    <string name=\"pick_source\">Fuentes</string>\n    <string name=\"reload_error\">Reintentar conexión…</string>\n    <string name=\"go_back\">Regresar</string>\n    <string name=\"downloading\">Descargando</string>\n    <string name=\"download_paused\">Descarga pausada</string>\n    <string name=\"download_started\">Descarga iniciada</string>\n    <string name=\"download_failed\">Descarga fallida</string>\n    <string name=\"download_canceled\">Descarga Cancelada</string>\n    <string name=\"download_done\">Descarga Finalizada</string>\n    <string name=\"stream\">Flujo de datos</string>\n    <string name=\"error_loading_links_toast\">Error cargando enlaces</string>\n    <string name=\"download_storage_text\">Almacenamiento Interno</string>\n    <string name=\"app_dubbed_text\">Doblado</string>\n    <string name=\"app_subbed_text\">Subtitulado</string>\n    <string name=\"popup_delete_file\">Borrar Archivo</string>\n    <string name=\"popup_play_file\">Reproducir Archivo</string>\n    <string name=\"home_more_info\">Más información</string>\n    <string name=\"home_play\">Reproducir</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"filter_bookmarks\">Filtrar Marcadores</string>\n    <string name=\"error_bookmarks_text\">Marcadores</string>\n    <string name=\"action_remove_from_bookmarks\">Eliminar</string>\n    <string name=\"action_add_to_bookmarks\">Seleccionar estado de visualización</string>\n    <string name=\"sort_copy\">Copiar</string>\n    <string name=\"sort_close\">Cerrar</string>\n    <string name=\"sort_clear\">Limpiar</string>\n    <string name=\"sort_save\">Guardar</string>\n    <string name=\"subs_text_color\">Color de Texto</string>\n    <string name=\"subs_outline_color\">Color de Contorno</string>\n    <string name=\"subs_window_color\">Color de Ventana</string>\n    <string name=\"subs_edge_type\">Tipo de Borde</string>\n    <string name=\"subs_subtitle_elevation\">Elevación de Subtítulo</string>\n    <string name=\"search_provider_text_providers\">Buscar usando proveedores</string>\n    <string name=\"picture_in_picture_des\">Continúa la reproducción en un reproductor en miniatura encima de otras aplicaciones</string>\n    <string name=\"player_size_settings\">Botón de cambio de tamaño del reproductor</string>\n    <string name=\"player_size_settings_des\">Eliminar bordes negros</string>\n    <string name=\"subs_auto_select_language\">Seleccionar idioma automáticamente</string>\n    <string name=\"subs_download_languages\">Descargar Idiomas</string>\n    <string name=\"subs_subtitle_languages\">Idioma del subtítulo</string>\n    <string name=\"picture_in_picture\">Imagen en Imagen (PIP)</string>\n    <string name=\"search_provider_text_types\">Buscar por tipos</string>\n    <string name=\"benene_count_text\">%d bananas otorgadas a los desarrolladores</string>\n    <string name=\"benene_count_text_none\">No se otorgaron bananas</string>\n    <string name=\"subs_hold_to_reset_to_default\">Mantenga pulsado para restablecer los valores predeterminados</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importar fuentes colocándolas en %s</string>\n    <string name=\"continue_watching\">Continuar Viendo</string>\n    <string name=\"action_remove_watching\">Eliminar</string>\n    <string name=\"action_open_watching\">Más info</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Tal vez se requiera una VPN para que este proveedor funcione correctamente</string>\n    <string name=\"vpn_torrent\">Este proveedor es un torrent, se recomienda una VPN</string>\n    <string name=\"provider_info_meta\">El sitio no proporciona los metadatos, la carga del video fallará si no existe en el sitio.</string>\n    <string name=\"torrent_plot\">Descripción</string>\n    <string name=\"normal_no_plot\">Trama no encontrada</string>\n    <string name=\"torrent_no_plot\">Descripción no encontrada</string>\n    <string name=\"show_log_cat\">Mostrar Logcat 🐈</string>\n    <string name=\"eigengraumode_settings\">Velocidad de reproducción</string>\n    <string name=\"swipe_to_seek_settings\">Deslice para avanzar/retroceder</string>\n    <string name=\"swipe_to_change_settings\">Deslice para cambiar la configuración</string>\n    <string name=\"swipe_to_change_settings_des\">Deslice hacia arriba o hacia abajo en el lado izquierdo o derecho para cambiar el brillo o el volumen</string>\n    <string name=\"double_tap_to_seek_settings\">Toca dos veces para buscar</string>\n    <string name=\"double_tap_to_pause_settings\">Tocar dos veces para pausar</string>\n    <string name=\"double_tap_to_seek_settings_des\">Toque dos veces en el lado derecho o izquierdo para buscar hacia adelante o hacia atrás</string>\n    <string name=\"double_tap_to_pause_settings_des\">Toque dos veces en el medio para hacer una pausa</string>\n    <string name=\"use_system_brightness_settings\">Usar brillo del sistema</string>\n    <string name=\"restore_settings\">Restaurar datos desde el backup</string>\n    <string name=\"backup_settings\">Hacer copia de los datos (backup)</string>\n    <string name=\"restore_success\">Archivo de backup cargado</string>\n    <string name=\"updates_settings_des\">Busque automáticamente nuevas actualizaciones después de iniciar la aplicación.</string>\n    <string name=\"redo_setup_process\">Rehacer el proceso de configuración inicial</string>\n    <string name=\"show_fillers_settings\">Mostrar episodio de relleno para Anime</string>\n    <string name=\"play_episode_toast\">Reproducir Episodio</string>\n    <string name=\"episode\">Episodio</string>\n    <string name=\"episodes\">Episodios</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Falló la restauración de los datos desde el archivo %s</string>\n    <string name=\"backup_success\">Datos guardados</string>\n    <string name=\"backup_failed\">Faltan permisos de almacenamiento. Por favor intente de nuevo.</string>\n    <string name=\"backup_failed_error_format\">Error de backup de %s</string>\n    <string name=\"search\">Buscar</string>\n    <string name=\"category_account\">Cuentas y seguridad</string>\n    <string name=\"category_updates\">Actualizaciones y copias de seguridad</string>\n    <string name=\"settings_info\">Información</string>\n    <string name=\"advanced_search\">Búsqueda Avanzada</string>\n    <string name=\"advanced_search_des\">Mostrar los resultados de la búsqueda por proveedor</string>\n    <string name=\"show_trailers_settings\">Mostrar avances</string>\n    <string name=\"kitsu_settings\">Mostrar pósters de Kitsu</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">App de novela ligera de los mismos desarrolladores</string>\n    <string name=\"anim\">App de Anime de los mismos desarrolladores</string>\n    <string name=\"discord\">Únete a Discord</string>\n    <string name=\"benene\">Dale una banana a los desarrolladores</string>\n    <string name=\"benene_des\">Banana otorgada</string>\n    <string name=\"no_chromecast_support_toast\">El proveedor no tiene soporte para Chromecast</string>\n    <string name=\"no_links_found_toast\">Enlaces no encontrados</string>\n    <string name=\"copy_link_toast\">Enlaces copiados al portapapeles</string>\n    <string name=\"subs_default_reset_toast\">Reiniciar a valores predefinidos</string>\n    <string name=\"season\">Temporada</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Ninguna Temporada</string>\n    <string name=\"season_short\">T</string>\n    <string name=\"delete_file\">Borrar Archivo</string>\n    <string name=\"delete\">Borrar</string>\n    <string name=\"cancel\">Cancelar</string>\n    <string name=\"unexpected_error\">Error inesperado del reproductor</string>\n    <string name=\"episode_action_chromecast_episode\">Episodio en Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Reproducir en la aplicación</string>\n    <string name=\"pause\">Pausar</string>\n    <string name=\"resume\">Continuar</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nfaltante</string>\n    <string name=\"status_ongoing\">En curso</string>\n    <string name=\"status_completed\">Completado</string>\n    <string name=\"status\">Estado</string>\n    <string name=\"limit_title\">Máxima cantidad de caracteres en el título del reproductor</string>\n    <string name=\"pref_category_app_updates\">Actualizaciones de la aplicación</string>\n    <string name=\"automatic\">Automático</string>\n    <string name=\"pref_category_actions\">Acciones</string>\n    <string name=\"enable_nsfw_on_providers\">Activar NSFW en las extensiones compatibles</string>\n    <string name=\"category_providers\">Proveedores</string>\n    <string name=\"pref_category_defaults\">Predeterminados</string>\n    <string name=\"preferred_media_settings\">Medios preferidos</string>\n    <string name=\"pref_category_gestures\">Gestos</string>\n    <string name=\"provider_lang_settings\">Idiomas de la extensión</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">%s Cargado</string>\n    <string name=\"subtitles_remove_bloat\">Eliminar excedente (bloat) de los subtítulos</string>\n    <string name=\"skip_setup\">Omitir configuración</string>\n    <string name=\"preferred_media_subtext\">Qué quieres ver</string>\n    <string name=\"uppercase_all_subtitles\">Poner en MAYÚSCULAS todos los subtítulos</string>\n    <string name=\"apply_on_restart\">Se aplicarán los cambios al reiniciar la App.</string>\n    <string name=\"player_settings_play_in_app\">Reproductor interno</string>\n    <string name=\"extension_language\">Idioma</string>\n    <string name=\"apk_installer_legacy\">Tradicional</string>\n    <string name=\"apk_installer_package_installer\">Instalador de programas</string>\n    <string name=\"blank_repo_message\">CloudStream no tiene sitios instalados por defecto. Necesitas instalar los sitios desde los repositorios. \\n \\nÚnete a nuestro Discord o busca en línea.</string>\n    <string name=\"download_all_plugins_from_repo\">Advertencia: ¡CloudStream 3 no asume ninguna responsabilidad por el uso de extensiones de terceros y no brinda ningún soporte para ellas!</string>\n    <string name=\"updates_settings\">Mostrar actualizaciones de la aplicación</string>\n    <string name=\"apk_installer_settings\">Instalador de APK</string>\n    <string name=\"apk_installer_settings_des\">Algunos dispositivos no soportan el nuevo instalador de paquetes. Pruebe la opción antigua (legacy) si las actualizaciones no se instalan.</string>\n    <string name=\"episode_sync_settings_des\">Sincronizar automáticamente el progreso de su episodio actual</string>\n    <string name=\"automatic_plugin_updates\">Actualización automática de plugins</string>\n    <string name=\"pref_category_player_features\">Características del reproductor</string>\n    <string name=\"automatic_plugin_download\">Descarga automática de plugins</string>\n    <string name=\"automatic_plugin_download_summary\">Instala automáticamente todos los plugins aún no instalados de los repositorios agregados.</string>\n    <string name=\"pref_category_looks\">Aspecto</string>\n    <string name=\"pref_category_ui_features\">Características</string>\n    <string name=\"random_button_settings\">Botón aleatorio</string>\n    <string name=\"random_button_settings_desc\">Mostrar el botón aleatorio en la página de inicio y en la biblioteca</string>\n    <string name=\"account\">Cuenta</string>\n    <string name=\"logout\">Cerrar sesión</string>\n    <string name=\"switch_account\">Cambiar cuenta</string>\n    <string name=\"add_account\">Añadir cuenta</string>\n    <string name=\"upload_sync\">Sincronizar</string>\n    <string name=\"sync_score\">Clasificado</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s autenticado</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">No se pudo autenticar a %s</string>\n    <string name=\"recommended\">Recomendado</string>\n    <string name=\"poster_image\">Imagen del póster</string>\n    <string name=\"trailer\">Tráiler</string>\n    <string name=\"coming_soon\">Próximamente…</string>\n    <string name=\"home_random\">Aleatorio</string>\n    <string name=\"actor_main\">Principal</string>\n    <string name=\"error_invalid_data\">Datos no válidos</string>\n    <string name=\"add_sync\">Añadir seguimiento</string>\n    <string name=\"home_source\">Fuente</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Añadido %s</string>\n    <string name=\"login\">Iniciar sesión</string>\n    <string name=\"year\">Año</string>\n    <string name=\"rating\">Calificación</string>\n    <string name=\"duration\">Duración</string>\n    <string name=\"site\">Sitio</string>\n    <string name=\"synopsis\">Sinopsis</string>\n    <string name=\"queued\">Puesto en cola</string>\n    <string name=\"free_storage\">Libre</string>\n    <string name=\"used_storage\">Usado</string>\n    <string name=\"app_storage\">Aplicación</string>\n    <string name=\"movies\">Películas</string>\n    <string name=\"tv_series\">Series de TV</string>\n    <string name=\"cartoons\">Dibujos animados</string>\n    <string name=\"show_title\">Título</string>\n    <string name=\"poster_ui_settings\">Alternar elementos de la interfaz de usuario en el póster</string>\n    <string name=\"no_update_found\">No se encontró ninguna actualización</string>\n    <string name=\"category_general\">General</string>\n    <string name=\"primary_color_settings\">Color principal</string>\n    <string name=\"app_theme_settings\">Tema de la aplicación</string>\n    <string name=\"example_email\">hola@mundo.com</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"all\">Todo</string>\n    <string name=\"subtitle_offset_hint\">1000ms</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Sin retraso de subtítulos</string>\n    <string name=\"actor_supporting\">Secundario</string>\n    <string name=\"actor_background\">Extra</string>\n    <string name=\"resolution_and_title\">Resolución y título</string>\n    <string name=\"error\">Error</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"documentaries\">Documentales</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Dramas asiáticos</string>\n    <string name=\"movies_singular\">Película</string>\n    <string name=\"tv_series_singular\">Serie</string>\n    <string name=\"cartoons_singular\">Dibujo animado</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Documental</string>\n    <string name=\"asian_drama_singular\">Drama asiático</string>\n    <string name=\"source_error\">Error de fuente</string>\n    <string name=\"remote_error\">Error remoto</string>\n    <string name=\"render_error\">Error del renderizador</string>\n    <string name=\"storage_error\">Error de descarga, verifique los permisos de almacenamiento</string>\n    <string name=\"show_hd\">Etiqueta de calidad</string>\n    <string name=\"show_dub\">Etiqueta de doblaje</string>\n    <string name=\"show_sub\">Etiqueta de subtitulado</string>\n    <string name=\"check_for_update\">Buscar actualizaciones</string>\n    <string name=\"display_subbed_dubbed_settings\">Mostrar anime doblado/subtitulado</string>\n    <string name=\"video_lock\">Bloquear</string>\n    <string name=\"video_aspect_ratio_resize\">Redimensionar</string>\n    <string name=\"video_source\">Fuente</string>\n    <string name=\"dont_show_again\">No volver a mostrar</string>\n    <string name=\"update\">Actualizar</string>\n    <string name=\"video_buffer_size_settings\">Tamaño del búfer de vídeo</string>\n    <string name=\"video_buffer_length_settings\">Duración del búfer de vídeo</string>\n    <string name=\"video_buffer_disk_settings\">Caché de vídeo en disco</string>\n    <string name=\"video_buffer_clear_settings\">Limpiar caché de imágenes y vídeos</string>\n    <string name=\"video_ram_description\">Provocará bloqueos aleatorios si se establece demasiado alto. No lo cambie si tiene poca memoria RAM, como un Android TV o un teléfono antiguo.</string>\n    <string name=\"video_disk_description\">Puede causar problemas en sistemas con poco espacio de almacenamiento, como dispositivos Android TV, si lo configura demasiado alto.</string>\n    <string name=\"dns_pref\">DNS sobre HTTPS</string>\n    <string name=\"dns_pref_summary\">Útil para eludir los bloqueos del ISP</string>\n    <string name=\"add_site_pref\">Clonar sitio</string>\n    <string name=\"remove_site_pref\">Eliminar sitio</string>\n    <string name=\"add_site_summary\">Añade un clon de un sitio existente, con una URL diferente</string>\n    <string name=\"download_path_pref\">Ruta de descarga</string>\n    <string name=\"nginx_url_pref\">URL del servidor Nginx</string>\n    <string name=\"resize_fit\">Ajustar a la pantalla</string>\n    <string name=\"resize_fill\">Estirar</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"legal_notice\">Descargo de responsabilidad</string>\n    <string name=\"bottom_title_settings\">Ubicación del título en el póster</string>\n    <string name=\"bottom_title_settings_des\">Coloca el título debajo del póster</string>\n    <string name=\"example_password\">contraseña123</string>\n    <string name=\"example_username\">Nombre de usuario</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NewSiteName</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"none\">Ninguno</string>\n    <string name=\"max\">Máximo</string>\n    <string name=\"min\">Mínimo</string>\n    <string name=\"subtitle_offset\">Sincronizar subtítulos</string>\n    <string name=\"subtitle_offset_title\">Retraso de subtítulos</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">BlueRay</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"title\">Título</string>\n    <string name=\"resolution\">Resolución</string>\n    <string name=\"error_invalid_id\">Identificación no válida</string>\n    <string name=\"livestreams\">Transmisiones en vivo</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Otros</string>\n    <string name=\"live_singular\">Transmisión en vivo</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"pref_category_links\">Enlaces</string>\n    <string name=\"pref_category_backup\">Backup</string>\n    <string name=\"pref_category_cache\">Caché</string>\n    <string name=\"create_account\">Crear cuenta</string>\n    <string name=\"error_invalid_url\">URL Inválida</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"referer\">Referencia (opcional)</string>\n    <string name=\"next\">Siguiente</string>\n    <string name=\"previous\">Anterior</string>\n    <string name=\"setup_done\">Hecho</string>\n    <string name=\"plugin_loaded\">Plugin cargado</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Iniciada descarga de %1$d %2$s…</string>\n    <string name=\"batch_download\">Descarga por lotes</string>\n    <string name=\"plugin_singular\">plugin</string>\n    <string name=\"plugin\">plugins</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d plugins actualizados</string>\n    <string name=\"view_public_repositories_button\">Ver repositorios de la comunidad</string>\n    <string name=\"view_public_repositories_button_short\">Lista pública</string>\n    <string name=\"tracks\">Pistas</string>\n    <string name=\"audio_tracks\">Pistas de audio</string>\n    <string name=\"video_tracks\">Pistas de video</string>\n    <string name=\"safe_mode_title\">Modo seguro ACTIVADO</string>\n    <string name=\"safe_mode_crash_info\">Ver información de fallos</string>\n    <string name=\"extension_rating\" formatted=\"true\">Puntaje:%s</string>\n    <string name=\"extension_version\">Versión</string>\n    <string name=\"extension_status\">Estado</string>\n    <string name=\"extension_size\">Tamaño</string>\n    <string name=\"extension_authors\">Autores</string>\n    <string name=\"extension_types\">Soportado</string>\n    <string name=\"extension_install_first\">Instale las extensiones primero</string>\n    <string name=\"hls_playlist\">Lista de reproducción HLS</string>\n    <string name=\"clear_history\">Limpiar historial</string>\n    <string name=\"history\">Historial</string>\n    <string name=\"action_mark_as_watched\">Marcar como visto</string>\n    <string name=\"clipboard_too_large\">Demasiado texto. No se puede guardar en el portapapeles.</string>\n    <string name=\"no\">No</string>\n    <string name=\"update_notification_downloading\">Descargando actualización de la aplicación…</string>\n    <string name=\"update_notification_installing\">Instalando actualización de la aplicación…</string>\n    <string name=\"update_notification_failed\">No se pudo instalar la nueva versión de la aplicación</string>\n    <string name=\"app_not_found_error\">App no encontrada</string>\n    <string name=\"plugin_deleted\">Plugin Borrado</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">No puede cargar %s</string>\n    <string name=\"extension_description\">Descripción</string>\n    <string name=\"skip_type_intro\">Intro</string>\n    <string name=\"enable_skip_op_from_database_des\">Muestrar botones emergentes para saltar apertura/finalización del video</string>\n    <string name=\"yes\">Si</string>\n    <string name=\"delayed_update_notice\">La aplicación se actualizará al salir</string>\n    <string name=\"update_started\">Actualización iniciada</string>\n    <string name=\"plugin_downloaded\">Plugin descargado</string>\n    <string name=\"action_remove_from_watched\">Quitar de visto</string>\n    <string name=\"sort_by\">Ordenar por</string>\n    <string name=\"sort\">Ordenar</string>\n    <string name=\"sort_rating_desc\">Valoración (más a menos)</string>\n    <string name=\"sort_rating_asc\">Valoración (menos a más)</string>\n    <string name=\"sort_updated_new\">Actualizado (nuevo a antiguo)</string>\n    <string name=\"sort_updated_old\">Actualizado (antiguo a nuevo)</string>\n    <string name=\"sort_alphabetical_a\">Alfabéticamente (A a Z)</string>\n    <string name=\"browser\">Navegador</string>\n    <string name=\"library\">Biblioteca</string>\n    <string name=\"empty_library_logged_in_message\">Esta lista está vacía. Intenta cambiar a otra.</string>\n    <string name=\"sort_alphabetical_z\">Alfabéticamente (Z a A)</string>\n    <string name=\"select_library\">Seleccionar biblioteca</string>\n    <string name=\"open_with\">Abrir con</string>\n    <string name=\"empty_library_no_accounts_message\">Tu biblioteca está vacía :(\n\\nInicia sesión en una cuenta de biblioteca o añade series desde tu biblioteca local.</string>\n    <string name=\"safe_mode_file\">¡Se encontró un archivo en modo seguro!\n\\nNo cargar ninguna extensión al inicio hasta que se elimine el archivo.</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Reproductor visible - buscar cantidad</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Reproductor oculto - buscar cantidad</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Tiempo de búsqueda usado (en segundos) cuando el reproductor está visible</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Tiempo de búsqueda usado (en segundos) cuando el reproductor está oculto</string>\n    <string name=\"stop\">Parar</string>\n    <string name=\"test_failed\">Falló</string>\n    <string name=\"test_log\">Registro</string>\n    <string name=\"start\">Empezar</string>\n    <string name=\"test_passed\">Aprobado</string>\n    <string name=\"category_provider_test\">Verificar proveedores</string>\n    <string name=\"restart\">Reiniciar</string>\n    <string name=\"subscription_list_name\">Suscrito</string>\n    <string name=\"subscription_new\">Suscrito a %s</string>\n    <string name=\"subscription_deleted\">Darse de baja de %s</string>\n    <string name=\"subscription_in_progress_notification\">Actualizando los programas suscritos</string>\n    <string name=\"subscription_episode_released\">¡Episodio %d publicado!</string>\n    <string name=\"jsdelivr_proxy\">Proxy de GitHub</string>\n    <string name=\"jsdelivr_enabled\">No se ha podido acceder a GitHub. Activando el proxy jsDelivr…</string>\n    <string name=\"jsdelivr_proxy_summary\">Eludir el bloqueo de URLs crudas de github usando jsDelivr. Puede causar que las actualizaciones se retrasen unos días.</string>\n    <string name=\"revert\">Revertir</string>\n    <string name=\"pref_category_bypass\">ISP Bypasses</string>\n    <string name=\"watch_quality_pref_data\">Calidad de visualización preferida (Datos móviles)</string>\n    <string name=\"help\">Ayuda</string>\n    <string name=\"quality_profile_help\">Aquí puedes cambiar el orden de las fuentes. Si un vídeo tiene una prioridad más alta, aparecerá más arriba en la selección de las fuentes. La suma de la prioridad de la fuente y la prioridad de la calidad es la prioridad del vídeo.\n\\n\n\\nFuente A: 3\n\\nCalidad B: 7\n\\nTendrá una prioridad en el vídeo combinada de 10.\n\\n\n\\nNOTA: ¡Si la suma es 10 o más el reproductor saltará automáticamente la carga cuando se cargue ese enlace!</string>\n    <string name=\"profile_number\">Perfil %d</string>\n    <string name=\"wifi\">Wifi</string>\n    <string name=\"edit\">Editar</string>\n    <string name=\"profiles\">Perfiles</string>\n    <string name=\"mobile_data\">Datos móviles</string>\n    <string name=\"set_default\">Establecer por defecto</string>\n    <string name=\"use\">Usar</string>\n    <string name=\"qualities\">Calidades</string>\n    <string name=\"profile_background_des\">Fondo de perfil</string>\n    <string name=\"unable_to_inflate\">La interfaz de usuario no se ha podido crear correctamente, se trata de un GRAN BUG y debe ser reportado inmediatamente %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Seleccionar modo para filtrar los plugins descargados</string>\n    <string name=\"disable\">Deshabilitar</string>\n    <string name=\"no_plugins_found_error\">No se encontraron plugins en el repositorio</string>\n    <string name=\"no_repository_found_error\">Repositorio no encontrado, comprueba la URL y prueba la VPN</string>\n    <string name=\"already_voted\">Ya has votado</string>\n    <string name=\"backup_frequency\">Frecuencia de la copia de seguridad</string>\n    <string name=\"favorite_removed\">%s eliminado de favoritos</string>\n    <string name=\"favorites_list_name\">Favoritos</string>\n    <string name=\"favorite_added\">%s añadido a favoritos</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Se han encontrado posibles elementos duplicados en su biblioteca:\n\\n\n\\n%s\n\\n\n\\n¿Desea añadir este elemento de todos modos, sustituir los existentes o cancelar la acción?</string>\n    <string name=\"duplicate_title\">Posible duplicado encontrado</string>\n    <string name=\"lock_profile\">Bloquear perfil</string>\n    <string name=\"action_add_to_favorites\">Añadido a favoritos</string>\n    <string name=\"duplicate_replace_all\">Remplazar todo</string>\n    <string name=\"pin_error_incorrect\">PIN incorrecto. Por favor, inténtelo de nuevo.</string>\n    <string name=\"action_unsubscribe\">Cancelar la suscripción</string>\n    <string name=\"pin_error_length\">El PIN debe tener 4 caracteres</string>\n    <string name=\"duplicate_replace\">Remplazar</string>\n    <string name=\"duplicate_add\">Añadir</string>\n    <string name=\"action_subscribe\">Suscríbase</string>\n    <string name=\"action_remove_from_favorites\">Eliminar de favoritos</string>\n    <string name=\"select_an_account\">Seleccione una cuenta</string>\n    <string name=\"duplicate_message_single\">Parece que ya existe un elemento potencialmente duplicado en su colección: «%s». \\n \\n¿Quiere añadir este elemento de todos modos, sustituir el existente o cancelar la acción?</string>\n    <string name=\"enter_pin\">Introducir el PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">Introduzca el PIN actual</string>\n    <string name=\"logged_account\" formatted=\"true\">Conectado como %s</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Introduzca el PIN para %s</string>\n    <string name=\"use_default_account\">Utilizar la cuenta por defecto</string>\n    <string name=\"skip_startup_account_select_pref\">Omitir la selección de cuenta al inicio</string>\n    <string name=\"manage_accounts\">Gestionar las cuentas</string>\n    <string name=\"edit_account\">Editar la cuenta</string>\n    <string name=\"links_reloaded_toast\">Enlaces recargados</string>\n    <string name=\"rotate_video_desc\">Mostrar un botón para cambiar la orientación de la pantalla</string>\n    <string name=\"auto_rotate_video\">Giro automático</string>\n    <string name=\"rotate_video\">Girar</string>\n    <string name=\"auto_rotate_video_desc\">Activar el cambio automático de la orientación de la pantalla en función de la orientación del vídeo</string>\n    <string name=\"test_extensions_summary\">Esta prueba está destinada únicamente a desarrolladores y no verifica ni niega el funcionamiento de ninguna extensión.</string>\n    <string name=\"subscribe_tooltip\">Notificación de nuevo episodio</string>\n    <string name=\"result_search_tooltip\">Buscar en otras extensiones</string>\n    <string name=\"recommendations_tooltip\">Mostrar recomendaciones</string>\n    <string name=\"speed_setting_summary\">Añade una opción de velocidad en el reproductor</string>\n    <string name=\"test_extensions\">Probar todas las extensiones</string>\n    <string name=\"biometric_setting\">Bloquear biometricamente</string>\n    <string name=\"password_pin_authentication_title\">Autenticación mediante contraseña/PIN</string>\n    <string name=\"biometric_setting_summary\">Desbloquea la aplicación con huella dactilar, Face ID, PIN, patrón y contraseña.</string>\n    <string name=\"biometric_authentication_title\">Desbloquear CloudStream</string>\n    <string name=\"biometric_unsupported\">La autenticación biométrica no es compatible con este dispositivo</string>\n    <string name=\"biometric_prompt_description\">Después de algunos intentos fallidos, el mensaje se cerrará. Simplemente reinicie la aplicación para volver a intentarlo.</string>\n    <string name=\"biometric_warning\">Ahora se ha realizado una copia de seguridad de sus datos de CloudStream. Aunque la posibilidad de que esto ocurra es muy baja, todos los dispositivos pueden comportarse de forma diferente. En el raro caso de que no puedas acceder a la aplicación, borra completamente los datos de la aplicación y restaura desde una copia de seguridad. Sentimos mucho las molestias que esto pueda ocasionarte.</string>\n    <string name=\"favorite\">Favorito</string>\n    <string name=\"unfavorite\">Eliminar de favoritos</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nrestante</string>\n    <string name=\"repo_copy_label\">Nombre y URL del repositorio</string>\n    <string name=\"toast_copied\">¡Copiado!</string>\n    <string name=\"clipboard_unknown_error\">Error al copiar. Por favor, copie el logcat y comuníquese con el soporte de la aplicación.</string>\n    <string name=\"clipboard_permission_error\">Error al acceder al portapapeles. Inténtelo de nuevo.</string>\n    <string name=\"ok\">De acuerdo</string>\n    <string name=\"battery_dialog_title\">Desactivar optimización de batería</string>\n    <string name=\"music_singlar\">Música</string>\n    <string name=\"app_unrestricted_toast\">El uso de la batería de la aplicación está configurado sin restricciones</string>\n    <string name=\"app_info_intent_error\">No se puede abrir la información de la aplicación CloudStream.</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"audio_book_singular\">Audiolibro</string>\n    <string name=\"battery_dialog_message\">Para garantizar las notificaciones y descargas sin interrupciones de programas de TV suscritos, CloudStream necesita permiso para ejecutarse en segundo plano. Al presionar Aceptar, se abrirá la información de la aplicación. Presione «Permitir».\\n\\nTenga en cuenta que este permiso no significa que CS3 consumirá la batería. Solo funcionará en segundo plano cuando es necesario, como cuando se reciben notificaciones o se descargan vídeos desde extensiones oficiales.</string>\n    <string name=\"reset_btn\">Reset</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Próximamente en %s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">La temporada %1$d y el episodio %2$d se estrenarán en</string>\n    <string name=\"player_settings_select_cast_device\">Seleccionar el dispositivo para transmitir</string>\n    <string name=\"episode_action_cast_mirror\">Espejo de transmisión</string>\n    <string name=\"cs3wiki\">Wiki de CloudStream</string>\n    <string name=\"pref_category_security\">Seguridad</string>\n    <string name=\"pref_category_accounts\">Cuentas</string>\n    <string name=\"auth_locally\">Autenticación local</string>\n    <string name=\"qr_image\">Imagen del código QR</string>\n    <string name=\"dismiss\">Descartar</string>\n    <string name=\"open_downloaded_repo\">Abrir repositorio</string>\n    <string name=\"device_pin_url_message\">Visita <b> %s </b> en tu smartphone o ordenador e introduce el código anterior</string>\n    <string name=\"device_pin_expired_message\">¡El código PIN ya ha caducado!</string>\n    <string name=\"device_pin_counter_text\">El código caduca en %1$d mín y %2$d s</string>\n    <string name=\"device_pin_error_message\">No puedo obtener el código PIN del dispositivo; intente con la autenticación local</string>\n    <string name=\"play_from_beginning_img_des\">Reproducir desde el principio</string>\n    <string name=\"open_local_video\">Abrir vídeo de forma local</string>\n    <string name=\"test_warning\">Advertencia</string>\n    <string name=\"downloads_empty\">Actualmente no hay descargas disponibles.</string>\n    <string name=\"delete_plugin\">Eliminar complemento</string>\n    <string name=\"hide_player_control_names\">Ocultar los nombres de los controles del reproductor</string>\n    <string name=\"sort_release_date_old\">Fecha de lanzamiento (antigua a nueva)</string>\n    <string name=\"sort_release_date_new\">Fecha de lanzamiento (de nueva a antigua)</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">¿Estás seguro de que quieres borrar permanentemente todos los episodios de la serie?\n\\n\n\\n%s</string>\n    <string name=\"downloads_delete_select\">Seleccionar elementos para eliminar</string>\n    <string name=\"offline_file\">Disponible para visualizar sin conexión</string>\n    <string name=\"select_all\">Seleccionar todo</string>\n    <string name=\"deselect_all\">Deseleccionar todo</string>\n    <string name=\"delete_files\">Borrar archivos</string>\n    <string name=\"delete_format\" formatted=\"true\">Borrar (%1$d | %2$s)</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">¿Seguro que quieres borrar de forma permanente los siguientes elementos?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">¿Estás seguro de que deseas eliminar permanentemente los siguientes episodios en %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">También borrará permanentemente todos los episodios de las siguientes series:\n\\n\n\\n%s</string>\n    <string name=\"preview_seekbar_desc\">Activar la previsualización para las miniaturas en la barra de búsqueda</string>\n    <string name=\"preview_seekbar\">Previsualización de Seekbar</string>\n    <string name=\"no_subtitles_loaded\">Aún no hay subtítulos cargados</string>\n    <string name=\"confirm_before_exiting_desc\">Mostrar el diálogo antes de salir de la aplicación</string>\n    <string name=\"show\">Mostrar</string>\n    <string name=\"dont_show\">No mostrar</string>\n    <string name=\"confirm_before_exiting_title\">Confirmar antes de salir</string>\n    <string name=\"backup_path_title\">Ubicación de la carpeta de respaldo</string>\n    <string name=\"custom\">Personalizada</string>\n    <string name=\"torrent_info\">Este video está en una red de torrents, lo que significa que se puede rastrear su uso.\\nAsegúrese de comprender las redes de torrents antes de continuar.</string>\n    <string name=\"subs_edge_size\">Tamaño del borde</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"encoding_error\">Error de codificación</string>\n    <string name=\"unsupported_error\">Error no soportado</string>\n    <string name=\"player_load_one_subtitle_online\">Cargar primero disponible</string>\n    <string name=\"torrent_preferred_media\">Habilitación torrent en Opciones/Proveedores/Medio preferido</string>\n    <string name=\"torrent_not_accepted\">Reiniciar app y aceptar aparición de Stream Torrent para proceder.</string>\n    <string name=\"software_decoding\">Software de decodificado</string>\n    <string name=\"software_decoding_desc\">El software de decodificado permite que el reproductor reproduzca archivos de video no soportados por su dispositivo, lo cual podría causar una reproducción lenta o inestable en alta resolución.</string>\n    <string name=\"player_notification_channel_description\">La notificación del reproductor para controlar la reproducción en segundo plano</string>\n    <string name=\"sort_episodes_rating_high_low\">Puntuación (Más alta)</string>\n    <string name=\"sort_episodes_number_desc\">Episodio (Descendente)</string>\n    <string name=\"sort_episodes_rating_low_high\">Puntuación (Más baja)</string>\n    <string name=\"sort_episodes_date_newest\">Fecha de emisión (más nueva)</string>\n    <string name=\"starting_plugin_update_manually\">¡Iniciando el proceso de actualización del plugin!</string>\n    <string name=\"update_plugins_manually\">Actualizar complementos manualmente</string>\n    <string name=\"player_notification_channel_name\">Notificaciones del reproductor</string>\n    <string name=\"update_plugins\">Actualizar complementos</string>\n    <string name=\"sort_episodes_date_oldest\">Fecha de emisión (más antigua)</string>\n    <string name=\"sort_button_rating\">Puntuar %s</string>\n    <string name=\"plugins_updated_manually\">¡%d complemento(s) actualizados correctamente!</string>\n    <string name=\"no_plugins_updated_manually\">No se actualizó ningún complemento.</string>\n    <string name=\"sort_episodes_number_asc\">Episodio (Ascendente)</string>\n    <string name=\"speech_recognition_unavailable\">Reconocimiento de habla no disponible</string>\n    <string name=\"begin_speaking\">Empiece a hablar…</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_date\">Fecha %s</string>\n    <string name=\"subtitles_from_embedded\">Integrado</string>\n    <string name=\"subtitles_from_online\">En línea</string>\n    <string name=\"all_subtitles_italic\">Poner todos los subtítulos en cursiva</string>\n    <string name=\"all_subtitles_bold\">Poner todos los subtítulos en negrita</string>\n    <string name=\"background_radius\">Radio del fondo</string>\n    <string name=\"volume_exceeded_100\">El volumen ha excedido 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Desliza hacia arriba otra vez para sobrepasar 100%</string>\n    <string name=\"download_parallel_settings_des\">Cuántos elementos diferentes pueden descargarse en paralelo</string>\n    <string name=\"player_settings_always_ask\">Preguntar siempre</string>\n    <string name=\"parallel_downloads\">Descargas en paralelo</string>\n    <string name=\"concurrent_connections\">Conexiones simultáneas</string>\n    <string name=\"concurrent_connections_settings_des\">Cuántas conexiones simultáneas puede usar cada descarga</string>\n    <string name=\"go_to_downloads\">Ir a Descargas</string>\n    <string name=\"no_internet_connection\">Sin conexión a internet. \\n\\nConéctese a internet y vuelva a intentarlo, o mire sus descargas mientras está sin conexión.</string>\n    <string name=\"overscan_settings_des\">Cambios en los límites de la pantalla</string>\n    <string name=\"overscan_settings\">Sobreexploración</string>\n    <string name=\"poster_size_settings_des\">Cambios en el tamaño de los pósteres</string>\n    <string name=\"poster_size_settings\">Tamaño del póster</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$d h %2$d m %3$d s</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$d m %2$d s</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d s</string>\n    <string name=\"show_rating\">Etiqueta de valoración</string>\n    <string name=\"speedup_summary\">Mantenga presionado para duplicar la velocidad</string>\n    <string name=\"no_account\">Sin cuenta</string>\n    <string name=\"edit_profile_image_error_empty\">Ninguna URL Encontrada</string>\n    <string name=\"edit_profile_image_error_invalid\">URL o imagen no válida</string>\n    <string name=\"edit_profile_image_success\">Imagen Actualizada Correctamente</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Marcar como vigilado en este episodio</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Retirar vigilado para este episodio</string>\n    <string name=\"action_reload\">Recargado</string>\n    <string name=\"episode_action_play_mirror\">Reproducir en espejo</string>\"\n    <string name=\"edit_profile_image_title\">Editar imagen de perfil</string>\n    <string name=\"edit_profile_image_hint\">Introducir URL de imagen de perfil</string>\n    <string name=\"reload_provider\">Recargar proveedor</string>\n    <string name=\"name\">Nombre</string>\n    <string name=\"resolution_and_name\">Resolución y nombre</string>\n    <string name=\"subs_subtitle_alignment\">Alineación de subtítulos</string>\n    <string name=\"bottom_left\">Inferior izquierda</string>\n    <string name=\"bottom_center\">Inferior central</string>\n    <string name=\"bottom_right\">Inferior derecho</string>\n    <string name=\"top_center\">Arriba centrado</string>\n    <string name=\"top_right\">Arriba derecha</string>\n    <string name=\"play_full_series_button\">Reproducir toda la serie</string>\n    <string name=\"install_prerelease\">Instalar version pre-lanzamiento</string>\n    <string name=\"prerelease_already_installed\">Pre-lanzamiento ya está instalada.</string>\n    <string name=\"prerelease_install_failed\">La instalación pre-lanzamiento ha fallado.</string>\n    <string name=\"show_episode_text\">Texto del episodio</string>\n    <string name=\"speedup_title\">Alternar velocidad de pulsación larga</string>\n    <string name=\"middle_left\">Medio izquierda</string>\n    <string name=\"middle_center\">Medio centro</string>\n    <string name=\"middle_right\">Medio derecha</string>\n    <string name=\"top_left\">Arriba a la izquierda</string>\n    <string name=\"search_suggestions\">Sugerencias de Búsqueda</string>\n    <string name=\"search_suggestions_des\">Mostrar sugerencias de búsqueda mientras escribe</string>\n    <string name=\"clear_suggestions\">Borrar Sugerencias</string>\n    <string name=\"show_cast_in_details\">Mostrar panel de reparto</string>\n    <string name=\"extra_brightness_settings\">Atenuación extra</string>\n    <string name=\"extra_brightness_settings_des\">Active el filtro de atenuación cuando se supere el 100 % de brillo de la pantalla</string>\n    <string name=\"extra_brightness_key\">atenuación_extra_activado</string>\n    <string name=\"video_info\">Información del archivo multimedia</string>\n    <string name=\"source_name\">Nombre de origen</string>\n    <string name=\"download_queue\">Cola de descarga</string>\n    <string name=\"queue_empty_message\">Actualmente no hay descargas encoladas.</string>\n    <string name=\"source_priority\">Prioridad de origen</string>\n    <string name=\"source_priority_help\">Decida como los orígenes del vídeo estarían ordenados en el reproductor</string>\n    <string name=\"download_all\">Descargar todo</string>\n    <string name=\"cancel_all\">Cancelar todo</string>\n    <string name=\"download_episode_range\">¿Desea descargar el episodio %s?</string>\n    <string name=\"cancel_queue_message\">¿Desea cancelar todas las descargas de la cola?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d descarga activa</item>\n        <item quantity=\"many\">%d descargas activas</item>\n        <item quantity=\"other\">%d descargas activas</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d descarga encolada</item>\n        <item quantity=\"many\">%d descargas encoladas</item>\n        <item quantity=\"other\">%d descargas encoladas</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+fa/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"delete\">حذف</string>\n    <string name=\"pause\">مکث</string>\n    <string name=\"queued\">در صف</string>\n    <string name=\"download\">دانلود</string>\n    <string name=\"downloading\">در حال دانلود</string>\n    <string name=\"download_done\">داتلود پایان یافت</string>\n    <string name=\"stream\">پخش آنلاین</string>\n    <string name=\"download_failed\">دانلود ناموفق بود</string>\n    <string name=\"filter_bookmarks\">فیلتر کردن نشانک ها</string>\n    <string name=\"search\">جست‌وجو</string>\n    <string name=\"resize_fit\">اندازه کردن با صفحه نمایش</string>\n    <string name=\"resize_fill\">پر کردن</string>\n    <string name=\"resize_zoom\">بزرگ‌نمایی</string>\n    <string name=\"all\">همه</string>\n    <string name=\"tracks\">قطعه‌ها</string>\n    <string name=\"status\">وضعیت</string>\n    <string name=\"loading\">درحال بارگیری…</string>\n    <string name=\"show_title\">عنوان منبع</string>\n    <string name=\"logout\">خروج</string>\n    <string name=\"login\">ورود</string>\n    <string name=\"none\">هیچ‌کدام</string>\n    <string name=\"title\">عنوان</string>\n    <string name=\"history\">تاریخچه</string>\n    <string name=\"search_poster_img_des\">پوستر</string>\n    <string name=\"result_poster_img_des\">پوستر</string>\n    <string name=\"episode_poster_img_des\">پوستر قسمت</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dروز %2$dساعت %3$dدقیقه</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s قسمت %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">بازیگران: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">قسمت %d پخش خواهد شد در</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dساعت %2$dدقیقه</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dدقیقه</string>\n    <string name=\"home_main_poster_img_des\">پوستر اصلی</string>\n    <string name=\"torrent\">تورنت‌ها</string>\n    <string name=\"free_storage\">آزاد</string>\n    <string name=\"documentaries\">مستند‌ها</string>\n    <string name=\"ova\">انیمیشن ویدیویی اصلی</string>\n    <string name=\"max\">حداکثر</string>\n    <string name=\"movies\">فیلم‌ها</string>\n    <string name=\"tv_series\">سریال های تلویزیونی</string>\n    <string name=\"asian_drama\">درام‌های آسیایی</string>\n    <string name=\"anime\">انیمه</string>\n    <string name=\"cartoons\">کارتون‌ها</string>\n    <string name=\"used_storage\">استفاده شده</string>\n    <string name=\"app_storage\">برنامه</string>\n    <string name=\"go_back_img_des\">بازگشت</string>\n    <string name=\"autoplay_next_settings_des\">آغاز قسمت بعد پس از پایان قسمت فعلی</string>\n    <string name=\"home_change_provider_img_des\">تغییر ارائه‌دهنده</string>\n    <string name=\"action_remove_watching\">حذف</string>\n    <string name=\"action_open_watching\">اطلاعات بیشتر</string>\n    <string name=\"torrent_plot\">توضیحات</string>\n    <string name=\"subs_subtitle_languages\">زبان زیرنویس</string>\n    <string name=\"player_subtitles_settings\">زیرنویس‌ها</string>\n    <string name=\"action_remove_from_bookmarks\">حذف</string>\n    <string name=\"download_started\">دانلود آغاز شد</string>\n    <string name=\"sort_clear\">پاک کردن</string>\n    <string name=\"update_started\">به‌روزرسانی آغاز شد</string>\n    <string name=\"sort_copy\">کپی</string>\n    <string name=\"home_more_info\">اطلاعات بیشتر</string>\n    <string name=\"subs_auto_select_language\">انتخاب زبان خودکار</string>\n    <string name=\"continue_watching\">ادامهٔ تماشا</string>\n    <string name=\"subs_download_languages\">دانلود زبان‌ها</string>\n    <string name=\"subs_background_color\">رنگ پس‌زمینه</string>\n    <string name=\"popup_pause_download\">توقف دانلود</string>\n    <string name=\"app_dubbed_text\">دوبله</string>\n    <string name=\"torrent_no_plot\">هیچ توضیحی یافت نشد</string>\n    <string name=\"subtitles_settings\">تنظیمات زیرنویس</string>\n    <string name=\"subs_window_color\">رنگ پنجره</string>\n    <string name=\"download_canceled\">دانلود لغو شد</string>\n    <string name=\"home_expanded_hide\">پنهان کردن</string>\n    <string name=\"sort_apply\">اعمال کردن</string>\n    <string name=\"normal_no_plot\">پیرنگی یافت نشد</string>\n    <string name=\"download_paused\">دانلود متوقف شده</string>\n    <string name=\"popup_delete_file\">حذف فایل</string>\n    <string name=\"downloaded\">دانلود شده</string>\n    <string name=\"popup_resume_download\">ازسرگیری دانلود</string>\n    <string name=\"subs_text_color\">رنگ متن</string>\n    <string name=\"popup_play_file\">نمایش فایل</string>\n    <string name=\"go_back\">بازگشت</string>\n    <string name=\"sort_save\">ذخیره</string>\n    <string name=\"home_play\">نمایش</string>\n    <string name=\"autoplay_next_settings\">پخش خودکار قسمت بعد</string>\n    <string name=\"picture_in_picture\">تصویر در تصویر</string>\n    <string name=\"sort_close\">بستن</string>\n    <string name=\"home_next_random_img_des\">تصادفی بعدی</string>\n    <string name=\"preview_background_img_des\">پیش‌نمایش پس‌زمینه</string>\n    <string name=\"filler\" formatted=\"true\">فیلتر</string>\n    <string name=\"duration_format\" formatted=\"true\">%d دقیقه</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">پخش با CloudStream</string>\n    <string name=\"title_home\">خانه</string>\n    <string name=\"title_search\">جست‌وجو</string>\n    <string name=\"title_settings\">تنظیمات</string>\n    <string name=\"search_hint\">جست‌وجو…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">جست‌و‌جوی %s…</string>\n    <string name=\"result_tags\">ژانرها</string>\n    <string name=\"play_livestream_button\">پخش‌زنده</string>\n    <string name=\"pick_subtitle\">زیرنویس‌ها</string>\n    <string name=\"reload_error\">تلاش دوباره برای اتصال…</string>\n    <string name=\"type_re_watching\">تماشای دوباره</string>\n    <string name=\"pick_source\">منابع</string>\n    <string name=\"no_data\">داده‌ای نیست</string>\n    <string name=\"episode_more_options_des\">گزینه‌های بیشتر</string>\n    <string name=\"next_episode\">قسمت بعدی</string>\n    <string name=\"skip_loading\">پرش از بارگذاری</string>\n    <string name=\"subscribe_tooltip\">اعلان قسمت جدید</string>\n    <string name=\"result_search_tooltip\">جست‌و‌جو در سایر افزونه‌ها</string>\n    <string name=\"recommendations_tooltip\">نمایش پیشنهادات</string>\n    <string name=\"links_reloaded_toast\">پیوندها دوباره بارگیری شدند</string>\n    <string name=\"player_speed\">سرعت پخش‌کننده</string>\n    <string name=\"type_watching\">در حال تماشا</string>\n    <string name=\"title_downloads\">بارگیری‌ها</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">سرعت (%.2f برابر)</string>\n    <string name=\"new_update_format\" formatted=\"true\">بروزرسانی جدید پیدا شد!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"play_movie_button\">پخش فیلم</string>\n    <string name=\"browser\">مرورگر</string>\n    <string name=\"play_episode\">پخش قسمت</string>\n    <string name=\"action_add_to_bookmarks\">تنظیم وضعیت تماشا</string>\n    <string name=\"download_storage_text\">حافظه درونی(داخلی)</string>\n    <string name=\"result_share\">اشتراک‌گذاری</string>\n    <string name=\"play_trailer_button\">پخش تریلر</string>\n    <string name=\"error_loading_links_toast\">خطای بارگذاری پیوندها</string>\n    <string name=\"error_bookmarks_text\">نشانک‌ها</string>\n    <string name=\"type_completed\">کامل شده</string>\n    <string name=\"result_open_in_browser\">باز کردن در مرورگر</string>\n    <string name=\"type_plan_to_watch\">برنامه‌ریزی برای تماشا</string>\n    <string name=\"subs_hold_to_reset_to_default\">برای بازنشانی به پیشفرض نگه‌دارید</string>\n    <string name=\"library\">کتابخانه</string>\n    <string name=\"status_ongoing\">در ادامه</string>\n    <string name=\"delete_message\" formatted=\"true\">این فرآیند بطور کامل %s را حذف می‌کند\n\\nآیا از این کار اطمینان دارید؟</string>\n    <string name=\"repo_copy_label\">نام مخزن و نشانی</string>\n    <string name=\"toast_copied\">کپی شد!</string>\n    <string name=\"settings_info\">درباره</string>\n    <string name=\"subs_font\">قلم</string>\n    <string name=\"subs_font_size\">اندازه قلم</string>\n    <string name=\"swipe_to_change_settings\">برای تغییر تنظیمات بکشید</string>\n    <string name=\"swipe_to_change_settings_des\">برای تغییر میزان روشنایی یا صدا در گوشه چپ و راست به بالا یا پایین بکشید</string>\n    <string name=\"automatic_plugin_updates\">بروزرسانی خودکار پلاگین</string>\n    <string name=\"start\">آغاز</string>\n    <string name=\"app_language\">زبان برنامه</string>\n    <string name=\"play_episode_toast\">پخش قسمت</string>\n    <string name=\"year\">سال</string>\n    <string name=\"movies_singular\">فیلم</string>\n    <string name=\"tv_series_singular\">سریال</string>\n    <string name=\"anime_singular\">انیمه</string>\n    <string name=\"subs_outline_color\">رنگ حاشیه متن</string>\n    <string name=\"player_size_settings\">دکمه تغییر‌اندازه پخش‌کننده</string>\n    <string name=\"speed_setting_summary\">گزینه سرعت در پخش‌کننده را اضافه می‌کند</string>\n    <string name=\"category_updates\">بروزرسانی و پشتیبانی</string>\n    <string name=\"kitsu_settings\">نمیش پوستر از kitsu</string>\n    <string name=\"advanced_search\">جستجوی پیشرفته</string>\n    <string name=\"season\">فصل</string>\n    <string name=\"episode\">قسمت</string>\n    <string name=\"season_short\">ف</string>\n    <string name=\"episode_short\">ق</string>\n    <string name=\"other_singular\">ویدئو</string>\n    <string name=\"source_error\">خطای منبع</string>\n    <string name=\"test_log\">گزارش</string>\n    <string name=\"player_size_settings_des\">حذف حاشیه سیاه</string>\n    <string name=\"player_subtitles_settings_des\">تنظیمات زیرنویس‌های پخش‌کننده</string>\n    <string name=\"category_account\">حساب‌ها و امنیت</string>\n    <string name=\"show_log_cat\">نمایش Logcat 🐈</string>\n    <string name=\"copy_link_toast\">پیوند در حافظه موقت کپی شد</string>\n    <string name=\"no_links_found_toast\">هیچ پیوندی یافت‌ نشد</string>\n    <string name=\"asian_drama_singular\">درام آسیایی</string>\n    <string name=\"automatic_plugin_download\">بارگیری خودکار افزونه‌ها (پلاگین ها)</string>\n    <string name=\"documentaries_singular\">مستند</string>\n    <string name=\"eigengraumode_settings\">سرعت پخش</string>\n    <string name=\"no_episodes_found\">هیچ قسمتی یافت‌ نشد</string>\n    <string name=\"rated_format\" formatted=\"true\">امتیاز: %.1f</string>\n    <string name=\"subs_import_text\" formatted=\"true\">قلم‌ها را با گذاشتن در %s وارد کنید</string>\n    <string name=\"resume\">ادامه</string>\n    <string name=\"subs_default_reset_toast\">بازگردانی به مقدار پیشفرض</string>\n    <string name=\"go_back_30\">−۳۰</string>\n    <string name=\"go_forward_30\">+۳۰</string>\n    <string name=\"delete_file\">حذف پرونده</string>\n    <string name=\"show_trailers_settings\">نمایش تریلر ها</string>\n    <string name=\"episodes\">قسمت‌ها</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dد\n\\nباقی‌مانده</string>\n    <string name=\"github\">گیتهاب</string>\n    <string name=\"pref_filter_search_quality\">پنهان کردن ویدیو مشخص شده از نتایج جستجو</string>\n    <string name=\"cancel\">لغو</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nباقی‌مانده</string>\n    <string name=\"action_default\">پیش‌فرض</string>\n    <string name=\"cartoons_singular\">کارتون</string>\n    <string name=\"torrent_singular\">تورنت</string>\n    <string name=\"vpn_torrent\">این ارائه‌دهنده تورنتی است، استفاده از VPN توصیه می‌شود</string>\n    <string name=\"restore_success\">بارگزاری پرونده پشتیبانی‌</string>\n    <string name=\"subs_subtitle_elevation\">ارتفاع زیرنویس</string>\n    <string name=\"search_provider_text_providers\">جستجو از طریق ارائه‌دهنده‌ها</string>\n    <string name=\"backup_frequency\">فرکانس پشتیبان‌گیری</string>\n    <string name=\"swipe_to_seek_settings\">برای جلورفتن بکشید</string>\n    <string name=\"backup_success\">داده ذخیره‌سازی شده</string>\n    <string name=\"render_error\">خطای پردازنده</string>\n    <string name=\"others\">سایر</string>\n    <string name=\"duration\">طول</string>\n    <string name=\"vpn_might_be_needed\">شاید برای درست کارکردن این ارائه‌دهنده به VPN نیاز باشد</string>\n    <string name=\"use_system_brightness_settings\">استفاده از میزان روشنایی دستگاه</string>\n    <string name=\"subs_edge_type\">نوع گوشه</string>\n    <string name=\"no_season\">بدون فصل</string>\n    <string name=\"show_fillers_settings\">نمایش فیلتر قسمت برای انیمه</string>\n    <string name=\"type_dropped\">رها شده</string>\n    <string name=\"app_subbed_text\">زیرنویس</string>\n    <string name=\"home_info\">درباره</string>\n    <string name=\"search_provider_text_types\">جستجو از طریق انواع</string>\n    <string name=\"backup_settings\">پشتیبانی‌گیری داده</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">مشکل در بازگردانی داده از پرونده %s</string>\n    <string name=\"site\">وبگاه</string>\n    <string name=\"benene_des\">انعام دادن</string>\n    <string name=\"discord\">عضویت در دیسکورد</string>\n    <string name=\"benene\">هدیه انعام به توسعه‌دهندگان</string>\n    <string name=\"status_completed\">تمام‌شده</string>\n    <string name=\"no_subtitles\">بدون زیرنویس</string>\n    <string name=\"test_passed\">متوقف‌شده</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"open_local_video\">باز کردن ویدیو محلی</string>\n    <string name=\"provider_info_meta\">متاداده توسط سایت ارائه نشده، اگه در سایت وجود نداشته باشد بارگیری به مشکل می‌خورد .</string>\n    <string name=\"type_on_hold\">در انتظار</string>\n    <string name=\"play_from_beginning_img_des\">پخش از ابتدا</string>\n    <string name=\"downloads_empty\">در حال حاضر دانلودی وجود ندارد.</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">فصل %1$d قسمت %2$d پخش خواهد شد در</string>\n    <string name=\"play_torrent_button\">استریم تورنت</string>\n    <string name=\"downloads_delete_select\">انتخاب برای حذف</string>\n    <string name=\"offline_file\">در دسترس برای تماشای آفلاین</string>\n    <string name=\"select_all\">انتخاب همه</string>\n    <string name=\"deselect_all\">انتخاب نکردن همه</string>\n    <string name=\"benene_count_text\">%d Benenes به توسعه دهندگان داده می‌شود</string>\n    <string name=\"benene_count_text_none\">بدون Benenes</string>\n    <string name=\"chromecast_subtitles_settings\">زیرنویس Chromecast</string>\n    <string name=\"torrent_info\">این ویدیو یک تورنت است، این بدان معنی است که فعالیت ویدیویی شما قابل ردیابی است. \\nقبل از ادامه، مطمئن شوید که تورنت را درک کرده اید.</string>\n    <string name=\"picture_in_picture_des\">پخش را در یک پخش کننده مینیاتوری در بالای برنامه های دیگر ادامه می دهد</string>\n    <string name=\"error_invalid_data\">داده نامعتبر</string>\n    <string name=\"check_for_update\">چک‌کردن به‌روزرسانی</string>\n    <string name=\"wifi\">وای‌فای</string>\n    <string name=\"pref_category_player_features\">قابلیت‌های پخش‌کننده</string>\n    <string name=\"remote_error\">خطای ریموت</string>\n    <string name=\"watch_quality_pref_data\">کیفیت تماشای برگزیده (برای دیتای گوشی)</string>\n    <string name=\"add_site_pref\">مبدل‌سازی سایت</string>\n    <string name=\"nginx_url_pref\">نشانی سرور NGINX</string>\n    <string name=\"provider_lang_settings\">زبان‌های افزونه</string>\n    <string name=\"preferred_media_settings\">محتوا برگزیده</string>\n    <string name=\"limit_title_rez\">کیفیت پخش‌کننده ویدئو</string>\n    <string name=\"preferred_media_subtext\">چه می‌خواهید تماشا کنید</string>\n    <string name=\"all_languages_preference\">تمام زبان‌ها</string>\n    <string name=\"watch_quality_pref\">کیفیت تماشای برگزیده (برای وای‌فای)</string>\n    <string name=\"mobile_data\">دیتای گوشی</string>\n    <string name=\"torrent_preferred_media\">تورنت را در تنظیمات/ارائه‌دهنده/محتوا برگزیده فعال کنید</string>\n    <string name=\"chromecast_subtitles_settings_des\">تنظیمات زیرنویس‌های Chromecast</string>\n    <string name=\"error_invalid_url\">نشانی نامعتبر</string>\n    <string name=\"category_provider_test\">تست ارائه‌دهنده</string>\n    <string name=\"swipe_to_seek_settings_des\">از گوشه به گوشه برای کنترل موقعیت خود در یک ویدئو بکشید</string>\n    <string name=\"extension_language\">زبان</string>\n    <string name=\"app_not_found_error\">برنامه پیدا نشد</string>\n    <string name=\"error\">خطا</string>\n    <string name=\"pref_category_ui_features\">قابلیت‌ها</string>\n    <string name=\"category_providers\">ارائه‌دهنده ها</string>\n    <string name=\"storage_error\">خطای دانلود، دسترسی به حافظه را چک کنید</string>\n    <string name=\"resolution\">کیفیت</string>\n    <string name=\"resolution_and_title\">کیفیت و عنوان</string>\n    <string name=\"custom_media_singluar\">محتوا</string>\n    <string name=\"double_tap_to_seek_amount_settings\">مقدار جلورفتن پخش‌کننده</string>\n    <string name=\"no_repository_found_error\">مخزن پیدا نشد، نشانی را چک کنید و فیلترشکن را امتحان کنید</string>\n    <string name=\"example_lang_name\">کد زبان (انگلیسی)</string>\n    <string name=\"unexpected_error\">خطا غیرمنتظره پخش‌کننده</string>\n    <string name=\"unsupported_error\">خطای پشتیبانی‌نشده</string>\n    <string name=\"provider_languages_tip\">تماشای ویدئوها در این زبان‌ها</string>\n    <string name=\"subtitles_filter_lang\">فیلتر توسط زبان محتوا برگزیده</string>\n    <string name=\"player_pref\">پخش‌کننده ویدئو برگزیده</string>\n    <string name=\"error_invalid_id\">شناسه نامعتبر</string>\n    <string name=\"repository_url_hint\">نشانی مخزن یا Shortcode</string>\n    <string name=\"open_downloaded_repo\">بازکردن مخزن</string>\n    <string name=\"backup_path_title\">مکان پوشه پشتیبانی</string>\n    <string name=\"clipboard_permission_error\">خطا در دسترسی به حافظه موقت، لطفا دوباره تلاش کنید.</string>\n    <string name=\"repository_name_hint\">نام مخزن (اختیاری)</string>\n    <string name=\"no_plugins_found_error\">هیچ افزونه‌ای در مخزن پیدا نشد</string>\n    <string name=\"delete_repository\">حذف مخزن</string>\n    <string name=\"backup_failed_error_format\">خطا در پشتیبانی‌گیری %s</string>\n    <string name=\"backup_failed\">دسترسی به حافظه فعال نیست. لطفا دوباره تلاش کنید.</string>\n    <string name=\"delete_files\">حذف پرونده‌ها</string>\n    <string name=\"delete_format\" formatted=\"true\">حذف (%1$d | %2$s)</string>\n    <string name=\"add_repository\">افزودن مخزن</string>\n    <string name=\"plugin_deleted\">افزونه حذف شد</string>\n    <string name=\"restore_settings\">بازیابی داده از پشتیبانی</string>\n    <string name=\"pref_category_bypass\">دورزدن سرویس‌دهنده اینترنت</string>\n    <string name=\"pref_category_backup\">پشتیبانی</string>\n    <string name=\"clipboard_unknown_error\">خطا در کپی کردن، لطفا Logcat را کپی کنید و با پشتیبانی برنامه تماس بگیرید.</string>\n    <string name=\"add_site_summary\">یک بدل از یک سایت موجود اضافه کنید، با یک نشانی متفاوت</string>\n    <string name=\"jsdelivr_proxy_summary\">دورزدن نشانی‌های خام github توسط jsDelivr. ممکن است باعث تاخیر چند روزه به‌روزرسانی شود.</string>\n    <string name=\"dns_pref_summary\">برای دورزدن سرویس‌دهنده اینترنت مفید است</string>\n    <string name=\"encoding_error\">خطای رمزگذاری</string>\n    <string name=\"subtitles_encoding\">رمزگذاری زیرنویس</string>\n    <string name=\"delete_plugin\">حذف افزونه</string>\n    <string name=\"delete_repository_plugins\">این همچنین تمام مخزن افزونه‌ها را پاک می‌کند</string>\n    <string name=\"referer\">مرجع (اختیاری)</string>\n    <string name=\"double_tap_to_pause_settings\">برای مکث دوبار ضربه بزنید</string>\n    <string name=\"double_tap_to_seek_settings\">برای جستجو دو ضربه بزنید</string>\n    <string name=\"double_tap_to_seek_settings_des\">دو بار در سمت راست یا چپ ضربه بزنید تا به جلو یا عقب بگردید</string>\n    <string name=\"double_tap_to_pause_settings_des\">برای مکث دو بار در وسط ضربه بزنید</string>\n    <string name=\"use_system_brightness_settings_des\">Use system brightness in the app player instead of a dark overlay</string>\n    <string name=\"episode_sync_settings\">به‌روزرسانی پیشرفت ساعت</string>\n    <string name=\"begin_speaking\">شروع کنید به صحبت کردن…</string>\n    <string name=\"advanced_search_des\">جواب سرچ های شما با تامین کننده</string>\n    <string name=\"updates_settings\">نشان دادن آپدیت های برنامه</string>\n    <string name=\"redo_setup_process\">دوباره پروسه راه اندازی را انجام بده</string>\n    <string name=\"apk_installer_settings\">نصب کننده APK</string>\n    <string name=\"lightnovel\">برنامه سبک رمان از توسعه دهندگان یکسان</string>\n    <string name=\"anim\">برنامه انیمه از توسعه دهندگان یکسان</string>\n    <string name=\"no_chromecast_support_toast\">این ارائه دهنده هیچ پشتیبانی از کروم کست ندارد</string>\n    <string name=\"test_failed\">با شکست مواجه شد</string>\n    <string name=\"test_warning\">اخطار</string>\n    <string name=\"rating\">امتیاز</string>\n    <string name=\"livestreams\">استریم های زنده</string>\n    <string name=\"nsfw\">مثبت ۱۸ سال</string>\n    <string name=\"ova_singular\">انیمه خانگی</string>\n    <string name=\"live_singular\">پخش زنده</string>\n    <string name=\"nsfw_singular\">مثبت ۱۸ سال</string>\n    <string name=\"music_singlar\">موسیقی</string>\n    <string name=\"audio_book_singular\">کتاب صوتی</string>\n    <string name=\"audio_singluar\">صدا</string>\n    <string name=\"podcast_singluar\">پادکست</string>\n    <string name=\"episode_action_play_in_app\">پخش کردن در برنامه</string>\n    <string name=\"episode_action_auto_download\">دانلود اتوماتیک</string>\n    <string name=\"no_update_found\">هیچ آپدیتی پیدا نشد</string>\n    <string name=\"video_lock\">قفل</string>\n    <string name=\"video_aspect_ratio_resize\">تغییر اندازه</string>\n    <string name=\"video_source\">منبع</string>\n    <string name=\"dont_show_again\">دیگر نمایش نده</string>\n    <string name=\"skip_update\">این آپدیت را اسکیپ کن</string>\n    <string name=\"update\">آپدیت</string>\n    <string name=\"video_ram_description\">اگر در دستگاه های دارای حافظه کم در تنظیمات بالا گذاشته شود باعث کرش می‌شود، مانند تلویزیون های اندروید</string>\n    <string name=\"remove_site_pref\">از بین بردن سایت</string>\n    <string name=\"download_path_pref\">راه دانلود</string>\n    <string name=\"display_subbed_dubbed_settings\">نمایش دادن انیمه های دوبله شده یا دارای زیرنویس</string>\n    <string name=\"legal_notice\">هشدار</string>\n    <string name=\"pref_category_links\">لینک ها</string>\n    <string name=\"pref_category_app_updates\">آپدیت های برنامه</string>\n    <string name=\"pref_category_extensions\">افزونه ها</string>\n    <string name=\"pref_category_android_tv\">تلویزیون اندروید</string>\n    <string name=\"pref_category_security\">محافظت</string>\n    <string name=\"pref_category_accounts\">اکانت ها</string>\n    <string name=\"pref_category_subtitles\">زیرنویس ها</string>\n    <string name=\"pref_category_defaults\">حالت عادی</string>\n    <string name=\"category_general\">کلی</string>\n    <string name=\"random_button_settings\">دکمه رندوم</string>\n    <string name=\"test_extensions\">­همه افزونه ها را تست کنید</string>\n    <string name=\"automatic\">خودکار</string>\n    <string name=\"primary_color_settings\">رنگ اصلی</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+fil/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"pin_error_incorrect\">Maling PIN. Pakisubukang muli.</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Alisin ang napanood hanggang sa episode na ito</string>\n    <string name=\"no_internet_connection\">Walang koneksyon sa internet.\\n\\nKumonekta sa internet at subukang muli, o panoorin ang iyong mga na-download habang ikaw ay offline.</string>\n    <string name=\"player_notification_channel_description\">Ang abiso ng player para sa pagkontrol sa pag-playback mula sa background</string>\n    <string name=\"plugins_updated_manually\">Matagumpay na na-update ang %d plugin!</string>\n    <string name=\"overscan_settings_des\">Binabago ang mga hangganan ng screen</string>\n    <string name=\"all_subtitles_bold\">Gawing bold ( ≖‿ ≖ ) ang lahat ng subtitle</string>\n    <string name=\"all_subtitles_italic\">Gawing italic ang lahat ng subtitle</string>\n    <string name=\"volume_exceeded_100\">Lakas ng tunog ay lumampas sa 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Muling mag-slide pataas upang lumampas sa 100%</string>\n    <string name=\"confirm_before_exiting_desc\">Ipakita ang dialog bago lumabas sa app</string>\n    <string name=\"preview_seekbar_desc\">Paganahin ang preview thumbnail sa seekbar</string>\n    <string name=\"no_subtitles_loaded\">Wala pang na-load na mga subtitle</string>\n    <string name=\"confirm_before_exiting_title\">Kumpirmahin bago lumabas</string>\n    <string name=\"torrent_not_accepted\">I-restart ang app at tanggapin ang Stream Torrent pop-up upang magpatuloy.</string>\n    <string name=\"software_decoding_desc\">Binibigyang-daan ng software decoding ang player na mag-play ng mga video file na hindi sinusuportahan ng iyong telepono, ngunit maaaring magdulot ng laggy o hindi maayos na pag-playback sa mataas na resolution</string>\n    <string name=\"backup_path_title\">Lokasyon ng backup na folder</string>\n    <string name=\"hide_player_control_names\">Itago ang mga pangalan ng mga kontrol ng player</string>\n    <string name=\"biometric_warning\">Na-back up na ngayon ang iyong data sa CloudStream. Bagama\\'t napakababa ng posibilidad nito, lahat ng device ay maaaring kumilos nang iba. Sa pambihirang kaso, na ma-lock out ka mula sa pag-access sa app, ganap na i-clear ang data ng app at i-restore mula sa isang backup. Lubos kaming humihingi ng paumanhin para sa anumang abala na dulot nito.</string>\n    <string name=\"skip_startup_account_select_pref\">Laktawan ang pagpili ng account sa pagsisimula</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">May nakitang potensyal na mga nag-doble na mga items sa iyong library: \\n\\n%s \\n\\nGusto mo pa rin bang idagdag ang item na ito, palitan ang mga nauna na, o kanselahin ito?</string>\n    <string name=\"favorites_list_name\">Mga paborito &lt;3</string>\n    <string name=\"quality_profile_help\">Dito maaari mong baguhin kung paano inayos ang mga pinagmulan. Kung ang isang video ay may mas mataas na priyoridad, ito ay lalabas na mas mataas sa pagpili ng pinagmulan. Ang kabuuan ng priyoridad ng source at priyoridad sa quality ay ang priyoridad ng video. \\n\\nSource A: 3 \\nQuality B: 7 \\nMagkakaroon ng pinagsamang priyoridad ng video na 10. \\n\\nTANDAAN: Kung ang kabuuan ay 10 o higit pa ang player ay awtomatikong lalaktawan ang paglo-load kapag na-load ang link na iyon!</string>\n    <string name=\"unable_to_inflate\">Hindi magawa nang tama ang UI, isa itong MAJOR BUG at dapat na iulat kaagad %s</string>\n    <string name=\"action_add_to_favorites\">Idagdag sa mga paborito &lt;3</string>\n    <string name=\"action_remove_from_favorites\">Alisin sa mga paborito &lt;/3</string>\n    <string name=\"duplicate_title\">May Natagpuan na Nag-doble</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Lumalabas na mayroong potensyal na nag-doble na item sa iyong library: \\'%s.\\' \\n\\nGusto mo pa rin bang idagdag ang item na ito, palitan ang nauna, o kanselahin ito?</string>\n    <string name=\"battery_dialog_message\">Para matiyak ang mga walang patid na pag-download at notification para sa mga naka-subscribe na palabas sa TV, kailangan ng CloudStream ng pahintulot na tumakbo sa background. Sa pamamagitan ng pagpindot sa OK, ipapakita sa iyo ang isang dialog. Mangyaring pindutin ang \\'Allow\\'.\\n\\nPakitandaan, ang pahintulot na ito ay hindi nangangahulugan na maubos ng CS3 ang iyong baterya. Ito ay gagana lamang sa background kung kinakailangan, tulad ng kapag tumatanggap ng mga notification o nagda-download ng mga video mula sa mga opisyal na extension.</string>\n    <string name=\"blank_repo_message\">Ang CloudStream ay walang mga site na naka-install sa umpisa. Kailangan mong i-install ang mga site mula sa mga repositoryo. \\n \\nSumali sa aming Discord o maghanap online.</string>\n    <string name=\"download_all_plugins_from_repo\">Babala: Walang pananagutan ang CloudStream 3 sa paggamit ng mga extension ng third-party at hindi kami nagbibigay ng anumang suporta para sa kanila!</string>\n    <string name=\"speech_recognition_unavailable\">Hindi available ang speech recognition</string>\n    <string name=\"result_open_in_browser\">Buksan sa Browser</string>\n    <string name=\"torrent_info\">Ang video na ito ay isang Torrent, nangangahulugan ito na ang iyong aktibidad sa video ay maaaring masubaybayan.\\nTiyaking naiintindihan mo ang Torrenting bago magpatuloy.</string>\n    <string name=\"downloads_delete_select\">Piliin ang Mga Item na Tatanggalin</string>\n    <string name=\"downloads_empty\">Kasalukuyang walang mga dina-download.</string>\n    <string name=\"offline_file\">Available para mapanood offline</string>\n    <string name=\"select_all\">Piliin Lahat</string>\n    <string name=\"deselect_all\">Alisin sa pagkakapili ang Lahat</string>\n    <string name=\"vpn_might_be_needed\">Maaaring kailanganin ng VPN para gumana ang provider na ito</string>\n    <string name=\"vpn_torrent\">Ang provider na ito ay isang torrent, inirerekomendang gumamit ng VPN</string>\n    <string name=\"provider_info_meta\">Ang metadata ay hindi ibinigay ng site, hindi gagana ang video kung wala ito sa site.</string>\n    <string name=\"picture_in_picture_des\">Ipinagpapatuloy ang pag-playback sa isang miniature na player sa ibabaw ng iba pang mga app</string>\n    <string name=\"speed_setting_summary\">Nagdaragdag ng opsyon sa bilis sa player</string>\n    <string name=\"swipe_to_seek_settings_des\">Mag-swipe mula sa gilid patungo sa kabilang gilid upang kontrolin ang iyong posisyon sa isang video</string>\n    <string name=\"swipe_to_change_settings_des\">Mag-slide pataas o pababa sa kaliwa o kanang bahagi upang baguhin ang liwanag o volume</string>\n    <string name=\"episode_sync_settings_des\">Awtomatikong i-sync ang iyong kasalukuyang episode</string>\n    <string name=\"backup_failed\">Nawawala ang mga pahintulot sa storage. Pakisubukang muli.</string>\n    <string name=\"advanced_search_des\">Binibigyan ka ng mga resulta ng paghahanap na pinaghihiwalay ng provider</string>\n    <string name=\"pref_filter_search_quality\">Itago ang napiling quality ng video sa mga resulta ng paghahanap</string>\n    <string name=\"automatic_plugin_download_mode_title\">Pumili ng mode upang i-filter ang pag-download ng mga plugin</string>\n    <string name=\"automatic_plugin_download_summary\">Awtomatikong i-install ang lahat ng hindi pa naka-install na plugin mula sa mga idinagdag na repository.</string>\n    <string name=\"cast_format\" formatted=\"true\">Tauhan: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Kabanata %d ay ipapalabas sa</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Season %1$d Kabanata %2$d ay ipapalabas sa</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$da %2$do %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$do %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$do %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"episode_poster_img_des\">Poster ng Kabanata</string>\n    <string name=\"home_next_random_img_des\">Susunod na Kahit Ano</string>\n    <string name=\"go_back_img_des\">Bumalik</string>\n    <string name=\"play_from_beginning_img_des\">Ipatugtog mula sa Simula</string>\n    <string name=\"home_change_provider_img_des\">Baguhin ang Tagatustos</string>\n    <string name=\"preview_background_img_des\">Background ng Pasilip</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Bilis (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Na-rate: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">May nakitang bagong update!\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"play_with_app_name\">Ipatugtog sa CloudStream</string>\n    <string name=\"title_home\">Bahay</string>\n    <string name=\"title_search\">Maghanap</string>\n    <string name=\"title_downloads\">Mga Download</string>\n    <string name=\"download_queue\">Nakapila na download</string>\n    <string name=\"title_settings\">Mga pagpipilian</string>\n    <string name=\"search_hint\">Maghanap…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Maghanap %s…</string>\n    <string name=\"begin_speaking\">Magsimulang magsalita…</string>\n    <string name=\"no_data\">Walang Data</string>\n    <string name=\"episode_more_options_des\">Iba pang Mga Pagpipilian</string>\n    <string name=\"next_episode\">Susunod na kabanata</string>\n    <string name=\"result_tags\">Mga Genre</string>\n    <string name=\"result_share\">Ibahagi</string>\n    <string name=\"browser\">Browser</string>\n    <string name=\"skip_loading\">Laktawan ang paglo-load</string>\n    <string name=\"loading\">Naglo-load…</string>\n    <string name=\"type_watching\">Pinapanood</string>\n    <string name=\"type_on_hold\">Nakabinbin</string>\n    <string name=\"type_completed\">Nakumpleto</string>\n    <string name=\"type_plan_to_watch\">Pinaplanong Panoorin</string>\n    <string name=\"type_re_watching\">Pinapanood muli</string>\n    <string name=\"play_movie_button\">Ipatugtog ang Pelikula</string>\n    <string name=\"play_trailer_button\">Ipatugtog ang Trailer</string>\n    <string name=\"play_livestream_button\">Ipatugtog ang Livestream</string>\n    <string name=\"play_full_series_button\">Ipatugtog ang Buong Serye</string>\n    <string name=\"pick_source\">Mga Mapagkukunan</string>\n    <string name=\"pick_subtitle\">Mga saling-teksto</string>\n    <string name=\"reload_error\">Subukang muli kumonekta…</string>\n    <string name=\"go_back\">Bumalik</string>\n    <string name=\"play_episode\">Ipatugtog ang Kabanata</string>\n    <string name=\"play_torrent_button\">I-stream ang Torrent</string>\n    <string name=\"download\">I-download</string>\n    <string name=\"downloaded\">Na-download</string>\n    <string name=\"downloading\">Dina-download</string>\n    <string name=\"download_paused\">Hininto ang pag-download</string>\n    <string name=\"download_started\">Sinimulan ang pag-download</string>\n    <string name=\"download_failed\">Nabigong ma-download</string>\n    <string name=\"download_canceled\">Kinansela ang pag-download</string>\n    <string name=\"download_done\">Natapos ang pag-download</string>\n    <string name=\"queue_empty_message\">Kasalukuyang walang nakapilang mga download.</string>\n    <string name=\"update_started\">Sinimulan ang pag-update</string>\n    <string name=\"open_local_video\">Buksan ang local video</string>\n    <string name=\"error_loading_links_toast\">Nagkamali sa paglo-load ng mga link</string>\n    <string name=\"links_reloaded_toast\">Ini-load muli ang mga link</string>\n    <string name=\"download_storage_text\">Imbakan</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Burahin ang File</string>\n    <string name=\"popup_play_file\">Ipatugtog ang File</string>\n    <string name=\"popup_resume_download\">Ipagpatuloy ang pag-download</string>\n    <string name=\"popup_pause_download\">Ihinto ang pag-download</string>\n    <string name=\"home_more_info\">Higit pang impormasyon</string>\n    <string name=\"home_expanded_hide\">Itago</string>\n    <string name=\"home_play\">Ipatugtog</string>\n    <string name=\"home_info\">Impormasyon</string>\n    <string name=\"filter_bookmarks\">I-filter ang Mga Bookmark</string>\n    <string name=\"error_bookmarks_text\">Mga Bookmark</string>\n    <string name=\"action_remove_from_bookmarks\">Alisin</string>\n    <string name=\"action_add_to_bookmarks\">Itakda ang kapalaran ng panonood</string>\n    <string name=\"sort_apply\">Ilapat</string>\n    <string name=\"sort_copy\">Ikopya</string>\n    <string name=\"sort_close\">Isara</string>\n    <string name=\"sort_clear\">Alisin</string>\n    <string name=\"sort_save\">I-save</string>\n    <string name=\"repo_copy_label\">Pangalan ng repository at URL</string>\n    <string name=\"toast_copied\">nakopya!</string>\n    <string name=\"subscribe_tooltip\">Bagong notipikasyon ng kabanata</string>\n    <string name=\"result_search_tooltip\">Maghanap sa iba pang mga extension</string>\n    <string name=\"recommendations_tooltip\">Ipakita ang mga rekomendasyon</string>\n    <string name=\"player_speed\">Bilis ng Manlalaro</string>\n    <string name=\"subtitles_settings\">Pagpipilian sa Saling-teksto</string>\n    <string name=\"subs_text_color\">Kulay ng Teksto</string>\n    <string name=\"subs_outline_color\">Kulay ng Balangkas</string>\n    <string name=\"subs_background_color\">Kulay ng Likuran</string>\n    <string name=\"subs_window_color\">Kulay ng Bintana</string>\n    <string name=\"subs_subtitle_elevation\">Kataasan ng Saling-teksto</string>\n    <string name=\"subs_font\">Font</string>\n    <string name=\"subs_font_size\">Laki ng Font</string>\n    <string name=\"search_provider_text_providers\">Maghanap gamit ang mga tagatustos</string>\n    <string name=\"search_provider_text_types\">Maghanap gamit ang mga uri</string>\n    <string name=\"benene_count_text\">%d Benenes naibigay sa mga dev</string>\n    <string name=\"benene_count_text_none\">Walang Benenes na binigay</string>\n    <string name=\"subs_auto_select_language\">Awtomatikong Piliin ang Wika</string>\n    <string name=\"subs_download_languages\">Mag-download ng Mga Wika</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Accueil</string>\n    <string name=\"title_search\">Rechercher</string>\n    <string name=\"title_downloads\">Téléchargements</string>\n    <string name=\"title_settings\">Paramètres</string>\n    <string name=\"search_hint\">Rechercher…</string>\n    <string name=\"search_poster_img_des\">Affiche</string>\n    <string name=\"no_data\">Aucune donnée</string>\n    <string name=\"episode_more_options_des\">Plus d\\'options</string>\n    <string name=\"go_back_img_des\">Retour</string>\n    <string name=\"next_episode\">Épisode suivant</string>\n    <string name=\"result_poster_img_des\">Affiche</string>\n    <string name=\"result_tags\">Genres</string>\n    <string name=\"result_share\">Partager</string>\n    <string name=\"result_open_in_browser\">Ouvrir dans le navigateur</string>\n    <string name=\"skip_loading\">Passer le chargement</string>\n    <string name=\"loading\">Chargement…</string>\n    <string name=\"type_watching\">En visionnage</string>\n    <string name=\"type_on_hold\">En pause</string>\n    <string name=\"type_completed\">Terminé</string>\n    <string name=\"type_dropped\">Abandonné</string>\n    <string name=\"type_plan_to_watch\">À regarder</string>\n    <string name=\"play_movie_button\">Lire</string>\n    <string name=\"play_torrent_button\">Streamer le Torrent</string>\n    <string name=\"pick_source\">Sources</string>\n    <string name=\"pick_subtitle\">Sous-titres</string>\n    <string name=\"reload_error\">Réessayer la connection…</string>\n    <string name=\"go_back\">Retour</string>\n    <string name=\"episode_poster_img_des\">Affiche de l\\'épisode</string>\n    <string name=\"play_episode\">Lire l\\'Épisode</string>\n    <!--<string name=\"need_storage\">Permet de télécharger les épisodes</string>-->\n    <string name=\"download\">Télécharger</string>\n    <string name=\"downloaded\">Téléchargé</string>\n    <string name=\"downloading\">Téléchargement</string>\n    <string name=\"download_paused\">Téléchargement en pause</string>\n    <string name=\"download_started\">Téléchargement commencé</string>\n    <string name=\"download_failed\">Échec du téléchargement</string>\n    <string name=\"download_canceled\">Téléchargement annulé</string>\n    <string name=\"download_done\">Téléchargement terminé</string>\n    <string name=\"error_loading_links_toast\">Erreur lors du téléchargement des liens</string>\n    <string name=\"download_storage_text\">Stockage interne</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Supprimer le fichier</string>\n    <string name=\"popup_play_file\">Lire le fichier</string>\n    <string name=\"popup_resume_download\">Reprendre le téléchargement</string>\n    <string name=\"popup_pause_download\">Mettre en pause le téléchargement</string>\n    <string name=\"home_more_info\">Plus d\\'information</string>\n    <string name=\"home_expanded_hide\">Cacher</string>\n    <string name=\"home_main_poster_img_des\">Affiche principale</string>\n    <string name=\"home_play\">Lecture</string>\n    <string name=\"home_info\">Infos</string>\n    <string name=\"home_next_random_img_des\">Aléatoire suivant</string>\n    <string name=\"home_change_provider_img_des\">Changer le fournisseur</string>\n    <string name=\"filter_bookmarks\">Filtrer les marques-pages</string>\n    <string name=\"error_bookmarks_text\">Marque-pages</string>\n    <string name=\"action_remove_from_bookmarks\">Supprimer</string>\n    <string name=\"sort_apply\">Appliquer</string>\n    <string name=\"player_speed\">Vitesse de lecture</string>\n    <string name=\"preview_background_img_des\">Aperçu de l\\'arrière-plan</string>\n    <string name=\"benene\">Donner une benene aux devs</string>\n    <string name=\"benene_des\">benenes données</string>\n    <string name=\"app_language\">Language de l\\'application</string>\n    <string name=\"no_chromecast_support_toast\">Ce fournisseur ne supporte pas le Chromecast</string>\n    <string name=\"no_links_found_toast\">Aucun lien trouvé</string>\n    <string name=\"copy_link_toast\">Lien copié dans le presse-papier</string>\n    <string name=\"play_episode_toast\">Lecture de l\\'episode</string>\n    <string name=\"subs_default_reset_toast\">Réinitialiser aux valeurs par défault</string>\n    <string name=\"season\">Saison</string>\n    <string name=\"no_season\">Pas de Saison</string>\n    <string name=\"episode\">Épisode</string>\n    <string name=\"episodes\">Épisodes</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"delete_file\">Supprimer le Fichier</string>\n    <string name=\"delete\">Supprimer</string>\n    <string name=\"cancel\">Annuler</string>\n    <string name=\"pause\">Pause</string>\n    <string name=\"resume\">Reprendre</string>\n    <string name=\"delete_message\">Cela va supprimer définitivement %s\n\\nÊtes-vous sûr ?</string>\n    <string name=\"status_ongoing\">En cours</string>\n    <string name=\"status_completed\">Terminé</string>\n    <string name=\"status\">Statut</string>\n    <string name=\"year\">Année</string>\n    <string name=\"rating\">Note</string>\n    <string name=\"duration\">Durée</string>\n    <string name=\"site\">Site</string>\n    <string name=\"synopsis\">Synopsis</string>\n    <string name=\"queued\">Liste d\\'attente</string>\n    <string name=\"no_subtitles\">Pas de sous-titres</string>\n    <string name=\"action_default\">Défault</string>\n    <string name=\"free_storage\">Libre</string>\n    <string name=\"used_storage\">Utilisé</string>\n    <string name=\"app_storage\">Application</string>\n    <string name=\"movies\">Films</string>\n    <string name=\"tv_series\">Séries TV</string>\n    <string name=\"cartoons\">Dessins animés</string>\n    <string name=\"anime\">Animés</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"source_error\">Erreur de la source</string>\n    <string name=\"remote_error\">Erreur distante</string>\n    <string name=\"render_error\">Erreur d\\'affichage</string>\n    <string name=\"unexpected_error\">Erreur inattendue du lecteur</string>\n    <string name=\"storage_error\">Erreur du téléchargement, vérifier l\\'autorisation du stockage</string>\n    <string name=\"episode_action_chromecast_episode\">Épisode Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Miroir Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Lecture dans l\\'application</string>\n    <string name=\"episode_action_play_in_format\">Lecture dans %s</string>\n    <string name=\"episode_action_auto_download\">Téléchargement automatique</string>\n    <string name=\"episode_action_download_mirror\">Télécharger depuis le miroir</string>\n    <string name=\"episode_action_reload_links\">Recharger les liens</string>\n    <string name=\"no_update_found\">Pas de mise-à-jour trouvés</string>\n    <string name=\"check_for_update\">Vérifier les mise-à-jour</string>\n    <string name=\"video_lock\">Verouiller</string>\n    <string name=\"video_aspect_ratio_resize\">Redimensionner</string>\n    <string name=\"video_source\">Source</string>\n    <string name=\"video_skip_op\">Passer l\\'OP</string>\n    <string name=\"dont_show_again\">Ne pas afficher à nouveau</string>\n    <string name=\"update\">Mettre à jour</string>\n    <string name=\"dns_pref_summary\">Utile pour contourner les bloquages des FAI</string>\n    <string name=\"download_path_pref\">Emplacement de téléchargement</string>\n    <string name=\"new_update_format\" formatted=\"true\">Nouvelle mise à jour trouvée !\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Épisode spécial</string>\n    <string name=\"watch_quality_pref\">Qualité de visionnage préférée (WiFi)</string>\n    <string name=\"video_buffer_size_settings\">Taille de la mémoire cache</string>\n    <string name=\"resize_fill\">Étendre</string>\n    <string name=\"legal_notice\">Non-responsabilité</string>\n    <string name=\"primary_color_settings\">Couleur principale</string>\n    <string name=\"app_theme_settings\">Thème de l\\'application</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Vitesse (%.2fx)</string>\n    <string name=\"category_general\">Général</string>\n    <string name=\"dns_pref\">DNS avec HTTPS</string>\n    <string name=\"display_subbed_dubbed_settings\">Afficher les animés en Anglais (Dub) / sous-titrés</string>\n    <string name=\"phone_layout\">Disposition en mode téléphone</string>\n    <string name=\"app_dub_sub_episode_text_format\">%1$s Ep %2$d</string>\n    <string name=\"rated_format\" formatted=\"true\">Note : %.1f</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"resize_fit\">Adapter à l\\'écran</string>\n    <string name=\"app_layout\">Disposition de l\\'application</string>\n    <string name=\"tv_layout\">Disposition TV</string>\n    <string name=\"provider_lang_settings\">Langues des extensions</string>\n    <string name=\"preferred_media_settings\">Médias préférées</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"cast_format\">Distribution : %s</string>\n    <string name=\"duration_format\">%d min</string>\n    <string name=\"search_hint_site\">Rechercher sur %s…</string>\n    <string name=\"type_re_watching\">À re-regarder</string>\n    <string name=\"no_episodes_found\">Aucun épisode trouvé</string>\n    <string name=\"documentaries\">Documentaires</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Dramas Asiatiques</string>\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Séries</string>\n    <string name=\"cartoons_singular\">Dessin animé</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Documentaire</string>\n    <string name=\"asian_drama_singular\">Drame Asiatique</string>\n    <string name=\"episode_action_download_subtitle\">Télécharger les sous-titres</string>\n    <string name=\"limit_title\">Nombre maximal de caractères dans le titre du lecteur vidéo</string>\n    <string name=\"video_buffer_length_settings\">Longueur de la mémoire vidéo tampon</string>\n    <string name=\"video_buffer_disk_settings\">Longueur du cache de la vidéo</string>\n    <string name=\"video_buffer_clear_settings\">Effacer les vidéos et les images en cache</string>\n    <string name=\"video_ram_description\">Causera des crashs si la valeur choisie est trop élevée sur un appareil avec peu de ram comme une télévision android.</string>\n    <string name=\"video_disk_description\">Cause des problèmes si la valeur choisie est trop élevée sur un appareil avec peu de stockage comme une télévision android.</string>\n    <string name=\"random_button_settings\">Bouton aléatoire</string>\n    <string name=\"random_button_settings_desc\">Afficher un bouton aléatoire sur la page d\\'accueil et la librairie</string>\n    <string name=\"emulator_layout\">Disposition émulateur</string>\n    <string name=\"bottom_title_settings\">Position du titre du poster</string>\n    <string name=\"bottom_title_settings_des\">Mettre le titre sous le poster</string>\n    <string name=\"account\">compte</string>\n    <string name=\"logout\">Se déconnecter</string>\n    <string name=\"login\">Se connecter</string>\n    <string name=\"switch_account\">Changer de compte</string>\n    <string name=\"add_account\">Ajouter un compte</string>\n    <string name=\"add_sync\">Ajouter un suivi</string>\n    <string name=\"added_sync_format\">%s ajouté</string>\n    <string name=\"upload_sync\">Synchroniser</string>\n    <string name=\"sync_score\">Noté</string>\n    <string name=\"authenticated_user_fail\">Impossible de se connecté à %s</string>\n    <string name=\"none\">Aucun</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">Tous</string>\n    <string name=\"max\">Max</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Contour</string>\n    <string name=\"subtitles_depressed\">Déprimé</string>\n    <string name=\"subtitles_shadow\">Ombre</string>\n    <string name=\"subtitles_raised\">Élévation</string>\n    <string name=\"subtitle_offset\">Synchroniser les sous-titres</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Délai des sous-titres</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Utilisez cela si les sous-titres sont affichés %d ms trop tôt</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Utilisez cela si les sous-titres sont affichés %d ms trop tard</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Aucun délai de sous-titre</string>\n    <string name=\"subtitles_example_text\">Portez ce vieux whisky au juge blond qui fume</string>\n    <string name=\"recommended\">Recommandé</string>\n    <string name=\"player_loaded_subtitles\">%s chargé</string>\n    <string name=\"player_load_subtitles\">Charger depuis le fichier</string>\n    <string name=\"downloaded_file\">Fichier téléchargé</string>\n    <string name=\"actor_main\">Principal</string>\n    <string name=\"actor_supporting\">Supporte</string>\n    <string name=\"actor_background\">Arrière plan</string>\n    <string name=\"home_source\">Source</string>\n    <string name=\"home_random\">Aléatoire</string>\n    <string name=\"coming_soon\">Bientôt disponible…</string>\n    <string name=\"poster_image\">Image de l\\'affiche</string>\n    <string name=\"authenticated_user\">%s Connecté</string>\n    <string name=\"action_add_to_bookmarks\">Définir le statut de visionage</string>\n    <string name=\"sort_copy\">Copier</string>\n    <string name=\"sort_close\">Fermer</string>\n    <string name=\"sort_clear\">Vider</string>\n    <string name=\"sort_save\">Enregistrer</string>\n    <string name=\"subtitles_settings\">Paramètres des sous-titres</string>\n    <string name=\"subs_text_color\">Couleur du texte</string>\n    <string name=\"subs_outline_color\">Couleur des contours</string>\n    <string name=\"subs_background_color\">Couleur d\\'arrière-plan</string>\n    <string name=\"subs_window_color\">Couleur de la fenêtre</string>\n    <string name=\"subs_edge_type\">Type de bordure</string>\n    <string name=\"subs_subtitle_elevation\">Élévation des sous-titres</string>\n    <string name=\"subs_font\">Police</string>\n    <string name=\"subs_font_size\">Taille de la police</string>\n    <string name=\"search_provider_text_providers\">Recherche par fournisseur</string>\n    <string name=\"search_provider_text_types\">Recherche par types</string>\n    <string name=\"benene_count_text\">%d bananes offertes aux devs</string>\n    <string name=\"benene_count_text_none\">Aucune banane n\\'a été offerte</string>\n    <string name=\"subs_auto_select_language\">Sélection automatique de la langue</string>\n    <string name=\"subs_download_languages\">Télécharger les langues</string>\n    <string name=\"subs_subtitle_languages\">Langue des sous-titres</string>\n    <string name=\"subs_hold_to_reset_to_default\">Maintenir pour rétablir les valeurs par défaut</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importez des polices en les plaçant dans %s</string>\n    <string name=\"continue_watching\">Continuer à regarder</string>\n    <string name=\"action_remove_watching\">Retirer</string>\n    <string name=\"action_open_watching\">Plus d\\'informations</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Un VPN peut être nécessaire pour que ce fournisseur fonctionne correctement</string>\n    <string name=\"vpn_torrent\">Ce fournisseur est un torrent, un VPN est recommandé</string>\n    <string name=\"provider_info_meta\">Les métadonnées ne sont pas fournies par le site, le chargement de la vidéo échouera si elles n\\'existent pas sur le site.</string>\n    <string name=\"torrent_plot\">Description</string>\n    <string name=\"normal_no_plot\">Aucune trace trouvée</string>\n    <string name=\"torrent_no_plot\">Aucune description trouvée</string>\n    <string name=\"show_log_cat\">Afficher le Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Picture-in-picture</string>\n    <string name=\"picture_in_picture_des\">Poursuite de la lecture dans un lecteur miniature au-dessus d\\'autres applications</string>\n    <string name=\"player_size_settings\">Bouton de redimensionnement du lecteur</string>\n    <string name=\"player_size_settings_des\">Supprimer les bordures noires</string>\n    <string name=\"player_subtitles_settings\">Sous-titres</string>\n    <string name=\"player_subtitles_settings_des\">Paramètres des sous-titres du lecteur</string>\n    <string name=\"chromecast_subtitles_settings\">Sous-titres Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Paramètres des sous-titres Chromecast</string>\n    <string name=\"eigengraumode_settings\">Vitesse de lecture</string>\n    <string name=\"swipe_to_seek_settings\">Balayez pour chercher</string>\n    <string name=\"swipe_to_seek_settings_des\">Balayez d\\'un côté ou de l\\'autre pour contrôler la position dans la vidéo</string>\n    <string name=\"swipe_to_change_settings\">Balayez pour modifier les paramètres</string>\n    <string name=\"swipe_to_change_settings_des\">Glissez vers le haut ou le bas depuis le côté gauche ou droit pour modifier la luminosité ou le volume</string>\n    <string name=\"autoplay_next_settings\">Lecture automatique du prochain épisode</string>\n    <string name=\"autoplay_next_settings_des\">Démarrer l\\'épisode suivant lorsque l\\'épisode en cours se termine</string>\n    <string name=\"double_tap_to_seek_settings\">Double tape pour chercher</string>\n    <string name=\"double_tap_to_pause_settings\">Double tape pour mettre en pause</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Temps de recherche du lecteur vidéo (Secondes)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Tapez deux fois sur le côté droit ou gauche pour aller en avant ou en arrière</string>\n    <string name=\"double_tap_to_pause_settings_des\">Tapez deux fois au milieu pour mettre en pause</string>\n    <string name=\"use_system_brightness_settings\">Utiliser la luminosité du système</string>\n    <string name=\"use_system_brightness_settings_des\">Utiliser la luminosité du système dans le lecteur d\\'applications au lieu du sombre</string>\n    <string name=\"episode_sync_settings\">Mise à jour de la progression du visionnage</string>\n    <string name=\"episode_sync_settings_des\">Synchronisation automatique de la progression de votre épisode en cours</string>\n    <string name=\"restore_settings\">Restaurer des données à partir d\\'une sauvegarde</string>\n    <string name=\"backup_settings\">Sauvegarde des données</string>\n    <string name=\"restore_success\">Fichier de sauvegarde chargé</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Échec de la restauration des données du fichier %s</string>\n    <string name=\"backup_success\">Données stockées</string>\n    <string name=\"backup_failed\">Permissions de stockage manquantes. Veuillez réessayer.</string>\n    <string name=\"backup_failed_error_format\">Erreur de sauvegarde %s</string>\n    <string name=\"search\">Recherche</string>\n    <string name=\"category_account\">Comptes et Sécurité</string>\n    <string name=\"category_updates\">Mises à jour et Sauvegarde</string>\n    <string name=\"settings_info\">Info</string>\n    <string name=\"advanced_search\">Recherche avancée</string>\n    <string name=\"advanced_search_des\">Vous donne les résultats de la recherche séparés par fournisseur</string>\n    <string name=\"show_fillers_settings\">Afficher les épisodes spéciaux pour les animés</string>\n    <string name=\"show_trailers_settings\">Montrer les bandes-annonces</string>\n    <string name=\"kitsu_settings\">Montrer les affiches provenant de Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Masque la qualité vidéo sélectionnée dans les résultats de recherche</string>\n    <string name=\"automatic_plugin_updates\">Mises à jour automatiques des plugins</string>\n    <string name=\"updates_settings\">Afficher les mises à jour de l\\'application</string>\n    <string name=\"updates_settings_des\">Recherche automatique de nouvelles mises à jour au démarrage.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Application Light Novel par les mêmes devs</string>\n    <string name=\"anim\">Anime app by the same devs</string>\n    <string name=\"discord\">Rejoignez le Discord</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$d h %2$d min</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d min</string>\n    <string name=\"play_with_app_name\">Lire avec CloudStream</string>\n    <string name=\"play_livestream_button\">Lire en direct</string>\n    <string name=\"skip_type_ed\">Fin</string>\n    <string name=\"history\">Historique</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"all_languages_preference\">Toutes les langues</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Ignorer %s</string>\n    <string name=\"skip_type_op\">Ouverture</string>\n    <string name=\"skip_type_recap\">Récap</string>\n    <string name=\"skip_type_creddits\">Crédits</string>\n    <string name=\"skip_type_intro\">Intro</string>\n    <string name=\"clear_history\">Effacer l\\'historique</string>\n    <string name=\"yes\">Oui</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d j %2$d h %3$d min</string>\n    <string name=\"stream\">Stream</string>\n    <string name=\"confirm_exit_dialog\">Êtes-vous sûr·e de vouloir quitter ?</string>\n    <string name=\"no\">Non</string>\n    <string name=\"update_notification_downloading\">Téléchargement de la mise à jour…</string>\n    <string name=\"next_episode_format\" formatted=\"true\">L\\'épisode %d sera publié dans</string>\n    <string name=\"show_hd\">Étiquette de qualité</string>\n    <string name=\"limit_title_rez\">Afficher les informations du lecteur</string>\n    <string name=\"add_site_pref\">Cloner le site</string>\n    <string name=\"remove_site_pref\">Supprimer le site</string>\n    <string name=\"add_site_summary\">Ajoute un clone à un site déjà existant, avec une URL différente</string>\n    <string name=\"nginx_url_pref\">URL du serveur NGINX</string>\n    <string name=\"example_site_name\">Nouveau Nom du site</string>\n    <string name=\"error_invalid_id\">ID invalide</string>\n    <string name=\"automatic_plugin_download_summary\">Installer automatiquement les plugins qui sont dans les repository mais qui n\\'ont pas encore été installés.</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nrestant</string>\n    <string name=\"livestreams\">En direct</string>\n    <string name=\"others\">Autres</string>\n    <string name=\"live_singular\">En direct</string>\n    <string name=\"other_singular\">Vidéo</string>\n    <string name=\"show_dub\">Étiquette Dub (doublage anglais)</string>\n    <string name=\"show_sub\">Étiquette sous titre</string>\n    <string name=\"show_title\">Titre</string>\n    <string name=\"enable_nsfw_on_providers\">Activer NSFW sur les extensions prises en charge</string>\n    <string name=\"example_password\">motdepasse123</string>\n    <string name=\"example_username\">Nom d\\'utilisateur</string>\n    <string name=\"example_lang_name\">Code de la langue (fr)</string>\n    <string name=\"create_account\">Créer un compte</string>\n    <string name=\"player_load_subtitles_online\">Charger depuis internet</string>\n    <string name=\"resolution_and_title\">Résolution et titre</string>\n    <string name=\"category_player\">Lecteur</string>\n    <string name=\"error_invalid_url\">URL invalide</string>\n    <string name=\"error\">Erreur</string>\n    <string name=\"subtitles_remove_captions\">Enlever les sous-titres pour sourds et malentendants</string>\n    <string name=\"automatic_plugin_download\">Télécharger automatiquement les plugins</string>\n    <string name=\"poster_ui_settings\">Activer ou désactiver les éléments du poster</string>\n    <string name=\"skip_update\">Ignorer cette mise-à-jour</string>\n    <string name=\"error_invalid_data\">Données invalides</string>\n    <string name=\"subtitles_encoding\">Encodage des sous titres</string>\n    <string name=\"category_providers\">Fournisseurs</string>\n    <string name=\"category_ui\">Disposition</string>\n    <string name=\"example_site_url\">https://exemple.com</string>\n    <string name=\"title\">Titre</string>\n    <string name=\"resolution\">Résolution</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"next\">Suivant</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"anime_singular\">@string/anime</string>\n    <string name=\"ova_singular\">OAV</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"subtitles_filter_lang\">Filtrez par langue préférée</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"network_adress_example\">https://exemple.com/exemple.mp4</string>\n    <string name=\"referer\">Référent (facultatif)</string>\n    <string name=\"apk_installer_settings\">Installeur APK</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"subtitles_remove_bloat\">Supprimer les éléments superflus des sous-titres</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"provider_languages_tip\">Regardez les vidéos dans ces langues</string>\n    <string name=\"app_layout_subtext\">Modifier le style de l\\'application pour être assortie à votre appareil</string>\n    <string name=\"uppercase_all_subtitles\">Tous les sous-titres en majuscules</string>\n    <string name=\"view_public_repositories_button\">Voir les repository de la communauté</string>\n    <string name=\"view_public_repositories_button_short\">Liste publique</string>\n    <string name=\"action_mark_as_watched\">Marquer comme vu</string>\n    <string name=\"repository_url_hint\">URL de dépôt ou code court</string>\n    <string name=\"setup_done\">Finir</string>\n    <string name=\"add_repository\">Ajouter le repository</string>\n    <string name=\"preferred_media_subtext\">Ce que vous voulez voir</string>\n    <string name=\"extensions\">Extensions</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Impossible de charger %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"plugin_loaded\">Plugin Chargé</string>\n    <string name=\"plugin_deleted\">Plugin Supprimé</string>\n    <string name=\"batch_download\">Téléchargement par lots</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Début du téléchargement %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Téléchargé %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Tous les %s déjà téléchargés</string>\n    <string name=\"setup_extensions_subtext\">Télécharger la liste de sites que vous voulez utiliser</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Téléchargé : %d</string>\n    <string name=\"video_tracks\">Pistes vidéo</string>\n    <string name=\"apply_on_restart\">Redémarrez l\\'application pour voir les changements.</string>\n    <string name=\"safe_mode_description\">Toutes les extensions ont été désactivé à cause d\\'un crash pour vous aider à trouver l\\'extension causant le problème.</string>\n    <string name=\"safe_mode_title\">Mode sans échec activé</string>\n    <string name=\"extension_size\">Taille</string>\n    <string name=\"extension_version\">Version</string>\n    <string name=\"extension_rating\" formatted=\"true\">Note : %s</string>\n    <string name=\"extension_description\">Description</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"extension_install_first\">Installer l\\'extension d\\'abord</string>\n    <string name=\"hls_playlist\">Playlist HLS</string>\n    <string name=\"player_pref\">Lecteur vidéo préféré</string>\n    <string name=\"skip_type_mixed_ed\">Fin mitigée</string>\n    <string name=\"skip_type_mixed_op\">Introduction mitigée</string>\n    <string name=\"update_notification_installing\">Installation de la mise a jour de l\\'application…</string>\n    <string name=\"update_notification_failed\">Impossible d\\'installer la nouvelle version de l\\'application</string>\n    <string name=\"apk_installer_settings_des\">Certains appareils ne supportent pas le nouvel installateur d\\'application. Essayez l\\'option de l\\'ancien installateur si les mises-à-jour ne s\\'installe pas.</string>\n    <string name=\"previous\">Précédent</string>\n    <string name=\"skip_setup\">Ignorer la configuration</string>\n    <string name=\"repository_name_hint\">Nom de dépôt (optionnel)</string>\n    <string name=\"plugin_singular\">plugin</string>\n    <string name=\"delete_repository\">Supprimer le repository</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Désactivé : %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Non téléchargé : %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d plugins mis-à-jour</string>\n    <string name=\"download_all_plugins_from_repo\">Avertissement : CloudStream 3 décline toute responsabilité concernant l’utilisation d’extensions tierces et ne fournit aucun support pour celles-ci !</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Désactivé)</string>\n    <string name=\"tracks\">Pistes</string>\n    <string name=\"audio_tracks\">Pistes audio</string>\n    <string name=\"safe_mode_crash_info\">Afficher les infos du crash</string>\n    <string name=\"extension_authors\">Auteurs</string>\n    <string name=\"extension_types\">Supporté</string>\n    <string name=\"player_settings_play_in_app\">Lecteur interne</string>\n    <string name=\"app_not_found_error\">Application introuvable</string>\n    <string name=\"clipboard_too_large\">Trop de texte. Impossible de sauvegarder dans le presse papier.</string>\n    <string name=\"apk_installer_package_installer\">Installateur de paquet</string>\n    <string name=\"plugin\">plugins</string>\n    <string name=\"delete_repository_plugins\">Cela supprimera également tous les plugins du repository</string>\n    <string name=\"blank_repo_message\">CloudStream n\\'a aucun site installé par défaut. Vous devez installer les sites à partir de dépôts.\n\\n\n\\nRejoignez notre Discord ou cherchez en ligne.</string>\n    <string name=\"extension_language\">Langage</string>\n    <string name=\"enable_skip_op_from_database_des\">Afficher les popups skip pour les intro / fins</string>\n    <string name=\"apk_installer_legacy\">Ancienne méthode d\\'installation</string>\n    <string name=\"pref_category_links\">Liens</string>\n    <string name=\"pref_category_gestures\">Gestes</string>\n    <string name=\"pref_category_player_features\">Fonctionnalités du lecteur</string>\n    <string name=\"pref_category_subtitles\">Sous-titres</string>\n    <string name=\"pref_category_player_layout\">Disposition</string>\n    <string name=\"pref_category_defaults\">Valeurs par défaut</string>\n    <string name=\"pref_category_looks\">Apparence</string>\n    <string name=\"pref_category_ui_features\">Fonctionnalités</string>\n    <string name=\"play_trailer_button\">Lire la bande-annonce</string>\n    <string name=\"pref_category_app_updates\">Mises à jour de l\\'application</string>\n    <string name=\"pref_category_backup\">Sauvegarde</string>\n    <string name=\"pref_category_extensions\">Extensions</string>\n    <string name=\"pref_category_actions\">Actions</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"redo_setup_process\">Refaire le processus d\\'installation</string>\n    <string name=\"update_started\">Mise à jour commencée</string>\n    <string name=\"delayed_update_notice\">L\\'application sera mise à jour dès la fin de la session</string>\n    <string name=\"plugin_downloaded\">Plugin Téléchargé</string>\n    <string name=\"action_remove_from_watched\">Retirer de la vue</string>\n    <string name=\"library\">Bibliothèque</string>\n    <string name=\"browser\">Navigateur</string>\n    <string name=\"sort\">Trier</string>\n    <string name=\"sort_rating_asc\">Note (basse à haute)</string>\n    <string name=\"sort_rating_desc\">Note (haut à bas)</string>\n    <string name=\"sort_alphabetical_a\">Alphabétique (A à Z)</string>\n    <string name=\"empty_library_no_accounts_message\">Votre bibliothèque est vide :(\n\\nConnectez-vous à un compte de bibliothèque ou ajoutez des séries à votre bibliothèque locale.</string>\n    <string name=\"empty_library_logged_in_message\">Cette liste est vide. Essayez d\\'en changer.</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"sort_by\">Trier par</string>\n    <string name=\"sort_alphabetical_z\">Alphabétique (Z à A)</string>\n    <string name=\"select_library\">Sélectionnez la bibliothèque</string>\n    <string name=\"open_with\">Ouvrir avec</string>\n    <string name=\"sort_updated_new\">Mis à jour (Nouveau vers ancien)</string>\n    <string name=\"sort_updated_old\">Mis à jour (ancien vers nouveau)</string>\n    <string name=\"safe_mode_file\">Fichier du mode sans échec trouvé !\n\\nAucune extension ne sera chargée au démarrage avant que le fichier ne soit enlevé.</string>\n    <string name=\"stop\">Arrêter</string>\n    <string name=\"revert\">Annuler</string>\n    <string name=\"test_log\">Enregistrer</string>\n    <string name=\"watch_quality_pref_data\">Qualité de visionnage préférée (données mobiles)</string>\n    <string name=\"subscription_new\">Abonné à %s</string>\n    <string name=\"start\">Démarrer</string>\n    <string name=\"category_provider_test\">Test des fournisseurs</string>\n    <string name=\"test_passed\">Réussi</string>\n    <string name=\"subscription_deleted\">Désabonné de %s</string>\n    <string name=\"restart\">Redémarrer</string>\n    <string name=\"subscription_list_name\">Abonné</string>\n    <string name=\"jsdelivr_proxy\">Proxy GitHub</string>\n    <string name=\"pref_category_bypass\">Contournements de FAI</string>\n    <string name=\"subscription_episode_released\">L\\'épisode %d est sorti !</string>\n    <string name=\"test_failed\">Échec</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Le temps de recherche utilisé lorsque le lecteur est invisible</string>\n    <string name=\"subscription_in_progress_notification\">Mise à jour des programmes auxquels vous êtes abonné(e)</string>\n    <string name=\"jsdelivr_proxy_summary\">Contourne le blocage de GitHub en utilisant jsDelivr. Cela peut retarder les mises à jour de quelques jours.</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Le temps de recherche utilisé lorsque le lecteur vidéo est visible</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Lecteur Visible - Temps de recherche</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Lecteur Invisible - Temps de recherche</string>\n    <string name=\"jsdelivr_enabled\">Impossible d\\'atteindre GitHub. Activation du proxy jsDelivr…</string>\n    <string name=\"already_voted\">Vous avez déjà voté</string>\n    <string name=\"disable\">Désactivé</string>\n    <string name=\"quality_profile_help\">Ici, vous pouvez modifier la façon dont les sources sont ordonnées. Si une vidéo a une priorité plus élevée, elle apparaîtra plus haut dans la sélection de la source. La somme de la priorité source et de la priorité qualité est la priorité vidéo.\n\\n\n\\nSource A : 3\n\\nQualité B : 7\n\\nLa priorité vidéo combinée sera de 10.\n\\n\n\\nREMARQUE : Si la somme est de 10 ou plus, le joueur sautera automatiquement le chargement lorsque ce lien est chargé !</string>\n    <string name=\"no_plugins_found_error\">Aucun plugin trouvé dans ce dossier</string>\n    <string name=\"no_repository_found_error\">Dépôt introuvable, vérifiez l\\'URL et essayez avec un VPN</string>\n    <string name=\"mobile_data\">Données mobiles</string>\n    <string name=\"set_default\">Définir par défaut</string>\n    <string name=\"use\">Utiliser</string>\n    <string name=\"edit\">Modifier</string>\n    <string name=\"profiles\">Profils</string>\n    <string name=\"help\">Aide</string>\n    <string name=\"profile_number\">Profil %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"qualities\">Qualités</string>\n    <string name=\"unable_to_inflate\">L\\'interface utilisateur n\\'a pas pu être créée correctement. Il s\\'agit d\\'un bogue majeur qui doit être signalé immédiatement %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Sélectionnez le mode pour filtrer le téléchargement des plugins</string>\n    <string name=\"profile_background_des\">Fond de profil</string>\n    <string name=\"favorite_removed\">%s retiré(e) des favoris</string>\n    <string name=\"favorite_added\">%s ajouté(e) aux favoris</string>\n    <string name=\"backup_frequency\">Fréquence de sauvegarde</string>\n    <string name=\"use_default_account\">Utiliser le compte par défaut</string>\n    <string name=\"action_add_to_favorites\">Ajouter aux favoris</string>\n    <string name=\"manage_accounts\">Gérer les comptes</string>\n    <string name=\"duplicate_replace_all\">Tout remplacer</string>\n    <string name=\"edit_account\">Modifier le compte</string>\n    <string name=\"pin_error_incorrect\">PIN incorrect. Ressayez s\\'il vous plait.</string>\n    <string name=\"pin_error_length\">Le PIN doit être de 4 caractères</string>\n    <string name=\"duplicate_replace\">Remplacer</string>\n    <string name=\"duplicate_add\">Ajouter</string>\n    <string name=\"action_remove_from_favorites\">Retirer des favoris</string>\n    <string name=\"select_an_account\">Sélectionnez un compte</string>\n    <string name=\"enter_pin\">Saisir le code PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"favorites_list_name\">Favoris</string>\n    <string name=\"logged_account\" formatted=\"true\">Connecté en tant que %s</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Des doublons potentiels ont été trouvés dans votre bibliothèque :\n\\n\n\\n%s\n\\n\n\\nSouhaitez-vous ajouter cet élément, remplacer les éléments existants ou annuler l\\'action ?</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Saisir le code PIN pour %s</string>\n    <string name=\"duplicate_title\">Doublon potentiel trouvé</string>\n    <string name=\"lock_profile\">Verrouiller le profil</string>\n    <string name=\"skip_startup_account_select_pref\">Ignorer la sélection de compte au démarrage</string>\n    <string name=\"action_unsubscribe\">Se désabonner</string>\n    <string name=\"action_subscribe\">S\\'abonner</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Il semble qu\\'un élément potentiellement dupliqué existe déjà dans votre bibliothèque : \\'%s.\n\\n\n\\nSouhaitez-vous ajouter cet élément, remplacer l\\'élément existant ou annuler l\\'action ?</string>\n    <string name=\"enter_current_pin\">Saisir le code PIN actuel</string>\n    <string name=\"rotate_video\">Pivoter</string>\n    <string name=\"links_reloaded_toast\">Les liens ont été rechargés</string>\n    <string name=\"rotate_video_desc\">Afficher un bouton pour l’orientation de l’écran</string>\n    <string name=\"auto_rotate_video\">Rotation automatique</string>\n    <string name=\"auto_rotate_video_desc\">Activer la rotation automatique de l’écran en fonction de l’orientation vidéo</string>\n    <string name=\"subscribe_tooltip\">Notification de nouvel épisode</string>\n    <string name=\"result_search_tooltip\">Rechercher dans d\\'autres extensions</string>\n    <string name=\"speed_setting_summary\">Ajoute une option de vitesse dans le lecteur</string>\n    <string name=\"test_extensions\">Testez toutes les extensions</string>\n    <string name=\"recommendations_tooltip\">Afficher les recommandations</string>\n    <string name=\"test_extensions_summary\">Ce test est destiné uniquement aux développeurs et ne vérifie ni n\\'empêche le fonctionnement d\\'aucune extension.</string>\n    <string name=\"toast_copied\">Copié !</string>\n    <string name=\"repo_copy_label\">Nom du dépôt et adresse internet</string>\n    <string name=\"favorite\">Favori</string>\n    <string name=\"biometric_warning\">Vos données CloudStream viennent d\\'être sauvegardées. Bien que cette éventualité soit très faible, tous les appareils peuvent se comporter différemment. Dans le rare cas où l\\'accès à l\\'application est bloqué, effacez complètement les données de l\\'application et restaurez à partir d\\'une sauvegarde. Nous sommes sincèrement désolés pour les désagréments occasionnés par cette situation.</string>\n    <string name=\"battery_dialog_title\">Désactiver l\\'optimisation de la batterie</string>\n    <string name=\"app_info_intent_error\">Impossible d\\'ouvrir les informations de l\\'application CloudStream.</string>\n    <string name=\"biometric_authentication_title\">Déverrouiller CloudStream</string>\n    <string name=\"music_singlar\">Musique</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s \\nrestants</string>\n    <string name=\"clipboard_permission_error\">Erreur d\\'accès au presse-papiers, veuillez réessayer.</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"biometric_unsupported\">L\\'authentification biométrique n\\'est pas prise en charge sur cet appareil</string>\n    <string name=\"audio_book_singular\">Livre Audio</string>\n    <string name=\"password_pin_authentication_title\">Mot de passe/Code PIN</string>\n    <string name=\"clipboard_unknown_error\">Erreur de copie, Veuillez copier le logcat et contacter le support de l\\'application.</string>\n    <string name=\"biometric_setting_summary\">Déverrouiller l\\'appli avec l\\'empreinte digitale, l\\'identification faciale, le code PIN, le motif et le mot de passe.</string>\n    <string name=\"biometric_prompt_description\">Après quelques tentatives infructueuses, le message se fermera. Redémarrez simplement l’application pour réessayer.</string>\n    <string name=\"battery_dialog_message\">Pour garantir des téléchargements ininterrompus et des notifications pour les émissions de télévision auxquelles vous êtes abonné, CloudStream a besoin d\\'une autorisation pour fonctionner en arrière-plan. En appuyant sur OK, une boite de dialogue sera affiché. Appuyé sur \\'autoriser\\'.\\n\\nVeuillez noter que cette autorisation ne signifie pas que CS3 épuisera votre batterie. Il ne fonctionnera en arrière-plan que lorsque cela sera nécessaire, par exemple lors de la réception de notifications ou du téléchargement de vidéos à partir d\\'extensions officielles.</string>\n    <string name=\"app_unrestricted_toast\">L\\'utilisation de la batterie de l\\'application est déjà réglée sur illimitée</string>\n    <string name=\"unfavorite\">Supprimer des favoris</string>\n    <string name=\"custom_media_singluar\">Média</string>\n    <string name=\"reset_btn\">Réinitialiser</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">À venir dans %s</string>\n    <string name=\"biometric_setting\">Verrouillage biométrique</string>\n    <string name=\"player_settings_select_cast_device\">Sélectionnez un appareil de diffusion</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Saison %1$d Episode %2$d sera publié dans</string>\n    <string name=\"play_from_beginning_img_des\">Regarder depuis le début</string>\n    <string name=\"open_local_video\">Ouvrir une vidéo locale</string>\n    <string name=\"test_warning\">Attention</string>\n    <string name=\"downloads_empty\">Aucun téléchargement.</string>\n    <string name=\"delete_files\">Supprimer des fichiers</string>\n    <string name=\"downloads_delete_select\">Sélectionner les éléments à supprimer</string>\n    <string name=\"offline_file\">Disponible pour le visionnage hors-ligne</string>\n    <string name=\"select_all\">Tout sélectionner</string>\n    <string name=\"deselect_all\">Tout désélectionner</string>\n    <string name=\"delete_format\" formatted=\"true\">Supprimer (%1$d | %2$s)</string>\n    <string name=\"open_downloaded_repo\">Ouvrir le dépôt</string>\n    <string name=\"device_pin_counter_text\">Code expire dans %1$dm %2$ds</string>\n    <string name=\"cs3wiki\">Wiki de CloudStream</string>\n    <string name=\"device_pin_expired_message\">Le code PIN est maintenant expiré !</string>\n    <string name=\"qr_image\">Image du code QR</string>\n    <string name=\"delete_plugin\">Supprimer l\\'extension</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Êtes-vous sûr de vouloir supprimer définitivement les éléments suivants ? \\n \\n%s</string>\n    <string name=\"auth_locally\">Authentification locale</string>\n    <string name=\"sort_release_date_old\">Date de sortie (du plus ancien au plus récent)</string>\n    <string name=\"sort_release_date_new\">Date de sortie (du plus récent au plus ancien)</string>\n    <string name=\"preview_seekbar\">Aperçu de la barre de recherche</string>\n    <string name=\"pref_category_security\">Sécurité</string>\n    <string name=\"device_pin_url_message\">Visitez <b>%s</b> sur votre téléphone ou votre ordinateur et saisissez le code ci-dessus</string>\n    <string name=\"preview_seekbar_desc\">Activer l’aperçu des miniatures sur la barre de recherche</string>\n    <string name=\"subs_edge_size\">Taille du bord</string>\n    <string name=\"show\">Afficher</string>\n    <string name=\"dont_show\">Ne pas afficher</string>\n    <string name=\"hide_player_control_names\">Masquer les noms des commandes du lecteur</string>\n    <string name=\"device_pin_error_message\">Impossible d’obtenir le code PIN de l’appareil, essayez l’authentification locale</string>\n    <string name=\"pref_category_accounts\">Comptes</string>\n    <string name=\"torrent_info\">Cette vidéo est un torrent, ce qui signifie que votre activité vidéo peut être suivie.\\nAssurez-vous de comprendre le fonctionnement des torrents avant de continuer.</string>\n    <string name=\"dismiss\">Ignorer</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Vous allez également supprimer définitivement tous les épisodes des séries suivantes :\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Êtes-vous sûr de vouloir supprimer définitivement tous les épisodes des séries suivantes ?\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Êtes-vous sûr de vouloir supprimer définitivement les épisodes suivants dans %1$s ?\\n\\n%2$s</string>\n    <string name=\"episode_action_cast_mirror\">Recopier l’écran</string>\n    <string name=\"no_subtitles_loaded\">Aucun sous-titre n’a encore été chargé</string>\n    <string name=\"backup_path_title\">Emplacement du dossier de sauvegarde</string>\n    <string name=\"custom\">Personnalisé</string>\n    <string name=\"confirm_before_exiting_desc\">Afficher une boîte de dialogue avant de quitter l’application</string>\n    <string name=\"confirm_before_exiting_title\">Confirmer avant de quitter</string>\n    <string name=\"unsupported_error\">Erreur non supportée</string>\n    <string name=\"encoding_error\">Erreur d\\'encodage</string>\n    <string name=\"software_decoding_desc\">Le décodage logiciel permet au lecteur de lire des fichiers vidéo non pris en charge par votre appareil, mais peut entraîner une lecture lente ou instable en haute résolution.</string>\n    <string name=\"software_decoding\">Décodage logiciel</string>\n    <string name=\"torrent_preferred_media\">Activer les torrents dans Paramètres/Sources/Média préféré</string>\n    <string name=\"torrent_not_accepted\">Redémarrez l\\'application et acceptez la fenêtre contextuelle Stream Torrent pour continuer.</string>\n    <string name=\"player_load_one_subtitle_online\">Charger le premier disponible</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"sort_button_episode\">Ép %s</string>\n    <string name=\"sort_button_rating\">Note %s</string>\n    <string name=\"sort_button_date\">Date %s</string>\n    <string name=\"update_plugins\">Mettre à jour les plugins</string>\n    <string name=\"plugins_updated_manually\">%d plugin(s) mis à jour avec succès !</string>\n    <string name=\"no_plugins_updated_manually\">Aucun plugin n\\'a été mis à jour.</string>\n    <string name=\"sort_episodes_rating_high_low\">Note (Plus Haute)</string>\n    <string name=\"update_plugins_manually\">Mettre à jour les plugins manuellement</string>\n    <string name=\"sort_episodes_number_desc\">Épisode (Ordre Descendant)</string>\n    <string name=\"sort_episodes_number_asc\">Épisode (Ordre Ascendant)</string>\n    <string name=\"sort_episodes_date_oldest\">Date (Plus Ancien)</string>\n    <string name=\"player_notification_channel_name\">Notifications du lecteur</string>\n    <string name=\"player_notification_channel_description\">La notification du lecteur pour contrôler la lecture en arrière-plan</string>\n    <string name=\"sort_episodes_date_newest\">Date (Plus Récent)</string>\n    <string name=\"sort_episodes_rating_low_high\">Note (Plus Basse)</string>\n    <string name=\"starting_plugin_update_manually\">Démarrage du processus de mise à jour du plugin !</string>\n    <string name=\"subtitles_from_embedded\">Intégré</string>\n    <string name=\"subtitles_from_online\">En ligne</string>\n    <string name=\"speech_recognition_unavailable\">La reconnaissance vocale n\\'est pas disponible</string>\n    <string name=\"begin_speaking\">Commencez à parler…</string>\n    <string name=\"volume_exceeded_100\">Le volume a dépassé 100 %</string>\n    <string name=\"slide_up_again_to_exceed_100\">Glisser à nouveau vers le haut pour dépasser 100 %</string>\n    <string name=\"all_subtitles_bold\">Mettre tous les sous-titres en gras</string>\n    <string name=\"background_radius\">Rayon d\\'arrière-plan</string>\n    <string name=\"all_subtitles_italic\">Mettre tous les sous-titres en italique</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"show_rating\">Étiquette de notation</string>\n    <string name=\"player_settings_always_ask\">Demandez toujours</string>\n    <string name=\"download_parallel_settings_des\">Combien d\\'objets différents peuvent être téléchargés en parallèle</string>\n    <string name=\"parallel_downloads\">Téléchargements parallèles</string>\n    <string name=\"concurrent_connections\">Connections simultanées</string>\n    <string name=\"concurrent_connections_settings_des\">Combien de connexions simultanées chaque téléchargement peut utiliser pendant le téléchargement</string>\n    <string name=\"go_to_downloads\">Aller aux téléchargements</string>\n    <string name=\"no_internet_connection\">Pas de connexion Internet.\\n\\nConnectez-vous à Internet et essayez à nouveau, ou regardez vos téléchargements pendant que vous êtes hors ligne.</string>\n    <string name=\"overscan_settings_des\">Change les limites de l\\'écran</string>\n    <string name=\"overscan_settings\">Surbalayage</string>\n    <string name=\"poster_size_settings_des\">Change la taille des affiches</string>\n    <string name=\"poster_size_settings\">Taille des affiches</string>\n    <string name=\"speedup_title\">Basculement de vitesse par appui long</string>\n    <string name=\"speedup_summary\">Maintenir pour vitesse 2x</string>\n    <string name=\"no_account\">Pas de compte</string>\n    <string name=\"edit_profile_image_title\">Modifier le profil Image</string>\n    <string name=\"edit_profile_image_hint\">Saisir l\\'URL de la photo de profil</string>\n    <string name=\"edit_profile_image_error_empty\">Aucune URL trouvée</string>\n    <string name=\"edit_profile_image_error_invalid\">Image ou URL Invalide</string>\n    <string name=\"edit_profile_image_success\">Image mise à jour avec succès</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Marquer comme vu jusqu’à cet épisode</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Supprimer l\\'historique de visionnage jusqu\\'à cet épisode</string>\n    <string name=\"action_reload\">Rechargé</string>\n    <string name=\"reload_provider\">Recharger le fournisseur</string>\n    <string name=\"resolution_and_name\">Solution et nom</string>\n    <string name=\"name\">Nom</string>\n    <string name=\"episode_action_play_mirror\">Lancer le miroir</string>\"\n    <string name=\"subs_subtitle_alignment\">Alignement des Sous-titres</string>\n    <string name=\"bottom_left\">En bas à gauche</string>\n    <string name=\"bottom_center\">En bas au centre</string>\n    <string name=\"bottom_right\">En bas à droite</string>\n    <string name=\"middle_left\">Au milieu à gauche</string>\n    <string name=\"middle_center\">Au milieu au centre</string>\n    <string name=\"middle_right\">Au milieu à droite</string>\n    <string name=\"top_left\">En haut à gauche</string>\n    <string name=\"top_center\">En haut au centre</string>\n    <string name=\"top_right\">En haut à droite</string>\n    <string name=\"play_full_series_button\">Jouer la série complète</string>\n    <string name=\"install_prerelease\">Installer la version préliminaire</string>\n    <string name=\"prerelease_already_installed\">La version préliminaire est déjà installée.</string>\n    <string name=\"prerelease_install_failed\">L\\'installation de la version préliminaire a échouée.</string>\n    <string name=\"show_episode_text\">Texte de l\\'épisode</string>\n    <string name=\"search_suggestions\">Suggestions de recherche</string>\n    <string name=\"search_suggestions_des\">Afficher des suggestions de recherche pendant la saisie</string>\n    <string name=\"clear_suggestions\">Effacer les suggestions</string>\n    <string name=\"extra_brightness_settings\">Luminosité supplémentaire</string>\n    <string name=\"extra_brightness_settings_des\">Activer le filtre de luminosité lorsque la luminosité dépasse 100 %</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"show_cast_in_details\">Afficher le panneau de cast</string>\n    <string name=\"video_info\">Information du média</string>\n    <string name=\"source_name\">Nom de la source</string>\n    <string name=\"download_queue\">File d\\'attente de téléchargements</string>\n    <string name=\"queue_empty_message\">Il n\\'y a actuellement aucun téléchargement en attente.</string>\n    <string name=\"source_priority\">Priorité de la source</string>\n    <string name=\"source_priority_help\">Déterminez comment les sources vidéo seront triées dans le lecteur</string>\n    <string name=\"download_all\">Télécharger tout</string>\n    <string name=\"cancel_all\">Tout annuler</string>\n    <string name=\"download_episode_range\">Voulez-vous télécharger l\\'épisode %s ?</string>\n    <string name=\"cancel_queue_message\">Vous voulez annuler tous les téléchargements en file d\\'attente ?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d téléchargement actif</item>\n        <item quantity=\"many\">%d téléchargements actifs</item>\n        <item quantity=\"other\">%d téléchargements actifs</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d téléchargement en attente</item>\n        <item quantity=\"many\">%d téléchargements en attente</item>\n        <item quantity=\"other\">%d téléchargements en attente</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+gl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"home_main_poster_img_des\">Póster Principal</string>\n    <string name=\"home_next_random_img_des\">Seguinte ó azar</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Elenco: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">O episodio %d se lanzará en</string>\n    <string name=\"result_poster_img_des\">Póster</string>\n    <string name=\"search_poster_img_des\">Cartel</string>\n    <string name=\"episode_poster_img_des\">Póster do Episodio</string>\n    <string name=\"go_back_img_des\">Regresar</string>\n    <string name=\"home_change_provider_img_des\">Cambiar provedor</string>\n    <string name=\"new_update_format\" formatted=\"true\">Nova actualización atopada!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Recheo</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"title_settings\">Configuración</string>\n    <string name=\"search_hint\">Procurar…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Procurar en %s…</string>\n    <string name=\"no_data\">Sen datos</string>\n    <string name=\"episode_more_options_des\">Máis opcións</string>\n    <string name=\"next_episode\">Seguinte episodio</string>\n    <string name=\"result_tags\">Xéneros</string>\n    <string name=\"type_watching\">Mirando</string>\n    <string name=\"type_on_hold\">En espera</string>\n    <string name=\"type_completed\">Completado</string>\n    <string name=\"type_dropped\">Descartado</string>\n    <string name=\"type_plan_to_watch\">Planeando ver</string>\n    <string name=\"type_re_watching\">Remirando</string>\n    <string name=\"error_bookmarks_text\">Marcadores</string>\n    <string name=\"action_remove_from_bookmarks\">Borrar</string>\n    <string name=\"action_add_to_bookmarks\">Seleccionar estado de visualización</string>\n    <string name=\"sort_apply\">Aplicar</string>\n    <string name=\"sort_copy\">Copiar</string>\n    <string name=\"sort_close\">Cerrar</string>\n    <string name=\"sort_clear\">Limpar</string>\n    <string name=\"sort_save\">Gardar</string>\n    <string name=\"player_speed\">Velocidade do reproductor</string>\n    <string name=\"subtitles_settings\">Configurar Subtítulos</string>\n    <string name=\"subs_background_color\">Cor de Fondo</string>\n    <string name=\"subs_text_color\">Cor de Texto</string>\n    <string name=\"subs_outline_color\">Cor de Contorno</string>\n    <string name=\"subs_window_color\">Cor de Ventá</string>\n    <string name=\"continue_watching\">Continuar Vendo</string>\n    <string name=\"rated_format\" formatted=\"true\">Nota: %.1f</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Inicio</string>\n    <string name=\"title_downloads\">Descarga</string>\n    <string name=\"result_share\">Compartir</string>\n    <string name=\"result_open_in_browser\">Abrir no Navegador</string>\n    <string name=\"browser\">Navegador</string>\n    <string name=\"skip_loading\">Omitir carga</string>\n    <string name=\"loading\">Cargando…</string>\n    <string name=\"play_movie_button\">Reproducir o filme</string>\n    <string name=\"play_trailer_button\">Reproducir Trailer</string>\n    <string name=\"play_livestream_button\">Reproducir transmisión en vivo</string>\n    <string name=\"play_torrent_button\">Transmitir Torrent</string>\n    <string name=\"pick_source\">Fontes</string>\n    <string name=\"reload_error\">Tentar de novo a conexión…</string>\n    <string name=\"go_back\">Volver</string>\n    <string name=\"play_episode\">Reproducir Episodio</string>\n    <string name=\"download\">Descargar</string>\n    <string name=\"downloaded\">Descargado</string>\n    <string name=\"downloading\">Descargando</string>\n    <string name=\"download_paused\">Descarga Pausada</string>\n    <string name=\"download_started\">Descarga comezada</string>\n    <string name=\"download_failed\">Descarga Fallida</string>\n    <string name=\"download_canceled\">Descarga Cancelada</string>\n    <string name=\"download_done\">Descarga rematada</string>\n    <string name=\"update_started\">Actualización Comezada</string>\n    <string name=\"app_subbed_text\">Subtitulado</string>\n    <string name=\"popup_delete_file\">Borrar Arquivo</string>\n    <string name=\"popup_play_file\">Reproducir Arquivo</string>\n    <string name=\"popup_resume_download\">Continuar Descarga</string>\n    <string name=\"popup_pause_download\">Pausar Descarga</string>\n    <string name=\"home_more_info\">Máis información</string>\n    <string name=\"home_expanded_hide\">Agochar</string>\n    <string name=\"home_play\">Reproducir</string>\n    <string name=\"subs_edge_type\">Tipo de Borde</string>\n    <string name=\"subs_font\">Fonte</string>\n    <string name=\"benene_count_text_none\">Non se deron bananas</string>\n    <string name=\"subs_auto_select_language\">Seleccionar idioma automáticamente</string>\n    <string name=\"subs_download_languages\">Descargar Idiomas</string>\n    <string name=\"subs_subtitle_languages\">Idioma do Subtítulo</string>\n    <string name=\"subs_hold_to_reset_to_default\">Manteña premido para restablecer os valores predeterminados</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importar fontes colocandoas en %s</string>\n    <string name=\"action_remove_watching\">Borrar</string>\n    <string name=\"action_open_watching\">Máis Info</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Unha VPN pode ser necesaria para o correcto funcionamento deste provedor</string>\n    <string name=\"vpn_torrent\">Este proveedor é un torrent, recomendase o uso dunha VPN</string>\n    <string name=\"provider_info_meta\">Os metadatos non son proporcionados polo sitio, a carga do video fallará se non existe no sitio</string>\n    <string name=\"torrent_plot\">Descripción</string>\n    <string name=\"normal_no_plot\">Trama non atopada</string>\n    <string name=\"torrent_no_plot\">Descripción non atopada</string>\n    <string name=\"show_log_cat\">Amosar Logcat 🐈</string>\n    <string name=\"test_log\">Rexistro</string>\n    <string name=\"picture_in_picture_des\">Continúa a reprodución nun reproductor miniatura enriba doutras aplicacións</string>\n    <string name=\"play_with_app_name\">Reproducir con CloudStream</string>\n    <string name=\"title_search\">Procurar</string>\n    <string name=\"preview_background_img_des\">Vista previa do fondo</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Velocidade (%.2fx)</string>\n    <string name=\"pick_subtitle\">Subtítulos</string>\n    <string name=\"stream\">Fluxo de datos</string>\n    <string name=\"error_loading_links_toast\">Error Cargando Ligazón</string>\n    <string name=\"app_dubbed_text\">Dobrado</string>\n    <string name=\"filter_bookmarks\">Filtrar Marcadores</string>\n    <string name=\"download_storage_text\">Almacenamento Interno</string>\n    <string name=\"subs_font_size\">Tamaño de Fonte</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"subs_subtitle_elevation\">Elevación de Subtítulo</string>\n    <string name=\"search_provider_text_providers\">Procurar usando proveedores</string>\n    <string name=\"benene_count_text\">%d Bananas dadas aos desenvolvedores</string>\n    <string name=\"search_provider_text_types\">Procurar por tipos</string>\n    <string name=\"picture_in_picture\">Imaxe en Imaxe</string>\n    <string name=\"player_subtitles_settings_des\">Configuración de subtítulos do reprodutor</string>\n    <string name=\"chromecast_subtitles_settings\">Subtítulos de Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Configuración de subtítulos de Chromecast</string>\n    <string name=\"eigengraumode_settings\">Velocidade de reproducción</string>\n    <string name=\"swipe_to_seek_settings\">Deslice para avanzar/retroceder</string>\n    <string name=\"swipe_to_seek_settings_des\">Deslice o dedo de lado a lado para controlar a posición nun video</string>\n    <string name=\"swipe_to_change_settings\">Deslice para cambiar a configuración</string>\n    <string name=\"swipe_to_change_settings_des\">Deslice cara arriba ou cara abaixo no lado esquerdo ou dereito para cambiar o brillo ou o volumen</string>\n    <string name=\"autoplay_next_settings\">Reproducir automáticamente episodio seguinte</string>\n    <string name=\"autoplay_next_settings_des\">Comezar o seguinte episodio cando o actual remate</string>\n    <string name=\"double_tap_to_seek_settings\">Toca dúas veces para procurar</string>\n    <string name=\"double_tap_to_pause_settings\">Tocar dúas veces para pausar</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Tempo de rebobinado do reprodutor (segundos)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Toque dúas veces no lado dereito ou esquerdo para rebobinar cara adiante ou cara atrás</string>\n    <string name=\"double_tap_to_pause_settings_des\">Toque dúas veces no medio para pausar</string>\n    <string name=\"use_system_brightness_settings\">Usar brillo do sistema</string>\n    <string name=\"episode_sync_settings\">Actualizar progreso do visto</string>\n    <string name=\"restore_settings\">Restaurar datos dende o respaldo</string>\n    <string name=\"backup_settings\">Crear respaldo de datos</string>\n    <string name=\"restore_success\">Arquivo de respaldo cargado</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Fallou a restauración dos datos dende o arquivo %s</string>\n    <string name=\"backup_success\">Datos gardados</string>\n    <string name=\"backup_failed\">Faltan permisos de almacenamento. Por favor tenteo de novo.</string>\n    <string name=\"backup_failed_error_format\">Error respaldando de %s</string>\n    <string name=\"search\">Procurar</string>\n    <string name=\"library\">Biblioteca</string>\n    <string name=\"category_account\">Contas e seguridade</string>\n    <string name=\"category_updates\">Actualizacións e copias de seguridade</string>\n    <string name=\"settings_info\">Info</string>\n    <string name=\"advanced_search\">Procura Avanzada</string>\n    <string name=\"advanced_search_des\">Da os resultados da procura separados por proveedor</string>\n    <string name=\"player_size_settings\">Botón de cambio de tamaño do reprodutor</string>\n    <string name=\"player_size_settings_des\">Eliminar bordes negros</string>\n    <string name=\"player_subtitles_settings\">Subtítulos</string>\n    <string name=\"episode_sync_settings_des\">Sincronizar automáticamente o progreso do episodio actual</string>\n    <string name=\"use_system_brightness_settings_des\">Use o brillo do sistema no reprodutor da aplicación en lugar dunha superposición oscura</string>\n    <string name=\"show_fillers_settings\">Mostrar episodio de recheo para Anime</string>\n    <string name=\"show_trailers_settings\">Mostrar Trailers</string>\n    <string name=\"kitsu_settings\">Mostrar pósters de Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Ocultar calidade de video nos resultados da procura</string>\n    <string name=\"automatic_plugin_updates\">Actualicación automática de complementos</string>\n    <string name=\"automatic_plugin_download\">Descarga automática de complementos</string>\n    <string name=\"automatic_plugin_download_mode_title\">Selecciona o modo para filtrar a descarga dos complementos</string>\n    <string name=\"automatic_plugin_download_summary\">Instala automáticamente todos os complementos aínda non instalados dos repositorios engadidos.</string>\n    <string name=\"updates_settings\">Mostrar actualizacións da aplicación</string>\n    <string name=\"subs_default_reset_toast\">Reiniciar aos valores predefinidos</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"audio_book_singular\">Audiolibro</string>\n    <string name=\"test_warning\">Advertencia</string>\n    <string name=\"site\">Páxina Web</string>\n    <string name=\"downloads_empty\">Non hay descargas dispoñíbeis</string>\n    <string name=\"anim\">Aplicativo de Anime dos mesmos desenvolvedores</string>\n    <string name=\"discord\">Únete o Discord</string>\n    <string name=\"speed_setting_summary\">Engade unha opción de velocidade no reproductor</string>\n    <string name=\"lightnovel\">Aplicativo de novela lixeira dos mesmos desenvolvedores</string>\n    <string name=\"no_episodes_found\">Non se atoparon capítulos</string>\n    <string name=\"delete\">Borrar</string>\n    <string name=\"resume\">Continuar</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"no_update_found\">Non se atoparon actualizacións</string>\n    <string name=\"check_for_update\">Buscar actualizacións</string>\n    <string name=\"video_lock\">Bloquear</string>\n    <string name=\"episode_action_download_subtitle\">Descargar subtítulos</string>\n    <string name=\"links_reloaded_toast\">Ligazóns recargadas</string>\n    <string name=\"updates_settings_des\">Busque de forma automática novas actualizacións despois de iniciar o aplicativo.</string>\n    <string name=\"apk_installer_settings_des\">Algúns dispositivos non soportan o novo instalador de paquetes. Probe a opción antiga se as actualizacións non se instalan.</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Está seguro de querer borrar permanentemente os seguintes elementos?\\n\\n%s</string>\n    <string name=\"delete_message\" formatted=\"true\">Esto borrarase %s permanentemente\\nEstás seguro?</string>\n    <string name=\"cartoons_singular\">Debuxo animado</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"cartoons\">Debuxos animados</string>\n    <string name=\"render_error\">Erro do renderizador</string>\n    <string name=\"benene_des\">Banana dada</string>\n    <string name=\"app_language\">Idioma do aplicativo</string>\n    <string name=\"redo_setup_process\">Volver a facer o proceso de configuración inicial</string>\n    <string name=\"no_season\">Nengunha temportada</string>\n    <string name=\"synopsis\">Sinopse</string>\n    <string name=\"source_error\">Erro na fonte</string>\n    <string name=\"action_default\">Por defecto</string>\n    <string name=\"start\">Comezar</string>\n    <string name=\"duration\">Duración</string>\n    <string name=\"asian_drama_singular\">Drama asiático</string>\n    <string name=\"toast_copied\">¡Copiado!</string>\n    <string name=\"video_source\">Fonte</string>\n    <string name=\"unexpected_error\">Erro inesperado do reproductor</string>\n    <string name=\"episode\">Capítulo</string>\n    <string name=\"music_singlar\">Música</string>\n    <string name=\"episode_short\">C</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\\nrestantes</string>\n    <string name=\"status_ongoing\">En curso</string>\n    <string name=\"queued\">En cola</string>\n    <string name=\"status_completed\">Rematado</string>\n    <string name=\"status\">Estado</string>\n    <string name=\"year\">Ano</string>\n    <string name=\"no_subtitles\">Sen subtítulos</string>\n    <string name=\"rating\">Puntuación</string>\n    <string name=\"asian_drama\">Dramas asiáticos</string>\n    <string name=\"livestreams\">Transmisións en vivo</string>\n    <string name=\"others\">Outros</string>\n    <string name=\"episode_action_reload_links\">Recargar ligazóns</string>\n    <string name=\"show_hd\">Etiqueta de calidade</string>\n    <string name=\"show_dub\">Etiqueta de doblaxe</string>\n    <string name=\"show_sub\">Etiqueta de subtitulado</string>\n    <string name=\"show_title\">Título</string>\n    <string name=\"backup_frequency\">Frecuencia da copia de seguridade</string>\n    <string name=\"subscribe_tooltip\">Notificación de novo capítulo</string>\n    <string name=\"repo_copy_label\">Nome do repositorio e a sua URL</string>\n    <string name=\"play_from_beginning_img_des\">Reproducir dende o comezo</string>\n    <string name=\"open_local_video\">Abrir vídeo localmente</string>\n    <string name=\"apk_installer_settings\">Instalador de APK</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">A temporada %1$d e o capítulo %2$d se estrearán en</string>\n    <string name=\"downloads_delete_select\">Escolla os elementos para eliminar</string>\n    <string name=\"offline_file\">Dispoñibel para visualizar sen conexión</string>\n    <string name=\"select_all\">Seleccionar todo</string>\n    <string name=\"deselect_all\">Deseleccionar todo</string>\n    <string name=\"result_search_tooltip\">Buscar noutras extensións</string>\n    <string name=\"recommendations_tooltip\">Amosar recomendacións</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Está seguro de querer borrar permanentemente todos os episodios da serie?\\n\\n%s</string>\n    <string name=\"free_storage\">Libre</string>\n    <string name=\"used_storage\">Usado</string>\n    <string name=\"app_storage\">Aplicativo</string>\n    <string name=\"movies\">Películas</string>\n    <string name=\"tv_series\">Series de Televisión</string>\n    <string name=\"documentaries\">Documentales</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"movies_singular\">Película</string>\n    <string name=\"tv_series_singular\">Serie</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Documental</string>\n    <string name=\"live_singular\">Transmisión en vivo</string>\n    <string name=\"other_singular\">Vídeo</string>\n    <string name=\"remote_error\">Erro remoto</string>\n    <string name=\"storage_error\">Erro de descarga, comproba os permisos de almacenamento</string>\n    <string name=\"episode_action_chromecast_episode\">Capítulo no Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Duplicar no Chromecast</string>\n    <string name=\"episode_action_cast_mirror\">Transmitir en espello</string>\n    <string name=\"episode_action_play_in_app\">Reproducir na aplicación</string>\n    <string name=\"episode_action_auto_download\">Descarga automática</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Próximamente en %s</string>\n    <string name=\"delete_file\">Borrar arquivo</string>\n    <string name=\"test_failed\">Errou</string>\n    <string name=\"test_passed\">Aprobado</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\nrestante</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"episode_action_play_in_format\">Reproducir en %s</string>\n    <string name=\"github\">Github</string>\n    <string name=\"benene\">Dalle unha banana ós desenvolvedores</string>\n    <string name=\"no_chromecast_support_toast\">Este provedor non ten soporte para Chromecast</string>\n    <string name=\"no_links_found_toast\">Ligazóns non atopadas</string>\n    <string name=\"copy_link_toast\">Ligazón copiada ó portapapeis</string>\n    <string name=\"play_episode_toast\">Reproducir capítulo</string>\n    <string name=\"season\">Temporada</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">T</string>\n    <string name=\"delete_files\">Borrar arquivos</string>\n    <string name=\"delete_format\" formatted=\"true\">Borrar (%1$d | %2$s)</string>\n    <string name=\"cancel\">Cancelar</string>\n    <string name=\"pause\">Pausar</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Está seguro de querer borrar permanentemente os seguientes capítulos en %1$s?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Tamén borrará permanentemente todos os capítulos das seguintes series:\\n\\n%s</string>\n    <string name=\"episode_action_download_mirror\">Descargar dende un servidor alternativo</string>\n    <string name=\"poster_ui_settings\">Alternar elementos da interfaz de usuario no póster</string>\n    <string name=\"video_aspect_ratio_resize\">Redimensionar</string>\n    <string name=\"video_skip_op\">Omitir introducción</string>\n    <string name=\"dont_show_again\">Non volver a amosar</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+hi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">स्पीड (%.2fx)</string>\n    <string name=\"new_update_format\" formatted=\"true\">नया अपडेट आया है!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"title_home\">होम</string>\n    <string name=\"title_search\">खोजें</string>\n    <string name=\"title_downloads\">डाउनलोडस</string>\n    <string name=\"title_settings\">सेटिंग्स</string>\n    <string name=\"no_data\">डेटा उपलब्ध नहीं</string>\n    <string name=\"episode_more_options_des\">और विकल्प</string>\n    <string name=\"next_episode\">अगला एपिसोड</string>\n    <string name=\"result_tags\">शैलियां</string>\n    <string name=\"result_share\">साझा करें</string>\n    <string name=\"result_open_in_browser\">ब्राउज़र में खोलें</string>\n    <string name=\"type_watching\">देखा जा रहा है</string>\n    <string name=\"type_on_hold\">होल्ड पर</string>\n    <string name=\"type_completed\">पूरा देखा</string>\n    <string name=\"type_dropped\">अधूरा छोड़ा</string>\n    <string name=\"type_plan_to_watch\">देखने की योजना</string>\n    <string name=\"play_movie_button\">मूवी चलाएं</string>\n    <string name=\"play_torrent_button\">टोरेंट चलाएं</string>\n    <string name=\"pick_source\">स्त्रोत</string>\n    <string name=\"reload_error\">पुनः प्रयास करें…</string>\n    <string name=\"go_back\">वापिस जाए</string>\n    <string name=\"play_episode\">एपिसोड चलाएं</string>\n    <!--<string name=\"need_storage\">Allow to download episodes</string>-->\n    <string name=\"download\">डाउनलोड</string>\n    <string name=\"downloaded\">डाउनलोड किया गया</string>\n    <string name=\"downloading\">डाउनलोड हो रहा</string>\n    <string name=\"download_paused\">डाउनलोड रोका गया</string>\n    <string name=\"download_started\">डाउनलोड शुरू हुआ</string>\n    <string name=\"download_failed\">डाउनलोड विफल</string>\n    <string name=\"download_canceled\">डाउनलोड रद्द</string>\n    <string name=\"download_done\">डाउनलोड मुकम्मल</string>\n    <string name=\"error_loading_links_toast\">लिंक लोड करने में त्रुटि</string>\n    <string name=\"download_storage_text\">अंदरूनी स्टोरेज</string>\n    <string name=\"popup_delete_file\">फ़ाइल मिटाएँ</string>\n    <string name=\"popup_play_file\">फ़ाइल चलाएं</string>\n    <string name=\"popup_resume_download\">डाउनलोड फिर शुरू करें</string>\n    <string name=\"popup_pause_download\">डाउनलोड रोकें</string>\n    <string name=\"home_more_info\">और जानकारी</string>\n    <string name=\"home_expanded_hide\">छिपाएं</string>\n    <string name=\"home_play\">चलाएं</string>\n    <string name=\"home_info\">जानकारी</string>\n    <string name=\"filter_bookmarks\">बुकमार्क छांटे</string>\n    <string name=\"error_bookmarks_text\">बुकमार्क्स</string>\n    <string name=\"action_remove_from_bookmarks\">हटाएँ</string>\n    <string name=\"sort_apply\">लागू करें</string>\n    <string name=\"player_speed\">प्लेयर स्पीड</string>\n    <string name=\"search_provider_text_providers\">प्रोवाइडरों का उपयोग कर खोजें</string>\n    <string name=\"search_provider_text_types\">प्रकार का उपयोग करके खोजें</string>\n    <string name=\"benene_count_text\">%d केले डेवलपर्स को दिए गए</string>\n    <string name=\"benene_count_text_none\">कोई केले नहीं दिए गए</string>\n    <string name=\"subs_hold_to_reset_to_default\">डिफ़ॉल्ट पर रीसेट करने के लिए दबाए रखें</string>\n    <string name=\"continue_watching\">देखना जारी रखें</string>\n    <string name=\"action_remove_watching\">हटाएँ</string>\n    <string name=\"action_open_watching\">अधिक जानकारी</string>\n    <string name=\"vpn_might_be_needed\">इस प्रोवाइडर को सही ढंग से काम करने के लिए VPN की ज़रूरत पड़ सकती है</string>\n    <string name=\"vpn_torrent\">यह प्रोवाइडर एक torrent है, एक VPN इस्तेमाल करने की सिफारिश की जाती है</string>\n    <string name=\"torrent_plot\">वर्णन</string>\n    <string name=\"normal_no_plot\">कोई विषय नहीं मिला</string>\n    <string name=\"torrent_no_plot\">कोई वर्णन नहीं मिला</string>\n    <string name=\"picture_in_picture_des\">अन्य ऐप्स के ऊपर एक लघु प्लेयर में प्लेबैक जारी रखता है</string>\n    <string name=\"player_size_settings_des\">काले बॉर्डर हटाएँ</string>\n    <string name=\"player_subtitles_settings_des\">प्लेयर उपशीर्षक सेटिंग्स</string>\n    <string name=\"swipe_to_seek_settings_des\">किसी वीडियो में अपनी स्थिति नियंत्रित करने के लिए एक ओर से दूसरी ओर स्वाइप करें</string>\n    <string name=\"swipe_to_change_settings_des\">चमक या वॉल्यूम बदलने के लिए बाईं या दाईं ओर ऊपर या नीचे स्लाइड करें</string>\n    <string name=\"double_tap_to_seek_settings_des\">आगे या पीछे करने के लिए दाईं या बाईं ओर दो बार टैप करें</string>\n    <string name=\"search\">खोजें</string>\n    <string name=\"settings_info\">जानकारी</string>\n    <string name=\"advanced_search_des\">खोज नतीजों को प्रोवाइडरों के हिसाब से अलग-अलग आपको दिखाता है</string>\n    <string name=\"updates_settings_des\">हर बार एप खुलने पर स्वचालित रूप से नए अपडेट खोजें।</string>\n    <string name=\"lightnovel\">उन्हीं डेवलपर्स द्वारा Light novel ऐप</string>\n    <string name=\"anim\">उन्हीं डेवलपर्स द्वारा Anime ऐप</string>\n    <string name=\"discord\">Discord से जुड़िये</string>\n    <string name=\"benene\">इस प्रोग्राम के निर्माता को केला दें</string>\n    <string name=\"benene_des\">केले दे दिए गए</string>\n    <string name=\"app_language\">ऍप की भाषा</string>\n    <string name=\"no_chromecast_support_toast\">यह प्रोवाइडर क्रोमकास्ट का समर्थन नहीं करता</string>\n    <string name=\"no_links_found_toast\">कोई लिंक नहीं मिले</string>\n    <string name=\"copy_link_toast\">लिंक क्लिपबोर्ड पर कॉपी किया गया</string>\n    <string name=\"play_episode_toast\">एपिसोड चलायें</string>\n    <string name=\"delete_file\">फ़ाइल डिलीट करें</string>\n    <string name=\"delete\">डिलीट</string>\n    <string name=\"cancel\">रद्द करें</string>\n    <string name=\"pause\">रोकें</string>\n    <string name=\"resume\">फिर से चलाएं</string>\n    <string name=\"delete_message\">इससे %s स्थायी रूप से हट जाएगा\n\\nक्या आपका निर्णय निश्चित है ?</string>\n    <string name=\"status_ongoing\">अभी चालू है</string>\n    <string name=\"status_completed\">मुकम्मल हुया</string>\n    <string name=\"status\">स्थिति</string>\n    <string name=\"year\">साल</string>\n    <string name=\"rating\">रेटिंग</string>\n    <string name=\"duration\">अवधि</string>\n    <string name=\"site\">साइट</string>\n    <string name=\"synopsis\">सारांश</string>\n    <string name=\"free_storage\">ख़ाली</string>\n    <string name=\"used_storage\">इस्तेमाल में</string>\n    <string name=\"app_storage\">ऍप</string>\n    <string name=\"movies\">मूवीज</string>\n    <string name=\"tv_series\">टीवी सीरियल</string>\n    <string name=\"cartoons\">कार्टून</string>\n    <string name=\"anime\">एनिमे</string>\n    <string name=\"torrent\">टोरेंट</string>\n    <string name=\"episode_action_chromecast_episode\">क्रोमकास्ट एपिसोड</string>\n    <string name=\"episode_action_chromecast_mirror\">क्रोमकास्ट मिरर</string>\n    <string name=\"episode_action_play_in_app\">एप्प में चलाएं</string>\n    <string name=\"episode_action_play_in_format\">%s में चलाएं</string>\n    <string name=\"episode_action_auto_download\">डाउनलोड करें</string>\n    <string name=\"episode_action_download_mirror\">मिरर डाउनलोड</string>\n    <string name=\"episode_action_reload_links\">लिंक दोबारा लोड करें</string>\n    <string name=\"no_update_found\">कोई अपडेट नहीं मिला</string>\n    <string name=\"check_for_update\">अपडेट के लिये जांचें</string>\n    <string name=\"video_lock\">ताला</string>\n    <string name=\"video_aspect_ratio_resize\">आकार बदलें</string>\n    <string name=\"video_source\">सोर्स</string>\n    <string name=\"video_skip_op\">OP स्किप करें</string>\n    <string name=\"dont_show_again\">फिर ना दिखाएँ</string>\n    <string name=\"update\">अपडेट</string>\n    <string name=\"watch_quality_pref\">देखने की तरजीही क्वालिटी (वाईफ़ाई)</string>\n    <string name=\"dns_pref_summary\">ISP ब्लॉक से छुटकारा पाएं</string>\n    <string name=\"provider_lang_settings\">एक्सटेंशन की भाषाएं</string>\n    <string name=\"app_layout\">ऐप का रुप दर्शन</string>\n    <string name=\"preferred_media_settings\">पसंदीदा मीडिया</string>\n    <string name=\"download_path_pref\">डाउनलोड पथ</string>\n    <string name=\"display_subbed_dubbed_settings\">डब किए /सबब् किए एनीमे दिखाएं</string>\n    <string name=\"tv_layout\">टीवी रुप दर्शन</string>\n    <string name=\"phone_layout\">फ़ोन रुप दर्शन</string>\n    <string name=\"primary_color_settings\">मुख्य रंग</string>\n    <string name=\"app_theme_settings\">ऐप थीम</string>\n    <string name=\"action_mark_as_watched\">देखा हुआ चिह्नित करें</string>\n    <string name=\"history\">इतिहास</string>\n    <string name=\"next_episode_format\" formatted=\"true\">भाग %d रिलीज़ किया जाएगा</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"home_next_random_img_des\">अगला रैंडम</string>\n    <string name=\"go_back_img_des\">वापिस जाओ</string>\n    <string name=\"search_poster_img_des\">पोस्टर</string>\n    <string name=\"preview_background_img_des\">प्रीव्यू बैकग्राउंड</string>\n    <string name=\"home_change_provider_img_des\">प्रोवाइडर बदलें</string>\n    <string name=\"cast_format\" formatted=\"true\">Cast: %s</string>\n    <string name=\"home_main_poster_img_des\">मुख्य पोस्टर</string>\n    <string name=\"episode_poster_img_des\">एपिसोड का पोस्टर</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"filler\" formatted=\"true\">पूरक</string>\n    <string name=\"rated_format\" formatted=\"true\">रेटिंग: %.1f</string>\n    <string name=\"search_hint_site\" formatted=\"true\">%s पर खोजें…</string>\n    <string name=\"search_hint\">खोजें…</string>\n    <string name=\"duration_format\" formatted=\"true\">%d मिनट</string>\n    <string name=\"app_name\">क्लाउडस्ट्रीम</string>\n    <string name=\"play_with_app_name\">क्लाउडस्ट्रीम के साथ चलाएं</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">आपकी लाइब्रेरी में संभावित डुप्लिकेट आइटम पाए गए हैं:\n\\n\n\\n%s\n\\n\n\\nक्या आप किसी भी तरह इस आइटम को जोड़ना चाहेंगे, मौजूदा आइटम को बदलना चाहेंगे, या कार्रवाई रद्द करना चाहेंगे?</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">%s के लिए पिन दर्ज करें</string>\n    <string name=\"duplicate_title\">संभावित डुप्लिकेट मिला</string>\n    <string name=\"update_started\">अपडेट शुरू हुआ</string>\n    <string name=\"lock_profile\">प्रोफ़ाइल लॉक करें</string>\n    <string name=\"duplicate_replace_all\">सबको बदली करें</string>\n    <string name=\"pin_error_incorrect\">ग़लत पिन. कृपया पुन: प्रयास करें।</string>\n    <string name=\"browser\">ब्राउज़र</string>\n    <string name=\"pick_subtitle\">उपशीर्षक</string>\n    <string name=\"pin_error_length\">पिन 4 अक्षर का होना चाहिए</string>\n    <string name=\"duplicate_replace\">बदली</string>\n    <string name=\"duplicate_add\">जोड़े</string>\n    <string name=\"play_trailer_button\">ट्रेलर देखे</string>\n    <string name=\"play_livestream_button\">लाइवस्ट्रीम देखे</string>\n    <string name=\"result_poster_img_des\">विज्ञापन</string>\n    <string name=\"type_re_watching\">दोबारा देखे</string>\n    <string name=\"auto_rotate_video\">स्वत: घुमाएँ</string>\n    <string name=\"select_an_account\">अकाउंट चुनिये</string>\n    <string name=\"skip_loading\">लोडिंग स्किप करे</string>\n    <string name=\"loading\">लोडिंग…</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">ऐसा प्रतीत होता है कि संभावित रूप से डुप्लिकेट आइटम आपकी लाइब्रेरी में पहले से मौजूद है: \\'%s.\\'\n\\n\n\\nक्या आप किसी भी तरह इस आइटम को जोड़ना चाहेंगे, मौजूदा आइटम को बदलना चाहेंगे, या कार्रवाई रद्द करना चाहेंगे?</string>\n    <string name=\"enter_pin\">पिन दर्ज करें</string>\n    <string name=\"pin\">पिन</string>\n    <string name=\"links_reloaded_toast\">लिंक पुन्ह खुली</string>\n    <string name=\"enter_current_pin\">वर्तमान पिन दर्ज करें</string>\n    <string name=\"stream\">नेटवर्क स्ट्रीम</string>\n    <string name=\"sort_clear\">साफ़ करें</string>\n    <string name=\"subtitles_settings\">उपशीर्षक सेटिंग्स</string>\n    <string name=\"subs_font_size\">अक्षर का माप</string>\n    <string name=\"sort_close\">बंद करें</string>\n    <string name=\"repo_copy_label\">रिपॉजिटरी का नाम और यूआरएल</string>\n    <string name=\"toast_copied\">कॉपी!</string>\n    <string name=\"sort_save\">सहेजें</string>\n    <string name=\"subscribe_tooltip\">नये एपिसोड की अधिसूचना</string>\n    <string name=\"result_search_tooltip\">अन्य एक्सटेंशन में खोजें</string>\n    <string name=\"recommendations_tooltip\">सुझाव दिखाएं</string>\n    <string name=\"subs_background_color\">पृष्ठभूमि का रंग</string>\n    <string name=\"subs_edge_type\">रूपरेखा प्रकार</string>\n    <string name=\"subs_text_color\">अक्षर का रंग</string>\n    <string name=\"subs_window_color\">बॉक्स का रंग</string>\n    <string name=\"subs_outline_color\">रूपरेखा रंग</string>\n    <string name=\"subs_subtitle_elevation\">उपशीर्षक ऊंचाई</string>\n    <string name=\"subs_font\">मुद्रलिपि</string>\n    <string name=\"downloads_empty\">वर्तमान में कोई डाउनलोड नहीं है।</string>\n    <string name=\"play_from_beginning_img_des\">आरम्भ से शुरू करें</string>\n    <string name=\"downloads_delete_select\">मिटाने के लिए वस्तु चुनें</string>\n    <string name=\"subs_import_text\" formatted=\"true\">फ़ॉन्ट को %s में रखकर आयात करें</string>\n    <string name=\"test_log\">अभिलेख</string>\n    <string name=\"open_local_video\">स्थानीय वीडियो खोलें</string>\n    <string name=\"subs_subtitle_languages\">उपशीर्षक भाषा</string>\n    <string name=\"player_size_settings\">प्लेयर आकार परिवर्तन बटन</string>\n    <string name=\"eigengraumode_settings\">प्रतिश्रवण गति</string>\n    <string name=\"autoplay_next_settings\">आगामी प्रकरण स्वतः चलाएं</string>\n    <string name=\"autoplay_next_settings_des\">वर्तमान प्रकरण समाप्त होने पर आगामी प्रकरण चलाएं</string>\n    <string name=\"app_subbed_text\">सब</string>\n    <string name=\"action_add_to_bookmarks\">दर्शन स्थिति सेट करें</string>\n    <string name=\"swipe_to_seek_settings\">आगे पीछे जाने के लिए स्वाइप करें</string>\n    <string name=\"subs_auto_select_language\">स्वतः चयन भाषा</string>\n    <string name=\"show_log_cat\">लोगकैट दिखाएं</string>\n    <string name=\"sort_copy\">प्रतिलिपि</string>\n    <string name=\"provider_info_meta\">मेटाडाटा साइट द्वारा प्रदान नहीं किया गया है, अगर यह साइट पर विद्यमान नहीं है तो वीडियो लोडिंग विफल हो जाएगी।</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">सीजन %1$d एपिसोड %2$d में जारी किया जाएगा</string>\n    <string name=\"picture_in_picture\">चित्र में चित्र</string>\n    <string name=\"chromecast_subtitles_settings\">क्रोमकास्ट उपशीर्षक</string>\n    <string name=\"chromecast_subtitles_settings_des\">क्रोमकास्ट उपशीर्षक सेटिंग्स</string>\n    <string name=\"double_tap_to_seek_settings\">आगे पीछे जाने के लिए दो बार टैप करें</string>\n    <string name=\"double_tap_to_pause_settings\">रुकने के लिए दो बार टैप करें</string>\n    <string name=\"offline_file\">ऑफ़लाइन देखने के लिए उपलब्ध</string>\n    <string name=\"select_all\">सभी चुनें</string>\n    <string name=\"deselect_all\">सभी अचयनित करें</string>\n    <string name=\"app_dubbed_text\">डब</string>\n    <string name=\"subs_download_languages\">भाषा डाउनलोड करें</string>\n    <string name=\"player_subtitles_settings\">उपशीर्षक</string>\n    <string name=\"speed_setting_summary\">प्लेयर में गति विकल्प जोड़ता है</string>\n    <string name=\"swipe_to_change_settings\">सेटिंग्स परिवर्तित करने के लिए स्वाइप करें</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"cartoons_singular\">हास्यचित्र</string>\n    <string name=\"show_trailers_settings\">झलकी दिखाएं</string>\n    <string name=\"others\">अन्य</string>\n    <string name=\"episode\">प्रकरण</string>\n    <string name=\"use_system_brightness_settings_des\">ऐप प्लेयर में सिस्टम ब्राइटनेस इस्तेमाल करें काले ओवरले को छोड़कर</string>\n    <string name=\"restore_success\">बैकअप फाइल सहेज ली गई है</string>\n    <string name=\"season\">सत्र</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">सत्र मौजूद नहीं है</string>\n    <string name=\"start\">शुरू करें</string>\n    <string name=\"test_warning\">चेतावनी</string>\n    <string name=\"go_forward_30\">+३०</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"anime_singular\">एनिमे</string>\n    <string name=\"torrent_singular\">टोरेंट</string>\n    <string name=\"remote_error\">दूरस्थ त्रुटि</string>\n    <string name=\"episode_sync_settings_des\">अपने वर्तमान प्रकरण की प्रगति को स्वचालित रूप से समकालीन बनाएं</string>\n    <string name=\"show_fillers_settings\">एनीमे के लिए पूरक प्रकरण दिखाएं</string>\n    <string name=\"backup_success\">आंकड़े संगृहीत हो गए</string>\n    <string name=\"music_singlar\">संगीत</string>\n    <string name=\"torrent_info\">यह वीडियो एक टॉरेंट है, इसका मतलब यह है कि आपकी वीडियो गतिविधि पर नजर रखी जा सकती है।\\nजारी रखने से पहले सुनिश्चित करें कि आप टोरेंटिंग को समझते है।</string>\n    <string name=\"double_tap_to_pause_settings_des\">रोकने के लिए बीच में दो बार टैप करें</string>\n    <string name=\"episode_sync_settings\">देखा हुआ प्रोग्रेस अपडेट करें</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">फाइल %s से आंकड़ों को पुनर्स्थापित करने में विफल</string>\n    <string name=\"backup_failed_error_format\">%s के बैकअप करने में विफलता</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">क्या आप वाकई निम्नलिखित श्रृंखला के सभी प्रकरण को स्थायी रूप से हटाना चाहते हैं?\\n\\n%s</string>\n    <string name=\"category_updates\">अद्यतन और बैकअप</string>\n    <string name=\"no_episodes_found\">कोई प्रकरण नहीं मिले</string>\n    <string name=\"go_back_30\">-३०</string>\n    <string name=\"other_singular\">वीडियो</string>\n    <string name=\"use_system_brightness_settings\">सिस्टम की चमक का इस्तेमाल करें</string>\n    <string name=\"backup_settings\">डाटा काबैकअप</string>\n    <string name=\"backup_frequency\">बैकअप आवृत्ति</string>\n    <string name=\"backup_failed\">संग्रहण अनुमतियाँ अनुपलब्ध हैं। कृपया फिर से कोशिश करें।</string>\n    <string name=\"category_account\">खाते और सुरक्षा</string>\n    <string name=\"advanced_search\">उन्नत खोज</string>\n    <string name=\"kitsu_settings\">Kitsu से पोस्टर दिखाएं</string>\n    <string name=\"automatic_plugin_updates\">स्वचालित प्लग-इन अद्यतन</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">%s में</string>\n    <string name=\"delete_files\">फ़ाइलें हटाएँ</string>\n    <string name=\"delete_format\" formatted=\"true\">(%1$d | %2$s) हटाएं</string>\n    <string name=\"test_passed\">उत्तीर्ण</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">क्या आप वाकई निम्नलिखित चीजों को स्थायी रूप से हटाना चाहते हैं?\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">क्या आप वाकई %1$s से निम्नलिखित प्रकरण को स्थायी रूप से हटाना चाहते हैं?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">आप निम्नलिखित श्रृंखला के सभी प्रकरण भी स्थायी रूप से हटा देंगे:\\n\\n%s</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\nबाकी</string>\n    <string name=\"queued\">कतार में</string>\n    <string name=\"no_subtitles\">कोई उपशीर्षक नहीं</string>\n    <string name=\"action_default\">डिफॉल्ट</string>\n    <string name=\"tv_series_singular\">सीरीज</string>\n    <string name=\"documentaries_singular\">वृत्तचित्र</string>\n    <string name=\"asian_drama_singular\">एशियाई नाटक</string>\n    <string name=\"live_singular\">लाइव स्ट्रीम</string>\n    <string name=\"audio_book_singular\">ऑडियो बुक</string>\n    <string name=\"source_error\">स्रोत से त्रुटि</string>\n    <string name=\"poster_ui_settings\">पोस्टर तत्वों को सक्षम या अक्षम करें</string>\n    <string name=\"livestreams\">लाइव स्ट्रीम</string>\n    <string name=\"movies_singular\">फिल्म</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"test_failed\">विफ़ल</string>\n    <string name=\"restore_settings\">बैकअप से आंकड़े पुनर्स्थापित करें</string>\n    <string name=\"asian_drama\">एशियाई नाटक</string>\n    <string name=\"automatic_plugin_download\">स्वचालित रूप से प्लगइन डाउनलोड करें</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"github\">गीटहब</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\\nबाकी</string>\n    <string name=\"documentaries\">वृत्तचित्र</string>\n    <string name=\"unexpected_error\">कोई नहीं जानता ये प्लेयर एरर क्यों आया</string>\n    <string name=\"episode_action_download_subtitle\">उपशीर्षक डाउनलोड करें</string>\n    <string name=\"show_title\">शीर्षक</string>\n    <string name=\"library\">लाइब्रेरी</string>\n    <string name=\"custom_media_singluar\">मीडिया</string>\n    <string name=\"pref_filter_search_quality\">खोज परिणामों में चयनित वीडियो गुणवत्ता छुपाएं</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"double_tap_to_seek_amount_settings\">प्लेयर में आगे पीछे जाने का समय (सेकंड्स)</string>\n    <string name=\"automatic_plugin_download_summary\">जोड़े गए रिपॉजिटरीज से अभी तक इंस्टॉल नहीं किए गए सभी प्लगइन्स को स्वचालित रूप से इंस्टॉल करें।</string>\n    <string name=\"speech_recognition_unavailable\">वाक् पहचान उपलब्ध नहीं है</string>\n    <string name=\"begin_speaking\">बोलना शुरू करें…</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$d मि %2$d से</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d सेकंड</string>\n    <string name=\"automatic_plugin_download_mode_title\">प्लगइन डाउनलोड को फ़िल्टर करने के लिए मोड चुने</string>\n    <string name=\"updates_settings\">ऐप अपडेट दिखाएं</string>\n    <string name=\"redo_setup_process\">सेटअप प्रक्रिया दोबारा करें</string>\n    <string name=\"apk_installer_settings\">APK इंस्टॉलर</string>\n    <string name=\"apk_installer_settings_des\">कुछ डिवाइस नए पैकेज इंस्टॉलर को सपोर्ट नहीं करते हैं। यदि अपडेट इंस्टॉल नहीं होते हैं, तो पुराने विकल्प को आज़माएं।</string>\n    <string name=\"subs_default_reset_toast\">डिफ़ॉल्ट मान पर रीसेट करें</string>\n    <string name=\"audio_singluar\">ऑडियो</string>\n    <string name=\"podcast_singluar\">पॉडकास्ट</string>\n    <string name=\"render_error\">रेंडरर त्रुटि</string>\n    <string name=\"encoding_error\">एन्कोडिंग त्रुटि</string>\n    <string name=\"unsupported_error\">एरर क्योंकि सपोर्टेड नहीं</string>\n    <string name=\"storage_error\">डाउनलोड नहीं कर पाए , प्लीज स्टोरेज परमिशन चेक करे</string>\n    <string name=\"episode_action_cast_mirror\">टीवी में देखे</string>\n    <string name=\"episode_action_play_mirror\">Play mirror</string>\"\n    <string name=\"show_hd\">कितना hd है वो वाला लेबल</string>\n    <string name=\"play_full_series_button\">पूरी सीरीज़ शरु करे</string>\n    <string name=\"install_prerelease\">प्री-रिलीज़ संस्करण स्थापित करें</string>\n    <string name=\"prerelease_already_installed\">प्री-रिलीज़ पहले से ही स्थापित है।</string>\n    <string name=\"prerelease_install_failed\">प्री-रिलीज़ इंस्टॉल करने में विफल रहा।</string>\n    <string name=\"show_dub\">डब लेबल</string>\n    <string name=\"show_sub\">सब लेबल</string>\n    <string name=\"show_rating\">रेटिंग लेबल</string>\n    <string name=\"skip_update\">इस अपडेट को छोड़ें</string>\n    <string name=\"watch_quality_pref_data\">पसंदीदा देखने की गुणवत्ता (मोबाइल डेटा)</string>\n    <string name=\"limit_title\">वीडियो प्लेयर शीर्षक अधिकतम वर्ण</string>\n    <string name=\"limit_title_rez\">वीडियो प्लेयर रिज़ॉल्यूशन</string>\n    <string name=\"video_buffer_size_settings\">वीडियो बफर साइज़</string>\n    <string name=\"video_buffer_length_settings\">वीडियो बफर की लंबाई</string>\n    <string name=\"video_buffer_disk_settings\">डिस्क पर वीडियो कैश</string>\n    <string name=\"video_buffer_clear_settings\">वीडियो और इमेज कैश साफ़ करें</string>\n    <string name=\"android_tv_interface_on_seek_settings\">प्लेयर दिखाये - सीक मूल्य</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">जब प्लेयर दिखाई दे रहा हो तो इस्तेमाल की जाने वाली सीक राशि</string>\n    <string name=\"android_tv_interface_off_seek_settings\">प्लेयर छुपाए - सीक मूल्य</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">जब प्लेयर छिपा होता है तो इस्तेमाल की जाने वाली सीक राशि</string>\n    <string name=\"video_ram_description\">अगर कम मेमोरी वाले डिवाइस, जैसे कि Android TV पर इसे बहुत ज़्यादा सेट किया जाता है, तो इससे क्रैश हो सकता है।</string>\n    <string name=\"video_disk_description\">अगर कम मेमोरी वाले डिवाइस, जैसे कि एन्ड्रोइड टीवी पर इसे बहुत ज़्यादा सेट किया जाता है, तो इससे क्रैश हो सकता है।</string>\n    <string name=\"dns_pref\">एचटीटीपीएस पर डीएनएस</string>\n    <string name=\"jsdelivr_proxy\">गिटहब प्रॉक्सी</string>\n    <string name=\"jsdelivr_enabled\">गिटहब तक नहीं पहुंचा जा सका। जेएस डीलीवर प्रॉक्सी चालू किया जा रहा है…</string>\n    <string name=\"jsdelivr_proxy_summary\">जेएस डीलीवर का इस्तेमाल करके रॉ गिटहब यूआरएल ब्लॉकिंग को बायपास करें। इससे अपडेट में कुछ दिनों की देरी हो सकती है।</string>\n    <string name=\"add_site_pref\">क्लोन साइट</string>\n    <string name=\"remove_site_pref\">साइट हटाएं</string>\n    <string name=\"add_site_summary\">मौजूदा साइट का एक क्लोन, अलग यूआरएल के साथ जोड़ें</string>\n    <string name=\"nginx_url_pref\">एनजीआईएनएक्ष (एंजिन एक्स) सर्वर यूआरएल</string>\n    <string name=\"resize_fit\">स्क्रीन पर फिट करें</string>\n    <string name=\"resize_fill\">खींचा हुआ</string>\n    <string name=\"resize_zoom\">ज़ूम</string>\n    <string name=\"legal_notice\">अस्वीकरण</string>\n    <string name=\"pref_category_bypass\">आईएसपी बाईपास</string>\n    <string name=\"pref_category_links\">लिंक्स</string>\n    <string name=\"pref_category_app_updates\">ऐप अपडेट्स</string>\n    <string name=\"pref_category_backup\">बैकअप</string>\n    <string name=\"pref_category_extensions\">एक्सटेंशन्स</string>\n    <string name=\"pref_category_actions\">कार्यवाही</string>\n    <string name=\"pref_category_cache\">कैश</string>\n    <string name=\"pref_category_android_tv\">एंड्रॉइड टीवी</string>\n    <string name=\"pref_category_gestures\">इशारे</string>\n    <string name=\"pref_category_security\">सुरक्षा</string>\n    <string name=\"pref_category_accounts\">अकाउंट</string>\n    <string name=\"pref_category_player_features\">प्लेयर की विशेषताएं</string>\n    <string name=\"pref_category_subtitles\">उपशीर्षक</string>\n    <string name=\"pref_category_player_layout\">रुप दर्शन</string>\n    <string name=\"pref_category_defaults\">डिफ़ॉलट्स</string>\n    <string name=\"pref_category_looks\">रुप</string>\n    <string name=\"pref_category_ui_features\">विशेषताएँ</string>\n    <string name=\"category_general\">सामान्य</string>\n    <string name=\"random_button_settings\">यादृच्छिक बटन</string>\n    <string name=\"random_button_settings_desc\">मुखपृष्ठ और लाइब्रेरी पर यादृच्छिक बटन दिखाएं</string>\n    <string name=\"enable_nsfw_on_providers\">सपोर्टेड एक्सटेंशन पर एन एस एफ डब्ल्यू (NSFW) चालू करें</string>\n    <string name=\"subtitles_encoding\">उपशीर्षक एन्कोडिंग</string>\n    <string name=\"category_providers\">प्रदाताओं</string>\n    <string name=\"category_provider_test\">प्रदाता परीक्षण</string>\n    <string name=\"test_extensions\">सभी एक्सटेंशन का परीक्षण करें</string>\n    <string name=\"test_extensions_summary\">यह परीक्षण मात्र डेवलपर्स के लिए है और किसी भी एक्सटेंशन के काम करने की पुष्टि या खंडन नहीं करता है।</string>\n    <string name=\"category_ui\">रुप दर्शन</string>\n    <string name=\"automatic\">स्वतह्</string>\n    <string name=\"emulator_layout\">एमुलेटर रुप दर्शन</string>\n    <string name=\"bottom_title_settings\">पोस्टर शीर्षक स्थान</string>\n    <string name=\"bottom_title_settings_des\">शीर्षक को पोस्टर के नीचे रखें</string>\n    <string name=\"example_password\">पासवर्ड१२३</string>\n    <string name=\"example_username\">उपयोगकर्ता नाम</string>\n    <string name=\"example_email\">हैलो@वर्ल्ड.कॉम</string>\n    <string name=\"example_ip\">१२७.०.०.१</string>\n    <string name=\"example_site_name\">नई साइट का नाम</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">भाषा कोड (en)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">खाता</string>\n    <string name=\"logout\">लॉग आउट</string>\n    <string name=\"login\">लॉग इन</string>\n    <string name=\"auth_locally\">स्थानीय रूप से प्रमाणित करें</string>\n    <string name=\"switch_account\">खाता स्थानांतरित करें</string>\n    <string name=\"add_account\">खाता जोड़ें</string>\n    <string name=\"create_account\">खाता बनाएं</string>\n    <string name=\"add_sync\">ट्रैकिंग जोड़ें</string>\n    <string name=\"added_sync_format\" formatted=\"true\">जोड़ा गया %s</string>\n    <string name=\"upload_sync\">Sync</string>\n    <string name=\"sync_score\">रेटेड</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+hr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s epizoda %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Glumačka postava: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Epizoda %d će izaći za</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dmin</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dmin</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dmin</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Poster</string>\n    <string name=\"episode_poster_img_des\">Poster epizode</string>\n    <string name=\"home_main_poster_img_des\">Glavni poster</string>\n    <string name=\"home_next_random_img_des\">Sljedeće slučajno odabrano</string>\n    <string name=\"go_back_img_des\">Idi natrag</string>\n    <string name=\"home_change_provider_img_des\">Promijeni pružatelja usluge</string>\n    <string name=\"preview_background_img_des\">Pregled slike pozadine</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Brzina (%.2f×)</string>\n    <string name=\"rated_format\" formatted=\"true\">Ocjena: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Pronađeno je novo ažuriranje!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Umetak</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Pokreni s CloudStreamom</string>\n    <string name=\"title_home\">Početna stranica</string>\n    <string name=\"title_search\">Traži</string>\n    <string name=\"title_downloads\">Preuzimanja</string>\n    <string name=\"title_settings\">Postavke</string>\n    <string name=\"search_hint\">Traži …</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Traži %s …</string>\n    <string name=\"no_data\">Nema podataka</string>\n    <string name=\"episode_more_options_des\">Više opcija</string>\n    <string name=\"next_episode\">Sljedeća epizoda</string>\n    <string name=\"result_tags\">Žanrovi</string>\n    <string name=\"result_share\">Dijeli</string>\n    <string name=\"result_open_in_browser\">Otvori u pregledniku</string>\n    <string name=\"skip_loading\">Preskoči učitavanje</string>\n    <string name=\"loading\">Učitavanje …</string>\n    <string name=\"type_watching\">Gledam</string>\n    <string name=\"type_on_hold\">Na čekanju</string>\n    <string name=\"type_completed\">Dovršeno</string>\n    <string name=\"type_dropped\">Ispušteno</string>\n    <string name=\"type_plan_to_watch\">Planiram gledati</string>\n    <string name=\"type_re_watching\">Ponovo gledam</string>\n    <string name=\"play_movie_button\">Pokreni film</string>\n    <string name=\"play_livestream_button\">Pokreni LiveStream</string>\n    <string name=\"play_torrent_button\">Pokreni Torrent</string>\n    <string name=\"pick_source\">Izvori</string>\n    <string name=\"pick_subtitle\">Titlovi</string>\n    <string name=\"reload_error\">Ponovni pokušaj povezivanja …</string>\n    <string name=\"go_back\">Idi natrag</string>\n    <string name=\"play_episode\">Pokreni epizodu</string>\n    <!--<string name=\"need_storage\">Allow to download episodes</string>-->\n    <string name=\"download\">Preuzmi</string>\n    <string name=\"downloaded\">Preuzeto</string>\n    <string name=\"downloading\">Preuzimanje u tijeku</string>\n    <string name=\"download_paused\">Preuzimanje pauzirano</string>\n    <string name=\"download_started\">Preuzimanje započeto</string>\n    <string name=\"download_failed\">Preuzimanje neuspjelo</string>\n    <string name=\"download_canceled\">Preuzimanje otkazano</string>\n    <string name=\"download_done\">Preuzimanje dovršeno</string>\n    <string name=\"stream\">Mrežni stream</string>\n    <string name=\"error_loading_links_toast\">Pogreška pri učitavanju poveznica</string>\n    <string name=\"download_storage_text\">Interna pohrana</string>\n    <string name=\"app_dubbed_text\">Sinkronizacija</string>\n    <string name=\"app_subbed_text\">Titlovi</string>\n    <string name=\"popup_delete_file\">Izbriši datoteku</string>\n    <string name=\"popup_play_file\">Pokreni datoteku</string>\n    <string name=\"popup_resume_download\">Nastavi preuzimanje</string>\n    <string name=\"popup_pause_download\">Pauziraj preuzimanje</string>\n    <string name=\"home_more_info\">Više informacija</string>\n    <string name=\"home_expanded_hide\">Sakrij</string>\n    <string name=\"home_play\">Pokreni</string>\n    <string name=\"home_info\">Informacije</string>\n    <string name=\"filter_bookmarks\">Filtriraj oznake</string>\n    <string name=\"error_bookmarks_text\">Oznake</string>\n    <string name=\"action_remove_from_bookmarks\">Ukloni</string>\n    <string name=\"action_add_to_bookmarks\">Postavi status gledanja</string>\n    <string name=\"sort_apply\">Primijeni</string>\n    <string name=\"sort_copy\">Kopiraj</string>\n    <string name=\"sort_close\">Zatvori</string>\n    <string name=\"sort_clear\">Izbriši</string>\n    <string name=\"sort_save\">Spremi</string>\n    <string name=\"player_speed\">Brzina playera</string>\n    <string name=\"subtitles_settings\">Postavke titlova</string>\n    <string name=\"subs_text_color\">Boja teksta</string>\n    <string name=\"subs_outline_color\">Boja konture</string>\n    <string name=\"subs_background_color\">Boja pozadine</string>\n    <string name=\"subs_window_color\">Boja prozora</string>\n    <string name=\"subs_edge_type\">Vrsta ruba</string>\n    <string name=\"subs_subtitle_elevation\">Visina titlova</string>\n    <string name=\"subs_font\">Font</string>\n    <string name=\"subs_font_size\">Veličina fonta</string>\n    <string name=\"search_provider_text_providers\">Traži koristeći pružatelje usluga</string>\n    <string name=\"search_provider_text_types\">Traži koristeći vrste</string>\n    <string name=\"benene_count_text\">%d banana dano programerima</string>\n    <string name=\"benene_count_text_none\">Nisi dao ni jednu bananu</string>\n    <string name=\"subs_auto_select_language\">Automatski odabir jezika</string>\n    <string name=\"subs_download_languages\">Preuzmi jezike</string>\n    <string name=\"subs_subtitle_languages\">Jezik titlova</string>\n    <string name=\"subs_hold_to_reset_to_default\">Pritisni za vraćanje na zadane postavke</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Uvezi fontove postavljanjem u %s</string>\n    <string name=\"continue_watching\">Nastavi gledati</string>\n    <string name=\"action_remove_watching\">Ukloni</string>\n    <string name=\"action_open_watching\">Više informacija</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Za ispravan rad ovog pružatelja usluga je možda potreban VPN</string>\n    <string name=\"vpn_torrent\">Ovaj pružatelj usluga je torrent, preporučuje se VPN</string>\n    <string name=\"provider_info_meta\">Stranica ne sadrži metapodatke. Učitavanje videa neće uspjeti ako ne postoje na stranici.</string>\n    <string name=\"torrent_plot\">Opis</string>\n    <string name=\"normal_no_plot\">Radnja nije pronađena</string>\n    <string name=\"torrent_no_plot\">Opis nije pronađen</string>\n    <string name=\"show_log_cat\">Prikaži Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Slika u slici</string>\n    <string name=\"picture_in_picture_des\">Nastavlja reprodukciju u minijaturnom playeru ispred drugih aplikacija</string>\n    <string name=\"player_size_settings\">Gumb za mijenjenje veličine playera</string>\n    <string name=\"player_size_settings_des\">Ukloni crne rubove</string>\n    <string name=\"player_subtitles_settings\">Titlovi</string>\n    <string name=\"player_subtitles_settings_des\">Postavke titlova playera</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast titlovi</string>\n    <string name=\"chromecast_subtitles_settings_des\">Postavke Chromecast titlova</string>\n    <string name=\"eigengraumode_settings\">Brzina reprodukcije</string>\n    <string name=\"swipe_to_seek_settings\">Klizni prstom za pomicanje</string>\n    <string name=\"swipe_to_seek_settings_des\">Klizni prstom ulijevo ili udesno za postavljanje pozicije videa</string>\n    <string name=\"swipe_to_change_settings\">Klizni prstom za mijenjanje postavki</string>\n    <string name=\"swipe_to_change_settings_des\">Klizni prstom prema gore ili dolje na lijevoj ili desnoj strani za mijenjanje svjetline ili glasnoće</string>\n    <string name=\"autoplay_next_settings\">Automatski pokreni sljedeću epizodu</string>\n    <string name=\"autoplay_next_settings_des\">Pokreni sljedeću epizodu kada trenutačna epizoda završi</string>\n    <string name=\"double_tap_to_seek_settings\">Dodirni dvaput za pomicanje</string>\n    <string name=\"double_tap_to_pause_settings\">Dodirni dvaput za pauziranje</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Količina pomicanja u playeru (sekunde)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Dodirni dvaput desnu ili lijevu stranu za pomicanje prema naprijed ili natrag</string>\n    <string name=\"double_tap_to_pause_settings_des\">Dodirni dvaput u sredinu za pauziranje</string>\n    <string name=\"use_system_brightness_settings\">Koristi svjetlinu sustava</string>\n    <string name=\"use_system_brightness_settings_des\">Koristi svjetlinu sustava u playeru aplikacija umjesto tamnog preklopa</string>\n    <string name=\"episode_sync_settings\">Ažuriraj napredak gledanja</string>\n    <string name=\"episode_sync_settings_des\">Automatski sinkronizira vaš trenutni napredak u filmu ili epizodi</string>\n    <string name=\"restore_settings\">Obnovi podatke iz sigurnosne kopije</string>\n    <string name=\"backup_settings\">Sigurnosno kopiranje podataka</string>\n    <string name=\"restore_success\">Datoteka sigurnosne kopije je učitana</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Obnavljanje podataka iz datoteke %s nije uspjelo</string>\n    <string name=\"backup_success\">Podaci pohranjeni</string>\n    <string name=\"backup_failed\">Nedostaju dozvole za pohranu, pokušaj ponovo.</string>\n    <string name=\"backup_failed_error_format\">Pogreška pri sigurnosnom kopiranju %s</string>\n    <string name=\"search\">Traži</string>\n    <string name=\"category_account\">Računi i sigurnost</string>\n    <string name=\"category_updates\">Ažuriranja i sigurnosna kopija</string>\n    <string name=\"settings_info\">Informacije</string>\n    <string name=\"advanced_search\">Napredna pretraga</string>\n    <string name=\"advanced_search_des\">Daje rezultate pretrage odvojene prema pružatelju usluga</string>\n    <string name=\"show_fillers_settings\">Prikaži dodatnu epizodu za anime</string>\n    <string name=\"show_trailers_settings\">Prikaži trailere</string>\n    <string name=\"kitsu_settings\">Prikaži postere iz Kitsua</string>\n    <string name=\"pref_filter_search_quality\">Sakrij odabranu kvalitetu videa u rezultatima pretrage</string>\n    <string name=\"automatic_plugin_updates\">Automatsko ažuriranje dodataka</string>\n    <string name=\"updates_settings\">Prikaži ažuriranja aplikacije</string>\n    <string name=\"updates_settings_des\">Automatski traži nova ažuriranja nakon pokretanja aplikacije.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Aplikacija za romane od istih programera</string>\n    <string name=\"anim\">Anime aplikacija od istih programera</string>\n    <string name=\"discord\">Pridruži se Discordu</string>\n    <string name=\"benene\">Daj bananu programerima</string>\n    <string name=\"benene_des\">Dane banane</string>\n    <string name=\"app_language\">Jezik aplikacije</string>\n    <string name=\"no_chromecast_support_toast\">Ovaj pružatelj usluga nema podršku za Chromecast</string>\n    <string name=\"no_links_found_toast\">Nisu pronađene poveznice</string>\n    <string name=\"copy_link_toast\">Poveznica je kopirana u međuspremnik</string>\n    <string name=\"play_episode_toast\">Pokreni epizodu</string>\n    <string name=\"subs_default_reset_toast\">Vrati na zadanu vrijednost</string>\n    <string name=\"season\">Sezona</string>\n    <string name=\"no_season\">Nema sezone</string>\n    <string name=\"episode\">Epizoda</string>\n    <string name=\"episodes\">Epizoda</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Nisu pronađene epizode</string>\n    <string name=\"delete_file\">Izbriši datoteku</string>\n    <string name=\"delete\">Izbriši</string>\n    <string name=\"cancel\">Odustani</string>\n    <string name=\"pause\">Pauziraj</string>\n    <string name=\"resume\">Nastavi</string>\n    <string name=\"go_back_30\">−30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Ovo će trajno izbrisati %s\n\\nJeste li sigurni?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dmin\n\\npreostalo</string>\n    <string name=\"status_ongoing\">U tijeku</string>\n    <string name=\"status_completed\">Završeno</string>\n    <string name=\"status\">Status</string>\n    <string name=\"year\">Godina</string>\n    <string name=\"rating\">Ocjena</string>\n    <string name=\"duration\">Trajanje</string>\n    <string name=\"site\">Stranica</string>\n    <string name=\"synopsis\">Sinopsis</string>\n    <string name=\"queued\">u redu čekanja</string>\n    <string name=\"no_subtitles\">Bez titlova</string>\n    <string name=\"action_default\">Zadano</string>\n    <string name=\"free_storage\">Slobodno</string>\n    <string name=\"used_storage\">Iskorišteno</string>\n    <string name=\"app_storage\">Aplikacija</string>\n    <!--plural-->\n    <string name=\"movies\">Filmovi</string>\n    <string name=\"tv_series\">TV Serije</string>\n    <string name=\"cartoons\">Crtići</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrenti</string>\n    <string name=\"documentaries\">Dokumentarci</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Azijske drame</string>\n    <string name=\"livestreams\">Livestreamovi</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Ostali</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Serija</string>\n    <string name=\"cartoons_singular\">Crtić</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Dokumentarac</string>\n    <string name=\"asian_drama_singular\">Azijska drama</string>\n    <string name=\"live_singular\">Livestream</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"source_error\">Pogreška u izvoru</string>\n    <string name=\"remote_error\">Pogreška eksternog računala</string>\n    <string name=\"render_error\">Pogreška u prikazu</string>\n    <string name=\"unexpected_error\">Neočekivana pogreška playera</string>\n    <string name=\"storage_error\">Pogreška tijekom preuzimanja, provjeri dozvole za pohranu</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast epizoda</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast duplikat</string>\n    <string name=\"episode_action_play_in_app\">Pokreni u aplikaciji</string>\n    <string name=\"episode_action_play_in_format\">Pokreni u %s</string>\n    <string name=\"episode_action_auto_download\">Automatsko preuzimanje</string>\n    <string name=\"episode_action_download_mirror\">Preuzmi zrcalo</string>\n    <string name=\"episode_action_reload_links\">Ponovo učitaj poveznice</string>\n    <string name=\"episode_action_download_subtitle\">Preuzmi titlove</string>\n    <string name=\"show_hd\">Oznaka za kvalitetu</string>\n    <string name=\"show_dub\">Oznaka za sinkronizaciju</string>\n    <string name=\"show_sub\">Oznaka za titlove</string>\n    <string name=\"show_title\">Naslov</string>\n    <string name=\"poster_ui_settings\">Uključi/isključi elemente korisničkog sučelja na posteru</string>\n    <string name=\"no_update_found\">Nije pronađeno ažuriranje</string>\n    <string name=\"check_for_update\">Provjeri ažuriranja</string>\n    <string name=\"video_lock\">Zaključaj</string>\n    <string name=\"video_aspect_ratio_resize\">Promijeni veličinu</string>\n    <string name=\"video_source\">Izvor</string>\n    <string name=\"video_skip_op\">Preskoči OP</string>\n    <string name=\"dont_show_again\">Nemoj više prikazivati</string>\n    <string name=\"skip_update\">Preskoči ovo ažuriranje</string>\n    <string name=\"update\">Ažuriraj</string>\n    <string name=\"watch_quality_pref\">Preferirana kvaliteta gledanja (WiFi)</string>\n    <string name=\"limit_title\">Maksimalni broj znakova u naslovu video playera</string>\n    <string name=\"limit_title_rez\">Prikaži podatke playera</string>\n    <string name=\"video_buffer_size_settings\">Veličina međuspremnika videa</string>\n    <string name=\"video_buffer_length_settings\">Duljina međuspremnika videa</string>\n    <string name=\"video_buffer_disk_settings\">Predmemorija videa na disku</string>\n    <string name=\"video_buffer_clear_settings\">Izbriši predmemoriju videa i slika</string>\n    <string name=\"video_ram_description\">Uzrokuje rušenje aplikacije ako se postavi previsoko na uređajima s malom količinom RAM-a kao što je Android TV.</string>\n    <string name=\"video_disk_description\">Uzrokuje probleme ako se postavi previsoko na uređajima s malom količinom memorije kao što je Android TV.</string>\n    <string name=\"dns_pref\">DNS preko HTTPS-a</string>\n    <string name=\"dns_pref_summary\">Korisno za zaobilaženje blokada ISP-a</string>\n    <string name=\"add_site_pref\">Kloniraj web stranicu</string>\n    <string name=\"remove_site_pref\">Ukloni web stranicu</string>\n    <string name=\"add_site_summary\">Dodajte klon postojeće web-lokacije s drugim url-om</string>\n    <string name=\"download_path_pref\">Putanja preuzimanja</string>\n    <string name=\"nginx_url_pref\">NGINX server URL</string>\n    <string name=\"display_subbed_dubbed_settings\">Prikaži sinkronizirani anime ili s titlovima</string>\n    <string name=\"resize_fit\">Prilagodi veličini ekrana</string>\n    <string name=\"resize_fill\">Rastegni</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"legal_notice\">Pravna obavijest</string>\n    <string name=\"category_general\">Općenito</string>\n    <string name=\"random_button_settings\">Gumb za slučajni odabir</string>\n    <string name=\"random_button_settings_desc\">Prikaži gumb za slučajni odabir na početnoj stranici i biblioteci</string>\n    <string name=\"provider_lang_settings\">Jezici proširenja</string>\n    <string name=\"app_layout\">Izgled aplikacije</string>\n    <string name=\"preferred_media_settings\">Preferirani mediji</string>\n    <string name=\"enable_nsfw_on_providers\">Omogući NSFW na podržanim proširenjima</string>\n    <string name=\"subtitles_encoding\">Kodiranje titlova</string>\n    <string name=\"category_providers\">Pružatelji usluga</string>\n    <string name=\"category_ui\">Raspored</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"tv_layout\">TV izgled</string>\n    <string name=\"phone_layout\">Izgled za telefone</string>\n    <string name=\"emulator_layout\">Izgled za emulatore</string>\n    <string name=\"primary_color_settings\">Primarna boja</string>\n    <string name=\"app_theme_settings\">Tema aplikacije</string>\n    <string name=\"bottom_title_settings\">Mjesto naslova postera</string>\n    <string name=\"bottom_title_settings_des\">Stavlja naslov ispod postera</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">lozinka123</string>\n    <string name=\"example_username\">Korisničko ime</string>\n    <string name=\"example_email\">bok@svijete.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NovoImeStranice</string>\n    <string name=\"example_site_url\">https://primjer.com</string>\n    <string name=\"example_lang_name\">Šifra jezika (hr)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">račun</string>\n    <string name=\"logout\">Odjava</string>\n    <string name=\"login\">Prijava</string>\n    <string name=\"switch_account\">Promijeni račun</string>\n    <string name=\"add_account\">Dodaj račun</string>\n    <string name=\"create_account\">Stvori račun</string>\n    <string name=\"add_sync\">Dodaj praćenje</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Dodano %s</string>\n    <string name=\"upload_sync\">Sinkroniziraj</string>\n    <string name=\"sync_score\">Ocijenjeno</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s ovjeren</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Nije moguće prijaviti se na %s</string>\n    <!-- ============ -->\n    <string name=\"none\">Nijedan</string>\n    <string name=\"normal\">Normalno</string>\n    <string name=\"all\">Sve</string>\n    <string name=\"max\">Maks.</string>\n    <string name=\"min\">Min.</string>\n    <string name=\"subtitles_outline\">Kontura</string>\n    <string name=\"subtitles_depressed\">Udubljeno</string>\n    <string name=\"subtitles_shadow\">Sjena</string>\n    <string name=\"subtitles_raised\">Izdignuto</string>\n    <string name=\"subtitle_offset\">Sinkroniziraj titlove</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Kašnjenje titlova</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Koristi ovo ako se titlovi prikazuju %d ms prerano</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Koristite ovo ako se titlovi prikazuju %d ms prekasno</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Bez kašnjenja titlova</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">Gojazni đačić s biciklom drži hmelj i finu vatu u džepu nošnje</string>\n    <string name=\"recommended\">Preporučeno</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Učitano %s</string>\n    <string name=\"player_load_subtitles\">Učitaj iz datoteke</string>\n    <string name=\"player_load_subtitles_online\">Učitaj s interneta</string>\n    <string name=\"downloaded_file\">Preuzeta datoteka</string>\n    <string name=\"actor_main\">Glavni</string>\n    <string name=\"actor_supporting\">Sporedni</string>\n    <string name=\"actor_background\">Statist</string>\n    <string name=\"home_source\">Izvor</string>\n    <string name=\"home_random\">Slučajno</string>\n    <string name=\"coming_soon\">Dolazi uskoro …</string>\n    <string name=\"quality_cam\">Kamera</string>\n    <string name=\"quality_cam_rip\">Kamera</string>\n    <string name=\"quality_cam_hd\">Kamera</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-Ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Slika postera</string>\n    <string name=\"category_player\">Player</string>\n    <string name=\"resolution_and_title\">Rezolucija i naslov</string>\n    <string name=\"title\">Naslov</string>\n    <string name=\"resolution\">Rezolucija</string>\n    <string name=\"error_invalid_id\">Nevažeći ID</string>\n    <string name=\"error_invalid_data\">Nevažeći podaci</string>\n    <string name=\"error_invalid_url\">Nevažeći URL</string>\n    <string name=\"error\">Pogreška</string>\n    <string name=\"subtitles_remove_captions\">Ukloni titlove za gluhe osobe iz titlova</string>\n    <string name=\"subtitles_remove_bloat\">Ukloni nepotrebne elemente iz titlova (npr. oglase)</string>\n    <string name=\"subtitles_filter_lang\">Filtriraj po preferiranom jeziku medija</string>\n    <string name=\"extras\">Dodatni sadržaji</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"network_adress_example\">https://primjer.com/primjer.mp4</string>\n    <string name=\"referer\">Referent (opcionalno)</string>\n    <string name=\"next\">Sljedeće</string>\n    <string name=\"provider_languages_tip\">Gledaj videa na ovim jezicima</string>\n    <string name=\"previous\">Prethodno</string>\n    <string name=\"skip_setup\">Preskoči postavljanje</string>\n    <string name=\"app_layout_subtext\">Promijeni izgled aplikacije kako bi odgovarao tvom uređaju</string>\n    <string name=\"preferred_media_subtext\">Što želiš vidjeti</string>\n    <string name=\"setup_done\">Gotovo</string>\n    <string name=\"extensions\">Proširenja</string>\n    <string name=\"add_repository\">Dodaj repozitorij</string>\n    <string name=\"repository_name_hint\">Ime repozitorija (Neobavezno)</string>\n    <string name=\"repository_url_hint\">URL repozitorija ili kratki kod</string>\n    <string name=\"plugin_loaded\">Dodatak učitan</string>\n    <string name=\"plugin_deleted\">Dodatak izbrisan</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Nije moguće učitati %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Započeto preuzimanje %1$d %2$s …</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Preuzeto %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Sve %s već preuzeto</string>\n    <string name=\"batch_download\">Skupno preuzimanje</string>\n    <string name=\"plugin_singular\">dodatak</string>\n    <string name=\"plugin\">dodaci</string>\n    <string name=\"delete_repository_plugins\">Ovo će također izbrisati sve dodatke repozitorija</string>\n    <string name=\"delete_repository\">Izbriši repozitorij</string>\n    <string name=\"setup_extensions_subtext\">Preuzmi popis stranica koje želiš koristiti</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Preuzeto: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Onemogućeno: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Nepreuzeto: %d</string>\n    <string name=\"blank_repo_message\">CloudStream standardno nema instalirane web stranice. Stranice morate instalirati iz repozitorija.\n\\n\n\\nPridružite se našem Discordu ili tražite online.</string>\n    <string name=\"view_public_repositories_button\">Prikaži repozitorije zajednice</string>\n    <string name=\"view_public_repositories_button_short\">Javni popis</string>\n    <string name=\"uppercase_all_subtitles\">Koristi velika slova za sve titlove</string>\n    <string name=\"download_all_plugins_from_repo\">Upozorenje: CloudStream ne preuzima odgovornost za korištenje proširenja trećih strana i ne pruža podršku za njih!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (onemogućeno)</string>\n    <string name=\"tracks\">Zapisi</string>\n    <string name=\"audio_tracks\">Audio zapis</string>\n    <string name=\"video_tracks\">Video zapis</string>\n    <string name=\"apply_on_restart\">Za prikaz promjena ponovo pokreni aplikaciju.</string>\n    <string name=\"safe_mode_title\">Sigurnosni način rada uključen</string>\n    <string name=\"safe_mode_description\">Sva proširenja su isključena zbog rušenja aplikacije kako bi se pronašlo proširenje koje uzrokuje probleme.</string>\n    <string name=\"safe_mode_crash_info\">Pogledajte podatke o padu</string>\n    <string name=\"extension_rating\" formatted=\"true\">Ocjena: %s</string>\n    <string name=\"extension_description\">Opis</string>\n    <string name=\"extension_version\">Verzija</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"extension_size\">Veličina</string>\n    <string name=\"extension_authors\">Autori</string>\n    <string name=\"extension_types\">Podržano</string>\n    <string name=\"extension_language\">Jezik</string>\n    <string name=\"hls_playlist\">HLS playlista</string>\n    <string name=\"automatic_plugin_download\">Automatski instaliraj dodatke</string>\n    <string name=\"skip_type_creddits\">Zasluge</string>\n    <string name=\"automatic_plugin_download_summary\">Automatski instaliraj sve neinstalirane dodatke iz dodanih repozitorija.</string>\n    <string name=\"player_pref\">Preferirani video player</string>\n    <string name=\"player_settings_play_in_app\">Interni player</string>\n    <string name=\"extension_install_first\">Najprije instaliraj proširenje</string>\n    <string name=\"app_not_found_error\">Aplikacija nije pronađena</string>\n    <string name=\"all_languages_preference\">Svi jezici</string>\n    <string name=\"clipboard_too_large\">Previše teksta. Nije moguće spremiti u međuspremnik.</string>\n    <string name=\"action_mark_as_watched\">Označi kao gledano</string>\n    <string name=\"enable_skip_op_from_database_des\">Prikaži skočni prozor za uvod/kraj</string>\n    <string name=\"yes\">Da</string>\n    <string name=\"update_notification_downloading\">Preuzimanje ažuriranja aplikacije …</string>\n    <string name=\"confirm_exit_dialog\">Jeste li sigurni da želite izaći?</string>\n    <string name=\"no\">Ne</string>\n    <string name=\"update_notification_installing\">Instaliranje ažuriranja aplikacije …</string>\n    <string name=\"update_notification_failed\">Nije moguće instalirati novu verziju aplikacije</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Ažurirani dodaci: %d</string>\n    <string name=\"skip_type_mixed_op\">Mješoviti uvod</string>\n    <string name=\"skip_type_intro\">Uvod</string>\n    <string name=\"pref_category_links\">Poveznice</string>\n    <string name=\"play_trailer_button\">Pokreni trailer</string>\n    <string name=\"redo_setup_process\">Ponovi postupak postavljanja</string>\n    <string name=\"apk_installer_settings_des\">Neki uređaji ne podržavaju novi program za instaliranje paketa. Pokušaj sa starijom opcijom ako se ažuriranja ne instaliraju.</string>\n    <string name=\"apk_installer_settings\">Instalator APK-a</string>\n    <string name=\"pref_category_app_updates\">Ažuriranja aplikacije</string>\n    <string name=\"pref_category_backup\">Sigurnosna kopija</string>\n    <string name=\"pref_category_extensions\">Proširenja</string>\n    <string name=\"pref_category_actions\">Radnje</string>\n    <string name=\"pref_category_cache\">Predmemorija</string>\n    <string name=\"pref_category_gestures\">Geste</string>\n    <string name=\"pref_category_player_features\">Značajke playera</string>\n    <string name=\"pref_category_subtitles\">Titlovi</string>\n    <string name=\"pref_category_player_layout\">Raspored</string>\n    <string name=\"pref_category_defaults\">Zadane postavke</string>\n    <string name=\"pref_category_looks\">Izgledi</string>\n    <string name=\"pref_category_ui_features\">Značajke</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Preskoči %s</string>\n    <string name=\"skip_type_ed\">Kraj</string>\n    <string name=\"skip_type_recap\">Sažetak</string>\n    <string name=\"skip_type_mixed_ed\">Mješoviti kraj</string>\n    <string name=\"clear_history\">Izbriši povijest</string>\n    <string name=\"history\">Povijest</string>\n    <string name=\"apk_installer_legacy\">Legacy</string>\n    <string name=\"skip_type_op\">Uvod</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"update_started\">Aktualiziranje započeto</string>\n    <string name=\"delayed_update_notice\">Aplikacija će se ažurirati tijekom zatvaranja</string>\n    <string name=\"plugin_downloaded\">Dodatak preuzet</string>\n    <string name=\"action_remove_from_watched\">Ukloni iz pogledanog</string>\n    <string name=\"browser\">Preglednik</string>\n    <string name=\"library\">Biblioteka</string>\n    <string name=\"sort_rating_desc\">Ocjena (Veća do manje)</string>\n    <string name=\"sort_by\">Sortiraj prema</string>\n    <string name=\"sort\">Sortiraj</string>\n    <string name=\"sort_rating_asc\">Ocjena (Manja do veće)</string>\n    <string name=\"sort_updated_new\">Ažurirano (od novog prema starom)</string>\n    <string name=\"sort_updated_old\">Ažurirano (od starog prema novom)</string>\n    <string name=\"sort_alphabetical_a\">Abecedno (A do Ž)</string>\n    <string name=\"sort_alphabetical_z\">Abecedno (Ž do A)</string>\n    <string name=\"select_library\">Odaberite biblioteku</string>\n    <string name=\"open_with\">Otvori sa</string>\n    <string name=\"empty_library_no_accounts_message\">Vaša je biblioteka prazna :(\n\\nPrijavite se na račun biblioteke ili dodajte filmove / serije u svoju lokalnu biblioteku.</string>\n    <string name=\"empty_library_logged_in_message\">Ova je lista prazna. Pokušajte se prebaciti na jednu drugu listu.</string>\n    <string name=\"safe_mode_file\">Pronađena je datoteka sigurnog načina rada!\n\\nProširenja se ne učitavaju tijekom pokretanja dok se datoteka ne ukloni.</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Prikazan player – Količina pomicanja</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Količina pomicanja koja se koristi kada je player vidljiv</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Player skriven – Količina pomicanja</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Količina pomicanja koja se koristi kada je player skriven</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"test_passed\">Uspjelo</string>\n    <string name=\"restart\">Pokreni ponovo</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"start\">Pokreni</string>\n    <string name=\"test_failed\">Neuspjelo</string>\n    <string name=\"stop\">Prekini</string>\n    <string name=\"category_provider_test\">Test pružatelja usluga</string>\n    <string name=\"subscription_in_progress_notification\">Ažuriranje pretplaćenih emisija</string>\n    <string name=\"subscription_episode_released\">Epizoda %d izbačena!</string>\n    <string name=\"subscription_list_name\">Pretplaćeno</string>\n    <string name=\"subscription_new\">Pretplaćen na %s</string>\n    <string name=\"subscription_deleted\">Otkazana pretplata sa %s</string>\n    <string name=\"revert\">Vraćanje</string>\n    <string name=\"pref_category_bypass\">ISP zaobilaznice</string>\n    <string name=\"jsdelivr_proxy\">GitHub Proxy</string>\n    <string name=\"jsdelivr_enabled\">Neuspješno dohvaćanje GitHuba. Uključuje se jsdelivr proxy …</string>\n    <string name=\"jsdelivr_proxy_summary\">Zaobilazi blokiranje neobrađenih GitHub URL-ova koristeći jsDelivr. Može uzrokovati kašnjenje ažuriranja nekoliko dana.</string>\n    <string name=\"watch_quality_pref_data\">Preferirana kvaliteta gledanja (mobilni podaci)</string>\n    <string name=\"profile_number\">Profil %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Mobilni podaci</string>\n    <string name=\"set_default\">Postavi standardnu vrijednost</string>\n    <string name=\"use\">Koristi</string>\n    <string name=\"edit\">Uredi</string>\n    <string name=\"profiles\">Profili</string>\n    <string name=\"help\">Pomoć</string>\n    <string name=\"qualities\">Kvalitete</string>\n    <string name=\"profile_background_des\">Pozadina profila</string>\n    <string name=\"unable_to_inflate\">Nije bilo moguće ispravno izraditi korisničko sučelje. Ovo je ZNAČAJNA POGREŠKA i treba se odmah prijaviti %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Odaberi modus za filtriranje preuzimanja dodataka</string>\n    <string name=\"disable\">Onemogući</string>\n    <string name=\"no_plugins_found_error\">U repozitoriju nisu pronađeni dodaci</string>\n    <string name=\"no_repository_found_error\">Repozitorij nije pronađen. Provjeri URL i pokušaj VPN</string>\n    <string name=\"quality_profile_help\">Ovdje možete promijeniti način na koji su izvori poredani. Ako video ima viši prioritet, pojavit će se više u odabiru izvora. Zbroj prioriteta izvora i prioriteta kvalitete je prioritet videa.\n\\n\n\\nIzvor A: 3\n\\nKvaliteta B: 7\n\\nImat će kombinirani prioritet videa od 10.\n\\n\n\\nNAPOMENA: Ako je zbroj 10 ili više, video player će automatski preskočiti učitavanje kada se ta poveznica učita!</string>\n    <string name=\"already_voted\">Već si glasao/la</string>\n    <string name=\"backup_frequency\">Učestalost spremanja sigurnosne kopije</string>\n    <string name=\"favorite_removed\">%s uklonjeno iz favorita</string>\n    <string name=\"favorites_list_name\">Favoriti</string>\n    <string name=\"favorite_added\">%s dodano u favorite</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Potencijalni duplikati pronađeni su u vašoj biblioteci:\n\\n\n\\n%s\n\\n\n\\nŽelite li ipak dodati ovu stavku koja zamjenjuje postojeće ili poništiti radnju?</string>\n    <string name=\"duplicate_title\">Pronađen potencijalni duplikat</string>\n    <string name=\"lock_profile\">Zaključaj profil</string>\n    <string name=\"action_add_to_favorites\">Dodaj u favorite</string>\n    <string name=\"duplicate_replace_all\">Zamjeni sve</string>\n    <string name=\"pin_error_incorrect\">Netočan PIN. Pokušajte ponovno.</string>\n    <string name=\"action_unsubscribe\">Odjava pretplate</string>\n    <string name=\"pin_error_length\">PIN mora imati 4 znaka</string>\n    <string name=\"duplicate_replace\">Zamjeni</string>\n    <string name=\"duplicate_add\">Dodaj</string>\n    <string name=\"action_subscribe\">Pretplata</string>\n    <string name=\"action_remove_from_favorites\">Ukloni iz favorita</string>\n    <string name=\"select_an_account\">Odaberite račun</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Čini se da potencijalno duplicirana stavka već postoji u vašoj biblioteci: \\'%s.\\'\n\\n\n\\nŽelite li ipak dodati ovu stavku koja zamjenjuje postojeću ili poništiti radnju?</string>\n    <string name=\"enter_pin\">Unesite PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">Unesite trenutni PIN</string>\n    <string name=\"logged_account\" formatted=\"true\">Prijavljeni ste kao %s</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Unesite PIN za %s</string>\n    <string name=\"use_default_account\">Koristi zadani račun</string>\n    <string name=\"skip_startup_account_select_pref\">Preskoči odabir računa pri pokretanju</string>\n    <string name=\"manage_accounts\">Upravljanje računima</string>\n    <string name=\"edit_account\">Uredi račun</string>\n    <string name=\"links_reloaded_toast\">Poveznice su ponovo učitane</string>\n    <string name=\"rotate_video\">Rotiraj</string>\n    <string name=\"rotate_video_desc\">Prikaži gumb za prebacivanje orijentacije zaslona</string>\n    <string name=\"auto_rotate_video_desc\">Omogućuje automatsko mijenjanje orijentacije zaslona na temelju orijentacije videa</string>\n    <string name=\"auto_rotate_video\">Automatsko rotiranje</string>\n    <string name=\"subscribe_tooltip\">Obavijest za novu epizodu</string>\n    <string name=\"result_search_tooltip\">Traži u drugim proširenjima</string>\n    <string name=\"speed_setting_summary\">Dodaje opciju za brzinu u playeru</string>\n    <string name=\"test_extensions\">Testiraj sva proširenja</string>\n    <string name=\"test_extensions_summary\">Ovaj je test namijenjen samo programerima i ne provjerava niti negira rad bilo kojeg proširenja.</string>\n    <string name=\"recommendations_tooltip\">Prikaži preporuke</string>\n    <string name=\"repo_copy_label\">Ime repozitorija i URL</string>\n    <string name=\"toast_copied\">kopirano!</string>\n    <string name=\"biometric_setting\">Zaključaj s biometrijskim podatcima</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\npreostalo</string>\n    <string name=\"clipboard_permission_error\">Pogreška pri pristupanju međuspremnika. Pokušaj ponovo.</string>\n    <string name=\"biometric_authentication_title\">Otključaj CloudStream</string>\n    <string name=\"password_pin_authentication_title\">Lozinka/PIN autentifikacija</string>\n    <string name=\"biometric_unsupported\">Ovaj uređaj ne podržava biometrijsku autentifikaciju</string>\n    <string name=\"biometric_prompt_description\">Ovaj je ekran zatvoren zbog višestrukih neuspjelih pokušaja. Pokrenite aplikaciju ponovo.</string>\n    <string name=\"ok\">U redu</string>\n    <string name=\"battery_dialog_title\">Deaktiviraj optimizaciju baterije</string>\n    <string name=\"audio_book_singular\">Audio knjiga</string>\n    <string name=\"custom_media_singluar\">Medij</string>\n    <string name=\"app_unrestricted_toast\">Korištenje baterije aplikacije već je postavljeno na neograničeno</string>\n    <string name=\"app_info_intent_error\">Neuspjelo otvaranje podataka CloudStream aplikacije.</string>\n    <string name=\"favorite\">Favorit</string>\n    <string name=\"unfavorite\">Ukloni iz favorita</string>\n    <string name=\"music_singlar\">Glazba</string>\n    <string name=\"reset_btn\">Obnovi</string>\n    <string name=\"biometric_setting_summary\">Otključaj aplikaciju pomoću otiska prsta, ID-a lica, PIN-a, uzorka i lozinke.</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Sljedeća u %s</string>\n    <string name=\"clipboard_unknown_error\">Pogreška pri kopiranju. Kopirajte zapisnik i kontaktirajte podršku aplikacije.</string>\n    <string name=\"battery_dialog_message\">Da biste osigurali neprekinuta preuzimanja i obavijesti za pretplaćene TV emisije, CloudStream treba dopuštenje za rad u pozadini. Pritiskom na \\\"U redu\\\" prikazat će vam se dijaloški okvir s zahtjevom. Molimo vas da pritisnete \\\"Dopusti\\\".  \\n\\nNapominjemo da ovo dopuštenje ne znači da će CS3 trošiti vašu bateriju. Aplikacija će raditi u pozadini samo kada je to potrebno, primjerice prilikom primanja obavijesti ili preuzimanja videozapisa iz službenih proširenja.</string>\n    <string name=\"biometric_warning\">Vaši CloudStream podaci su sada spremljeni u sigurnosnu kopiju. Iako je vjerojatnost mala, neki se uređaji mogu ponašati drugačije. Ako izgubite pristup aplikaciji, potpuno izbrišite podatke aplikacije i obnovite ih pomoću sigurnosne kopije. Ispričavamo se zbog mogućih neugodnosti.</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Sezona %1$d epizoda %2$d izlazi za</string>\n    <string name=\"episode_action_cast_mirror\">Cast duplikat</string>\n    <string name=\"player_settings_select_cast_device\">Odaberi uređaj za emitiranje</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"pref_category_accounts\">Računi</string>\n    <string name=\"pref_category_security\">Sigurnost</string>\n    <string name=\"auth_locally\">Lokalna autentifikacija</string>\n    <string name=\"open_local_video\">Otvori lokalni video</string>\n    <string name=\"device_pin_url_message\">Posjeti <b>%s</b> na svom mobitelu ili računalu i unesi gore navedeni kod</string>\n    <string name=\"dismiss\">Odbaci</string>\n    <string name=\"play_from_beginning_img_des\">Pokreni od početka</string>\n    <string name=\"downloads_empty\">Trenutačno nema preuzimanja.</string>\n    <string name=\"device_pin_counter_text\">Kod isteče za %1$d min %2$d s</string>\n    <string name=\"qr_image\">Slika QR koda</string>\n    <string name=\"hide_player_control_names\">Sakrij nazive kontrola playera</string>\n    <string name=\"open_downloaded_repo\">Otvori repozitorij</string>\n    <string name=\"device_pin_expired_message\">PIN kod je sada istekao!</string>\n    <string name=\"sort_release_date_new\">Datum izdanja (od novog prema starom)</string>\n    <string name=\"sort_release_date_old\">Datum izdanja (od starog prema novom)</string>\n    <string name=\"device_pin_error_message\">Neuspjelo dobivanje PIN koda uređaja, pokušaj s lokalnom autentifikacijom</string>\n    <string name=\"test_warning\">Upozorenje</string>\n    <string name=\"delete_plugin\">Izbriši dodatak</string>\n    <string name=\"offline_file\">Dostupno za gledanje offline</string>\n    <string name=\"select_all\">Označi sve</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Stvarno želite trajno izbrisati sljedeće stavke?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Stvarno želite trajno izbrisati sljedeće epizode u %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Trajno ćete izbrisati i sve epizode u sljedećim serijama:\n\\n\n\\n%s</string>\n    <string name=\"downloads_delete_select\">Odaberi stavke za brisanje</string>\n    <string name=\"deselect_all\">Odznači sve</string>\n    <string name=\"delete_format\" formatted=\"true\">Izbriši (%1$d | %2$s)</string>\n    <string name=\"delete_files\">Izbriši datoteke</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Stvarno želite trajno izbrisati sve epizode u sljedećoj seriji?\n\\n\n\\n%s</string>\n    <string name=\"no_subtitles_loaded\">Još nije učitan nijedan titl</string>\n    <string name=\"preview_seekbar\">Pretpregled trake za traženje</string>\n    <string name=\"preview_seekbar_desc\">Omogući minijaturu pregleda na traci za pretraživanje</string>\n    <string name=\"confirm_before_exiting_title\">Potvrdi prije izlaza</string>\n    <string name=\"confirm_before_exiting_desc\">Prikaži dijaloški okvir prije izlaska iz aplikacije</string>\n    <string name=\"show\">Prikaži</string>\n    <string name=\"dont_show\">Ne prikazuj</string>\n    <string name=\"subs_edge_size\">Veličina ruba</string>\n    <string name=\"custom\">Prilagođeno</string>\n    <string name=\"backup_path_title\">Mjesto mape sigurnosnih kopija</string>\n    <string name=\"encoding_error\">Pogreška u kodiranju</string>\n    <string name=\"unsupported_error\">Nepodržana pogreška</string>\n    <string name=\"software_decoding\">Dekodiranje softvera</string>\n    <string name=\"software_decoding_desc\">Softversko dekodiranje omogućuje playeru reprodukciju video datoteka koje tvoj mobitel ne podržava, ali može uzrokovati kašnjenja ili nestabilnu reprodukciju pri visokoj rezoluciji.</string>\n    <string name=\"torrent_info\">Ovaj je video Torrent, što znači da se tvoja video aktivnost može pratiti.\\nInformiraj se o korištenju Torrenta prije nego što nastaviš.</string>\n    <string name=\"torrent_not_accepted\">Ponovno pokrenite aplikaciju i prihvatite skočni prozor Stream Torrent za nastavak.</string>\n    <string name=\"player_load_one_subtitle_online\">Učitaj prvi dostupni</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"torrent_preferred_media\">Aktiviraj torrent u Postavke/Pružatelji usluge/Preferirani mediji</string>\n    <string name=\"sort_episodes_number_asc\">Epizoda (Uzlazno)</string>\n    <string name=\"sort_episodes_number_desc\">Epizoda (Silazno)</string>\n    <string name=\"sort_episodes_rating_high_low\">Ocjena (Najviša)</string>\n    <string name=\"sort_episodes_rating_low_high\">Ocjena (Najniža)</string>\n    <string name=\"sort_episodes_date_newest\">Datum emitiranja (Najnovije)</string>\n    <string name=\"sort_episodes_date_oldest\">Datum emitiranja (Najstarije)</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_rating\">Ocjena %s</string>\n    <string name=\"sort_button_date\">Datum %s</string>\n    <string name=\"update_plugins\">Ažuriraj dodatke</string>\n    <string name=\"no_plugins_updated_manually\">Nijedan dodatak nije ažuriran.</string>\n    <string name=\"update_plugins_manually\">Ažuriraj podatke ručno</string>\n    <string name=\"starting_plugin_update_manually\">Pokreće se postupak ažuriranja dodataka!</string>\n    <string name=\"player_notification_channel_name\">Obavijesti reproduktora</string>\n    <string name=\"plugins_updated_manually\">Uspješno ažuriranih dodataka: %d!</string>\n    <string name=\"player_notification_channel_description\">Obavijest reproduktora za upravljanje reprodukcijom iz pozadine</string>\n    <string name=\"all_subtitles_italic\">Ukosite sve titlove</string>\n    <string name=\"all_subtitles_bold\">Podebljajte sve titlove</string>\n    <string name=\"background_radius\">Radijus pozadine</string>\n    <string name=\"volume_exceeded_100\">Glasnoća je premašila 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Ponovno kliznite prema gore da biste prešli preko 100%</string>\n    <string name=\"subtitles_from_embedded\">Ugrađen</string>\n    <string name=\"subtitles_from_online\">Online</string>\n    <string name=\"speech_recognition_unavailable\">Prepoznavanje govora nije dostupno</string>\n    <string name=\"begin_speaking\">Počnite govoriti…</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dmin %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dmin %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"show_rating\">Oznaka za ocjenjivanje</string>\n    <string name=\"player_settings_always_ask\">Uvijek pitaj</string>\n    <string name=\"no_account\">Nema računa</string>\n    <string name=\"download_parallel_settings_des\">Koliko se različitih stavki može istovremeno preuzimati</string>\n    <string name=\"parallel_downloads\">Istovremena preuzimanja</string>\n    <string name=\"concurrent_connections\">Istovremene veze</string>\n    <string name=\"concurrent_connections_settings_des\">Koliko istovremenih veza svako preuzimanje može koristiti tijekom preuzimanja</string>\n    <string name=\"go_to_downloads\">Idi na preuzimanja</string>\n    <string name=\"no_internet_connection\">Nema internetske veze.\\n\\nPovežite se s internetom i pokušajte ponovo ili gledajte svoje preuzete sadržaje kada niste povezani s internetom.</string>\n    <string name=\"overscan_settings_des\">Mijenja granice ekrana</string>\n    <string name=\"overscan_settings\">Slika veća od ekrana</string>\n    <string name=\"poster_size_settings_des\">Mijenja veličinu postera</string>\n    <string name=\"poster_size_settings\">Veličina postera</string>\n    <string name=\"speedup_title\">Prebacivanje brzine dugim pritiskom</string>\n    <string name=\"speedup_summary\">Držite pritisnuto za dvostruku brzinu</string>\n    <string name=\"edit_profile_image_title\">Uredi sliku profila</string>\n    <string name=\"edit_profile_image_hint\">Unesite URL slike profila</string>\n    <string name=\"edit_profile_image_error_empty\">Nijedan URL nije pronađen</string>\n    <string name=\"edit_profile_image_error_invalid\">Nevaljan URL ili slika</string>\n    <string name=\"edit_profile_image_success\">Slika uspješno ažurirana</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Označi kao gledano do ove epizode</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Ukloni gledano do ove epizode</string>\n    <string name=\"action_reload\">Ponovo učitano</string>\n    <string name=\"reload_provider\">Usluga ponovnog učitavanja</string>\n    <string name=\"play_full_series_button\">Reproduciraj cijelu seriju</string>\n    <string name=\"install_prerelease\">Instaliraj predizdanje</string>\n    <string name=\"prerelease_already_installed\">Predizdanje je već instalirano.</string>\n    <string name=\"prerelease_install_failed\">Instalacija predizdanja nije uspjela.</string>\n    <string name=\"episode_action_play_mirror\">Pokreni duplikat</string>\"\n    <string name=\"show_episode_text\">Tekst epizode</string>\n    <string name=\"name\">Ime</string>\n    <string name=\"resolution_and_name\">Rezolucija i ime</string>\n    <string name=\"subs_subtitle_alignment\">Poravnanje titlova</string>\n    <string name=\"bottom_left\">Dolje lijevo</string>\n    <string name=\"bottom_center\">Dolje u sredini</string>\n    <string name=\"bottom_right\">Dolje desno</string>\n    <string name=\"middle_left\">Sredina lijevo</string>\n    <string name=\"middle_center\">U sredini</string>\n    <string name=\"middle_right\">Desno u sredini</string>\n    <string name=\"top_left\">Gore lijevo</string>\n    <string name=\"top_center\">Gore u sredini</string>\n    <string name=\"top_right\">Gore desno</string>\n    <string name=\"extra_brightness_settings\">Dodatna svjetlina</string>\n    <string name=\"extra_brightness_settings_des\">Uključi filtar svjetline kada se prekorači 100 % svjetline ekrana</string>\n    <string name=\"extra_brightness_key\">dodatna_svjetlina_uključena</string>\n    <string name=\"search_suggestions\">Prijedlozi za pretraživanje</string>\n    <string name=\"search_suggestions_des\">Prikaži prijedloge za pretraživanje tijekom tipkanja</string>\n    <string name=\"clear_suggestions\">Izbriši prijedloge</string>\n    <string name=\"video_info\">Podaci medija</string>\n    <string name=\"source_name\">Ime izvora</string>\n    <string name=\"download_all\">Preuzmi sve</string>\n    <string name=\"cancel_all\">Odustani od svega</string>\n    <string name=\"download_queue\">Red preuzimanja</string>\n    <string name=\"queue_empty_message\">Sada nema preuzimanja u redu.</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d aktivno preuzimanje</item>\n        <item quantity=\"few\">%d aktivna preuzimanja</item>\n        <item quantity=\"other\">%d aktivnih preuzimanja</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d preuzimanje u redu čekanja</item>\n        <item quantity=\"few\">%d preuzimanja u redu čekanja</item>\n        <item quantity=\"other\">%d preuzimanja u redu čekanja</item>\n    </plurals>\n    <string name=\"source_priority\">Prioritet izvora</string>\n    <string name=\"source_priority_help\">Odluči kako razvrstati izvor videa u playeru</string>\n    <string name=\"download_episode_range\">Želiš li preuzeti epizodu %s?</string>\n    <string name=\"cancel_queue_message\">Želiš li otkazati sva preuzimanja u redu čekanja?</string>\n    <string name=\"show_cast_in_details\">Prikaži ploču glumačke postave</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"cast_format\" formatted=\"true\">Stáblista: %s</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dn %2$dó%3$dp</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dó%2$dp</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dp</string>\n    <string name=\"episode_poster_img_des\">Epizód Plakát</string>\n    <string name=\"home_main_poster_img_des\">Fő Plakát</string>\n    <string name=\"go_back_img_des\">Vissza</string>\n    <string name=\"home_change_provider_img_des\">Szolgáltató Váltás</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Sebesség (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Értékelés: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Új frissítés található!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration_format\" formatted=\"true\">%d perc</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$sEp%2$d</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"preview_background_img_des\">Háttér Előnézet</string>\n    <string name=\"download_failed\">Letöltés sikertelen</string>\n    <string name=\"download\">Letöltés</string>\n    <string name=\"search\">Keresés</string>\n    <string name=\"delete\">Törlés</string>\n    <string name=\"cancel\">Mégse</string>\n    <string name=\"pause\">Szüneteltetés</string>\n    <string name=\"queued\">sorba állítva</string>\n    <string name=\"resize_fit\">Igazítás</string>\n    <string name=\"resize_fill\">Kitöltés</string>\n    <string name=\"resize_zoom\">Nagyítás</string>\n    <string name=\"all\">Összes</string>\n    <string name=\"tracks\">Zeneszámok</string>\n    <string name=\"home_next_random_img_des\">Következő véletlenszerű</string>\n    <string name=\"logout\">Kijelentkezés</string>\n    <string name=\"login\">Bejelentkezés</string>\n    <string name=\"none\">Semmi</string>\n    <string name=\"title\">Cím</string>\n    <string name=\"loading\">Betöltés…</string>\n    <string name=\"status\">Állapot</string>\n    <string name=\"show_title\">Forrás címe</string>\n    <string name=\"history\">Előzmények</string>\n    <string name=\"eigengraumode_settings\">Visszajátszás sebessége</string>\n    <string name=\"subs_subtitle_elevation\">Felirat magassága</string>\n    <string name=\"download_started\">Letöltés elkezdve</string>\n    <string name=\"normal_no_plot\">Nem található cselekmény</string>\n    <string name=\"continue_watching\">Lejátszás folytatása</string>\n    <string name=\"filler\" formatted=\"true\">Filler</string>\n    <string name=\"play_with_app_name\">Lejátszás CloudStreamel</string>\n    <string name=\"title_home\">Kezdőlap</string>\n    <string name=\"title_search\">Keresés</string>\n    <string name=\"title_downloads\">Letöltések</string>\n    <string name=\"title_settings\">Beállítások</string>\n    <string name=\"search_hint\">Keresés…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Keresés %s…</string>\n    <string name=\"no_data\">Nincs adat</string>\n    <string name=\"episode_more_options_des\">Több opció</string>\n    <string name=\"next_episode\">Következő epizód</string>\n    <string name=\"result_tags\">Műfajok</string>\n    <string name=\"result_share\">Megosztás</string>\n    <string name=\"result_open_in_browser\">Megnyitás böngészőben</string>\n    <string name=\"skip_loading\">Betöltés kihagyása</string>\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Poszter</string>\n    <string name=\"type_watching\">Nézés</string>\n    <string name=\"type_completed\">Befejezve</string>\n    <string name=\"type_plan_to_watch\">Később megnézés</string>\n    <string name=\"type_re_watching\">Újranézés</string>\n    <string name=\"play_movie_button\">Film lejátszása</string>\n    <string name=\"play_trailer_button\">Előzetes lejátszása</string>\n    <string name=\"play_livestream_button\">Élőadás lejátszása</string>\n    <string name=\"play_torrent_button\">Torrent streamelése</string>\n    <string name=\"pick_source\">Források</string>\n    <string name=\"pick_subtitle\">Feliratok</string>\n    <string name=\"go_back\">Vissza</string>\n    <string name=\"download_done\">Letöltés kész</string>\n    <string name=\"stream\">Hálózati stream</string>\n    <string name=\"error_loading_links_toast\">Hiba a linkek betöltésekor</string>\n    <string name=\"download_storage_text\">Belső tárhely</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Fájl törlése</string>\n    <string name=\"popup_play_file\">Fájl lejátszása</string>\n    <string name=\"popup_resume_download\">Letöltés folytatása</string>\n    <string name=\"popup_pause_download\">Letöltés szüneteltetése</string>\n    <string name=\"home_more_info\">Több információ</string>\n    <string name=\"home_expanded_hide\">Elrejtés</string>\n    <string name=\"home_play\">Lejátszás</string>\n    <string name=\"home_info\">Információ</string>\n    <string name=\"filter_bookmarks\">Könyvjelző szűrése</string>\n    <string name=\"error_bookmarks_text\">Könyvjelzők</string>\n    <string name=\"action_remove_from_bookmarks\">Eltávolítás</string>\n    <string name=\"action_add_to_bookmarks\">Megtekintés állapotának beállítása</string>\n    <string name=\"sort_apply\">Alkalmazás</string>\n    <string name=\"sort_copy\">Másolás</string>\n    <string name=\"sort_close\">Bezárás</string>\n    <string name=\"sort_clear\">Törlés</string>\n    <string name=\"sort_save\">Mentés</string>\n    <string name=\"player_speed\">Lejátszás sebessége</string>\n    <string name=\"subtitles_settings\">Felirat beállítások</string>\n    <string name=\"subs_text_color\">Szövegszín</string>\n    <string name=\"subs_outline_color\">Körvonal szín</string>\n    <string name=\"subs_background_color\">Háttér szín</string>\n    <string name=\"subs_window_color\">Ablak szín</string>\n    <string name=\"subs_edge_type\">Él típusa</string>\n    <string name=\"subs_font\">Betűtípus</string>\n    <string name=\"search_provider_text_types\">Keresés típusok szerint</string>\n    <string name=\"search_provider_text_providers\">Keresés szolgáltatók szerint</string>\n    <string name=\"benene_count_text\">%d Banán adva a fejlesztőknek</string>\n    <string name=\"subs_download_languages\">Nyelvek letöltése</string>\n    <string name=\"subs_hold_to_reset_to_default\">Tartsa lenyomva az alapértelmezett érték visszaállításához</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Betűtípusok importálása %s</string>\n    <string name=\"action_remove_watching\">Eltávolítás</string>\n    <string name=\"action_open_watching\">Több információ</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">VPN szükséges lehet ehhez a szolgáltató megfelelő működéséhez</string>\n    <string name=\"vpn_torrent\">Ez a szolgáltató torrent, VPN ajánlott</string>\n    <string name=\"torrent_plot\">Leírás</string>\n    <string name=\"torrent_no_plot\">Nem található leírás</string>\n    <string name=\"show_log_cat\">Logcat megjelenítése 🐈</string>\n    <string name=\"picture_in_picture\">Kép-a-képben</string>\n    <string name=\"picture_in_picture_des\">Folytatja a lejátszást egy miniatűr lejátszóban, más alkalmazások mellett</string>\n    <string name=\"player_size_settings\">Lejátszó átméretezése gomb</string>\n    <string name=\"player_size_settings_des\">Fekete szegélyek eltávolítása</string>\n    <string name=\"player_subtitles_settings\">Feliratok</string>\n    <string name=\"player_subtitles_settings_des\">Lejátszó feliratok beállításai</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast Feliratok</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast feliratok beállításai</string>\n    <string name=\"play_episode\">Epizód lejátszása</string>\n    <string name=\"downloaded\">Letöltve</string>\n    <string name=\"download_paused\">Letöltés szüneteltetve</string>\n    <string name=\"download_canceled\">Letöltés megszakítva</string>\n    <string name=\"downloading\">Letöltés</string>\n    <string name=\"subs_font_size\">Betűtípus mérete</string>\n    <string name=\"subs_subtitle_languages\">Felirat nyelve</string>\n    <string name=\"provider_info_meta\">A metaadatokat a webhely nem biztosítja, a videó betöltése sikertelen lesz, ha nem létezik a webhelyen.</string>\n    <string name=\"subs_auto_select_language\">Nyelv automatikus kiválasztása</string>\n    <string name=\"category_updates\">Frissítések és Biztonsági Mentés</string>\n    <string name=\"advanced_search\">Speciális keresés</string>\n    <string name=\"show_fillers_settings\">Filler epizódok mutatása animéknél</string>\n    <string name=\"show_trailers_settings\">Előzetesek megjelenítése</string>\n    <string name=\"redo_setup_process\">Telepítési folyamat megismétlése</string>\n    <string name=\"anim\">Anime applikáció ugyanazoktól a fejlesztőktől</string>\n    <string name=\"lightnovel\">Light novel applikáció ugyanazoktól a fejlesztőktől</string>\n    <string name=\"app_language\">Alkalmazás nyelve</string>\n    <string name=\"episode\">Epizód</string>\n    <string name=\"episodes\">Epizódok</string>\n    <string name=\"season_short\">Év</string>\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"episode_short\">Ep</string>\n    <string name=\"no_episodes_found\">Nem található epizód</string>\n    <string name=\"delete_file\">Fájl törlése</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dp\n\\nhátra</string>\n    <string name=\"duration\">Időtartam</string>\n    <string name=\"free_storage\">Elérhető</string>\n    <string name=\"used_storage\">Használatban</string>\n    <string name=\"app_storage\">Alkalmazás</string>\n    <string name=\"status_completed\">Befejezve</string>\n    <string name=\"rating\">Értékelés</string>\n    <string name=\"cartoons\">Rajzfilmek</string>\n    <string name=\"livestreams\">Élőadások</string>\n    <string name=\"action_default\">Alapértelmezett</string>\n    <string name=\"movies\">Filmek</string>\n    <string name=\"tv_series\">TV sorozat</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrentek</string>\n    <string name=\"asian_drama\">Ázsiai drámák</string>\n    <string name=\"documentaries\">Dokumentumfilmek</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"others\">Egyebek</string>\n    <string name=\"tv_series_singular\">Sorozat</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"source_error\">Forráshiba</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"cartoons_singular\">Rajzfilm</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"live_singular\">Élőadás</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Videó</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Dokumentumfilm</string>\n    <string name=\"asian_drama_singular\">Ázsiai dráma</string>\n    <string name=\"episode_action_reload_links\">Linkek újratöltése</string>\n    <string name=\"episode_action_download_mirror\">Letöltés mirror</string>\n    <string name=\"episode_action_auto_download\">Automatikus letöltés</string>\n    <string name=\"backup_success\">Adatok eltárolva</string>\n    <string name=\"backup_failed_error_format\">Hiba a biztonsági mentés során %s</string>\n    <string name=\"category_account\">Fiókok és Biztonság</string>\n    <string name=\"advanced_search_des\">Szolgáltató szerint elkülönítve adja meg a keresési eredményeket</string>\n    <string name=\"kitsu_settings\">Poszterek megjelenítése Kitsu-ról</string>\n    <string name=\"pref_filter_search_quality\">Kiválasztott videóminőségek elrejtése keresési eredményekbe</string>\n    <string name=\"automatic_plugin_updates\">Automatikus bővítményfrissítések</string>\n    <string name=\"automatic_plugin_download\">Bővítmények automatikus letöltése</string>\n    <string name=\"automatic_plugin_download_summary\">Automatikusan telepíti az összes még nem telepített bővítményt a hozzáadott tárolókból.</string>\n    <string name=\"updates_settings\">Alkalmazás frissítések megjelenítése</string>\n    <string name=\"updates_settings_des\">Automatikusan keressen új frissítéseket indításkor.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"discord\">Csatlakozz a Discordhoz</string>\n    <string name=\"benene\">Adj Banánt a fejlesztőknek</string>\n    <string name=\"no_chromecast_support_toast\">Ez a szolgáltató nem támogatja a Chromecast-ot</string>\n    <string name=\"no_links_found_toast\">Nem található link</string>\n    <string name=\"copy_link_toast\">A link vágólapra másolva</string>\n    <string name=\"play_episode_toast\">Epizód lejátszása</string>\n    <string name=\"subs_default_reset_toast\">Alapértelmezett értékre visszaállítása</string>\n    <string name=\"season\">Évad</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Nincs évad</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Ezzel véglegesen törli a %s\n\\nBiztosan törli?</string>\n    <string name=\"status_ongoing\">Folyamatban levő</string>\n    <string name=\"year\">Év</string>\n    <string name=\"site\">Webhely</string>\n    <string name=\"synopsis\">Összegzés</string>\n    <string name=\"no_subtitles\">Nincsenek feliratok</string>\n    <string name=\"remote_error\">Távoli hiba</string>\n    <string name=\"render_error\">Render hiba</string>\n    <string name=\"unexpected_error\">Váratlan lejátszó hiba</string>\n    <string name=\"storage_error\">Letöltés hiba, ellenőrizze a tárolási engedélyeket</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast epizód</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast mirror</string>\n    <string name=\"episode_action_play_in_app\">Lejátszás az alkalmazásban</string>\n    <string name=\"episode_action_play_in_format\">Lejátszás %s</string>\n    <string name=\"episode_action_download_subtitle\">Feliratok letöltése</string>\n    <string name=\"reload_error\">Újracsatlakozás…</string>\n    <string name=\"swipe_to_seek_settings_des\">Húzd balra vagy jobbra a videólejátszóban az idő vezérléséhez</string>\n    <string name=\"swipe_to_change_settings\">Csúsztassa ujját a beállítások módosításához</string>\n    <string name=\"swipe_to_change_settings_des\">Csúsztassa felf/le az ujját a bal/jobb oldalon a fényerő vagy a hangerő megváltoztatásához</string>\n    <string name=\"backup_settings\">Biztonsági mentés</string>\n    <string name=\"benene_count_text_none\">0 Banán a fejlesztőknek</string>\n    <string name=\"swipe_to_seek_settings\">Húzd el, hogy beless</string>\n    <string name=\"autoplay_next_settings\">Következő epizód automatikus lejátszása</string>\n    <string name=\"autoplay_next_settings_des\">Következő epizód lejátszása amikor az aktuális epizód véget ér</string>\n    <string name=\"double_tap_to_seek_settings\">Dupla koppintás a kereséshez</string>\n    <string name=\"double_tap_to_pause_settings\">Dupla koppintás a szüneteltetéshez</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Lejátszó keresési értéke (Másodpercben)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Koppintson kétszer a jobb vagy bal oldalra az előre vagy hátra ugráshoz</string>\n    <string name=\"double_tap_to_pause_settings_des\">Koppintson kétszer középre a szüneteltetéshez</string>\n    <string name=\"use_system_brightness_settings\">Rendszer fényerejének használata</string>\n    <string name=\"use_system_brightness_settings_des\">Rendszer fényerejének használata az appban a sötét átfedés helyett</string>\n    <string name=\"episode_sync_settings\">Előrehaladás frissítése</string>\n    <string name=\"episode_sync_settings_des\">Automatikusan szinkronizálja az aktuális epizód előrehaladását</string>\n    <string name=\"restore_settings\">Adatok visszaállítása biztonsági mentésből</string>\n    <string name=\"restore_success\">Biztonsági mentés betöltve</string>\n    <string name=\"settings_info\">Információ</string>\n    <string name=\"resume\">Folytatás</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"update_started\">Frissítés elkezdődött</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Nem sikerült visszaállítani az adatokat a %s fájlból</string>\n    <string name=\"backup_failed\">Tárolási engedélyek hiányoznak. Kérjük próbálja újra.</string>\n    <string name=\"apk_installer_settings\">APK Telepítő</string>\n    <string name=\"apk_installer_settings_des\">Egyes telefonok nem támogatják az új csomag telepítőt. Ha a frissítések nem települnek, próbálja meg a régi opciót.</string>\n    <string name=\"benene_des\">Banán adva</string>\n    <string name=\"poster_ui_settings\">A felhasználói felület elemeinek bekapcsolása a poszteren</string>\n    <string name=\"no_update_found\">Nem található frissítés</string>\n    <string name=\"check_for_update\">Frissítés keresése</string>\n    <string name=\"video_lock\">Zárolás</string>\n    <string name=\"video_aspect_ratio_resize\">Átméretezés</string>\n    <string name=\"video_source\">Forrás</string>\n    <string name=\"video_skip_op\">Bevezető intro átugrása</string>\n    <string name=\"dont_show_again\">Ne mutasd újra</string>\n    <string name=\"next_episode_format\" formatted=\"true\">A(z) %d epizód ekkor jelenik meg</string>\n    <string name=\"type_on_hold\">Szüneteltetve</string>\n    <string name=\"type_dropped\">Elvetve</string>\n    <string name=\"show_hd\">Minőségi jelzés</string>\n    <string name=\"show_dub\">Szinkroncímke</string>\n    <string name=\"show_sub\">Alcímke</string>\n    <string name=\"pref_category_actions\">Műveletek</string>\n    <string name=\"random_button_settings\">Random gomb</string>\n    <string name=\"dns_pref\">DNS HTTPS-en keresztül</string>\n    <string name=\"browser\">Böngésző</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"pref_category_gestures\">Kézmozdulatok</string>\n    <string name=\"skip_update\">frissítés kihagyása</string>\n    <string name=\"pref_category_app_updates\">Alkalmazásfrissítések</string>\n    <string name=\"category_providers\">Szolgáltatók</string>\n    <string name=\"pref_category_ui_features\">Funkciók</string>\n    <string name=\"watch_quality_pref_data\">Előnyben részesített videóminőség (mobilinternet)</string>\n    <string name=\"limit_title\">Videolejátszó cím max karakterek</string>\n    <string name=\"jsdelivr_enabled\">Nem sikerült elérni a GitHubot, a jsdelivr proxy bekapcsolva…</string>\n    <string name=\"pref_category_extensions\">Bővítmények</string>\n    <string name=\"category_general\">Általános</string>\n    <string name=\"subtitles_encoding\">Felirat kódolása</string>\n    <string name=\"primary_color_settings\">Elsődleges szín</string>\n    <string name=\"app_theme_settings\">Alkalmazástéma</string>\n    <string name=\"category_provider_test\">Szolgáltató teszt</string>\n    <string name=\"test_failed\">Sikertelen</string>\n    <string name=\"video_disk_description\">Problémákat okoz, ha túl magasra van állítva az alacsony tárhellyel rendelkező eszközökön, például az Android TV-n.</string>\n    <string name=\"enable_nsfw_on_providers\">Korhatáros tartalmak engedélyezése a támogatott kiegészítőknél</string>\n    <string name=\"category_ui\">Elrendezés</string>\n    <string name=\"jsdelivr_proxy\">GitHub Proxy</string>\n    <string name=\"pref_category_player_features\">Lejátszó funkciók</string>\n    <string name=\"watch_quality_pref\">Előnyben részesített videóminőség (WiFi-n)</string>\n    <string name=\"dns_pref_summary\">Hasznos az internetszolgáltató blokkjainak megkerüléséhez</string>\n    <string name=\"pref_category_player_layout\">Elrendezés</string>\n    <string name=\"test_passed\">Sikerült</string>\n    <string name=\"nginx_url_pref\">NGINX szerver URL-címe</string>\n    <string name=\"display_subbed_dubbed_settings\">Szinkronizált/feliratozott animék megjelenítése</string>\n    <string name=\"pref_category_defaults\">Alapértelmezettek</string>\n    <string name=\"random_button_settings_desc\">Véletlenszerű gomb megjelenítése a Könyvtárban és Főoldalon</string>\n    <string name=\"download_path_pref\">Letöltési útvonal</string>\n    <string name=\"pref_category_cache\">Gyorsítótár</string>\n    <string name=\"provider_lang_settings\">Kiegészítők nyelvei</string>\n    <string name=\"test_log\">Napló</string>\n    <string name=\"library\">Könyvtár</string>\n    <string name=\"pref_category_bypass\">internetszolgáltató-kikerülések</string>\n    <string name=\"video_buffer_size_settings\">Videó buffer méret</string>\n    <string name=\"video_buffer_length_settings\">Videó buffer hossza</string>\n    <string name=\"limit_title_rez\">Videolejátszó felbontása</string>\n    <string name=\"video_buffer_disk_settings\">Videó gyorsítótár a lemezen</string>\n    <string name=\"pref_category_backup\">Biztonsági mentés</string>\n    <string name=\"pref_category_subtitles\">Feliratok</string>\n    <string name=\"preferred_media_settings\">Előnyben részesített média</string>\n    <string name=\"pref_category_links\">Hivatkozások</string>\n    <string name=\"video_buffer_clear_settings\">Videó és kép gyorsítótár törlése</string>\n    <string name=\"jsdelivr_proxy_summary\">A jsDelivr használatával a tiszta GitHub blokkolása megkerülhető. Néhány nappal késleltetheti a frissítéseket.</string>\n    <string name=\"video_ram_description\">Összeomlást okoz, ha túl magasra van állítva a kevés memóriával rendelkező eszközökön, például az Android TV-n.</string>\n    <string name=\"player_load_subtitles_online\">Betöltés az internetről</string>\n    <string name=\"video_tracks\">Videósávok</string>\n    <string name=\"apply_on_restart\">Alkalmazás újraindításkor</string>\n    <string name=\"safe_mode_description\">Az összes bővítményt kikapcsoltuk egy összeomlás miatt, hogy segítsünk megtalálni a problémát okozót.</string>\n    <string name=\"extension_authors\">Szerzők</string>\n    <string name=\"extension_types\">Támogatott</string>\n    <string name=\"update_notification_downloading\">Alkalmazásfrissítés letöltése…</string>\n    <string name=\"sort_updated_new\">Frissítve (újabbtól a régebbihez)</string>\n    <string name=\"empty_library_no_accounts_message\">Úgy tűnik, a könyvtárad üres :(\n\\nJelentkezz be egy könyvtár fiókba, vagy adj hozzá műsorokat a helyi könyvtárodhoz.</string>\n    <string name=\"empty_library_logged_in_message\">Úgy tűnik, ez a lista üres, próbálj meg egy másikra váltani.</string>\n    <string name=\"max\">Max</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"create_account\">Fiók létrehozása</string>\n    <string name=\"example_site_url\">https://példa.hu</string>\n    <string name=\"subtitle_offset\">Feliratok szinkronizálása</string>\n    <string name=\"update_notification_installing\">Alkalmazásfrissítés telepítése…</string>\n    <string name=\"clipboard_too_large\">Túl sok szöveg. Nem lehet a vágólapra menteni.</string>\n    <string name=\"plugin_singular\">bővítmény</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Nincs felirat késleltetés</string>\n    <string name=\"extension_description\">Leírás</string>\n    <string name=\"update\">Frissítés</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"subtitles_shadow\">Árnyék</string>\n    <string name=\"trailer\">Előzetes</string>\n    <string name=\"preferred_media_subtext\">Mit szeretnél látni</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Minden %s már letöltött</string>\n    <string name=\"extension_install_first\">Először telepítse a bővítményt</string>\n    <string name=\"pref_category_looks\">Kinézet</string>\n    <string name=\"app_layout\">Alkalmazás elrendezés</string>\n    <string name=\"upload_sync\">Szinkronizálás</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Nem sikerült bejelentkezni a %s-nál</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"recommended\">Ajánlott</string>\n    <string name=\"actor_main\">Fő</string>\n    <string name=\"error_invalid_data\">Érvénytelen adatok</string>\n    <string name=\"network_adress_example\">https://példa.hu/példa.mp4</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Nem sikerült betölteni: %s</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Elkezdődött a(z) %1$d %2$s letöltése…</string>\n    <string name=\"download_all_plugins_from_repo\">Töltse le az összes bővítményt ebből a tárolóból?</string>\n    <string name=\"safe_mode_title\">Biztonságos mód bekapcsolva</string>\n    <string name=\"extension_size\">Méret</string>\n    <string name=\"app_not_found_error\">Alkalmazás nem található</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"sort_by\">Rendezés e szerint</string>\n    <string name=\"subscription_new\">Feliratkozott a következőre: %s</string>\n    <string name=\"example_site_name\">ÚjOldalNév</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d plugin frissítve</string>\n    <string name=\"extension_rating\" formatted=\"true\">Értékelés: %s</string>\n    <string name=\"clear_history\">Előzmények törlése</string>\n    <string name=\"no\">Nem</string>\n    <string name=\"subscription_list_name\">Feliratkozva</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Használd ezt, ha a feliratok %d ms-sel korábban jelennek meg</string>\n    <string name=\"category_player\">Lejátszó</string>\n    <string name=\"resolution_and_title\">Felbontás és cím</string>\n    <string name=\"player_pref\">Előnyben részesített videolejátszó</string>\n    <string name=\"sort_rating_asc\">Értékelés (alacsonyabbtól a magasabbig)</string>\n    <string name=\"subtitle_offset_title\">Felirat késleltetése</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"error_invalid_id\">Érvénytelen azonosító</string>\n    <string name=\"provider_languages_tip\">Videók megtekintése ezeken a nyelveken</string>\n    <string name=\"previous\">Előző</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">%1$d%2$s letöltve</string>\n    <string name=\"batch_download\">Batch letöltés</string>\n    <string name=\"plugin\">bővítmények</string>\n    <string name=\"apk_installer_legacy\">Legacy</string>\n    <string name=\"sort_rating_desc\">Értékelés (magasabbtól az alacsonyig)</string>\n    <string name=\"subscription_in_progress_notification\">Feliratkozott műsorok frissítése</string>\n    <string name=\"subscription_episode_released\">Megjelent a(z) %d epizód!</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"example_lang_name\">Nyelvkód (hu)</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"subtitles_raised\">Emelt</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"hls_playlist\">HLS lejátszási lista</string>\n    <string name=\"update_notification_failed\">Nem sikerült telepíteni az alkalmazás új verzióját</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s hitelesítve</string>\n    <string name=\"subtitles_outline\">Körvonal</string>\n    <string name=\"player_load_subtitles\">Betöltés fájlból</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"app_layout_subtext\">Az alkalmazás megjelenésének módosítása, hogy az megfeleljen az eszközödnek</string>\n    <string name=\"view_public_repositories_button_short\">Nyilvános lista</string>\n    <string name=\"extension_status\">Állapot</string>\n    <string name=\"skip_type_recap\">Összefoglaló</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"open_with\">Megnyitás a következővel</string>\n    <string name=\"uppercase_all_subtitles\">Minden felirat nagybetűs</string>\n    <string name=\"skip_type_intro\">Intro</string>\n    <string name=\"subscription_deleted\">Leiratkozott a következőről: %s</string>\n    <string name=\"subtitles_remove_bloat\">Szükségtelen elemek eltávolítása a feliratokról</string>\n    <string name=\"subtitles_filter_lang\">Szűrés előnyben részesített médianyelv szerint</string>\n    <string name=\"confirm_exit_dialog\">Biztos vagy benne, hogy ki akarsz lépni?</string>\n    <string name=\"sort\">Rendezés</string>\n    <string name=\"revert\">Visszaállít</string>\n    <string name=\"error_invalid_url\">Érvénytelen URL</string>\n    <string name=\"subtitles_remove_captions\">Zárt feliratok eltávolítása a feliratokból</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"delete_repository_plugins\">Ez az összes tároló bővítményt is törli</string>\n    <string name=\"blank_repo_message\">A CloudStream alapértelmezés szerint nem telepített webhelyeket. A webhelyeket a tárolókból kell telepítenie.\n\\n\n\\nCsatlakozz a Discord-unkhoz vagy keress online.</string>\n    <string name=\"extension_version\">Verzió</string>\n    <string name=\"action_mark_as_watched\">Megjelölés megtekintettként</string>\n    <string name=\"action_remove_from_watched\">Eltávolítás a megnézettek közül</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"next\">Következő</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"resolution\">Felbontás</string>\n    <string name=\"restart\">Újraindítás</string>\n    <string name=\"stop\">Stop</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Nincs letöltve: %d</string>\n    <string name=\"error\">Hiba</string>\n    <string name=\"remove_site_pref\">Webhely eltávolítása</string>\n    <string name=\"example_email\">hello@vilag.com</string>\n    <string name=\"setup_extensions_subtext\">Töltse le a használni kívánt webhelyek listáját</string>\n    <string name=\"view_public_repositories_button\">Közösségi tárolók megtekintése</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Letiltva)</string>\n    <string name=\"audio_tracks\">Hangsávok</string>\n    <string name=\"safe_mode_crash_info\">Összeomlási információk megtekintése</string>\n    <string name=\"player_settings_play_in_app\">Belső lejátszó</string>\n    <string name=\"all_languages_preference\">Minden nyelv</string>\n    <string name=\"added_sync_format\" formatted=\"true\">%s hozzáadva</string>\n    <string name=\"plugin_deleted\">Bővítmény törölve</string>\n    <string name=\"extension_language\">Nyelv</string>\n    <string name=\"account\">Fiók</string>\n    <string name=\"extras\">Extrák</string>\n    <string name=\"delete_repository\">Tároló törlése</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">%d letiltva</string>\n    <string name=\"yes\">Igen</string>\n    <string name=\"delayed_update_notice\">Az alkalmazás kilépéskor frissül</string>\n    <string name=\"sort_alphabetical_a\">Betűrendben (A-tól a Z-ig)</string>\n    <string name=\"sort_updated_old\">Frissítve (régebbitől az újabbig)</string>\n    <string name=\"example_password\">jelszó123</string>\n    <string name=\"example_username\">Felhasználónév</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"switch_account\">Fiókváltás</string>\n    <string name=\"add_account\">Fiók hozzáadása</string>\n    <string name=\"subtitles_example_text\">Árvíztűrő tükörfúrógép</string>\n    <string name=\"downloaded_file\">Letöltött fájl</string>\n    <string name=\"actor_supporting\">Támogató</string>\n    <string name=\"actor_background\">Háttér</string>\n    <string name=\"home_source\">Forrás</string>\n    <string name=\"home_random\">Lepj meg</string>\n    <string name=\"coming_soon\">Hamarosan…</string>\n    <string name=\"setup_done\">Kész</string>\n    <string name=\"extensions\">Bővítmények</string>\n    <string name=\"add_repository\">Tároló hozzáadása</string>\n    <string name=\"repository_name_hint\">Tároló neve</string>\n    <string name=\"repository_url_hint\">Repó URL</string>\n    <string name=\"plugin_loaded\">Bővítmény betöltve</string>\n    <string name=\"plugin_downloaded\">Bővítmény letöltve</string>\n    <string name=\"skip_type_creddits\">Közreműködők</string>\n    <string name=\"sort_alphabetical_z\">Betűrendben (Z-től az A-ig)</string>\n    <string name=\"select_library\">Könyvtár kiválasztása</string>\n    <string name=\"safe_mode_file\">Biztonságos módú fájlba ütköztünk!\n\\nNem töltődik be semmilyen kiegészítő indításkor, amíg a fájl nem kerül törlésre.</string>\n    <string name=\"normal\">Normál</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">%s betöltve</string>\n    <string name=\"skip_setup\">Beállítás kihagyása</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">%d letöltve</string>\n    <string name=\"start\">Start</string>\n    <string name=\"emulator_layout\">Emulátor elrendezés</string>\n    <string name=\"add_sync\">Nyomkövetés hozzáadása</string>\n    <string name=\"phone_layout\">Telefon elrendezés</string>\n    <string name=\"bottom_title_settings\">Poszter cím helye</string>\n    <string name=\"bottom_title_settings_des\">Tegye a címet a poszter alá</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Az átugrás mértéke, amikor a lejátszó el van rejtve</string>\n    <string name=\"legal_notice\">Jogi nyilatkozat</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Lejátszó megjelenítve - Ugrási Érték</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Lejátszó Elrejtve - Ugrási Érték</string>\n    <string name=\"add_site_pref\">Klónozott oldal</string>\n    <string name=\"add_site_summary\">Egy meglévő webhely klónjának hozzáadása, más URL-címmel</string>\n    <string name=\"tv_layout\">TV elrendezés</string>\n    <string name=\"automatic\">Automatikus</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Az átugrás mértéke, amikor a lejátszó látható</string>\n    <string name=\"automatic_plugin_download_mode_title\">Válassza ki a módot a pluginek letöltésének szűréséhez</string>\n    <string name=\"backup_frequency\">Mentési gyakoriság</string>\n    <string name=\"sync_score\">Értékelt</string>\n    <string name=\"disable\">Kikapcsolás</string>\n    <string name=\"quality_cam_rip\">Kamera Rip</string>\n    <string name=\"skip_type_op\">Nyitás</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"subscribe_tooltip\">Új epizód értesítés</string>\n    <string name=\"result_search_tooltip\">Keresés más kiegészítőkben</string>\n    <string name=\"recommendations_tooltip\">Ajánlatok mutatása</string>\n    <string name=\"speed_setting_summary\">Sebesség opció megjelenítése a lejátszóban</string>\n    <string name=\"test_extensions\">Minden kiegészítő tesztelése</string>\n    <string name=\"test_extensions_summary\">Ez a teszt szigorúan fejlesztők számára készült, nem alkalmas egyes kiegészítők működésének visszaigazolására.</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"action_subscribe\">Feliratkozás</string>\n    <string name=\"action_unsubscribe\">Leiratkozás</string>\n    <string name=\"links_reloaded_toast\">Linkek Újratöltve</string>\n    <string name=\"skip_type_ed\">Zárás</string>\n    <string name=\"referer\">Hivatkozó (opcionális)</string>\n    <string name=\"no_plugins_found_error\">Nem találhatóak pluginek a repóban</string>\n    <string name=\"no_repository_found_error\">Repó nem található, ellenőrizze a címet vagy próbálja VPN-el</string>\n    <string name=\"skip_type_format\" formatted=\"true\">%s kihagyása</string>\n    <string name=\"enable_skip_op_from_database_des\">A kihagyási felugró ablakok mutatása nyitás/zárás esetén</string>\n    <string name=\"set_default\">Alapbeállítás</string>\n    <string name=\"use\">Használ</string>\n    <string name=\"profile_number\">%d profil</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Használja ezt ha a felirat %d ms-ot késik</string>\n    <string name=\"quality_cam_hd\">Kamera HD</string>\n    <string name=\"poster_image\">Poszter Kép</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"mobile_data\">Mobil adat</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"edit\">Szerkeszt</string>\n    <string name=\"quality_cam\">Kamera</string>\n    <string name=\"subtitles_depressed\">Nyomott</string>\n    <string name=\"skip_type_mixed_ed\">Kevert zárás</string>\n    <string name=\"skip_type_mixed_op\">Kevert nyitás</string>\n    <string name=\"help\">Segítség</string>\n    <string name=\"profiles\">Profilok</string>\n    <string name=\"action_remove_from_favorites\">Eltávolítás kedvencekből</string>\n    <string name=\"enter_current_pin\">Adja meg a jelenlegi PIN-t</string>\n    <string name=\"quality_profile_help\">Itt beállíthatja hogyan rendezze el a forrásokat. Ha egy videónak nagyobb a prioritása, előbb fog megjelenni a listában. A forrás prioritás és a minőség prioritás együttes értéke adja ki a videó prioritást.\n\\n\n\\nForrás A: 3\n\\nMinőség B: 7\n\\nEzek összértéke egy 10-es videó prioritást eredményez.\n\\n\n\\nFIGYELEM: Ha az összeg több mint 10, a lejátszó nem tölt be mást ha már a link betöltésre került!</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Potenciálisan dupla elemek a könyvtárjában:\n\\n\n\\n%s\n\\n\n\\nSzeretné hozzáadni ezt az elemet mindenképpen, ezzel felülírva a jelenlegit, vagy visszavonja a műveletet?</string>\n    <string name=\"skip_startup_account_select_pref\">Fiók választás kihagyása belépéskor</string>\n    <string name=\"use_default_account\">Használjon alapértelmezett fiókot</string>\n    <string name=\"rotate_video\">Elforgatás</string>\n    <string name=\"profile_background_des\">Profil háttér</string>\n    <string name=\"favorites_list_name\">Kedvencek</string>\n    <string name=\"favorite_added\">%s hozzáadva a kedvencekhez</string>\n    <string name=\"favorite_removed\">%s eltávolítva a kedvencekből</string>\n    <string name=\"action_add_to_favorites\">Hozzáadás a kedvencekhez</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Úgy tűnik egy potenciálisan dupla elem már létezik a könyvtárjában: \\'%s.\\'\n\\n\n\\nMindenképpen hozzá akarja adni ezt az elemet, ezzel felülírva a régit, vagy visszavonja a műveletet?</string>\n    <string name=\"enter_pin\">Adja meg a PIN-t</string>\n    <string name=\"lock_profile\">Profil Zárolása</string>\n    <string name=\"select_an_account\">Válasszon egy fiókot</string>\n    <string name=\"manage_accounts\">Fiókok kezelése</string>\n    <string name=\"edit_account\">Fiók módosítása</string>\n    <string name=\"logged_account\" formatted=\"true\">Belépve mint %s</string>\n    <string name=\"rotate_video_desc\">Jelenítsen meg egy kapcsolót a képorientáció váltáshoz</string>\n    <string name=\"duplicate_title\">Potenciális Dupla Találat</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Adja meg a PIN-t a %s-hoz</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"pin_error_incorrect\">Hibás PIN. Próbálja újra.</string>\n    <string name=\"unable_to_inflate\">A UI hibásan jelenítődött meg, ez egy JELENTŐS BUG ezért kérjük jelentse be %s</string>\n    <string name=\"already_voted\">Már korábban szavazott</string>\n    <string name=\"duplicate_add\">Hozzáadás</string>\n    <string name=\"duplicate_replace\">Kicserélés</string>\n    <string name=\"duplicate_replace_all\">Mind Kicserélése</string>\n    <string name=\"qualities\">Minőségek</string>\n    <string name=\"pin_error_length\">A PIN 4 karakter hosszú kell legyen</string>\n    <string name=\"auto_rotate_video\">Auto elforgatás</string>\n    <string name=\"auto_rotate_video_desc\">Az automatikus videó orientáció alapján való képernyő elforgatás bekapcsolása</string>\n    <string name=\"open_local_video\">Helyi videó megnyitása</string>\n    <string name=\"repo_copy_label\">Tárhely név és URL</string>\n    <string name=\"torrent_info\">Ez a videó egy Torrent, ami azt jelenti, hogy a videótevékenységed nyomon követhető.\\nGyőződj meg róla, hogy megérted a torrentezés működését, mielőtt folytatnád.</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Hamarosan érkezik a(z) %s</string>\n    <string name=\"toast_copied\">Másolva!</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">A(z) %1$d. évad %2$d. epizódja megjelenik ekkor</string>\n    <string name=\"play_from_beginning_img_des\">Lejátszás az elejétől</string>\n    <string name=\"downloads_empty\">Jelenleg nincs letöltés.</string>\n    <string name=\"downloads_delete_select\">Válassza ki a Törlendő Elemeket</string>\n    <string name=\"offline_file\">Elérhető offline megtekintésre</string>\n    <string name=\"select_all\">Mindet Kiválaszt</string>\n    <string name=\"deselect_all\">Mindent Kijelölés Eltávolítása</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"download_queue\">Letöltési sor</string>\n    <string name=\"speech_recognition_unavailable\">Beszédfelismerés nem elérhető</string>\n    <string name=\"begin_speaking\">Kezdjen beszélni…</string>\n    <string name=\"play_full_series_button\">Teljes sorozat lejátszása</string>\n    <string name=\"queue_empty_message\">Jelenleg nincs sorban álló letöltés.</string>\n    <string name=\"extra_brightness_settings\">Extra fényerő</string>\n    <string name=\"extra_brightness_settings_des\">A fényerő szűrő engedélyezése, ha a kijelző fényereje meghaladja a 100% -ot</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"search_suggestions\">Keresési javaslatok</string>\n    <string name=\"search_suggestions_des\">Mutasson keresési javaslatok gépelés közben</string>\n    <string name=\"clear_suggestions\">Javaslatok törlése</string>\n    <string name=\"show_cast_in_details\">Szereplők panel megjelenítése</string>\n    <string name=\"install_prerelease\">Telepít kiadás előtti verziót</string>\n    <string name=\"prerelease_already_installed\">Az előzetes verzió már telepítve van.</string>\n    <string name=\"prerelease_install_failed\">Az előzetes verzió telepítése sikertelen.</string>\n    <string name=\"delete_files\">Fájlok törlése</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Biztosan törölni szeretné az alábbi sorozat összes megjelenését?\\n\\n%s</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s \\nmaradék</string>\n    <string name=\"music_singlar\">Zene</string>\n    <string name=\"audio_book_singular\">Hangoskönyv</string>\n    <string name=\"custom_media_singluar\">Média</string>\n    <string name=\"audio_singluar\">Hang</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"encoding_error\">Kódolási hiba</string>\n    <string name=\"unsupported_error\">Hiba nem támogatott</string>\n    <string name=\"delete_format\" formatted=\"true\">Törlés (%1$d | %2$s)</string>\n    <string name=\"test_warning\">Figyelem</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Biztosan véglegesen szeretné törölni a következő tételeket?\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Biztosan véglegesen szeretné törölni a következő epizódokat?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">A következő sorozatok összes epizódját is véglegesen törli:\\n\\n%s</string>\n    <string name=\"episode_action_play_mirror\">Lejátszás tükrözve</string>\"\n    <string name=\"show_rating\">Értékelési címke</string>\n    <string name=\"show_episode_text\">Epizód szövege</string>\n    <string name=\"pref_category_security\">Biztonság</string>\n    <string name=\"pref_category_accounts\">Fiókok</string>\n    <string name=\"auth_locally\">Helyi hitelesítés</string>\n    <string name=\"player_load_one_subtitle_online\">Töltse be az első létezőt</string>\n    <string name=\"qr_image\">QR kód képe</string>\n    <string name=\"video_info\">Média információ</string>\n    <string name=\"delete_plugin\">Plugin törlése</string>\n    <string name=\"player_settings_always_ask\">Mindig kérdezzen</string>\n    <string name=\"player_settings_select_cast_device\">Válassza ki a lejátszó eszközt</string>\n    <string name=\"clipboard_permission_error\">Hiba történt a vágólap elérésénél, kérjük, próbálkozzon újra.</string>\n    <string name=\"clipboard_unknown_error\">Hiba történt a másolás során. Kérjük, másolja a logcat fájlt, és vegye fel a kapcsolatot az alkalmazás ügyfélszolgálatával.</string>\n    <string name=\"ok\">Rendben</string>\n    <string name=\"dismiss\">Elutasítás</string>\n    <string name=\"password_pin_authentication_title\">Jelszó/PIN-kód hitelesítés</string>\n    <string name=\"biometric_unsupported\">A biometrikus hitelesítés nem támogatott ezen az eszközön</string>\n    <string name=\"biometric_setting_summary\">Az alkalmazás feloldása ujjlenyomat, arcfelismerés, PIN-kód, minta vagy jelszó segítségével.</string>\n    <string name=\"biometric_prompt_description\">Néhány sikertelen kísérlet után a parancssor bezárul. Egyszerűen indítsa újra az alkalmazást, és próbálja meg újra.</string>\n    <string name=\"reset_btn\">Visszaállítás</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"device_pin_url_message\">Látogasson el <b>%s</b> okostelefonján vagy számítógépén, és írja be a fenti kódot</string>\n    <string name=\"device_pin_error_message\">Nem működik az eszköz PIN-kódja, próbálkozzon helyi hitelesítéssel</string>\n    <string name=\"device_pin_expired_message\">A PIN-kód most lejárt!</string>\n    <string name=\"device_pin_counter_text\">A kód %1$dm %2$ds után lejár</string>\n    <string name=\"sort_release_date_new\">Kiadás dátuma (újabbaktól régebbi felé)</string>\n    <string name=\"sort_release_date_old\">Kiadás dátuma (régitől újig)</string>\n    <string name=\"hide_player_control_names\">A lejátszó vezérlői neveinek elrejtése</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+in/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Pemeran: %s</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Poster</string>\n    <string name=\"episode_poster_img_des\">Poster Episode</string>\n    <string name=\"home_main_poster_img_des\">Poster Utama</string>\n    <string name=\"home_next_random_img_des\">Acak selanjutnya</string>\n    <string name=\"go_back_img_des\">Kembali</string>\n    <string name=\"home_change_provider_img_des\">Ganti Penyedia</string>\n    <string name=\"preview_background_img_des\">Pratinjau Latar Belakang</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Kecepatan (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Nilai: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Pembaruan ditemukan!\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Filler</string>\n    <string name=\"duration_format\" formatted=\"true\">%d mnt</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Beranda</string>\n    <string name=\"title_search\">Cari</string>\n    <string name=\"title_downloads\">Unduhan</string>\n    <string name=\"title_settings\">Pengaturan</string>\n    <string name=\"search_hint\">Cari…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Cari %s…</string>\n    <string name=\"no_data\">Tidak Ada Data</string>\n    <string name=\"episode_more_options_des\">Opsi Lainnya</string>\n    <string name=\"next_episode\">Episode selanjutnya</string>\n    <string name=\"result_tags\">Genre</string>\n    <string name=\"result_share\">Bagikan</string>\n    <string name=\"result_open_in_browser\">Buka di Peramban</string>\n    <string name=\"skip_loading\">Lewati Pemuatan</string>\n    <string name=\"loading\">Memuat…</string>\n    <string name=\"type_watching\">Sedang Ditonton</string>\n    <string name=\"type_on_hold\">Ditunda</string>\n    <string name=\"type_completed\">Selesai</string>\n    <string name=\"type_dropped\">Dihentikan</string>\n    <string name=\"type_plan_to_watch\">Ingin Ditonton</string>\n    <string name=\"type_re_watching\">Ditonton Ulang</string>\n    <string name=\"play_movie_button\">Putar Film</string>\n    <string name=\"play_torrent_button\">Stream Torrent</string>\n    <string name=\"pick_source\">Sumber</string>\n    <string name=\"pick_subtitle\">Subtitel</string>\n    <string name=\"reload_error\">Coba ulang koneksi…</string>\n    <string name=\"go_back\">Kembali</string>\n    <string name=\"play_episode\">Putar Episode</string>\n    <!--<string name=\"need_storage\">Allow to download episodes</string>-->\n    <string name=\"download\">Unduh</string>\n    <string name=\"downloaded\">Terunduh</string>\n    <string name=\"downloading\">Mengunduh</string>\n    <string name=\"download_paused\">Unduhan dijeda</string>\n    <string name=\"download_started\">Unduhan dimulai</string>\n    <string name=\"download_failed\">Unduhan gagal</string>\n    <string name=\"download_canceled\">Unduhan diibatalkan</string>\n    <string name=\"download_done\">Unduhan selesai</string>\n    <string name=\"error_loading_links_toast\">Galat Memuat Tautan</string>\n    <string name=\"download_storage_text\">Penyimpanan Internal</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Hapus Berkas</string>\n    <string name=\"popup_play_file\">Putar Berkas</string>\n    <string name=\"popup_resume_download\">Lanjutkan unduhan</string>\n    <string name=\"popup_pause_download\">Jeda unduhan</string>\n    <string name=\"home_more_info\">Lebih banyak info</string>\n    <string name=\"home_expanded_hide\">Sembunyikan</string>\n    <string name=\"home_play\">Putar</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"filter_bookmarks\">Filter Markah</string>\n    <string name=\"error_bookmarks_text\">Markah</string>\n    <string name=\"action_remove_from_bookmarks\">Hapus</string>\n    <string name=\"action_add_to_bookmarks\">Atur status tontonan</string>\n    <string name=\"sort_apply\">Terapkan</string>\n    <string name=\"sort_copy\">Salin</string>\n    <string name=\"sort_close\">Tutup</string>\n    <string name=\"sort_clear\">Bersihkan</string>\n    <string name=\"sort_save\">Simpan</string>\n    <string name=\"player_speed\">Kecepatan Pemutar</string>\n    <string name=\"subtitles_settings\">Pengaturan Subtitel</string>\n    <string name=\"subs_text_color\">Warna Teks</string>\n    <string name=\"subs_outline_color\">Warna Garis Luar</string>\n    <string name=\"subs_background_color\">Warna Latar Belakang</string>\n    <string name=\"subs_window_color\">Warna Jendela</string>\n    <string name=\"subs_edge_type\">Jenis Tepi</string>\n    <string name=\"subs_subtitle_elevation\">Ketinggian Subtitel</string>\n    <string name=\"subs_font\">Fonta</string>\n    <string name=\"subs_font_size\">Ukuran Fonta</string>\n    <string name=\"search_provider_text_providers\">Cari menggunakan penyedia</string>\n    <string name=\"search_provider_text_types\">Cari menggunakan jenis</string>\n    <string name=\"benene_count_text\">%d piseng diberikan kepada pengembang</string>\n    <string name=\"benene_count_text_none\">Tidak ada piseng yang diberikan</string>\n    <string name=\"subs_auto_select_language\">Pilih Bahasa Otomatis</string>\n    <string name=\"subs_download_languages\">Unduh Bahasa</string>\n    <string name=\"subs_hold_to_reset_to_default\">Tahan untuk mengatur ulang ke bawaan</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Impor fonta dengan meletakkan mereka di %s</string>\n    <string name=\"continue_watching\">Lanjutkan Menonton</string>\n    <string name=\"action_remove_watching\">Hapus</string>\n    <string name=\"action_open_watching\">Lebih banyak info</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">VPN mungkin diperlukan agar penyedia ini bisa bekerja dengan baik</string>\n    <string name=\"vpn_torrent\">Penyedia ini adalah torrent, VPN direkomendasikan</string>\n    <string name=\"provider_info_meta\">Metadata tidak disediakan oleh situs, pemuatan video akan gagal jika tidak ada di situs.</string>\n    <string name=\"torrent_plot\">Deskripsi</string>\n    <string name=\"normal_no_plot\">Plot Tidak Ditemukan</string>\n    <string name=\"torrent_no_plot\">Deskripsi Tidak Ditemukan</string>\n    <string name=\"show_log_cat\">Tampilkan Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Gambar-dalam-gambar</string>\n    <string name=\"picture_in_picture_des\">Lanjutkan pemutaran di pemutar mini di atas aplikasi lain</string>\n    <string name=\"player_size_settings\">Tombol ubah ukuran pemutar</string>\n    <string name=\"player_size_settings_des\">Hapus garis tepi hitam</string>\n    <string name=\"player_subtitles_settings\">Subtitel</string>\n    <string name=\"player_subtitles_settings_des\">Pengaturan subtitel pemutar</string>\n    <string name=\"chromecast_subtitles_settings\">Subtitel Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Pengaturan subtitel Chromecast</string>\n    <string name=\"eigengraumode_settings\">Kecepatan pemutaran</string>\n    <string name=\"swipe_to_seek_settings\">Geser untuk mengubah waktu</string>\n    <string name=\"swipe_to_seek_settings_des\">Geser dari sisi ke sisi untuk mengontrol posisi dalam video</string>\n    <string name=\"swipe_to_change_settings\">Geser untuk mengubah pengaturan</string>\n    <string name=\"swipe_to_change_settings_des\">Geser ke atas atau ke bawah di sisi kiri atau kanan untuk mengubah kecerahan atau volume</string>\n    <string name=\"double_tap_to_seek_settings\">Tekan dua kali untuk mengubah waktu</string>\n    <string name=\"double_tap_to_pause_settings\">Tekan dua kali untuk menjeda</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Jumlah pengubah waktu pemutar (Detik)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Tekan dua kali di sisi kanan atau kiri untuk mengubah waktu ke depan atau ke belakang</string>\n    <string name=\"double_tap_to_pause_settings_des\">Tekan dua kali di tengah untuk menjeda</string>\n    <string name=\"use_system_brightness_settings\">Gunakan kecerahan sistem</string>\n    <string name=\"use_system_brightness_settings_des\">Gunakan pencerahan sistem pada pemutar aplikasi daripada overlay gelap</string>\n    <string name=\"episode_sync_settings\">Perbarui progres tontonan</string>\n    <string name=\"episode_sync_settings_des\">Sinkronisasikan progres episode saat ini secara otomatis</string>\n    <string name=\"restore_settings\">Pulihkan data dari cadangan</string>\n    <string name=\"backup_settings\">Cadangkan data</string>\n    <string name=\"restore_success\">File cadangan termuat</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Gagal untuk memulihkan data dari file %s</string>\n    <string name=\"backup_success\">Data tersimpan</string>\n    <string name=\"backup_failed\">Izin penyimpanan tidak ditemukan, mohon coba lagi.</string>\n    <string name=\"backup_failed_error_format\">Gagal mencadangkan %s</string>\n    <string name=\"search\">Cari</string>\n    <string name=\"category_account\">Akun dan Keamanan</string>\n    <string name=\"category_updates\">Update dan Cadangan</string>\n    <string name=\"settings_info\">Info</string>\n    <string name=\"advanced_search\">Pencarian Lanjutan</string>\n    <string name=\"advanced_search_des\">Memberikan hasil pencarian yang dipisahkan berdasarkan penyedia</string>\n    <string name=\"show_fillers_settings\">Tampilkan episode filler untuk anime</string>\n    <string name=\"updates_settings\">Tampilkan pembaruan aplikasi</string>\n    <string name=\"updates_settings_des\">Secara otomatis mencari pembaruan baru setelah aplikasi dibuka.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Aplikasi novel ringan dari developer yang sama</string>\n    <string name=\"anim\">Aplikasi anime dari developer yang sama</string>\n    <string name=\"discord\">Bergabung dengan Discord</string>\n    <string name=\"benene\">Berikan sebuah piseng kepada developer</string>\n    <string name=\"benene_des\">Piseng yang diberikan</string>\n    <string name=\"app_language\">Bahasa Aplikasi</string>\n    <string name=\"no_chromecast_support_toast\">Penyedia ini tidak memiliki dukungan Chromecast</string>\n    <string name=\"no_links_found_toast\">Tidak Ada Tautan Yang Ditemukan</string>\n    <string name=\"copy_link_toast\">Tautan disalin ke papan klip</string>\n    <string name=\"play_episode_toast\">Putar Episode</string>\n    <string name=\"subs_default_reset_toast\">Ulang ke pengaturan default</string>\n    <string name=\"season\">Season</string>\n    <string name=\"no_season\">Tidak Ada Season</string>\n    <string name=\"episode\">Episode</string>\n    <string name=\"episodes\">Episode</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Episode Tidak Ditemukan</string>\n    <string name=\"delete_file\">Hapus File</string>\n    <string name=\"delete\">Hapus</string>\n    <string name=\"cancel\">Batalkan</string>\n    <string name=\"pause\">Jeda</string>\n    <string name=\"resume\">Lanjutkan</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Ini akan secara permanen menghapus %s\n\\nApakah anda yakin?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\ntersisa</string>\n    <string name=\"status_ongoing\">Masih Berlanjut</string>\n    <string name=\"status_completed\">Tamat</string>\n    <string name=\"status\">Status</string>\n    <string name=\"year\">Tahun</string>\n    <string name=\"rating\">Skor</string>\n    <string name=\"duration\">Durasi</string>\n    <string name=\"site\">Situs</string>\n    <string name=\"synopsis\">Sinopsis</string>\n    <string name=\"queued\">antri</string>\n    <string name=\"no_subtitles\">Tidak Ada Subtitel</string>\n    <string name=\"action_default\">Default</string>\n    <string name=\"free_storage\">Tersedia</string>\n    <string name=\"used_storage\">Terpakai</string>\n    <string name=\"app_storage\">Aplikasi</string>\n    <!--plural-->\n    <string name=\"movies\">Movie</string>\n    <string name=\"tv_series\">Seri TV</string>\n    <string name=\"cartoons\">Kartun</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrent</string>\n    <string name=\"documentaries\">Film Dokumenter</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Drama Asia</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Movie</string>\n    <string name=\"tv_series_singular\">Seri</string>\n    <string name=\"cartoons_singular\">Kartun</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Film Dokumenter</string>\n    <string name=\"asian_drama_singular\">Drama Asia</string>\n    <string name=\"source_error\">Error sumber</string>\n    <string name=\"remote_error\">Error jarak jauh</string>\n    <string name=\"render_error\">Error perender</string>\n    <string name=\"unexpected_error\">Error pemutar yang tidak terduga</string>\n    <string name=\"storage_error\">Galat unduh, periksa izin penyimpanan</string>\n    <string name=\"episode_action_chromecast_episode\">Episode Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Mirror Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Putar di aplikasi</string>\n    <string name=\"episode_action_play_in_format\">Putar di %s</string>\n    <string name=\"episode_action_auto_download\">Unduh otomatis</string>\n    <string name=\"episode_action_download_mirror\">Mirror unduh</string>\n    <string name=\"episode_action_reload_links\">Muat ulang tautan</string>\n    <string name=\"episode_action_download_subtitle\">Unduh subtitel</string>\n    <string name=\"show_hd\">Label kualitas</string>\n    <string name=\"show_dub\">Label dub</string>\n    <string name=\"show_sub\">Label sub</string>\n    <string name=\"show_title\">Judul</string>\n    <string name=\"poster_ui_settings\">Aktifkan atau nonaktifkan elemen UI pada poster</string>\n    <string name=\"no_update_found\">Tidak Ada Update Yang Ditemukan</string>\n    <string name=\"check_for_update\">Periksa pembaruan</string>\n    <string name=\"video_lock\">Kunci</string>\n    <string name=\"video_aspect_ratio_resize\">Ubah Ukuran</string>\n    <string name=\"video_source\">Sumber</string>\n    <string name=\"video_skip_op\">Skip OP</string>\n    <string name=\"dont_show_again\">Jangan tunjukkan lagi</string>\n    <string name=\"skip_update\">Skip Update ini</string>\n    <string name=\"update\">Update</string>\n    <string name=\"watch_quality_pref\">Kualitas nonton yang diinginkan (WiFi)</string>\n    <string name=\"limit_title\">Karakter maksimal judul pemutar video</string>\n    <string name=\"limit_title_rez\">Tampilkan informasi pemutar</string>\n    <string name=\"video_buffer_size_settings\">Ukuran buffer video</string>\n    <string name=\"video_buffer_length_settings\">Panjang buffer video</string>\n    <string name=\"video_buffer_disk_settings\">Cache video di disk</string>\n    <string name=\"video_buffer_clear_settings\">Membersihkan cache video dan gambar</string>\n    <string name=\"video_ram_description\">Dapat menyebabkan crash jika disetel terlalu tinggi. Jangan diubah jika perangkat anda memiliki jumlah RAM yang rendah, seperti TV Android atau ponsel lama.</string>\n    <string name=\"video_disk_description\">Dapat bermasalah pada sistem dengan ruang penyimpanan rendah, seperti Android TV, jika diatur terlalu tinggi.</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"dns_pref_summary\">Berguna untuk melewati blok ISP</string>\n    <string name=\"download_path_pref\">Lokasi unduhan</string>\n    <string name=\"nginx_url_pref\">NGINX server URL</string>\n    <string name=\"display_subbed_dubbed_settings\">Tampilkan Anime Dub/Sub</string>\n    <string name=\"resize_fit\">Paskan dengan layar</string>\n    <string name=\"resize_fill\">Regang</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"legal_notice\">Disclaimer</string>\n    <string name=\"category_general\">Umum</string>\n    <string name=\"random_button_settings\">Tombol Acak</string>\n    <string name=\"random_button_settings_desc\">Tampilkan tombol acak di Beranda dan Pustaka</string>\n    <string name=\"provider_lang_settings\">Bahasa ekstensi</string>\n    <string name=\"app_layout\">Tata Letak Aplikasi</string>\n    <string name=\"preferred_media_settings\">Preferensi media</string>\n    <string name=\"category_ui\">Antarmuka pengguna</string>\n    <string name=\"automatic\">Otomatis</string>\n    <string name=\"tv_layout\">Tata letak TV</string>\n    <string name=\"phone_layout\">Tata letak Ponsel</string>\n    <string name=\"emulator_layout\">Tata letak Emulator</string>\n    <string name=\"primary_color_settings\">Warna primer</string>\n    <string name=\"app_theme_settings\">Tema aplikasi</string>\n    <string name=\"bottom_title_settings\">Lokasi judul poster</string>\n    <string name=\"bottom_title_settings_des\">Meletakkan judul di bawah poster</string>\n    <!-- account stuff -->\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">akun</string>\n    <string name=\"logout\">Keluar</string>\n    <string name=\"login\">Masuk</string>\n    <string name=\"switch_account\">Ganti akun</string>\n    <string name=\"add_account\">Tambah akun</string>\n    <string name=\"add_sync\">Tambah pelacak</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Menambah %s</string>\n    <string name=\"upload_sync\">Sinkronisasi</string>\n    <string name=\"sync_score\">Skor</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s terautentikasi</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Gagal masuk ke %s</string>\n    <!-- ============ -->\n    <string name=\"none\">Tidak Ada</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">Semua</string>\n    <string name=\"max\">Maks</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Garis luar</string>\n    <string name=\"subtitles_depressed\">Ditekan</string>\n    <string name=\"subtitles_shadow\">Bayangan</string>\n    <string name=\"subtitles_raised\">Menonjol</string>\n    <string name=\"subtitle_offset\">Sinkronisasi sub</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Penundaan subtitel</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Gunakan ini jika subtitel ditampilkan %d ms terlalu cepat</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Gunakan ini jika subtitel ditampilkan %d ms terlalu lambat</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Tidak ada penundaan subtitel</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">The quick brown fox jumps over the lazy dog</string>\n    <string name=\"recommended\">Direkomendasikan</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Memuat %s</string>\n    <string name=\"player_load_subtitles\">Muat dari file</string>\n    <string name=\"downloaded_file\">Berkas terunduh</string>\n    <string name=\"actor_main\">Utama</string>\n    <string name=\"actor_supporting\">Pendukung</string>\n    <string name=\"actor_background\">Latar Belakang</string>\n    <string name=\"home_source\">Sumber</string>\n    <string name=\"home_random\">Acak</string>\n    <string name=\"coming_soon\">Segera hadir…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Gambar Poster</string>\n    <string name=\"category_player\">Pemutar</string>\n    <string name=\"resolution_and_title\">Resolusi dan judul</string>\n    <string name=\"title\">Judul</string>\n    <string name=\"resolution\">Resolusi</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dj %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episode %d akan dirilis tanggal</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dh %2$dj %3$dm</string>\n    <string name=\"automatic_plugin_updates\">Pembaruan plugin otomatis</string>\n    <string name=\"automatic_plugin_download\">Unduh plugin secara otomatis</string>\n    <string name=\"kitsu_settings\">Tampilkan poster dari Kitsu</string>\n    <string name=\"automatic_plugin_download_summary\">Pasang otomatis semua plugin yang belum terpasang dari repositori yang ditambahkan.</string>\n    <string name=\"live_singular\">Siaran langsung</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"example_password\">password123</string>\n    <string name=\"category_providers\">Penyedia</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_player_features\">Fitur Pemutar</string>\n    <string name=\"pref_category_subtitles\">Bahasa</string>\n    <string name=\"pref_category_player_layout\">Tampilan</string>\n    <string name=\"pref_category_defaults\">Bawaan</string>\n    <string name=\"pref_category_looks\">Tampilan</string>\n    <string name=\"pref_category_ui_features\">Fitur</string>\n    <string name=\"enable_nsfw_on_providers\">Aktifkan NSFW pada ekstensi yang didukung</string>\n    <string name=\"play_trailer_button\">Putar Cuplikan</string>\n    <string name=\"play_livestream_button\">Putar Siaran Langsung</string>\n    <string name=\"stream\">Streaming jaringan</string>\n    <string name=\"subs_subtitle_languages\">Bahasa Subtitel</string>\n    <string name=\"autoplay_next_settings\">Putar otomatis episode selanjutnya</string>\n    <string name=\"autoplay_next_settings_des\">Putar episode selanjutnya, setelah ini berakhir</string>\n    <string name=\"show_trailers_settings\">Tampilkan cuplikan</string>\n    <string name=\"redo_setup_process\">Ulang proses pemasangan</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Lainnya</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"add_site_pref\">Duplikasi Website</string>\n    <string name=\"add_site_summary\">Duplikasi website yang telah ada, dengan alamat berbeda</string>\n    <string name=\"pref_category_links\">Tautan</string>\n    <string name=\"pref_category_app_updates\">Perbarui aplikasi</string>\n    <string name=\"pref_category_backup\">Cadangkan</string>\n    <string name=\"pref_category_extensions\">Ekstensi</string>\n    <string name=\"play_with_app_name\">Putar di CloudStream</string>\n    <string name=\"pref_filter_search_quality\">Sembunyikan kualitas video terpilih di pencarian</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"livestreams\">Siaran langsung</string>\n    <string name=\"remove_site_pref\">Hapus Website</string>\n    <string name=\"example_username\">Username</string>\n    <string name=\"example_email\">contoh@email.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NamaSitusBaru</string>\n    <string name=\"example_site_url\">https://contoh.com</string>\n    <string name=\"extras\">Ekstra</string>\n    <string name=\"preferred_media_subtext\">Apa yang ingin anda lihat</string>\n    <string name=\"plugin_deleted\">Plugin terhapus</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d plugin diperbarui</string>\n    <string name=\"view_public_repositories_button\">Lihat repositori komunitas</string>\n    <string name=\"view_public_repositories_button_short\">Daftar publik</string>\n    <string name=\"blank_repo_message\">CloudStream tidak memiliki situs yang terinstal secara default. Anda perlu menginstal situs-situs dari repositori.\n\\n\n\\nBergabunglah dengan Discord kami atau cari secara online.</string>\n    <string name=\"repository_url_hint\">URL Repositori atau Kode Pendek</string>\n    <string name=\"create_account\">Buat Akun</string>\n    <string name=\"error\">Error</string>\n    <string name=\"subtitles_filter_lang\">Filter berdasarkan bahasa media pilihan</string>\n    <string name=\"trailer\">Cuplikan</string>\n    <string name=\"plugin_loaded\">Plugin terpasang</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Plugin %s gagal diambil</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"repository_name_hint\">Nama repositori (Opsional)</string>\n    <string name=\"plugin_singular\">plugin</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Semua %s telah terunduh</string>\n    <string name=\"batch_download\">Unduh bersamaan</string>\n    <string name=\"plugin\">plugin</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Tidak aktif: %d</string>\n    <string name=\"uppercase_all_subtitles\">Gunakan huruf besar untuk semua subtitel</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Terunduh: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Tidak terunduh: %d</string>\n    <string name=\"download_all_plugins_from_repo\">Peringatan: CloudStream 3 tidak bertanggung jawab atas penggunaan ekstensi pihak ketiga dan tidak menyediakan dukungan apa pun untuk ekstensi tersebut!</string>\n    <string name=\"safe_mode_title\">Mode aman aktif</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Tidak aktif)</string>\n    <string name=\"tracks\">Trek</string>\n    <string name=\"apply_on_restart\">Mulai ulang aplikasi untuk melihat perubahan.</string>\n    <string name=\"extension_description\">Keterangan</string>\n    <string name=\"extension_version\">Versi</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"safe_mode_crash_info\">Lihat log crash</string>\n    <string name=\"extension_rating\" formatted=\"true\">Peringkat: %s</string>\n    <string name=\"extension_authors\">Pembuat</string>\n    <string name=\"extension_language\">Bahasa</string>\n    <string name=\"player_pref\">Pemutar video utama</string>\n    <string name=\"player_settings_play_in_app\">Pemutar Bawaan</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Terunduh %1$d %2$s</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Memulai mengunduh %1$d %2$s…</string>\n    <string name=\"safe_mode_description\">Semua fitur tambahkan dimatikan karena crash, untuk memudahkanmu mencari penyebab crash.</string>\n    <string name=\"example_lang_name\">Kode bahasa (en)</string>\n    <string name=\"player_load_subtitles_online\">Ambil dari internet</string>\n    <string name=\"provider_languages_tip\">Putar video di bahasa ini</string>\n    <string name=\"add_repository\">Tambah repositori</string>\n    <string name=\"delete_repository_plugins\">Pilih ini untuk menghapus semua repositori plugin</string>\n    <string name=\"skip_setup\">Lewati pengaturan</string>\n    <string name=\"error_invalid_url\">URL salah</string>\n    <string name=\"network_adress_example\">https://contoh.com/contoh.mp4</string>\n    <string name=\"next\">Selanjutnya</string>\n    <string name=\"previous\">Sebelumnya</string>\n    <string name=\"app_layout_subtext\">Ubah tampilan aplikasi</string>\n    <string name=\"setup_done\">Selesai</string>\n    <string name=\"extensions\">Ekstensi</string>\n    <string name=\"delete_repository\">Hapus repositori</string>\n    <string name=\"setup_extensions_subtext\">Unduh semua situs yang ingin digunakan</string>\n    <string name=\"extension_size\">Ukuran</string>\n    <string name=\"error_invalid_id\">ID salah</string>\n    <string name=\"history\">Riwayat</string>\n    <string name=\"action_mark_as_watched\">Telah ditonton</string>\n    <string name=\"error_invalid_data\">Data salah</string>\n    <string name=\"subtitles_remove_captions\">Hapus closed caption dari subtitlel</string>\n    <string name=\"subtitles_remove_bloat\">Hapus teks tidak perlu pada subtitel</string>\n    <string name=\"audio_tracks\">Audio Trek</string>\n    <string name=\"video_tracks\">Video Trek</string>\n    <string name=\"extension_types\">Dukungan</string>\n    <string name=\"hls_playlist\">Daftar putar HLS</string>\n    <string name=\"apk_installer_settings\">Penginstal APK</string>\n    <string name=\"subtitles_encoding\">Enkode subtitel</string>\n    <string name=\"pref_category_gestures\">Gestur</string>\n    <string name=\"apk_installer_settings_des\">Beberapa perangkat tidak mendukung penginstal paket mode baru. Coba mode lama jika pembaruan tidak dapat diinstal.</string>\n    <string name=\"pref_category_actions\">Aksi</string>\n    <string name=\"referer\">Memberi referensi (opsional)</string>\n    <string name=\"yes\">Ya</string>\n    <string name=\"extension_install_first\">Install ekstensi terlebih dahulu</string>\n    <string name=\"all_languages_preference\">Semua Bahasa</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Lewati %s</string>\n    <string name=\"skip_type_op\">Pembuka</string>\n    <string name=\"skip_type_ed\">Sesi Akhir</string>\n    <string name=\"skip_type_recap\">Sinopsis</string>\n    <string name=\"skip_type_mixed_ed\">Sesi akhir ganda</string>\n    <string name=\"skip_type_creddits\">Sesi Kredit</string>\n    <string name=\"skip_type_intro\">Sesi Intro</string>\n    <string name=\"clipboard_too_large\">Terlalu banyak teks. Tidak dapat menyalin ke papan klip.</string>\n    <string name=\"confirm_exit_dialog\">Yakin ingin keluar?</string>\n    <string name=\"no\">Tidak</string>\n    <string name=\"update_notification_installing\">Memasang pembaruan…</string>\n    <string name=\"update_notification_failed\">Tidak dapat memasang versi terbaru</string>\n    <string name=\"app_not_found_error\">Aplikasi tidak ditemukan</string>\n    <string name=\"clear_history\">Hapus riwayat</string>\n    <string name=\"enable_skip_op_from_database_des\">Tampilkan popup untuk skip sesi pembuka/akhir</string>\n    <string name=\"update_notification_downloading\">Mengunduh pembaruan…</string>\n    <string name=\"apk_installer_legacy\">Versi lama</string>\n    <string name=\"skip_type_mixed_op\">Sesi pembuka ganda</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"plugin_downloaded\">Plugin terunduh</string>\n    <string name=\"delayed_update_notice\">Aplikasi akan diperbarui setelah keluar</string>\n    <string name=\"update_started\">Pembaruan Dimulai</string>\n    <string name=\"action_remove_from_watched\">Hapus dari tontonan</string>\n    <string name=\"browser\">Peramban</string>\n    <string name=\"select_library\">Pilih pustaka</string>\n    <string name=\"empty_library_no_accounts_message\">Yahh daftar pustaka kamu kosong :(\n\\nMasuk ke akun pustaka atau tambah perlihatkan ke lokal pustaka kamu.</string>\n    <string name=\"library\">Pustaka</string>\n    <string name=\"sort_by\">Urutkan berdasarkan</string>\n    <string name=\"sort\">Urutkan</string>\n    <string name=\"sort_rating_asc\">Peringkat (Rendah ke Tinggi)</string>\n    <string name=\"sort_updated_old\">Update (Lama ke Terbaru)</string>\n    <string name=\"sort_rating_desc\">Peringkat (Tinggi ke Rendah)</string>\n    <string name=\"sort_updated_new\">Update (Terbaru ke Lama)</string>\n    <string name=\"sort_alphabetical_a\">Abjad (A ke Z)</string>\n    <string name=\"sort_alphabetical_z\">Abjad (Z ke A)</string>\n    <string name=\"open_with\">Buka dengan</string>\n    <string name=\"empty_library_logged_in_message\">Yahh daftar ini kosong. Coba ganti ke yang lain.</string>\n    <string name=\"safe_mode_file\">Mode aman file ditemukan!\n\\nTidak memuat ekstensi pada startup sampai berkas dihapus.</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Sembunyikan Pemutaran - Geser</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Pemutar terlihat - Geser</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Geser untuk menghilangkan</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Geser untuk menghilangkan</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"test_passed\">Berhasil</string>\n    <string name=\"category_provider_test\">Tes penyedia</string>\n    <string name=\"stop\">Berhenti</string>\n    <string name=\"start\">Mulai</string>\n    <string name=\"restart\">Mulai ulang</string>\n    <string name=\"test_failed\">Gagal</string>\n    <string name=\"subscription_in_progress_notification\">Memperbarui acara langganan</string>\n    <string name=\"subscription_list_name\">Berlangganan</string>\n    <string name=\"subscription_new\">Berlangganan ke %s</string>\n    <string name=\"subscription_deleted\">Berhenti berlangganan di %s</string>\n    <string name=\"subscription_episode_released\">Episode %d telah rilis!</string>\n    <string name=\"jsdelivr_proxy\">Proxy GitHub</string>\n    <string name=\"jsdelivr_enabled\">Gagal terhubung ke GitHub. Mengaktifkan proksi jsDelivr…</string>\n    <string name=\"jsdelivr_proxy_summary\">Lewati pemblokiran raw URL github menggunakan jsDelivr. Dapat menyebabkan pembaruan tertunda selama beberapa hari.</string>\n    <string name=\"pref_category_bypass\">Bypass ISP</string>\n    <string name=\"revert\">Pulihkan</string>\n    <string name=\"watch_quality_pref_data\">Kualitas nonton yang diinginkan (Data Seluler)</string>\n    <string name=\"mobile_data\">Data seluler</string>\n    <string name=\"help\">Bantuan</string>\n    <string name=\"quality_profile_help\">Di sini anda dapat mengubah sumber yang diurutkan. Jika video memiliki prioritas lebih tinggi, video tersebut akan muncul lebih tinggi dalam pemilihan sumber. Jumlah prioritas sumber dan prioritas kualitas adalah prioritas video.\n\\n\n\\nSumber A: 3\n\\nKualitas B: 7\n\\nAkan memiliki prioritas video yang digabung 10.\n\\n\n\\nCATATAN: Jika jumlahnya 10 atau lebih, pemain akan melewatkan pemuatan secara otomatis saat tautan dimuat!</string>\n    <string name=\"profile_number\">Profil %d</string>\n    <string name=\"wifi\">Wifi</string>\n    <string name=\"set_default\">Pengaturan default</string>\n    <string name=\"use\">Gunakan</string>\n    <string name=\"edit\">Edit</string>\n    <string name=\"profiles\">Profil</string>\n    <string name=\"qualities\">Kualitas</string>\n    <string name=\"profile_background_des\">Latar belakang profil</string>\n    <string name=\"unable_to_inflate\">UI tidak dapat dibuat dengan benar, ini adalah BUG UTAMA dan harus segera dilaporkan %s</string>\n    <string name=\"disable\">Nonaktif</string>\n    <string name=\"automatic_plugin_download_mode_title\">Pilih mode filter unduhan plugin</string>\n    <string name=\"no_plugins_found_error\">Tidak ada plugin yang ditemukan di repositori</string>\n    <string name=\"no_repository_found_error\">Repositori tidak ditemukan, periksa URL dan coba VPN</string>\n    <string name=\"already_voted\">Kamu sudah voting</string>\n    <string name=\"favorite_removed\">%s dihapus dari favorit</string>\n    <string name=\"favorites_list_name\">Favorit</string>\n    <string name=\"favorite_added\">%s ditambahkan ke favorit</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Item duplikat potensial telah ditemukan di pustaka Anda: \\n \\n%s \\n \\nApakah Anda tetap ingin menambahkan item ini, mengganti item yang sudah ada, atau membatalkan tindakan?</string>\n    <string name=\"backup_frequency\">Frekuensi pencadangan</string>\n    <string name=\"duplicate_title\">Ditemukan Potensi Duplikat</string>\n    <string name=\"lock_profile\">Kunci Profil</string>\n    <string name=\"action_add_to_favorites\">Tambahkan ke favorit</string>\n    <string name=\"duplicate_replace_all\">Timpa Semua</string>\n    <string name=\"pin_error_incorrect\">PIN Salah. Silahkan coba lagi.</string>\n    <string name=\"action_unsubscribe\">Unsubscribe</string>\n    <string name=\"pin_error_length\">PIN harus terdiri 4 karakter</string>\n    <string name=\"duplicate_replace\">Timpa</string>\n    <string name=\"duplicate_add\">Tambahkan</string>\n    <string name=\"action_subscribe\">Subscribe</string>\n    <string name=\"action_remove_from_favorites\">Hapus dari favorit</string>\n    <string name=\"select_an_account\">Pilih Akun</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Tampaknya item yang berpotensi duplikat sudah ada di pustaka Anda: \\'%s.\\' \\n \\nApakah Anda tetap ingin menambahkan item ini, mengganti item yang sudah ada, atau membatalkan tindakan?</string>\n    <string name=\"enter_pin\">Masukan PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">Masukkan PIN saat Ini</string>\n    <string name=\"logged_account\" formatted=\"true\">Masuk sebagai %s</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Masukan PIN untuk %s</string>\n    <string name=\"use_default_account\">Gunakan Akun Default</string>\n    <string name=\"skip_startup_account_select_pref\">Lewati pemilihan akun saat startup</string>\n    <string name=\"manage_accounts\">Kelola Akun</string>\n    <string name=\"edit_account\">Edit akun</string>\n    <string name=\"rotate_video\">Putar</string>\n    <string name=\"rotate_video_desc\">Menampilkan tombol sakelar untuk orientasi layar</string>\n    <string name=\"links_reloaded_toast\">Tautan Dimuat Ulang</string>\n    <string name=\"auto_rotate_video_desc\">Mengaktifkan peralihan otomatis orientasi layar berdasarkan orientasi video</string>\n    <string name=\"auto_rotate_video\">Putar otomatis</string>\n    <string name=\"result_search_tooltip\">Cari di ekstensi lainnya</string>\n    <string name=\"speed_setting_summary\">Menambahkan opsi kecepatan di pemutar</string>\n    <string name=\"test_extensions_summary\">Tes ini hanya untuk pengembang dan tidak memverifikasi atau membantag fungsi ekstensi apa pun.</string>\n    <string name=\"subscribe_tooltip\">Notifikasi episode baru</string>\n    <string name=\"recommendations_tooltip\">Tampilkan rekomendasi</string>\n    <string name=\"test_extensions\">Tes semua ekstensi</string>\n    <string name=\"biometric_warning\">Data CloudStream Anda telah dicadangkan. Meskipun peluang terjadinya kasus ini sangat kecil dan jarang terjadi, tetapi semua perangkat berperilaku berbeda. Jika Anda ada dalam situasi terburuk, misalnya gagal untuk mengakses aplikasi, segera hapus data aplikasi sepenuhnya dan pulihkan data cadangan. Kami mohon maaf atas segala ketidaknyamanan yang mungkin ditimbulkan.</string>\n    <string name=\"password_pin_authentication_title\">Otentikasi Kata Sandi/PIN</string>\n    <string name=\"biometric_unsupported\">Otentikasi biometrik tidak didukung di perangkat ini</string>\n    <string name=\"biometric_setting_summary\">Buka kunci aplikasi dengan Sidik Jari, Face ID, PIN, Pola, dan Kata Sandi.</string>\n    <string name=\"biometric_prompt_description\">Setelah beberapa kali gagal, perintah akan ditutup. Cukup mulai ulang aplikasi untuk mencoba lagi.</string>\n    <string name=\"unfavorite\">Batalkan favorit</string>\n    <string name=\"biometric_authentication_title\">Buka kunci CloudStream</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\ntersisa</string>\n    <string name=\"favorite\">Favorit</string>\n    <string name=\"biometric_setting\">Kunci dengan Biometrik</string>\n    <string name=\"repo_copy_label\">Nama dan URL repositori</string>\n    <string name=\"clipboard_permission_error\">Gagal mengakses Papan Klip, mohon coba lagi.</string>\n    <string name=\"toast_copied\">disalin!</string>\n    <string name=\"clipboard_unknown_error\">Gagal menyalin, mohon salin logcat dan hubungi pengembang aplikasi.</string>\n    <string name=\"ok\">Oke</string>\n    <string name=\"battery_dialog_title\">Nonaktifkan optimasi baterai</string>\n    <string name=\"app_unrestricted_toast\">Pemakaian baterai untuk aplikasi ini sudah diatur menjadi tidak dibatasi</string>\n    <string name=\"app_info_intent_error\">Gagal membuka info aplikasi CloudStream.</string>\n    <string name=\"music_singlar\">Musik</string>\n    <string name=\"audio_book_singular\">Buku Audio</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"battery_dialog_message\">Untuk memastikan unduhan dan pemberitahuan tanpa gangguan untuk acara TV berlangganan, CloudStream memerlukan izin untuk berjalan di latar belakang. Dengan menekan OK, Anda akan diperlihatkan dialog permintaan. Silakan tekan ‘Izinkan’.\\n\\nHarap dicatat, izin ini tidak berarti CS3 akan menguras baterai Anda. Aplikasi ini hanya akan beroperasi di latar belakang jika diperlukan, misalnya saat menerima notifikasi atau mengunduh video dari ekstensi resmi.</string>\n    <string name=\"reset_btn\">Mengatur ulang</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Musim %1$d Episode %2$d akan dirilis pada</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Akan datang di %s</string>\n    <string name=\"episode_action_cast_mirror\">Cermin Cast</string>\n    <string name=\"player_settings_select_cast_device\">Pilih perangkat cast</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"pref_category_security\">Keamanan</string>\n    <string name=\"pref_category_accounts\">Akun</string>\n    <string name=\"test_warning\">Hati hati</string>\n    <string name=\"device_pin_expired_message\">Kode PIN sudah kedaluwarsa!</string>\n    <string name=\"qr_image\">Gambar Kode QR</string>\n    <string name=\"dismiss\">Tutup</string>\n    <string name=\"device_pin_counter_text\">Kode kedaluwarsa dalam %1$dm %2$dd</string>\n    <string name=\"auth_locally\">Otorisasi Lokal</string>\n    <string name=\"device_pin_url_message\">Kunjungi <b>%s</b> di ponsel pintar atau komputer Anda dan masukkan kode di atas</string>\n    <string name=\"preview_seekbar\">Pratinjau bilah pencarian</string>\n    <string name=\"preview_seekbar_desc\">Aktifkan pratinjau gambar mini di bilah pencarian</string>\n    <string name=\"hide_player_control_names\">Sembunyikan Nama Kontrol Pemain</string>\n    <string name=\"open_downloaded_repo\">Buka repositori</string>\n    <string name=\"play_from_beginning_img_des\">Putar dari awal</string>\n    <string name=\"downloads_empty\">Tidak ada unduhan.</string>\n    <string name=\"open_local_video\">Buka video lokal</string>\n    <string name=\"sort_release_date_old\">Tanggal Rilis (Lama ke Baru)</string>\n    <string name=\"sort_release_date_new\">Tanggal Rilis (Baru ke Lama)</string>\n    <string name=\"downloads_delete_select\">Pilih item untuk Dihapus</string>\n    <string name=\"offline_file\">Tersedia untuk menonton luring</string>\n    <string name=\"select_all\">Pilih Semua</string>\n    <string name=\"deselect_all\">Batal Pilih Semua</string>\n    <string name=\"delete_files\">Hapus File</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Apakah Anda yakin ingin menghapus item berikut secara permanen?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Apakah Anda yakin ingin menghapus episode berikut di %1$s secara permanen?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Anda juga akan menghapus semua episode dalam seri berikut secara permanen:\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Apakah Anda yakin ingin menghapus semua episode dalam seri berikut secara permanen?\n\\n\n\\n%s</string>\n    <string name=\"delete_format\" formatted=\"true\">Hapus (%1$d | %2$s)</string>\n    <string name=\"delete_plugin\">Hapus plugin</string>\n    <string name=\"device_pin_error_message\">Tidak bisa mendapatkan kode PIN perangkat, coba autentikasi lokal</string>\n    <string name=\"no_subtitles_loaded\">Belum ada subtitel yang dimuat</string>\n    <string name=\"subs_edge_size\">Ukuran Tepi</string>\n    <string name=\"torrent_info\">Video ini berformat Torrent, artinya aktivitas video Anda dapat dilacak.\\nPastikan Anda memahami Torrent sebelum melanjutkan.</string>\n    <string name=\"backup_path_title\">Lokasi folder cadangan</string>\n    <string name=\"custom\">Pilihan sendiri</string>\n    <string name=\"confirm_before_exiting_title\">Konfirmasi sebelum keluar</string>\n    <string name=\"confirm_before_exiting_desc\">Tampilkan dialog sebelum keluar dari aplikasi</string>\n    <string name=\"dont_show\">Jangan Tampilkan</string>\n    <string name=\"show\">Tampilkan</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"encoding_error\">Pengkodean error</string>\n    <string name=\"unsupported_error\">Error yang tidak didukung</string>\n    <string name=\"player_load_one_subtitle_online\">Muat yang pertama tersedia</string>\n    <string name=\"torrent_preferred_media\">Aktifkan torrent di dalam Pengaturan/Penyedia/Media pilihan</string>\n    <string name=\"torrent_not_accepted\">Mulai ulang aplikasi dan terima pop-up Stream Torrent untuk melanjutkan.</string>\n    <string name=\"software_decoding_desc\">Dekode perangkat lunak memungkinkan pemutar memainkan berkas video yang tidak didukung perangkat Anda, tetapi dapat memperburuk performa atau pemutaran yang tidak stabil pada resolusi tinggi.</string>\n    <string name=\"software_decoding\">Dekode perangkat lunak</string>\n    <string name=\"sort_episodes_rating_low_high\">Rating (Terendah)</string>\n    <string name=\"sort_button_date\">Tanggal %s</string>\n    <string name=\"sort_episodes_number_asc\">Episode (Naik)</string>\n    <string name=\"sort_episodes_number_desc\">Episode (Menurun)</string>\n    <string name=\"sort_episodes_rating_high_low\">Rating (Tertinggi)</string>\n    <string name=\"sort_episodes_date_newest\">Tanggal Tayang (Terbaru)</string>\n    <string name=\"sort_episodes_date_oldest\">Tanggal Tayang (Paling Lama)</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_rating\">Rating %s</string>\n    <string name=\"update_plugins\">Perbarui Plugin</string>\n    <string name=\"starting_plugin_update_manually\">Mulai proses pembaruan plugin!</string>\n    <string name=\"plugins_updated_manually\">Berhasil memperbarui %d plugin!</string>\n    <string name=\"update_plugins_manually\">Perbarui plugin secara manual</string>\n    <string name=\"no_plugins_updated_manually\">Tidak ada plugin yang diperbarui.</string>\n    <string name=\"player_notification_channel_description\">Pemberitahuan pemutar untuk mengontrol pemutaran dari latar belakang</string>\n    <string name=\"subtitles_from_online\">Daring</string>\n    <string name=\"begin_speaking\">Mulai bicara…</string>\n    <string name=\"subtitles_from_embedded\">Tertanam</string>\n    <string name=\"player_notification_channel_name\">Notifikasi pemain</string>\n    <string name=\"speech_recognition_unavailable\">Pengenalan ucapan tidak tersedia</string>\n    <string name=\"all_subtitles_bold\">Tebalkan semua subtitel</string>\n    <string name=\"all_subtitles_italic\">Miringkan semua subtitel</string>\n    <string name=\"background_radius\">Radius Latar Belakang</string>\n    <string name=\"volume_exceeded_100\">Volume telah melebihi 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Geser ke atas lagi untuk melampaui 100%</string>\n    <string name=\"player_settings_always_ask\">Selalu tanya</string>\n    <string name=\"download_parallel_settings_des\">Berapa banyak item yang bisa diunduh secara paralel</string>\n    <string name=\"parallel_downloads\">Pengunduhan paralel</string>\n    <string name=\"poster_size_settings_des\">Ubah ukuran poster</string>\n    <string name=\"poster_size_settings\">Ukuran poster</string>\n    <string name=\"speedup_summary\">Tahan untuk kecepatan 2x</string>\n    <string name=\"no_internet_connection\">Sambungan internet tidak tersedia.\\n\\nSilakan sambung ke internet dan coba lagi, atau tonton unduhan Anda saat sedang luring.</string>\n    <string name=\"overscan_settings_des\">Ubah batas layar</string>\n    <string name=\"go_to_downloads\">Kunjungi Unduhan</string>\n    <string name=\"concurrent_connections_settings_des\">Jumlah sambungan yang bisa digunakan secara bersamaan saat mengunduh</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dj %2$dm %3$dd</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$dd</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$dd</string>\n    <string name=\"show_rating\">Label Penilaian</string>\n    <string name=\"no_account\">Tidak ada akun</string>\n    <string name=\"concurrent_connections\">Koneksi bersamaan</string>\n    <string name=\"overscan_settings\">Pemotongan Layar Berlebih</string>\n    <string name=\"speedup_title\">Alih Kecepatan (tekan lama)</string>\n    <string name=\"edit_profile_image_title\">Sunting Gambar Profil</string>\n    <string name=\"edit_profile_image_hint\">Masukkan URL Gambar Profil</string>\n    <string name=\"edit_profile_image_error_empty\">URL Tidak Ditemukan</string>\n    <string name=\"edit_profile_image_error_invalid\">URL atau Gambar Tidak Valid</string>\n    <string name=\"edit_profile_image_success\">Gambar Profil Berhasil Diperbarui</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Tandai sebagai telah ditonton hingga episode ini</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Hapus penandaan telah ditonton hingga episode ini</string>\n    <string name=\"action_reload\">Dimuat Ulang</string>\n    <string name=\"reload_provider\">Muat Ulang Penyedia</string>\n    <string name=\"episode_action_play_mirror\">Putar mirror</string>\"\n    <string name=\"name\">Nama</string>\n    <string name=\"resolution_and_name\">Resolusi dan nama</string>\n    <string name=\"subs_subtitle_alignment\">Penyelarasan Subtitel</string>\n    <string name=\"bottom_left\">Bawah kiri</string>\n    <string name=\"bottom_center\">Bawah tengah</string>\n    <string name=\"bottom_right\">Bawah kanan</string>\n    <string name=\"middle_left\">Tengah kiri</string>\n    <string name=\"middle_center\">Tengah tengah</string>\n    <string name=\"middle_right\">Tengah kanan</string>\n    <string name=\"top_left\">Atas kiri</string>\n    <string name=\"top_center\">Atas tengah</string>\n    <string name=\"top_right\">Atas kanan</string>\n    <string name=\"play_full_series_button\">Putar Seri Penuh</string>\n    <string name=\"install_prerelease\">Pasang versi pra-rilis</string>\n    <string name=\"prerelease_already_installed\">Versi pra-rilis sudah terpasang.</string>\n    <string name=\"prerelease_install_failed\">Gagal memasang versi pra-rilis.</string>\n    <string name=\"show_episode_text\">Teks Episode</string>\n    <string name=\"extra_brightness_settings\">Kecerahan ekstra</string>\n    <string name=\"extra_brightness_settings_des\">Aktifkan filter kecerahan saat kecerahan layar melebihi 100%</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"clear_suggestions\">Hapus saran</string>\n    <string name=\"show_cast_in_details\">Tampilkan panel cast</string>\n    <string name=\"video_info\">Info media</string>\n    <string name=\"source_name\">Nama sumber</string>\n    <string name=\"search_suggestions\">Saran pencarian</string>\n    <string name=\"search_suggestions_des\">Tampilkan saran pencarian saat mengetik</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"other\">%d unduhan aktif</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"other\">%d unduhan dalam antrean</item>\n    </plurals>\n    <string name=\"download_queue\">Antrean unduhan</string>\n    <string name=\"queue_empty_message\">Tidak ada unduhan dalam antrean.</string>\n    <string name=\"source_priority\">Prioritas sumber</string>\n    <string name=\"source_priority_help\">Tentukan bagaimana sumber video harus diurutkan dalam pemutar</string>\n    <string name=\"download_all\">Unduh semua</string>\n    <string name=\"cancel_all\">Batalkan semua</string>\n    <string name=\"download_episode_range\">Apakah kamu ingin mengunduh episode %s?</string>\n    <string name=\"cancel_queue_message\">Apakah kamu ingin membatalkan semua unduhan dalam antrean?</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+it/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Cast: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">L\\'episodio %d uscirà in</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d min</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Poster</string>\n    <string name=\"episode_poster_img_des\">Poster episodio</string>\n    <string name=\"home_main_poster_img_des\">Poster principale</string>\n    <string name=\"home_next_random_img_des\">Prossimo casuale</string>\n    <string name=\"go_back_img_des\">Torna indietro</string>\n    <string name=\"home_change_provider_img_des\">Cambia provider</string>\n    <string name=\"preview_background_img_des\">Anteprima sfondo</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Velocità (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Valutato: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Nuovo aggiornamento trovato!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Filler</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <!-- <string name=\"app_name\">CloudStream</string> -->\n    <string name=\"play_with_app_name\">Riproduci con CloudStream</string>\n    <string name=\"title_home\">Home</string>\n    <string name=\"title_search\">Cerca</string>\n    <string name=\"title_downloads\">Scaricati</string>\n    <string name=\"title_settings\">Impostazioni</string>\n    <string name=\"search_hint\">Cerca…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Cerca in %s…</string>\n    <string name=\"no_data\">Nessun dato</string>\n    <string name=\"episode_more_options_des\">Più impostazioni</string>\n    <string name=\"next_episode\">Prossimo episodio</string>\n    <string name=\"result_tags\">Genere</string>\n    <string name=\"result_share\">Condividi</string>\n    <string name=\"result_open_in_browser\">Apri nel browser</string>\n    <string name=\"skip_loading\">Salta caricamento</string>\n    <string name=\"loading\">Caricamento…</string>\n    <string name=\"type_watching\">Guardando</string>\n    <string name=\"type_on_hold\">In attesa</string>\n    <string name=\"type_completed\">Completato</string>\n    <string name=\"type_dropped\">Abbandonato</string>\n    <string name=\"type_plan_to_watch\">Da guardare</string>\n    <string name=\"type_re_watching\">Riguardando</string>\n    <string name=\"play_movie_button\">Riproduci film</string>\n    <string name=\"play_livestream_button\">Riproduci Livestream</string>\n    <string name=\"play_torrent_button\">Stream Torrent</string>\n    <string name=\"pick_source\">Fonti</string>\n    <string name=\"pick_subtitle\">Sottotitoli</string>\n    <string name=\"reload_error\">Riprova connesisone…</string>\n    <string name=\"go_back\">Indietro</string>\n    <string name=\"play_episode\">Riproduci episodio</string>\n    <string name=\"download\">Scarica</string>\n    <string name=\"downloaded\">Scaricato</string>\n    <string name=\"downloading\">Download in corso</string>\n    <string name=\"download_paused\">Download in pausa</string>\n    <string name=\"download_started\">Download iniziato</string>\n    <string name=\"download_failed\">Download fallito</string>\n    <string name=\"download_canceled\">Download cancellato</string>\n    <string name=\"download_done\">Download completato</string>\n    <string name=\"stream\">Flusso di rete</string>\n    <string name=\"error_loading_links_toast\">Errore durante il caricamento dei link</string>\n    <string name=\"download_storage_text\">Archiviazione interna</string>\n    <string name=\"app_dubbed_text\">Doppiato</string>\n    <string name=\"app_subbed_text\">Sottotitolato</string>\n    <string name=\"popup_delete_file\">Elimina file</string>\n    <string name=\"popup_play_file\">Riproduci file</string>\n    <string name=\"popup_resume_download\">Riprendi download</string>\n    <string name=\"popup_pause_download\">Ferma download</string>\n    <string name=\"home_more_info\">Più info</string>\n    <string name=\"home_expanded_hide\">Nascondi</string>\n    <string name=\"home_play\">Riproduci</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"filter_bookmarks\">Filtra segnalibri</string>\n    <string name=\"error_bookmarks_text\">Segnalibri</string>\n    <string name=\"action_remove_from_bookmarks\">Rimuovi</string>\n    <string name=\"action_add_to_bookmarks\">Imposta stato riproduzione</string>\n    <string name=\"sort_apply\">Applica</string>\n    <string name=\"sort_copy\">Copia</string>\n    <string name=\"sort_close\">Chiudi</string>\n    <string name=\"sort_clear\">Cancella</string>\n    <string name=\"sort_save\">Salva</string>\n    <string name=\"player_speed\">Velocità lettore</string>\n    <string name=\"subtitles_settings\">Impostazioni sottotitoli</string>\n    <string name=\"subs_text_color\">Colore testo</string>\n    <string name=\"subs_outline_color\">Colore contorno</string>\n    <string name=\"subs_background_color\">Colore sfondo</string>\n    <string name=\"subs_window_color\">Colore finestra</string>\n    <string name=\"subs_edge_type\">Tipo bordo</string>\n    <string name=\"subs_subtitle_elevation\">Elevazione sottotitolo</string>\n    <string name=\"subs_font\">Carattere</string>\n    <string name=\"subs_font_size\">Dimensione</string>\n    <string name=\"search_provider_text_providers\">Cerca per provider</string>\n    <string name=\"search_provider_text_types\">Cerca per tipo</string>\n    <string name=\"benene_count_text\">%d banane date agli sviluppatori</string>\n    <string name=\"benene_count_text_none\">Nessuna banana data</string>\n    <string name=\"subs_auto_select_language\">Selezione automatica lingua</string>\n    <string name=\"subs_download_languages\">Lingue da scaricare</string>\n    <string name=\"subs_subtitle_languages\">Lingue sottotitoli</string>\n    <string name=\"subs_hold_to_reset_to_default\">Tenere premuto per ripristinare le impostazioni predefinite</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importa font mettendoli in %s</string>\n    <string name=\"continue_watching\">Continua a guardare</string>\n    <string name=\"action_remove_watching\">Rimuovi</string>\n    <string name=\"action_open_watching\">Più info</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Potrebbe essere necessaria una VPN per far funzionare correttamente questo provider</string>\n    <string name=\"vpn_torrent\">Questo provider è un torrent, si raccomanda una VPN</string>\n    <string name=\"provider_info_meta\">I metadati non sono forniti dal sito, il caricamento del video fallirà se non esiste sul sito.</string>\n    <string name=\"torrent_plot\">Descrizione</string>\n    <string name=\"normal_no_plot\">Nessuna trama trovata</string>\n    <string name=\"torrent_no_plot\">Nessuna descrizione trovata</string>\n    <string name=\"show_log_cat\">Mostra Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Picture-in-Picture</string>\n    <string name=\"picture_in_picture_des\">Continua la riproduzione in un lettore in miniatura sopra altre applicazioni</string>\n    <string name=\"player_size_settings\">Pulsante di ridimensionamento del video</string>\n    <string name=\"player_size_settings_des\">Rimuovi bordi neri</string>\n    <string name=\"player_subtitles_settings\">Sottotitoli</string>\n    <string name=\"player_subtitles_settings_des\">Impostazioni sottotitoli lettore</string>\n    <string name=\"chromecast_subtitles_settings\">Sottotitoli Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Impostazioni sottotitoli Chromecast</string>\n    <string name=\"eigengraumode_settings\">Velocità di riproduzione</string>\n    <string name=\"swipe_to_seek_settings\">Scorri per mandare avanti/indietro</string>\n    <string name=\"swipe_to_seek_settings_des\">Scorri da un lato all\\'altro per controllare la tua posizione in un video</string>\n    <string name=\"swipe_to_change_settings\">Scorri per cambiare le impostazioni</string>\n    <string name=\"swipe_to_change_settings_des\">Scorri il dito sul lato sinistro o destro per cambiare la luminosità o il volume</string>\n    <string name=\"autoplay_next_settings\">Riproduci automaticamente l\\'episodio successivo</string>\n    <string name=\"autoplay_next_settings_des\">Avvia l\\'episodio successivo al termine di quello in corso</string>\n    <string name=\"double_tap_to_seek_settings\">Doppio tocco per andare avanti/indietro</string>\n    <string name=\"double_tap_to_pause_settings\">Doppio tocco per mettere in pausa</string>\n    <string name=\"double_tap_to_seek_settings_des\">Tocca due volte il lato destro o sinistro dello schermo per mandare avanti o indietro il video</string>\n    <string name=\"double_tap_to_pause_settings_des\">Tocca due volte al centro per mettere in pausa</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Intervallo di avanzamento nel lettore (secondi)</string>\n    <string name=\"use_system_brightness_settings\">Usa luminosità del sistema</string>\n    <string name=\"use_system_brightness_settings_des\">Utilizza la luminosità del sistema nel lettore dell\\'app anziché una sovrapposizione scura</string>\n    <!--<string name=\"episode_sync_settings\">Update watch progress</string>-->\n    <string name=\"episode_sync_settings_des\">Sincronizza automaticamente gli episodi guardati</string>\n    <string name=\"restore_settings\">Ripristina dati da un backup</string>\n    <string name=\"backup_settings\">Backup dei dati</string>\n    <string name=\"restore_success\">File di backup caricato</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Impossibile ripristinare i dati dal file %s</string>\n    <string name=\"backup_success\">Dati salvati</string>\n    <string name=\"backup_failed\">Permessi di archiviazione mancanti. Per favore riprova.</string>\n    <string name=\"backup_failed_error_format\">Errore nel backup %s</string>\n    <string name=\"search\">Cerca</string>\n    <string name=\"category_account\">Account e sicurezza</string>\n    <string name=\"category_updates\">Aggiornamenti e Backup</string>\n    <string name=\"settings_info\">Info</string>\n    <string name=\"advanced_search\">Ricerca avanzata</string>\n    <string name=\"advanced_search_des\">Dividi i risultati della ricerca per provider</string>\n    <string name=\"show_fillers_settings\">Mostra tag [filler] per anime</string>\n    <string name=\"show_trailers_settings\">Mostra trailer</string>\n    <string name=\"kitsu_settings\">Mostra poster da Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Nascondi la qualità video selezionata dai risultati di ricerca</string>\n    <string name=\"automatic_plugin_updates\">Aggiorna automaticamente i plugin</string>\n    <string name=\"updates_settings\">Mostra gli aggiornamenti dell\\'app</string>\n    <string name=\"updates_settings_des\">Cerca automaticamente nuovi aggiornamenti dopo aver avviato l\\'app.</string>\n    <string name=\"github\">GitHub</string>\n    <string name=\"lightnovel\">App per Light Novel degli stessi sviluppatori</string>\n    <string name=\"anim\">App per Anime degli stessi sviluppatori</string>\n    <string name=\"discord\">Entra in Discord</string>\n    <string name=\"benene\">Dai una banana agli sviluppatori</string>\n    <string name=\"benene_des\">Dai una banana</string>\n    <string name=\"app_language\">Lingua app</string>\n    <string name=\"no_chromecast_support_toast\">Questo provider non ha il supporto per Chromecast</string>\n    <string name=\"no_links_found_toast\">Nessun link trovato</string>\n    <string name=\"copy_link_toast\">Link copiato negli appunti</string>\n    <string name=\"play_episode_toast\">Riproduci episodio</string>\n    <string name=\"subs_default_reset_toast\">Ripristina il valore predefinito</string>\n    <string name=\"season\">Stagione</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Nessuna stagione</string>\n    <string name=\"episode\">Episodio</string>\n    <string name=\"episodes\">Episodi</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Nessun episodio trovato</string>\n    <string name=\"delete_file\">Elimina file</string>\n    <string name=\"delete\">Elimina</string>\n    <string name=\"cancel\">Annulla</string>\n    <string name=\"pause\">Pausa</string>\n    <string name=\"resume\">Riprendi</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Stai per eliminare permanentemente %s\n\\nSei sicuro?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nrimanenti</string>\n    <string name=\"status_ongoing\">In corso</string>\n    <string name=\"status_completed\">Completato</string>\n    <string name=\"status\">Stato</string>\n    <string name=\"year\">Anno</string>\n    <string name=\"rating\">Valutazione</string>\n    <string name=\"duration\">Durata</string>\n    <string name=\"site\">Sito</string>\n    <string name=\"synopsis\">Sinossi</string>\n    <string name=\"queued\">In coda</string>\n    <string name=\"no_subtitles\">Nessun sottotiolo</string>\n    <string name=\"action_default\">Default</string>\n    <string name=\"free_storage\">Libero</string>\n    <string name=\"used_storage\">Usato</string>\n    <string name=\"app_storage\">App</string>\n    <!--plural-->\n    <string name=\"movies\">Film</string>\n    <string name=\"tv_series\">Serie TV</string>\n    <string name=\"cartoons\">Cartone</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"torrent\">Torrent</string>\n    <string name=\"documentaries\">Documentari</string>\n    <string name=\"asian_drama\">Drammi asiatici</string>\n    <string name=\"livestreams\">Livestreams</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Altri</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Serie</string>\n    <string name=\"cartoons_singular\">Cartoni</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Documentario</string>\n    <string name=\"asian_drama_singular\">Dramma asiatico</string>\n    <string name=\"live_singular\">Livestream</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Altro</string>\n    <string name=\"source_error\">Errore sorgente</string>\n    <string name=\"remote_error\">Errore remoto</string>\n    <string name=\"render_error\">Errore del renderer</string>\n    <string name=\"unexpected_error\">Errore imprevisto del lettore</string>\n    <string name=\"storage_error\">Errore download, controlla i permessi di archiviazione</string>\n    <string name=\"episode_action_chromecast_episode\">Episodio Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Mirror Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Riproduci nell\\'app</string>\n    <string name=\"episode_action_play_in_format\">Riproduci in %s</string>\n    <string name=\"episode_action_auto_download\">Download automatico</string>\n    <string name=\"episode_action_download_mirror\">Mirror download</string>\n    <string name=\"episode_action_reload_links\">Ricarica link</string>\n    <string name=\"episode_action_download_subtitle\">Download sottotitoli</string>\n    <string name=\"show_hd\">Etichetta qualità</string>\n    <string name=\"show_dub\">Etichetta dub</string>\n    <string name=\"show_sub\">Etichetta sub</string>\n    <string name=\"show_title\">Titolo</string>\n    <string name=\"poster_ui_settings\">Attiva/disattiva elementi dell\\'UI sul poster</string>\n    <string name=\"no_update_found\">Nessun aggiornamento trovato</string>\n    <string name=\"check_for_update\">Controlla aggiornamenti</string>\n    <string name=\"video_lock\">Blocca</string>\n    <string name=\"video_aspect_ratio_resize\">Ridimensiona</string>\n    <string name=\"video_source\">Sorgente</string>\n    <string name=\"video_skip_op\">Salta OP</string>\n    <string name=\"dont_show_again\">Non mostrare di nuovo</string>\n    <string name=\"skip_update\">Salta questo aggiornamento</string>\n    <string name=\"update\">Aggiorna</string>\n    <string name=\"watch_quality_pref\">Qualità di visualizzazione preferita (WiFi)</string>\n    <string name=\"limit_title\">Limita i caratteri del titolo nel lettore</string>\n    <string name=\"limit_title_rez\">Mostra informazioni sul lettore</string>\n    <string name=\"video_buffer_size_settings\">Dimensione cache video</string>\n    <string name=\"video_buffer_length_settings\">Lunghezza buffer video</string>\n    <string name=\"video_buffer_disk_settings\">Dimensione cache video su disco</string>\n    <string name=\"video_buffer_clear_settings\">Cancella cache immagini e video</string>\n    <string name=\"video_ram_description\">Causa arresti anomali se impostato troppo alto sui dispositivi con poca memoria, come Android TV.</string>\n    <string name=\"video_disk_description\">Se impostato troppo alto può causare problemi su sistemi con poca archiviazione interna, come i dispositivi Android TV.</string>\n    <string name=\"dns_pref\">DNS su HTTPS</string>\n    <string name=\"dns_pref_summary\">Utile per aggirare i blocchi ISP</string>\n    <string name=\"add_site_pref\">Clona un sito</string>\n    <string name=\"remove_site_pref\">Rimuovi sito</string>\n    <string name=\"add_site_summary\">Aggiungi un clone di un sito esistente, con un URL differente</string>\n    <string name=\"download_path_pref\">Percorso di download</string>\n    <string name=\"nginx_url_pref\">URL server NGINX</string>\n    <string name=\"display_subbed_dubbed_settings\">Mostra anime doppiati/sottotitolati</string>\n    <string name=\"resize_fit\">Adatta allo schermo</string>\n    <string name=\"resize_fill\">Allunga</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"legal_notice\">Avvertenza</string>\n    <string name=\"category_general\">Generale</string>\n    <string name=\"random_button_settings\">Random</string>\n    <string name=\"random_button_settings_desc\">Mostra pulsante casuale nella home page e nella libreria</string>\n    <string name=\"provider_lang_settings\">Lingue estensione</string>\n    <string name=\"app_layout\">Layout app</string>\n    <string name=\"preferred_media_settings\">Media preferito</string>\n    <string name=\"enable_nsfw_on_providers\">Abilita NSFW sulle estensioni supportate</string>\n    <string name=\"subtitles_encoding\">Encoding Sottotitoli</string>\n    <string name=\"category_providers\">Provider</string>\n    <string name=\"category_ui\">Interfaccia utente</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"tv_layout\">Layout TV</string>\n    <string name=\"phone_layout\">Layout Telefono</string>\n    <string name=\"emulator_layout\">Layout Emulatore</string>\n    <string name=\"primary_color_settings\">Colore primario</string>\n    <string name=\"app_theme_settings\">Tema</string>\n    <string name=\"bottom_title_settings\">Posizione Titolo sui Poster</string>\n    <string name=\"bottom_title_settings_des\">Titolo sotto il poster</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">password123</string>\n    <string name=\"example_username\">Nome utente</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NuovoNomeSito</string>\n    <string name=\"example_site_url\">https://esempio.com</string>\n    <string name=\"example_lang_name\">Codice lingua (it)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">account</string>\n    <string name=\"logout\">Disconnetti</string>\n    <string name=\"login\">Accedi</string>\n    <string name=\"switch_account\">Cambia account</string>\n    <string name=\"add_account\">Aggiungi account</string>\n    <string name=\"create_account\">Crea un account</string>\n    <string name=\"add_sync\">Aggiungi tracciamento</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Aggiunto %s</string>\n    <string name=\"upload_sync\">Sincronizza</string>\n    <string name=\"sync_score\">Valutato</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s autenticato</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Impossibile effettuare l\\'accesso a %s</string>\n    <!-- ============ -->\n    <string name=\"none\">Nessuno</string>\n    <string name=\"normal\">Normale</string>\n    <string name=\"all\">Tutto</string>\n    <string name=\"max\">Max</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Contorno</string>\n    <string name=\"subtitles_depressed\">Bassorilievo</string>\n    <string name=\"subtitles_shadow\">Ombra</string>\n    <string name=\"subtitles_raised\">Rilievo</string>\n    <string name=\"subtitle_offset\">Sincronizza sottotitoli</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Ritardo sottotitoli</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Usalo se i sottotitoli vengono mostrati %d ms in anticipo</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Usalo se i sottotitoli vengono mostrati %d ms in ritardo</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Nessun ritardo dei sottotitoli</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">Ma che bel gufo spenzola da quei travi</string>\n    <string name=\"recommended\">Consigliato</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Caricato %s</string>\n    <string name=\"player_load_subtitles\">Carica da file</string>\n    <string name=\"player_load_subtitles_online\">Carica da Internet</string>\n    <string name=\"downloaded_file\">File scaricato</string>\n    <string name=\"actor_main\">Protagonista</string>\n    <string name=\"actor_supporting\">Supporto</string>\n    <string name=\"actor_background\">Secondario</string>\n    <string name=\"home_source\">Sorgente</string>\n    <string name=\"home_random\">Casuale</string>\n    <string name=\"coming_soon\">Prossimamente…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Poster</string>\n    <string name=\"category_player\">Lettore</string>\n    <string name=\"resolution_and_title\">Risoluzione e titolo</string>\n    <string name=\"title\">Titolo</string>\n    <string name=\"resolution\">Risoluzione</string>\n    <string name=\"error_invalid_id\">ID non valido</string>\n    <string name=\"error_invalid_data\">Dati non validi</string>\n    <string name=\"error_invalid_url\">URL non valido</string>\n    <string name=\"error\">Errore</string>\n    <!--<string name=\"subtitles_remove_captions\">Remove closed captions from subtitles</string>-->\n    <!--<string name=\"subtitles_remove_bloat\">Remove bloat from subtitles</string>-->\n    <string name=\"subtitles_filter_lang\">Filtra in base alla lingua preferita</string>\n    <string name=\"extras\">Extra</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"network_adress_example\">https://esempio.com/esempio.mp4</string>\n    <string name=\"referer\">Referente (facoltativo)</string>\n    <string name=\"next\">Prossimo</string>\n    <string name=\"provider_languages_tip\">Guarda video in queste lingue</string>\n    <string name=\"previous\">Precedente</string>\n    <string name=\"skip_setup\">Salta configurazione</string>\n    <string name=\"app_layout_subtext\">Cambia l\\'aspetto dell\\'app per adattarla al proprio dispositivo</string>\n    <string name=\"preferred_media_subtext\">Cosa vuoi vedere</string>\n    <string name=\"setup_done\">Fatto</string>\n    <string name=\"extensions\">Estensioni</string>\n    <string name=\"add_repository\">Aggiungi repository</string>\n    <string name=\"repository_name_hint\">Nome repository (facoltativo)</string>\n    <string name=\"repository_url_hint\">URL repository o shortcode</string>\n    <string name=\"plugin_loaded\">Plugin caricato</string>\n    <string name=\"plugin_deleted\">Plugin eliminato</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Impossibile caricare %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Avviato il download di %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Scaricato %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Tutti %s già scaricati</string>\n    <string name=\"batch_download\">Download in blocco</string>\n    <string name=\"plugin_singular\">plugin</string>\n    <string name=\"plugin\">plugin</string>\n    <string name=\"delete_repository_plugins\">Questo eliminerà anche tutti i plugin del repository</string>\n    <string name=\"delete_repository\">Elimina repository</string>\n    <string name=\"setup_extensions_subtext\">Scarica la lista dei siti che vuoi usare</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Scaricato: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Disabilitato: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Non scaricato: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Aggiornati %d plugin</string>\n    <string name=\"blank_repo_message\">CloudStream non ha siti installati per impostazione predefinita. È necessario installare i siti dai repository.\n\\n\n\\nUnisciti al nostro Discord o cerca online.</string>\n    <string name=\"view_public_repositories_button\">Visualizza i repository della comunità</string>\n    <string name=\"view_public_repositories_button_short\">Lista pubblica</string>\n    <string name=\"uppercase_all_subtitles\">Tutti i sottotitoli in maiuscolo</string>\n    <string name=\"download_all_plugins_from_repo\">Attenzione: CloudStream non si assume alcuna responsabilità per l\\'utilizzo di estensioni di terze parti e non fornisce alcun supporto per esse!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Disabilitato)</string>\n    <string name=\"tracks\">Tracce</string>\n    <string name=\"audio_tracks\">Traccia audio</string>\n    <string name=\"video_tracks\">Traccia video</string>\n    <string name=\"apply_on_restart\">Riavvia app per visualizzare le modifiche.</string>\n    <string name=\"safe_mode_title\">Safe mode attiva</string>\n    <string name=\"safe_mode_description\">Tutte le estensioni sono state disabilitate a causa di un arresto anomalo per aiutarti a trovare l\\'estensione che causa il problema.</string>\n    <string name=\"safe_mode_crash_info\">Vedi informazioni del crash</string>\n    <string name=\"extension_rating\" formatted=\"true\">Voto: %s</string>\n    <string name=\"extension_description\">Descrizione</string>\n    <string name=\"extension_version\">Versione</string>\n    <string name=\"extension_status\">Stato</string>\n    <string name=\"extension_size\">Dimensione</string>\n    <string name=\"extension_authors\">Autori</string>\n    <string name=\"extension_types\">Supportati</string>\n    <string name=\"extension_language\">Lingua</string>\n    <string name=\"extension_install_first\">Prima installa l\\'estensione</string>\n    <string name=\"hls_playlist\">Playlist HLS</string>\n    <string name=\"player_pref\">Video lettore preferito</string>\n    <string name=\"player_settings_play_in_app\">Lettore interno</string>\n    <string name=\"app_not_found_error\">App non trovata</string>\n    <string name=\"all_languages_preference\">Tutte le lingue</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Salta %s</string>\n    <!--<string name=\"skip_type_op\">Opening</string>-->\n    <!--<string name=\"skip_type_ed\">Ending</string>-->\n    <string name=\"skip_type_recap\">Riassunto</string>\n    <!--<string name=\"skip_type_mixed_ed\">Mixed ending</string>-->\n    <!--<string name=\"skip_type_mixed_op\">Mixed opening</string>-->\n    <string name=\"skip_type_creddits\">Crediti</string>\n    <!--<string name=\"skip_type_intro\">Intro</string>-->\n    <string name=\"clear_history\">Cancella cronologia</string>\n    <string name=\"history\">Cronologia</string>\n    <string name=\"enable_skip_op_from_database_des\">Mostra popup di salto per apertura/fine</string>\n    <string name=\"clipboard_too_large\">Testo troppo lungo. Impossibile salvare negli appunti.</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"automatic_plugin_download\">Scarica automaticamente i plugins</string>\n    <string name=\"update_notification_failed\">Impossibile installare la nuova versione dell\\'app</string>\n    <string name=\"episode_sync_settings\">Aggiorna progresso di visione</string>\n    <string name=\"skip_type_mixed_op\">Opening misto</string>\n    <string name=\"update_notification_installing\">Installazione aggiornamento dell\\'app…</string>\n    <string name=\"subtitles_remove_captions\">Rimuovi le didascalie chiuse dai sottotitoli</string>\n    <string name=\"subtitles_remove_bloat\">Rimuovi il bloat dai sottotitoli</string>\n    <string name=\"skip_type_op\">Opening</string>\n    <string name=\"skip_type_ed\">Ending</string>\n    <string name=\"skip_type_mixed_ed\">Ending misto</string>\n    <string name=\"skip_type_intro\">Intro</string>\n    <string name=\"action_mark_as_watched\">Segna come visto</string>\n    <string name=\"confirm_exit_dialog\">Sei sicuro di voler uscire?</string>\n    <string name=\"yes\">Sì</string>\n    <string name=\"no\">No</string>\n    <string name=\"update_notification_downloading\">Download aggiornamento dell\\'app…</string>\n    <string name=\"automatic_plugin_download_summary\">Installa automaticamente tutti i plugin non ancora installati dai repository aggiunti.</string>\n    <string name=\"apk_installer_package_installer\">ProgrammaInstallazionePacchetti</string>\n    <string name=\"apk_installer_settings_des\">Alcuni dispositivi non supportano il nuovo programma di installazione dei pacchetti. Se gli aggiornamenti non vengono installati, prova l\\'opzione legacy.</string>\n    <string name=\"apk_installer_settings\">Installer APK</string>\n    <string name=\"apk_installer_legacy\">Legacy</string>\n    <string name=\"play_trailer_button\">Riproduci trailer</string>\n    <string name=\"redo_setup_process\">Ripeti il processo di configurazione</string>\n    <string name=\"pref_category_links\">Link</string>\n    <string name=\"pref_category_app_updates\">Aggiornamenti app</string>\n    <string name=\"pref_category_backup\">Backup</string>\n    <string name=\"pref_category_extensions\">Estensioni</string>\n    <string name=\"pref_category_actions\">Azioni</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_gestures\">Gesti</string>\n    <string name=\"pref_category_player_features\">Funzionalità lettore</string>\n    <string name=\"pref_category_subtitles\">Sottotitoli</string>\n    <string name=\"pref_category_player_layout\">Disposizione</string>\n    <string name=\"pref_category_defaults\">Predefiniti</string>\n    <string name=\"pref_category_looks\">Aspetto</string>\n    <string name=\"pref_category_ui_features\">Funzionalità</string>\n    <string name=\"delayed_update_notice\">L\\'app verrà aggiornata all\\'uscita</string>\n    <string name=\"update_started\">Aggiornamento avviato</string>\n    <string name=\"plugin_downloaded\">Plugin scaricato</string>\n    <string name=\"action_remove_from_watched\">Rimuovi dai già visti</string>\n    <string name=\"browser\">Browser</string>\n    <string name=\"sort_by\">Ordina per</string>\n    <string name=\"sort_rating_desc\">Punteggio (Decrescente)</string>\n    <string name=\"sort_rating_asc\">Punteggio (Crescente)</string>\n    <string name=\"sort_updated_new\">Aggiornato (Da nuovo a vecchio)</string>\n    <string name=\"sort_updated_old\">Aggiornato (Da vecchio a nuovo)</string>\n    <string name=\"sort_alphabetical_a\">Alfabetico (A - Z)</string>\n    <string name=\"sort_alphabetical_z\">Alfabetico (Z - A)</string>\n    <string name=\"empty_library_no_accounts_message\">La tua libreria è vuota :(\n\\nAccedi a un account di libreria o aggiungi degli show alla tua libreria locale.</string>\n    <string name=\"select_library\">Seleziona libreria</string>\n    <string name=\"open_with\">Apri con</string>\n    <string name=\"library\">Libreria</string>\n    <string name=\"sort\">Ordina</string>\n    <string name=\"empty_library_logged_in_message\">Questo elenco è vuoto. Prova a passare a un altro.</string>\n    <string name=\"safe_mode_file\">File \\\"safe mode\\\" trovato!\n\\nAll\\'avvio non sarà caricata alcuna estensione finchè il file non verrà rimosso.</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Intervallo di ricerca utilizzato quando il lettore è nascosto</string>\n    <string name=\"pref_category_android_tv\">TV Android</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Intervallo di ricerca utilizzato quando il lettore è visibile</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Lettore visibile - Intervallo di ricerca</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Lettore nascosto - Intervallo di ricerca</string>\n    <string name=\"test_log\">Registro</string>\n    <string name=\"start\">Avvia</string>\n    <string name=\"category_provider_test\">Test del provider</string>\n    <string name=\"restart\">Riavvia</string>\n    <string name=\"stop\">Ferma</string>\n    <string name=\"test_passed\">Superato</string>\n    <string name=\"test_failed\">Fallito</string>\n    <string name=\"jsdelivr_proxy\">Proxy GitHub</string>\n    <string name=\"subscription_deleted\">Disiscritto da %s</string>\n    <string name=\"subscription_list_name\">Iscritto</string>\n    <string name=\"subscription_new\">Iscritto a %s</string>\n    <string name=\"jsdelivr_enabled\">Impossibile raggiungere GitHub. Attivazione proxy jsDelivr…</string>\n    <string name=\"jsdelivr_proxy_summary\">Evita il blocco degli URL github non elaborati utilizzando jsDelivr. Potrebbe causare un ritardo degli aggiornamenti di alcuni giorni.</string>\n    <string name=\"pref_category_bypass\">Bypass ISP</string>\n    <string name=\"revert\">Ripristina</string>\n    <string name=\"subscription_in_progress_notification\">Aggiornando shows a cui sei iscritto</string>\n    <string name=\"subscription_episode_released\">L\\'episodio %d è stato rilasciato!</string>\n    <string name=\"watch_quality_pref_data\">Qualità di visualizzazione preferita (Dati mobili)</string>\n    <string name=\"quality_profile_help\">Qui puoi cambiare l\\'ordine delle fonti. Se un video ha una priorità maggiore, apparirà più in alto nella selezione delle fonti. La somma tra la priorità della fonte e la priorità della qualità è la priorità video.\n\\n\n\\nFonte A: 3\n\\nQualità B: 7\n\\nAvranno una priorità video combinata di 10.\n\\n\n\\nNOTA: se la somma è pari o superiore a 10, il lettore salterà automaticamente il caricamento quando viene caricato quel link!</string>\n    <string name=\"profile_number\">Profilo %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"set_default\">Imposta predefinito</string>\n    <string name=\"use\">Usa</string>\n    <string name=\"edit\">Modifica</string>\n    <string name=\"profiles\">Profili</string>\n    <string name=\"help\">Aiuto</string>\n    <string name=\"mobile_data\">Dati Mobili</string>\n    <string name=\"qualities\">Qualità</string>\n    <string name=\"profile_background_des\">Sfondo profilo</string>\n    <string name=\"no_plugins_found_error\">Nessun plugin trovato nel repository</string>\n    <string name=\"no_repository_found_error\">Repository non trovato, controlla l\\'URL e prova la VPN</string>\n    <string name=\"unable_to_inflate\">Non è stato possibile creare correttamente l\\'interfaccia utente, questo è un GRANDE BUG e dovrebbe essere segnalato immediatamente %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Seleziona la modalità per filtrare il download dei plugin</string>\n    <string name=\"disable\">Disabilita</string>\n    <string name=\"already_voted\">Hai già votato</string>\n    <string name=\"favorite_removed\">%s rimosso dai preferiti</string>\n    <string name=\"favorites_list_name\">Preferiti</string>\n    <string name=\"favorite_added\">%s aggiunto ai preferiti</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Dei possibili duplicati sono stati trovati nella tua libreria:\n\\n\n\\n%s\n\\n\n\\nVorresti aggiungere l\\'oggetto alla libreria comunque, rimpiazzare l\\'esistente, o cancellare l\\'azione?</string>\n    <string name=\"backup_frequency\">Frequenza di backup</string>\n    <string name=\"duplicate_title\">Trovato Possibile Duplicato</string>\n    <string name=\"action_add_to_favorites\">Aggiungi ai preferiti</string>\n    <string name=\"duplicate_replace_all\">Sostituisci tutto</string>\n    <string name=\"pin_error_incorrect\">PIN non corretto. Riprova.</string>\n    <string name=\"action_unsubscribe\">Disiscriviti</string>\n    <string name=\"pin_error_length\">Il PIN deve essere almeno di 4 caratteri</string>\n    <string name=\"duplicate_replace\">Sostituisci</string>\n    <string name=\"duplicate_add\">Aggiungi</string>\n    <string name=\"action_subscribe\">Iscriviti</string>\n    <string name=\"action_remove_from_favorites\">Rimuovi dai preferiti</string>\n    <string name=\"select_an_account\">Seleziona un account</string>\n    <string name=\"duplicate_message_single\">Sembra che nella tua libreria esista già un elemento potenzialmente duplicato: \\'%s.\\'\n\\n\n\\nDesideri aggiungere comunque questo elemento, sostituire quello esistente o annullare l\\'azione?</string>\n    <string name=\"enter_pin\">Inserisci PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">Inserisci PIN corrente</string>\n    <string name=\"logged_account\" formatted=\"true\">Connesso come %s</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Inserisci il PIN per %s</string>\n    <string name=\"lock_profile\">Blocca profilo</string>\n    <string name=\"use_default_account\">Usa account predefinito</string>\n    <string name=\"skip_startup_account_select_pref\">Salta la selezione dell\\'account all\\'avvio</string>\n    <string name=\"manage_accounts\">Gestisci account</string>\n    <string name=\"edit_account\">Modifica account</string>\n    <string name=\"links_reloaded_toast\">Collegamenti ricaricati</string>\n    <string name=\"rotate_video\">Ruota</string>\n    <string name=\"rotate_video_desc\">Visualizza un pulsante di commutazione per l\\'orientamento dello schermo</string>\n    <string name=\"auto_rotate_video_desc\">Abilita la commutazione automatica dell\\'orientamento dello schermo in base all\\'orientamento del video</string>\n    <string name=\"auto_rotate_video\">Rotazione automatica</string>\n    <string name=\"result_search_tooltip\">Cerca in altre estensioni</string>\n    <string name=\"recommendations_tooltip\">Mostra consigli</string>\n    <string name=\"speed_setting_summary\">Aggiunge un\\'opzione di velocità nel lettore</string>\n    <string name=\"test_extensions\">Prova tutte le estensioni</string>\n    <string name=\"test_extensions_summary\">Questo test è pensato solo per gli sviluppatori e non verifica o nega il funzionamento di alcuna estensione.</string>\n    <string name=\"subscribe_tooltip\">Notifica nuovo episodio</string>\n    <string name=\"biometric_authentication_title\">Sblocca CloudStream</string>\n    <string name=\"biometric_setting\">Blocco con dati biometrici</string>\n    <string name=\"password_pin_authentication_title\">Autenticazione con password/PIN</string>\n    <string name=\"biometric_unsupported\">L\\'autenticazione biometrica non è supportata su questo dispositivo</string>\n    <string name=\"biometric_setting_summary\">Sblocca app con impronta digitale, Face ID, PIN, sequenza e password.</string>\n    <string name=\"biometric_prompt_description\">Dopo alcuni tentativi falliti, il prompt si chiuderà. Riavvia semplicemente l\\'app per riprovare.</string>\n    <string name=\"biometric_warning\">È stato eseguito il backup dei tuoi dati CloudStream. Sebbene questa possibilità sia molto bassa, tutti i dispositivi possono comportarsi in modo diverso. Nel raro caso in cui ti venga bloccato l\\'accesso all\\'app, cancella completamente i dati dell\\'app e ripristina da un backup. Siamo molto spiacenti per qualsiasi inconveniente derivanti da questo.</string>\n    <string name=\"unfavorite\">Non preferito</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nresiduo</string>\n    <string name=\"favorite\">Preferito</string>\n    <string name=\"repo_copy_label\">Nome e URL del repository</string>\n    <string name=\"toast_copied\">copiato!</string>\n    <string name=\"clipboard_permission_error\">Errore durante l\\'accesso agli Appunti. Riprova.</string>\n    <string name=\"clipboard_unknown_error\">Errore durante la copia. Copia logcat e contatta il supporto dell\\'app.</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"battery_dialog_title\">Disabilita ottimizzazione della batteria</string>\n    <string name=\"app_info_intent_error\">Impossibile aprire le informazioni sull\\'app CloudStream.</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"battery_dialog_message\">Per garantire download e notifiche ininterrotti per le serie TV a cui si è abbonati, CloudStream necessita dell\\'autorizzazione per funzionare in background. Premendo OK, verrà mostrata una finestra di dialogo di richiesta. Premi \\\"Consenti\\\".\\n\\nNota che questa autorizzazione non significa che CS3 scaricherà la batteria. Funzionerà in background solo quando necessario, ad esempio quando si ricevono notifiche o si scaricano video da estensioni ufficiali.</string>\n    <string name=\"app_unrestricted_toast\">L\\'utilizzo della batteria dell\\'app è già impostato su \\\"Senza restrizioni\\\"</string>\n    <string name=\"music_singlar\">Musica</string>\n    <string name=\"audio_book_singular\">Audiolibro</string>\n    <string name=\"reset_btn\">Reimposta</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Prossimamente tra %s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">L\\'episodio %2$d della stagione %1$d uscirà tra</string>\n    <string name=\"episode_action_cast_mirror\">Mirror cast</string>\n    <string name=\"player_settings_select_cast_device\">Seleziona dispositivo per cast</string>\n    <string name=\"cs3wiki\">Wiki di CloudStream</string>\n    <string name=\"pref_category_accounts\">Conti</string>\n    <string name=\"pref_category_security\">Sicurezza</string>\n    <string name=\"auth_locally\">Autenticazione locale</string>\n    <string name=\"qr_image\">Immagine codice QR</string>\n    <string name=\"dismiss\">Respingi</string>\n    <string name=\"open_downloaded_repo\">Apri repository</string>\n    <string name=\"device_pin_url_message\">Visita <b>%s</b> sul tuo smartphone o computer e inserisci il codice sopra</string>\n    <string name=\"device_pin_error_message\">Impossibile ottenere il codice PIN del dispositivo, prova l\\'autenticazione locale</string>\n    <string name=\"device_pin_expired_message\">Il codice PIN è scaduto!</string>\n    <string name=\"device_pin_counter_text\">Il codice scadrà tra %1$dm %2$ds</string>\n    <string name=\"open_local_video\">Apri il video locale</string>\n    <string name=\"downloads_empty\">Al momento non ci sono download.</string>\n    <string name=\"play_from_beginning_img_des\">Riproduci dall\\'inizio</string>\n    <string name=\"test_warning\">Avvertimento</string>\n    <string name=\"delete_plugin\">Elimina plugin</string>\n    <string name=\"hide_player_control_names\">Nascondi i nomi dei controlli del lettore</string>\n    <string name=\"sort_release_date_new\">Data di rilascio (dal più nuovo)</string>\n    <string name=\"downloads_delete_select\">Seleziona elementi da eliminare</string>\n    <string name=\"offline_file\">Disponibile per la visione offline</string>\n    <string name=\"select_all\">Seleziona tutto</string>\n    <string name=\"deselect_all\">Deseleziona tutto</string>\n    <string name=\"delete_format\" formatted=\"true\">Elimina (%1$d | %2$s)</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Sei sicuro di voler eliminare definitivamente i seguenti episodi in %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Eliminerai definitivamente anche tutti gli episodi delle seguenti serie:\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Sei sicuro di voler eliminare definitivamente tutti gli episodi delle seguenti serie?\n\\n\n\\n%s</string>\n    <string name=\"sort_release_date_old\">Data di rilascio (dal più vecchio)</string>\n    <string name=\"delete_files\">Elimina file</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Sei sicuro di voler eliminare definitivamente i seguenti elementi?\n\\n\n\\n%s</string>\n    <string name=\"preview_seekbar\">Anteprima barra di avanzamento</string>\n    <string name=\"preview_seekbar_desc\">Abilita miniatura di anteprima sulla barra di avanzamento</string>\n    <string name=\"no_subtitles_loaded\">Nessun sottotitolo caricato</string>\n    <string name=\"confirm_before_exiting_title\">Conferma prima di uscire</string>\n    <string name=\"confirm_before_exiting_desc\">Mostra finestra di dialogo prima di uscire dall\\'app</string>\n    <string name=\"show\">Mostra</string>\n    <string name=\"dont_show\">Non mostrare</string>\n    <string name=\"backup_path_title\">Posizione cartella di backup</string>\n    <string name=\"custom\">Personalizzato</string>\n    <string name=\"torrent_info\">Questo video è un Torrent, il che significa che la tua attività video può essere tracciata.\\nAssicurati di aver capito il significato di scaricare tramite Torrent prima di continuare.</string>\n    <string name=\"subs_edge_size\">Dimensione bordo</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"unsupported_error\">Errore non supportato</string>\n    <string name=\"encoding_error\">Errore di codifica</string>\n    <string name=\"player_load_one_subtitle_online\">Carica il primo disponibile</string>\n    <string name=\"torrent_not_accepted\">Riavvia l\\'app e accetta il pop-up Stream Torrent per procedere.</string>\n    <string name=\"torrent_preferred_media\">Abilita torrent in Impostazioni/Provider/Media preferiti</string>\n    <string name=\"software_decoding\">Decodifica software</string>\n    <string name=\"software_decoding_desc\">La decodifica software consente al lettore di riprodurre file video non supportati dal dispositivo, ma potrebbe causare una riproduzione lenta o instabile ad alta risoluzione.</string>\n    <string name=\"sort_episodes_rating_high_low\">Valutazione (più alta)</string>\n    <string name=\"sort_episodes_rating_low_high\">Valutazione (più bassa)</string>\n    <string name=\"sort_episodes_date_newest\">Data di messa in onda (più recente)</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_date\">Data %s</string>\n    <string name=\"update_plugins\">Aggiorna plugin</string>\n    <string name=\"update_plugins_manually\">Aggiorna plugin manualmente</string>\n    <string name=\"sort_episodes_number_asc\">Episodio (ascendente)</string>\n    <string name=\"sort_episodes_number_desc\">Episodio (discendente)</string>\n    <string name=\"sort_episodes_date_oldest\">Data di messa in onda (più vecchia)</string>\n    <string name=\"sort_button_rating\">Valutazione %s</string>\n    <string name=\"starting_plugin_update_manually\">Avvio del processo di aggiornamento plugin!</string>\n    <string name=\"plugins_updated_manually\">%d plugin aggiornati con successo!</string>\n    <string name=\"no_plugins_updated_manually\">Nessun plugin è stato aggiornato.</string>\n    <string name=\"player_notification_channel_name\">Notifiche lettore</string>\n    <string name=\"player_notification_channel_description\">La notifica del lettore per controllare la riproduzione in background</string>\n    <string name=\"begin_speaking\">Inizia a parlare…</string>\n    <string name=\"speech_recognition_unavailable\">Il riconoscimento vocale non è disponibile</string>\n    <string name=\"subtitles_from_embedded\">Incorporato</string>\n    <string name=\"subtitles_from_online\">In linea</string>\n    <string name=\"all_subtitles_bold\">Rendi tutti i sottotitoli in grassetto</string>\n    <string name=\"all_subtitles_italic\">Rendi tutti i sottotitoli in corsivo</string>\n    <string name=\"background_radius\">Raggio di sfondo</string>\n    <string name=\"volume_exceeded_100\">Il volume ha superato il 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Scorri di nuovo verso l\\'alto per andare oltre il 100%</string>\n    <string name=\"download_parallel_settings_des\">Quanti oggetti possono essere scaricati contemporaneamente</string>\n    <string name=\"parallel_downloads\">Download paralleli</string>\n    <string name=\"concurrent_connections\">Connessioni concorrenti</string>\n    <string name=\"concurrent_connections_settings_des\">Quante connessioni simultanee può utilizzare ogni download durante il download</string>\n    <string name=\"go_to_downloads\">Vai ai Downloads</string>\n    <string name=\"no_internet_connection\">Nessuna connessione a internet. \\n\\nConnettiti a Internet e riprova oppure guarda i tuoi download mentre sei offline.</string>\n    <string name=\"overscan_settings_des\">Modifica limiti dello schermo</string>\n    <string name=\"overscan_settings\">Overscan</string>\n    <string name=\"poster_size_settings_des\">Modifica dimensioni dei poster</string>\n    <string name=\"poster_size_settings\">Dimensione poster</string>\n    <string name=\"player_settings_always_ask\">Chiedi sempre</string>\n    <string name=\"speedup_title\">Attiva/disattiva velocità LongPress</string>\n    <string name=\"speedup_summary\">Tieni premuto per velocità 2x</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"show_rating\">Etichetta di valutazione</string>\n    <string name=\"no_account\">Nessun account</string>\n    <string name=\"edit_profile_image_title\">Modifica immagine del profilo</string>\n    <string name=\"edit_profile_image_hint\">Inserisci l\\'URL dell\\'immagine del profilo</string>\n    <string name=\"edit_profile_image_error_empty\">Nessun URL trovato</string>\n    <string name=\"edit_profile_image_error_invalid\">URL o immagine non validi</string>\n    <string name=\"edit_profile_image_success\">Immagine aggiornata con successo</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Rimuovi gli episodi visti fino a questo</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Contrassegna come visto fino a questo episodio</string>\n    <string name=\"action_reload\">Ricaricato</string>\n    <string name=\"reload_provider\">Ricarica provider</string>\n    <string name=\"name\">Nome</string>\n    <string name=\"resolution_and_name\">Risoluzione e nome</string>\n    <string name=\"subs_subtitle_alignment\">Allineamento sottotitoli</string>\n    <string name=\"bottom_left\">In basso a sinistra</string>\n    <string name=\"episode_action_play_mirror\">Riproduci mirror</string>\"\n    <string name=\"bottom_center\">In basso al centro</string>\n    <string name=\"bottom_right\">In basso a destra</string>\n    <string name=\"middle_center\">In centro</string>\n    <string name=\"middle_right\">In centro a destra</string>\n    <string name=\"top_left\">In alto a sinistra</string>\n    <string name=\"top_center\">In alto al centro</string>\n    <string name=\"top_right\">In alto a destra</string>\n    <string name=\"middle_left\">In centro a sinistra</string>\n    <string name=\"play_full_series_button\">Riproduci serie completa</string>\n    <string name=\"install_prerelease\">Installa la versione pre-release</string>\n    <string name=\"prerelease_already_installed\">La versione pre-release è già installata.</string>\n    <string name=\"prerelease_install_failed\">Impossibile installare la versione pre-release.</string>\n    <string name=\"show_episode_text\">Testo dell\\'episodio</string>\n    <string name=\"search_suggestions\">Suggerimenti per la ricerca</string>\n    <string name=\"search_suggestions_des\">Mostra suggerimenti di ricerca durante la digitazione</string>\n    <string name=\"clear_suggestions\">Cancella suggerimenti</string>\n    <string name=\"show_cast_in_details\">Mostra pannello cast</string>\n    <string name=\"video_info\">Info sui media</string>\n    <string name=\"source_name\">Nome sorgente</string>\n    <string name=\"extra_brightness_settings\">Luminosità extra</string>\n    <string name=\"extra_brightness_settings_des\">Attiva il filtro di luminosità quando viene superato il 100% della luminosità dello schermo</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"download_queue\">Coda di download</string>\n    <string name=\"queue_empty_message\">Al momento non ci sono download in coda.</string>\n    <string name=\"download_all\">Scarica tutto</string>\n    <string name=\"cancel_all\">Annulla tutto</string>\n    <string name=\"download_episode_range\">Vuoi scaricare l\\'episodio %s?</string>\n    <string name=\"cancel_queue_message\">Vuoi annullare tutti i download in coda?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d download attivo</item>\n        <item quantity=\"many\">%d download attivi</item>\n        <item quantity=\"other\">%d download attivi</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d download in coda</item>\n        <item quantity=\"many\">%d download in coda</item>\n        <item quantity=\"other\">%d download in coda</item>\n    </plurals>\n    <string name=\"source_priority\">Priorità sorgente</string>\n    <string name=\"source_priority_help\">Decidi come le sorgenti video devono essere ordinate nel lettore</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"preview_background_img_des\">הרקע של ההצגה לפני</string>\n    <string name=\"cast_format\" formatted=\"true\">צוות שחקנים: %s</string>\n    <string name=\"go_back_img_des\">לחזור</string>\n    <string name=\"home_change_provider_img_des\">לשנות ספק</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">מהירות (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">דירוג: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">נמצא עדכון חדש!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">סינון</string>\n    <string name=\"duration_format\" formatted=\"true\">%d דקות</string>\n    <string name=\"app_name\">קלאודסטרים</string>\n    <string name=\"title_home\">בית</string>\n    <string name=\"title_search\">חיפוש</string>\n    <string name=\"title_downloads\">הורדות</string>\n    <string name=\"title_settings\">הגדרות</string>\n    <string name=\"search_hint\">חיפוש…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">חיפוש %s…</string>\n    <string name=\"no_data\">ללא נתונים</string>\n    <string name=\"episode_more_options_des\">יותר אפשרויות</string>\n    <string name=\"result_tags\">ז\\'אנרים</string>\n    <string name=\"result_share\">שיתוף</string>\n    <string name=\"result_open_in_browser\">לפתוח בדפדפן</string>\n    <string name=\"skip_loading\">דלג על טעינה</string>\n    <string name=\"next_episode_format\" formatted=\"true\">פרק %d יצא בעוד</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dימים %2$dשעות %3$dחודשים</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dשעות %2$dחודשים</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dחודשים</string>\n    <string name=\"result_poster_img_des\">פוסטר</string>\n    <string name=\"episode_poster_img_des\">הפוסטר של הפרק</string>\n    <string name=\"home_main_poster_img_des\">פוסטר ראשי</string>\n    <string name=\"home_next_random_img_des\">ארקאי הבא</string>\n    <string name=\"type_completed\">הושלם</string>\n    <string name=\"type_plan_to_watch\">בתכנון לצפייה</string>\n    <string name=\"type_re_watching\">צופה מחדש</string>\n    <string name=\"play_movie_button\">הפעל סרט</string>\n    <string name=\"play_trailer_button\">הפעל טריילר</string>\n    <string name=\"play_livestream_button\">הפעל שידור חי</string>\n    <string name=\"pick_source\">מקורות</string>\n    <string name=\"reload_error\">נסיון חדש לחיבור…</string>\n    <string name=\"type_dropped\">הפסיק</string>\n    <string name=\"play_torrent_button\">שדר טורנט</string>\n    <string name=\"go_back\">חזרה</string>\n    <string name=\"play_episode\">נגן פרק</string>\n    <string name=\"downloaded\">הורד</string>\n    <string name=\"downloading\">מוריד</string>\n    <string name=\"download_paused\">ההורדה מושהית</string>\n    <string name=\"download_started\">ההורדה התחילה</string>\n    <string name=\"download_failed\">ההורדה נכשלה</string>\n    <string name=\"download_canceled\">ההורדה בוטלה</string>\n    <string name=\"download_done\">נגן טריילר</string>\n    <string name=\"stream\">זרם רשתי</string>\n    <string name=\"error_loading_links_toast\">שגיאה בטעינת קישורים</string>\n    <string name=\"download_storage_text\">אחסון פנימי</string>\n    <string name=\"app_subbed_text\">עם כתוביות</string>\n    <string name=\"popup_delete_file\">מחיקת קובץ</string>\n    <string name=\"popup_play_file\">נגן קובץ</string>\n    <string name=\"popup_resume_download\">המשך הורדה</string>\n    <string name=\"popup_pause_download\">השהה את ההורדה</string>\n    <string name=\"home_play\">נגן</string>\n    <string name=\"home_info\">מידע</string>\n    <string name=\"filter_bookmarks\">סנן סימניות</string>\n    <string name=\"error_bookmarks_text\">סימניות</string>\n    <string name=\"action_remove_from_bookmarks\">הסר</string>\n    <string name=\"action_add_to_bookmarks\">הגדר מצב צפייה</string>\n    <string name=\"sort_apply\">ליישם</string>\n    <string name=\"sort_copy\">העתק</string>\n    <string name=\"sort_close\">לסגור</string>\n    <string name=\"sort_clear\">נקה</string>\n    <string name=\"sort_save\">לשמור</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s פרק %2$d</string>\n    <string name=\"play_with_app_name\">נגן עם קלאודסטרים</string>\n    <string name=\"next_episode\">פרק הבא</string>\n    <string name=\"loading\">טוען…</string>\n    <string name=\"type_watching\">צופה</string>\n    <string name=\"pick_subtitle\">כתוביות</string>\n    <string name=\"type_on_hold\">בהמתנה</string>\n    <string name=\"download\">להוריד</string>\n    <string name=\"app_dubbed_text\">מדובב</string>\n    <string name=\"home_more_info\">יותר מידע</string>\n    <string name=\"home_expanded_hide\">להתחבא</string>\n    <string name=\"player_speed\">מהירות הנגן</string>\n    <string name=\"subtitles_settings\">הגדרות הכתוביות</string>\n    <string name=\"subs_text_color\">צבע טקסט</string>\n    <string name=\"subs_outline_color\">צבע חיצון</string>\n    <string name=\"subs_edge_type\">סוג קצה</string>\n    <string name=\"subs_subtitle_elevation\">גובה הכתוביות</string>\n    <string name=\"subs_font_size\">גודל גופן</string>\n    <string name=\"search_provider_text_providers\">חפש באמצעות הספקים</string>\n    <string name=\"search_provider_text_types\">חפש באמצעות סוגים</string>\n    <string name=\"subs_auto_select_language\">בחירת שפה אוטומטית</string>\n    <string name=\"subs_download_languages\">הורדת שפות</string>\n    <string name=\"subs_subtitle_languages\">שפת הכתוביות</string>\n    <string name=\"subs_import_text\" formatted=\"true\">ייבא גופנים בהצבתם ב %s</string>\n    <string name=\"continue_watching\">המשך צפיה</string>\n    <string name=\"action_remove_watching\">להסיר</string>\n    <string name=\"action_open_watching\">עוד מידע</string>\n    <string name=\"vpn_torrent\">הספק הזה הוא טורנט, שימוש ב-VPN הוא מומלץ</string>\n    <string name=\"torrent_plot\">תיאור</string>\n    <string name=\"normal_no_plot\">עלילה לא נמצאה</string>\n    <string name=\"torrent_no_plot\">התיאור לא נמצאה</string>\n    <string name=\"picture_in_picture\">מצב תמונה בתמונה</string>\n    <string name=\"player_size_settings\">כפתור שינוי גודל הנגן</string>\n    <string name=\"player_size_settings_des\">הסר את הגבולות השחורים</string>\n    <string name=\"benene_count_text\">%d בנינים שניתנו למפתחים</string>\n    <string name=\"player_subtitles_settings_des\">הגדרות כתוביות הנגן</string>\n    <string name=\"chromecast_subtitles_settings_des\">הגדרות כתוביות כרומקאסט</string>\n    <string name=\"subs_font\">גופן</string>\n    <string name=\"subs_hold_to_reset_to_default\">החזק כדי לאפס לברירת מחדל</string>\n    <string name=\"subs_background_color\">צבע הרקע</string>\n    <string name=\"vpn_might_be_needed\">ייתכן שיהיה צורך לשימוש ב-VPN כדי שספק זה יפעל באופן נכון</string>\n    <string name=\"chromecast_subtitles_settings\">כתוביות כרומקאסט</string>\n    <string name=\"picture_in_picture_des\">ממשיך ניגון בנגן מינימלי מעל ישומים אחרים</string>\n    <string name=\"player_subtitles_settings\">כתוביות</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"history\">היסטוריה</string>\n    <string name=\"apk_installer_legacy\">מורשת</string>\n    <string name=\"no\">לא</string>\n    <string name=\"yes\">כן</string>\n    <string name=\"action_mark_as_watched\">סימון כנצפה</string>\n    <string name=\"status\">סטטוס</string>\n    <string name=\"logout\">התנתק</string>\n    <string name=\"login\">התחברות</string>\n    <string name=\"show_title\">כותרת</string>\n    <string name=\"none\">אין</string>\n    <string name=\"all\">הכל</string>\n    <string name=\"title\">כותרת</string>\n    <string name=\"update_started\">העדכון התחיל</string>\n    <string name=\"settings_info\">מידע</string>\n    <string name=\"automatic_plugin_download_summary\">התקן אוטומטית את כל התוספים שטרם הותקנו ממאגרים שנוספו.</string>\n    <string name=\"updates_settings_des\">חפש אוטומטית עדכונים חדשים לאחר פתיחת האפליקציה.</string>\n    <string name=\"updates_settings\">הצג עדכונים לאפליקציה</string>\n    <string name=\"redo_setup_process\">בצע מחדש את תהליך ההגדרה</string>\n    <string name=\"episodes\">פרקים</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode\">פרק</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">עו</string>\n    <string name=\"episode_short\">פר</string>\n    <string name=\"no_episodes_found\">לא נמצאו פרקים</string>\n    <string name=\"delete_file\">מחק קובץ</string>\n    <string name=\"delete\">מחק</string>\n    <string name=\"cancel\">בטל</string>\n    <string name=\"pause\">השהה</string>\n    <string name=\"resume\">המשך</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dדקות\n\\nנותרו</string>\n    <string name=\"delete_message\" formatted=\"true\">‬פעולה זאת תמחק לצמיתות את %s\n\\nהאם אתם בטוחים?</string>\n    <string name=\"status_ongoing\">מתמשך</string>\n    <string name=\"duration\">משך זמן</string>\n    <string name=\"rating\">דירוג</string>\n    <string name=\"year\">שנה</string>\n    <string name=\"no_subtitles\">ללא כתוביות</string>\n    <string name=\"action_default\">ברירת מחדל</string>\n    <string name=\"free_storage\">חינם</string>\n    <string name=\"used_storage\">משומש</string>\n    <string name=\"tv_series\">סדרת טלוויזיה</string>\n    <string name=\"cartoons\">סדרות/סרטים מצוירים</string>\n    <string name=\"anime_singular\">@string/anime</string>\n    <string name=\"ova_singular\">@string/ova</string>\n    <string name=\"asian_drama_singular\">דרמה אסייתית</string>\n    <string name=\"episode_action_chromecast_episode\">כרומקאסט את הפרק</string>\n    <string name=\"episode_action_chromecast_mirror\">כרומקאסט את המראה</string>\n    <string name=\"show_sub\">תווית כתוביות</string>\n    <string name=\"poster_ui_settings\">החלף רכיבי ממשק משתמש בפוסטר</string>\n    <string name=\"video_skip_op\">דלג על הפתיח</string>\n    <string name=\"dont_show_again\">אל תראה שוב</string>\n    <string name=\"skip_update\">דלג על עדכון זה</string>\n    <string name=\"update\">עדכון</string>\n    <string name=\"watch_quality_pref\">איכות צפייה מועדפת (WiFi)</string>\n    <string name=\"limit_title\">נגן וידאו כותרת מקסימום תווים</string>\n    <string name=\"limit_title_rez\">רזולוציית נגן וידאו</string>\n    <string name=\"add_sync\">הוסף מעקב</string>\n    <string name=\"create_account\">צור חשבון</string>\n    <string name=\"next\">הבא</string>\n    <string name=\"library\">ספריה</string>\n    <string name=\"provider_info_meta\">מטא-דאטה לא מסופק על ידי האתר, טעינת הסרטון תיכשל אם הוא לא קיים באתר.</string>\n    <string name=\"swipe_to_change_settings_des\">החלק בצד השמאלי או הימני כדי לשנות את הבהירות או עוצמת הקול</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">שחזור הנתונים מהקובץ נכשל %s</string>\n    <string name=\"category_updates\">עדכונים וגיבויים</string>\n    <string name=\"advanced_search_des\">נותן לך את תוצאות החיפוש מופרדות לפי ספק</string>\n    <string name=\"show_fillers_settings\">הצג פרק פילר (לא הכרחי לעלילה) לאנימה</string>\n    <string name=\"automatic_plugin_download\">הורדה אוטומטית של תוספים</string>\n    <string name=\"automatic_plugin_updates\">עדכוני תוספים אוטומטיים</string>\n    <string name=\"benene_des\">כמות בנינים שניתנו</string>\n    <string name=\"season\">עונה</string>\n    <string name=\"torrent\">טורנטים</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"render_error\">שגיאת מעבד</string>\n    <string name=\"episode_action_download_mirror\">הורד מראה</string>\n    <string name=\"episode_action_download_subtitle\">הורד כתוביות</string>\n    <string name=\"random_button_settings_desc\">הצג כפתור אקראי בדף הבית</string>\n    <string name=\"show_dub\">תווית דיבוב</string>\n    <string name=\"video_ram_description\">גורם לקריסות אם מוגדר גבוה מדי במכשירים עם זיכרון נמוך, כגון Android TV.</string>\n    <string name=\"video_source\">מקור</string>\n    <string name=\"category_providers\">ספקים</string>\n    <string name=\"remove_site_pref\">הסר אתר</string>\n    <string name=\"download_path_pref\">נתיב הורדה</string>\n    <string name=\"pref_category_looks\">נראה</string>\n    <string name=\"automatic\">אוטומטי</string>\n    <string name=\"tv_layout\">פריסת טלוויזיה</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"subtitles_filter_lang\">סנן לפי שפת מדיה מועדפת</string>\n    <string name=\"app_theme_settings\">נושא אפליקציה</string>\n    <string name=\"bottom_title_settings\">מיקום כותרת פוסטר</string>\n    <string name=\"preferred_media_subtext\">מה אתם רוצים לראות</string>\n    <string name=\"quality_hq\">איכות גבוהה</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"plugin_loaded\">תוסף טעון</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"pref_category_app_updates\">עדכוני אפליקציה</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"skip_setup\">דלג על ההגדרה</string>\n    <string name=\"pref_category_player_features\">תכונות נגן</string>\n    <string name=\"episode_sync_settings\">עדכן התקדמות צפייה</string>\n    <string name=\"dns_pref\">DNS מעל HTTPS</string>\n    <string name=\"double_tap_to_pause_settings_des\">לחץ פעמיים באמצע כדי לעצור</string>\n    <string name=\"swipe_to_seek_settings_des\">החלק מצד לצד כדי לשלוט על מיקומך בסרטון</string>\n    <string name=\"autoplay_next_settings\">נגן אוטומטית את הפרק הבא</string>\n    <string name=\"autoplay_next_settings_des\">התחל את הפרק הבא כאשר הפרק הנוכחי נגמר</string>\n    <string name=\"double_tap_to_seek_settings_des\">לחץ פעמיים על צד ימין או שמאל כדי להציץ קדימה או אחורה</string>\n    <string name=\"use_system_brightness_settings\">השתמש בבהירות המערכת</string>\n    <string name=\"backup_settings\">גבה נתונים</string>\n    <string name=\"subtitle_offset\">סנכרן את הכתוביות</string>\n    <string name=\"subtitle_offset_title\">עיכוב כתוביות</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">אין עיכוב בכתוביות</string>\n    <string name=\"recommended\">מומלץ</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">נטען %s</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">השתמש בזה אם הכתוביות מוצגות %d מילישניות מוקדם יותר</string>\n    <string name=\"home_random\">אקראי</string>\n    <string name=\"resolution\">רזולוציה</string>\n    <string name=\"quality_cam_hd\">איכות מצלמה</string>\n    <string name=\"error_invalid_url\">כתובת אתר לא מזוהה</string>\n    <string name=\"network_adress_example\">קישור לשידור</string>\n    <string name=\"referer\">המפנה</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"repository_url_hint\">כתובת אתר למאגר</string>\n    <string name=\"preferred_media_settings\">מדיה מועדפת</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"play_episode_toast\">נגן את הפרק</string>\n    <string name=\"no_links_found_toast\">לא נמצאו קישורים</string>\n    <string name=\"example_lang_name\">קוד שפה (אנגלית)</string>\n    <string name=\"error\">שגיאה</string>\n    <string name=\"provider_lang_settings\">שפות ספק</string>\n    <string name=\"pref_category_links\">קישורים</string>\n    <string name=\"app_layout\">פריסת אפליקציה</string>\n    <string name=\"advanced_search\">חיפוש מתקדם</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"search_poster_img_des\">פוסטר</string>\n    <string name=\"quality_cam\">איכות מצלמה</string>\n    <string name=\"swipe_to_seek_settings\">החלק כדי להציץ</string>\n    <string name=\"pref_category_backup\">גיבוי</string>\n    <string name=\"double_tap_to_seek_amount_settings\">כמות הזזת הנגן (שניות)</string>\n    <string name=\"other_singular\">סרטון</string>\n    <string name=\"github\">גיטהאב</string>\n    <string name=\"quality_cam_rip\">מצלמה</string>\n    <string name=\"swipe_to_change_settings\">החלק כדי לשנות הגדרות</string>\n    <string name=\"browser\">‪דפדפן</string>\n    <string name=\"subs_window_color\">צבע חלון</string>\n    <string name=\"show_log_cat\">הצג לוג</string>\n    <string name=\"double_tap_to_seek_settings\">לחץ פעמיים כדי להציץ</string>\n    <string name=\"double_tap_to_pause_settings\">לחץ פעמיים כדי לעצור</string>\n    <string name=\"use_system_brightness_settings_des\">התשתמש בבהירות המערכת בנגן האפליקציה במקום שכבת-על כהה</string>\n    <string name=\"episode_sync_settings_des\">סנכרן אוטומטית את התקדמות הפרק הנוכחית שלך</string>\n    <string name=\"restore_settings\">שחזר נתונים מגיבוי</string>\n    <string name=\"restore_success\">קובץ הגיבוי נטען</string>\n    <string name=\"backup_success\">נתונים מאוחסנים</string>\n    <string name=\"backup_failed\">חסרות הרשאות אחסון. אנא נסה שוב.</string>\n    <string name=\"backup_failed_error_format\">שגיאה בגיבוי %s</string>\n    <string name=\"search\">חיפוש</string>\n    <string name=\"category_account\">חשבונות ובטיחות</string>\n    <string name=\"benene_count_text_none\">לא ניתנו בנינים</string>\n    <string name=\"eigengraumode_settings\">מהירות ניגון</string>\n    <string name=\"show_trailers_settings\">הצג טריילרים</string>\n    <string name=\"kitsu_settings\">הצג פוסטרים מKitsu</string>\n    <string name=\"pref_filter_search_quality\">הסתר את איכות הסרטון שנבחרה בתוצאות החיפוש</string>\n    <string name=\"apk_installer_settings\">מתקין APK</string>\n    <string name=\"apk_installer_settings_des\">חלק מהטלפונים אינם תומכים במתקין החבילות החדש. נסו את האפשרות מדור קודם אם העדכונים לא מתקינים.</string>\n    <string name=\"lightnovel\">אפליקצית רומנים קלים על ידי אותו מפתחים</string>\n    <string name=\"anim\">אפליקצית אנימה על ידי אותו מפתחים</string>\n    <string name=\"discord\">הצטרפות לדיסקורד</string>\n    <string name=\"app_language\">שפת האפליקציה</string>\n    <string name=\"no_chromecast_support_toast\">לספק זה אין תמיכה בכרומקאסט</string>\n    <string name=\"copy_link_toast\">הקישור הועתק ללוח</string>\n    <string name=\"subs_default_reset_toast\">אפס לערך ברירת המחדל</string>\n    <string name=\"no_season\">אין עונה</string>\n    <string name=\"status_completed\">הושלם</string>\n    <string name=\"site\">אתר</string>\n    <string name=\"synopsis\">תקציר</string>\n    <string name=\"queued\">בתור</string>\n    <string name=\"benene\">לתת בניני למפתחים</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"app_storage\">אפליקציה</string>\n    <string name=\"movies\">סרטים</string>\n    <string name=\"anime\">אנימה</string>\n    <string name=\"documentaries\">סרטים תיעודיים</string>\n    <string name=\"ova\">אנימציית וידאו מקורית</string>\n    <string name=\"asian_drama\">דרמות אסייתיות</string>\n    <string name=\"livestreams\">שידורי חי</string>\n    <string name=\"others\">אחר</string>\n    <string name=\"movies_singular\">סרט</string>\n    <string name=\"tv_series_singular\">סדרה</string>\n    <string name=\"cartoons_singular\">סדרה/סרט מצויר</string>\n    <string name=\"torrent_singular\">טורנט</string>\n    <string name=\"documentaries_singular\">דוקומנטרי</string>\n    <string name=\"live_singular\">שידור חי</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"source_error\">שגיאת מקור</string>\n    <string name=\"remote_error\">שגיאה מרחוק</string>\n    <string name=\"unexpected_error\">שגיאת נגן לא צפויה</string>\n    <string name=\"storage_error\">שגיאת הורדה, בדוק הרשאות אחסון</string>\n    <string name=\"episode_action_play_in_app\">נגן באפליקציה</string>\n    <string name=\"episode_action_play_in_format\">נגן ב %s</string>\n    <string name=\"episode_action_auto_download\">הורדה אוטומטית</string>\n    <string name=\"episode_action_reload_links\">טען מחדש קישורים</string>\n    <string name=\"show_hd\">תווית איכות</string>\n    <string name=\"no_update_found\">לא נמצא עדכון</string>\n    <string name=\"check_for_update\">בדוק אם יש עדכון</string>\n    <string name=\"video_lock\">נעל</string>\n    <string name=\"video_aspect_ratio_resize\">שינוי גודל</string>\n    <string name=\"video_buffer_size_settings\">גודל מאגר וידאו</string>\n    <string name=\"video_buffer_length_settings\">אורך מאגר וידאו</string>\n    <string name=\"video_buffer_disk_settings\">מטמון וידאו בכונן</string>\n    <string name=\"video_buffer_clear_settings\">נקה מטמון וידאו ותמונה</string>\n    <string name=\"video_disk_description\">גורם לקריסות אם מוגדר גבוה מדי במכשירים עם מקום נמוך, כגון Android TV.</string>\n    <string name=\"dns_pref_summary\">שימושי עבור עקיפת מחסומי ספק שירותי אינטרנט</string>\n    <string name=\"add_site_pref\">אתר העתק</string>\n    <string name=\"add_site_summary\">הוסף העתק של אתר קיים, עם כתובת אתר אחרת</string>\n    <string name=\"nginx_url_pref\">NGINX שרת כתובת אתר</string>\n    <string name=\"display_subbed_dubbed_settings\">הצג אנימות מדובבות/מתורגמות</string>\n    <string name=\"resize_fit\">התאם למסך</string>\n    <string name=\"resize_fill\">מתוח</string>\n    <string name=\"resize_zoom\">זום</string>\n    <string name=\"legal_notice\">כתב ויתור</string>\n    <string name=\"pref_category_extensions\">הרחבות</string>\n    <string name=\"pref_category_actions\">פעולות</string>\n    <string name=\"pref_category_cache\">מטמון</string>\n    <string name=\"pref_category_gestures\">מחוות</string>\n    <string name=\"pref_category_subtitles\">כתוביות</string>\n    <string name=\"pref_category_player_layout\">פריסה</string>\n    <string name=\"pref_category_defaults\">ברירות מחדל</string>\n    <string name=\"pref_category_ui_features\">תכונות</string>\n    <string name=\"category_general\">כללי</string>\n    <string name=\"random_button_settings\">כפתור אקראי</string>\n    <string name=\"enable_nsfw_on_providers\">הרשה NSFW בספקים נתמכים</string>\n    <string name=\"subtitles_encoding\">קידוד כתוביות</string>\n    <string name=\"category_ui\">פריסה</string>\n    <string name=\"phone_layout\">פריסת טלפון</string>\n    <string name=\"emulator_layout\">פריסת אמולטור</string>\n    <string name=\"primary_color_settings\">צבע ראשוני</string>\n    <string name=\"bottom_title_settings_des\">שים את הכותרת מתחת לפוסטר</string>\n    <string name=\"example_password\">סיסמה123</string>\n    <string name=\"example_username\">שםהמשתמשהמגניבשלי</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">האתרהמגניבשלי</string>\n    <string name=\"example_site_url\">דוגמה.com</string>\n    <string name=\"account\">חשבון</string>\n    <string name=\"switch_account\">החלף חשבון</string>\n    <string name=\"add_account\">הוסף חשבון</string>\n    <string name=\"added_sync_format\" formatted=\"true\">נוסף %s</string>\n    <string name=\"upload_sync\">סנכרן</string>\n    <string name=\"sync_score\">מדורג</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s מאומת</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">לא ניתן להתחבר ב %s</string>\n    <string name=\"normal\">רגיל</string>\n    <string name=\"max\">מקסימום</string>\n    <string name=\"min\">מינימום</string>\n    <string name=\"subtitles_outline\">מתאר</string>\n    <string name=\"subtitles_depressed\">מדוכא</string>\n    <string name=\"subtitles_shadow\">צל</string>\n    <string name=\"subtitles_raised\">הורם</string>\n    <string name=\"subtitle_offset_hint\">1000 מילישניות</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">השתמש בזה אם הכתוביות מוצגות %d מילישניות מאוחר יותר</string>\n    <string name=\"subtitles_example_text\">השועל החום המהיר קופץ מעל הכלב העצלן</string>\n    <string name=\"player_load_subtitles\">טען מקובץ</string>\n    <string name=\"player_load_subtitles_online\">טען מהאינטרנט</string>\n    <string name=\"downloaded_file\">קובץ שהורד</string>\n    <string name=\"actor_main\">ראשי</string>\n    <string name=\"actor_supporting\">משנה</string>\n    <string name=\"actor_background\">רקע</string>\n    <string name=\"home_source\">מקור</string>\n    <string name=\"coming_soon\">בקרוב…</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">תמונת פוסטר</string>\n    <string name=\"category_player\">נגן</string>\n    <string name=\"resolution_and_title\">רזולוציה וכותרת</string>\n    <string name=\"error_invalid_id\">לא מזוהה ID</string>\n    <string name=\"error_invalid_data\">נתונים לא מזוהים</string>\n    <string name=\"subtitles_remove_captions\">הסר כיתובים סגורים מהכתוביות</string>\n    <string name=\"subtitles_remove_bloat\">הסר נפיחות מכתוביות</string>\n    <string name=\"extras\">תוספות</string>\n    <string name=\"trailer\">טריילר</string>\n    <string name=\"provider_languages_tip\">צפה בסרטונים בשפות אלה</string>\n    <string name=\"previous\">קודם</string>\n    <string name=\"app_layout_subtext\">שנה את מראה האפליקציה כך שיתאים למכשירך</string>\n    <string name=\"setup_done\">סוים</string>\n    <string name=\"extensions\">הרחבות</string>\n    <string name=\"add_repository\">הוסף מאגר</string>\n    <string name=\"repository_name_hint\">שם מאגר</string>\n    <string name=\"plugin_downloaded\">תוסף הורד</string>\n    <string name=\"plugin_deleted\">התוסף נמחק</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">לא יכול לטעון %s</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">התחיל להוריד %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">הוריד %1$d %2$s</string>\n    <string name=\"enable_skip_op_from_database_des\">הצג חלונות קופצים של דילוג בשביל פתיח/שיר סיום</string>\n    <string name=\"delete_repository\">מחק מאגר</string>\n    <string name=\"skip_type_mixed_op\">פתיח מעורב</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">כל %s כבר הורד</string>\n    <string name=\"extension_authors\">מחברים</string>\n    <string name=\"extension_language\">שפה</string>\n    <string name=\"skip_type_creddits\">קרדיטים</string>\n    <string name=\"sort\">מיין</string>\n    <string name=\"select_library\">בחר ספרייה</string>\n    <string name=\"empty_library_no_accounts_message\">נראה שהספרייה שלכם ריקה :(\n\\nהתחברו לחשבון ספריה או הוסיפו סדרות לספרייה המקומית שלכם.</string>\n    <string name=\"safe_mode_file\">קובץ מצב בטוח נמצא!\n\\nלא טוען שום תוספות בהפעלה עד להסרת הקובץ.</string>\n    <string name=\"update_notification_failed\">לא ניתן להתקין את הגרסה החדשה של האפליקציה</string>\n    <string name=\"batch_download\">הורדת אצווה</string>\n    <string name=\"plugin_singular\">תוסף</string>\n    <string name=\"download_all_plugins_from_repo\">הורד את כל התוספים ממאגר זה?</string>\n    <string name=\"audio_tracks\">רצועות שמע</string>\n    <string name=\"tracks\">מסלולים</string>\n    <string name=\"safe_mode_description\">כל התוספים נכבו עקב התרסקות כדי לעזור לך למצוא את האחד הגורם לצרות.</string>\n    <string name=\"apk_installer_package_installer\">מוריד החבילות</string>\n    <string name=\"plugins_updated\" formatted=\"true\">עודכן %d תוספים</string>\n    <string name=\"plugin\">תוספים</string>\n    <string name=\"delete_repository_plugins\">פעולה זו תמחק גם את כל תוספי המאגר</string>\n    <string name=\"setup_extensions_subtext\">הורד את רשימת האתרים שבהם ברצונך להשתמש</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">הורד: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">מוגבל: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">לא מורד: %d</string>\n    <string name=\"blank_repo_message\">לקלאודסטרים אין אתרים מותקנים כברירת מחדל. עליכם להתקין את האתרים ממאגרים.\n\\n\n\\nבגלל הסרת DMCA על ידי Sky UK LImited 🤮 אנחנו לא יכולים לקשר את אתר המאגרים באפליקציה.\n\\n\n\\nתצטרפו לדיסקורד שלנו או תחפשו באינטרנט.</string>\n    <string name=\"view_public_repositories_button\">הצג מאגרים קהילתיים</string>\n    <string name=\"view_public_repositories_button_short\">רשימה ציבורית</string>\n    <string name=\"uppercase_all_subtitles\">לשים את הכתוביות באותיות רישיות</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (מוגבל)</string>\n    <string name=\"video_tracks\">רצועות וידאו</string>\n    <string name=\"apply_on_restart\">החל על הפעלה מחדש</string>\n    <string name=\"safe_mode_title\">מצב בטוח מופעל</string>\n    <string name=\"safe_mode_crash_info\">הצג מידע על ההתרסקות</string>\n    <string name=\"extension_rating\" formatted=\"true\">דירוג: %s</string>\n    <string name=\"extension_description\">תיאור</string>\n    <string name=\"extension_version\">גרסה</string>\n    <string name=\"extension_status\">מצב</string>\n    <string name=\"extension_size\">גודל</string>\n    <string name=\"extension_types\">תומך</string>\n    <string name=\"extension_install_first\">התקן תחילה את התוסף</string>\n    <string name=\"hls_playlist\">פלייליסט HLS</string>\n    <string name=\"player_pref\">נגן וידאו מועדף</string>\n    <string name=\"player_settings_play_in_app\">נגן פנימי</string>\n    <string name=\"app_not_found_error\">האפליקציה לא נמצאה</string>\n    <string name=\"all_languages_preference\">כל השפות</string>\n    <string name=\"skip_type_format\" formatted=\"true\">דלג %s</string>\n    <string name=\"skip_type_op\">פתיח</string>\n    <string name=\"skip_type_ed\">שיר סיום</string>\n    <string name=\"skip_type_recap\">סיכום</string>\n    <string name=\"skip_type_mixed_ed\">שיר סיום מעורב</string>\n    <string name=\"skip_type_intro\">מבוא</string>\n    <string name=\"clear_history\">נקה היסטוריה</string>\n    <string name=\"clipboard_too_large\">יותר מדי טקסט. לא ניתן לשמור ללוח.</string>\n    <string name=\"action_remove_from_watched\">הסר מצפייה</string>\n    <string name=\"confirm_exit_dialog\">האם אתם בטוחים שאתם רוצים לצאת?</string>\n    <string name=\"update_notification_downloading\">מוריד עדכון אפליקציה…</string>\n    <string name=\"update_notification_installing\">מתקין עדכון אפליקציה…</string>\n    <string name=\"delayed_update_notice\">האפליקציה תעודכן עם היציאה</string>\n    <string name=\"sort_by\">מיין לפי</string>\n    <string name=\"sort_rating_desc\">דירוג (גבוה לנמוך)</string>\n    <string name=\"sort_rating_asc\">דירוג (נמוך לגבוה)</string>\n    <string name=\"sort_updated_new\">מעודכן (חדש לישן)</string>\n    <string name=\"sort_updated_old\">מעודכן (ישן לחדש)</string>\n    <string name=\"sort_alphabetical_a\">אלפביתי (א \\'עד ת\\')</string>\n    <string name=\"sort_alphabetical_z\">אלפביתי (ת\\' עד א\\')</string>\n    <string name=\"open_with\">פתח עם</string>\n    <string name=\"empty_library_logged_in_message\">נראה שהרשימה הזו ריקה, נסו לעבור לרשימה אחרת.</string>\n    <string name=\"subscription_new\">רשום ל%s</string>\n    <string name=\"subscription_in_progress_notification\">מעדכן סדרות שנרשמת אליהן</string>\n    <string name=\"android_tv_interface_off_seek_settings\">נגן מוסתר - כמות הזזה</string>\n    <string name=\"mobile_data\">רשת סלולארית</string>\n    <string name=\"subscription_list_name\">רשום</string>\n    <string name=\"revert\">חזור</string>\n    <string name=\"subscription_deleted\">הרשמה ל-%s מבוטלת</string>\n    <string name=\"jsdelivr_proxy\">פרוקסי עבור raw.githubusercontent.com</string>\n    <string name=\"profiles\">פרופילים</string>\n    <string name=\"unable_to_inflate\">הממשק לא נוצר נכון. זוהי שגיאה רצינית, נא לדווח עליה מיידית ל-%s</string>\n    <string name=\"edit\">עריכה</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"profile_background_des\">רקע הפרופיל</string>\n    <string name=\"test_log\">רשומה</string>\n    <string name=\"help\">עזרה</string>\n    <string name=\"start\">התחלה</string>\n    <string name=\"stop\">עצור</string>\n    <string name=\"profile_number\">פרופיל %d</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">הזמן שיזוז כשהנגן מוצג</string>\n    <string name=\"android_tv_interface_on_seek_settings\">נגן מוצג - כמות הזזה</string>\n    <string name=\"restart\">אתחול</string>\n    <string name=\"jsdelivr_proxy_summary\">עוקף את החסימה של GitHub באמצעות jsDelivr. עלול לגרום לעדכונים להתעכב בכמה ימים.</string>\n    <string name=\"automatic_plugin_download_mode_title\">בחר מצב כדי לסנן תוספים להורדה</string>\n    <string name=\"qualities\">איכויות</string>\n    <string name=\"use\">השתמש</string>\n    <string name=\"category_provider_test\">בדיקת ספק</string>\n    <string name=\"test_failed\">נכשל</string>\n    <string name=\"subscription_episode_released\">פרק %d שוחרר לצפיה!</string>\n    <string name=\"disable\">ביטול</string>\n    <string name=\"watch_quality_pref_data\">איכות צפיה מועדפת (אינטרנט סלולארי)</string>\n    <string name=\"no_repository_found_error\">המאגר לא נמצא, נא לבדוק את ה-URL ולנסות VPN</string>\n    <string name=\"jsdelivr_enabled\">ההתחברות אל GitHub נכשלה. מדליק פרוקסי אל jsDelivr…</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">הזמן שיזוז כשהנגן מוסתר</string>\n    <string name=\"already_voted\">כבר הצבעת</string>\n    <string name=\"no_plugins_found_error\">לא נמצאו תוספים במאגר</string>\n    <string name=\"pref_category_android_tv\">טלוויזיית אנדרואיד</string>\n    <string name=\"set_default\">קביעה כברירת מחדל</string>\n    <string name=\"test_passed\">עבר</string>\n    <string name=\"pref_category_bypass\">מעקף ספק אינטרנט</string>\n    <string name=\"quality_profile_help\">כאן ניתן לשנות את סדר המקורות. אם לוידיאו יש עדיפות גבוהה יותר, הוא יופיע גבוה יותר בבחירת המקור. סכום עדיפות המקור ועדיפות האיכות היא עדיפות הוידיאו.\n\\n\n\\nמקור א: 3\n\\nאיכות ב: 7\n\\nיגרמו לעדיפות הסרטון להיות 10.\n\\n\n\\nשימו לב: אם הסכום הוא 10 או יותר, הנגן ידלג על טעינת הסרטון כאשר הלינק נטען!</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">עונה %1$d פרק %2$d תשודר ב:</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$d שעות %2$d דקות %3$d שניות</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$d דקות %2$d שניות</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d שניות</string>\n    <string name=\"play_from_beginning_img_des\">נגן מההתחלה</string>\n    <string name=\"speech_recognition_unavailable\">זיהוי דיבור לא זמין</string>\n    <string name=\"begin_speaking\">התחל לדבר…</string>\n    <string name=\"torrent_info\">וידיאו זה הוא טורנט, זה אומר שניתן לעקוב אחרי פעילות הוידיאו שלך.\\nנא וודא שהינך מבין טורנטים לפני המשך.</string>\n    <string name=\"downloads_delete_select\">בחר פריטים למחוק</string>\n    <string name=\"downloads_empty\">אין הורדות כרגע.</string>\n    <string name=\"offline_file\">זמין לצפיה אופליין</string>\n    <string name=\"select_all\">בחר הכל</string>\n    <string name=\"deselect_all\">הסר בחירה מהכל</string>\n    <string name=\"open_local_video\">פתח וידיאו מקומי</string>\n    <string name=\"links_reloaded_toast\">קישורים נטענו</string>\n    <string name=\"repo_copy_label\">שם ו-URL רפוזיטורי</string>\n    <string name=\"toast_copied\">הועתק!</string>\n    <string name=\"subscribe_tooltip\">התרעת פרק חדש</string>\n    <string name=\"result_search_tooltip\">חיפוש בתוספים אחרים</string>\n    <string name=\"recommendations_tooltip\">הראה המלצות</string>\n    <string name=\"speed_setting_summary\">מוסיף אפשרות מהירות בנגן</string>\n    <string name=\"backup_frequency\">תדירות גיבוי</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d分</string>\n    <string name=\"title_downloads\">ダウンロード</string>\n    <string name=\"title_search\">検索</string>\n    <string name=\"title_settings\">設定</string>\n    <string name=\"result_share\">シェア</string>\n    <string name=\"movies\">映画</string>\n    <string name=\"title_home\">ホーム</string>\n    <string name=\"library\">ライブラリ</string>\n    <string name=\"home_play\">再生</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d日 %2$d時間%3$d分</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$d時間%2$d分</string>\n    <string name=\"search_hint\">検索…</string>\n    <string name=\"download\">ダウンロード</string>\n    <string name=\"home_info\">情報</string>\n    <string name=\"season\">シーズン</string>\n    <string name=\"trailer\">予告編</string>\n    <string name=\"tv_series_singular\">シリーズ</string>\n    <string name=\"episodes\">エピソード</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">再生速度 (%.2fx)</string>\n    <string name=\"next_episode\">次のエピソード</string>\n    <string name=\"sort_apply\">適用</string>\n    <string name=\"category_account\">ア﻿カ﻿ウ﻿ン﻿トとセキュリティ</string>\n    <string name=\"cartoons\">カートゥーン</string>\n    <string name=\"tv_series\">TVシリーズ</string>\n    <string name=\"torrent\">トレント</string>\n    <string name=\"documentaries\">ドキュメンタリー</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">アジアドラマ</string>\n    <string name=\"livestreams\">ライブ配信</string>\n    <string name=\"movies_singular\">映画</string>\n    <string name=\"others\">その他</string>\n    <string name=\"cartoons_singular\">カートゥーン</string>\n    <string name=\"torrent_singular\">トレント</string>\n    <string name=\"documentaries_singular\">ドキュメンタリー</string>\n    <string name=\"asian_drama_singular\">アジアドラマ</string>\n    <string name=\"live_singular\">ライブ配信</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"anime\">アニメ</string>\n    <string name=\"video_lock\">ロック</string>\n    <string name=\"video_source\">ソース</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"clear_history\">履歴を削除</string>\n    <string name=\"continue_watching\">視聴中コンテンツ</string>\n    <string name=\"category_general\">全般</string>\n    <string name=\"other_singular\">動画</string>\n    <string name=\"category_player\">プレーヤー</string>\n    <string name=\"type_plan_to_watch\">視聴予定</string>\n    <string name=\"play_trailer_button\">予告編を再生</string>\n    <string name=\"episode_short\">エピソード</string>\n    <string name=\"type_watching\">視聴</string>\n    <string name=\"result_tags\">ジャンル</string>\n    <string name=\"play_movie_button\">映画を再生</string>\n    <string name=\"pick_subtitle\">字幕</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">CloudStreamで再生</string>\n    <string name=\"browser\">ブラウザ</string>\n    <string name=\"type_completed\">完成</string>\n    <string name=\"type_dropped\">放置</string>\n    <string name=\"type_on_hold\">保留</string>\n    <string name=\"loading\">ローディング…</string>\n    <string name=\"result_open_in_browser\">ブラウザで開く</string>\n    <string name=\"season_short\">シーズン</string>\n    <string name=\"resume_time_left\" formatted=\"true\">残り\n\\n%d分</string>\n    <string name=\"play_episode\">再生エピソード</string>\n    <string name=\"downloaded\">ダウンロード済</string>\n    <string name=\"pref_category_backup\">バックアップ</string>\n    <string name=\"home_source\">ソース</string>\n    <string name=\"history\">履歴</string>\n    <string name=\"result_poster_img_des\">ポスター</string>\n    <string name=\"sort_copy\">コピー</string>\n    <string name=\"sort_close\">閉じる</string>\n    <string name=\"sort_save\">保存</string>\n    <string name=\"sort_clear\">消去</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$sエピ%2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">出演者：%s</string>\n    <string name=\"search_poster_img_des\">ポスター</string>\n    <string name=\"episode_poster_img_des\">エピソードポスター</string>\n    <string name=\"home_main_poster_img_des\">主要ポスター</string>\n    <string name=\"home_next_random_img_des\">次のランダム</string>\n    <string name=\"go_back_img_des\">戻り</string>\n    <string name=\"rated_format\" formatted=\"true\">評価: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">新しいアップデートを発見!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration_format\" formatted=\"true\">%d分</string>\n    <string name=\"search_hint_site\" formatted=\"true\">%sを検索…</string>\n    <string name=\"pick_source\">ソース</string>\n    <string name=\"filler\" formatted=\"true\">番外編</string>\n    <string name=\"reload_error\">接続を再試行…</string>\n    <string name=\"go_back\">戻り</string>\n    <string name=\"action_remove_from_bookmarks\">削除</string>\n    <string name=\"home_more_info\">詳細情報</string>\n    <string name=\"home_expanded_hide\">閉じる</string>\n    <string name=\"category_updates\">アップデートとバックアップ</string>\n    <string name=\"app_language\">アプリ言語</string>\n    <string name=\"github\">GitHub（ギットハブ）</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"legal_notice\">免責</string>\n    <string name=\"pref_category_extensions\">拡張機能</string>\n    <string name=\"pref_category_app_updates\">アプリ更新</string>\n    <string name=\"category_providers\">提供者</string>\n    <string name=\"pref_category_subtitles\">字幕</string>\n    <string name=\"pref_category_ui_features\">特徴</string>\n    <string name=\"pref_category_defaults\">デフォルト</string>\n    <string name=\"automatic\">自動</string>\n    <string name=\"home_random\">任意</string>\n    <string name=\"extensions\">拡張機能</string>\n    <string name=\"pref_category_links\">リンク</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"login\">ログイン</string>\n    <string name=\"logout\">ログアウト</string>\n    <string name=\"max\">最大</string>\n    <string name=\"min\">最小</string>\n    <string name=\"none\">なし</string>\n    <string name=\"next\">次</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"no\">否</string>\n    <string name=\"open_with\">で開く</string>\n    <string name=\"episode\">エピソード</string>\n    <string name=\"duration\">時間</string>\n    <string name=\"synopsis\">概要</string>\n    <string name=\"site\">サイト</string>\n    <string name=\"used_storage\">使用</string>\n    <string name=\"app_storage\">アプリ</string>\n    <string name=\"action_open_watching\">詳細情報</string>\n    <string name=\"action_remove_watching\">削除</string>\n    <string name=\"picture_in_picture\">ピクチャーインピクチャー</string>\n    <string name=\"player_subtitles_settings\">字幕</string>\n    <string name=\"settings_info\">情報</string>\n    <string name=\"pause\">一時停止</string>\n    <string name=\"play_episode_toast\">再生エピソード</string>\n    <string name=\"delete\">削除</string>\n    <string name=\"cancel\">キャンセル</string>\n    <string name=\"start\">開始</string>\n    <string name=\"status\">状態</string>\n    <string name=\"year\">年</string>\n    <string name=\"resume\">再開</string>\n    <string name=\"test_failed\">失敗</string>\n    <string name=\"test_passed\">合格</string>\n    <string name=\"free_storage\">空き</string>\n    <string name=\"status_completed\">完成</string>\n    <string name=\"status_ongoing\">進行中</string>\n    <string name=\"normal\">デフォルト</string>\n    <string name=\"extension_language\">言語</string>\n    <string name=\"extension_authors\">作成者</string>\n    <string name=\"extension_size\">サイズ</string>\n    <string name=\"extension_status\">状態</string>\n    <string name=\"extension_version\">バージョン</string>\n    <string name=\"extension_rating\" formatted=\"true\">視聴率 %s</string>\n    <string name=\"rating\">視聴率</string>\n    <string name=\"action_default\">デフォルト</string>\n    <string name=\"download_failed\">ダウンロード失敗</string>\n    <string name=\"download_started\">ダウンロード開始</string>\n    <string name=\"download_done\">ダウンロード完了</string>\n    <string name=\"download_canceled\">ダウンロード終了</string>\n    <string name=\"stream\">ネットワークストリーム</string>\n    <string name=\"update_started\">アップデート開始</string>\n    <string name=\"no_season\">シーズンなし</string>\n    <string name=\"no_subtitles\">字幕なし</string>\n    <string name=\"video_aspect_ratio_resize\">アスペクト比</string>\n    <string name=\"skip_loading\">ロードをスキップする</string>\n    <string name=\"episode_more_options_des\">その他のオプション</string>\n    <string name=\"no_data\">データなし</string>\n    <string name=\"downloading\">ダウンロード中</string>\n    <string name=\"error_bookmarks_text\">ブックマーク</string>\n    <string name=\"download_storage_text\">内部記憶装置</string>\n    <string name=\"download_paused\">ダウンロードが一時停止</string>\n    <string name=\"provider_info_meta\">メタデータはこのサイトでは提供されません。メタデータがサイト上に存在しない場合、ビデオの読み込みに失敗します。</string>\n    <string name=\"torrent_plot\">記述</string>\n    <string name=\"show_log_cat\">Logcat 🐈を表示</string>\n    <string name=\"test_log\">ログ</string>\n    <string name=\"search\">検索</string>\n    <string name=\"discord\">Discordに参加</string>\n    <string name=\"update\">アップデート</string>\n    <string name=\"check_for_update\">アップデートを確認</string>\n    <string name=\"show_title\">作品名</string>\n    <string name=\"update_notification_installing\">アプリのアップデートをインストール中…</string>\n    <string name=\"repository_url_hint\">リポジトリURLまたはショートコード</string>\n    <string name=\"subtitle_offset_title\">字幕ディレイ</string>\n    <string name=\"subscription_list_name\">登録済み</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">字幕遅延なし</string>\n    <string name=\"delete_repository\">リポジトリ削除</string>\n    <string name=\"download_all_plugins_from_repo\">警告: CloudStreamはサードパーティの拡張機能の使用について一切の責任を負わず、それらに対するサポートも提供しません！</string>\n    <string name=\"action_add_to_bookmarks\">視聴状態を設定</string>\n    <string name=\"subtitle_offset\">字幕を同期</string>\n    <string name=\"add_repository\">リポジトリを追加</string>\n    <string name=\"repository_name_hint\">リポジトリ名 (オプション)</string>\n    <string name=\"blank_repo_message\">CloudStreamはデフォルトでサイトがインストールされていません。リポジトリからサイトをインストールする必要があります。 \\n \\n私たちのDiscordに参加するか、オンラインで検索してください。</string>\n    <string name=\"preview_background_img_des\">バックグラウンドをプレビュー</string>\n    <string name=\"play_livestream_button\">ライブストリームの再生</string>\n    <string name=\"home_change_provider_img_des\">プロバイダーの変更</string>\n    <string name=\"next_episode_format\" formatted=\"true\">エピソード %d は にリリースされます</string>\n    <string name=\"type_re_watching\">再視聴</string>\n    <string name=\"play_torrent_button\">ストリームトレント</string>\n    <string name=\"subs_text_color\">文字の色</string>\n    <string name=\"popup_delete_file\">ファイルを削除</string>\n    <string name=\"popup_play_file\">再生ファイル</string>\n    <string name=\"subs_background_color\">背景の色</string>\n    <string name=\"subs_window_color\">窓の色</string>\n    <string name=\"subs_edge_type\">エッジタイプ</string>\n    <string name=\"popup_pause_download\">ダウンロードを一時停止する</string>\n    <string name=\"search_provider_text_types\">使用タイプの検索</string>\n    <string name=\"subs_font\">フォント</string>\n    <string name=\"subs_download_languages\">言語をダウンロードする</string>\n    <string name=\"subs_subtitle_languages\">字幕の言語</string>\n    <string name=\"subs_font_size\">フォントサイズ</string>\n    <string name=\"search_provider_text_providers\">プロバイダーから探す</string>\n    <string name=\"subs_auto_select_language\">言語の自動選択</string>\n    <string name=\"error_loading_links_toast\">リンクの読み込みエラー</string>\n    <string name=\"enter_pin\">137905</string>\n    <string name=\"links_reloaded_toast\">リンクがリロードされました</string>\n    <string name=\"player_speed\">プレーヤーの速度</string>\n    <string name=\"subtitles_settings\">字幕設定</string>\n    <string name=\"app_dubbed_text\">ダブ</string>\n    <string name=\"app_subbed_text\">サブ</string>\n    <string name=\"torrent_no_plot\">説明が見つかりません</string>\n    <string name=\"swipe_to_change_settings\">スワイプして設定を変更します</string>\n    <string name=\"subs_outline_color\">輪郭の色</string>\n    <string name=\"subs_subtitle_elevation\">字幕の標高</string>\n    <string name=\"benene_count_text\">%d ベネネスが開発者に与えられました</string>\n    <string name=\"vpn_might_be_needed\">このプロバイダーが正しく動作するには VPN が必要になる可能性があります</string>\n    <string name=\"vpn_torrent\">このプロバイダーは torrent です、VPN をお勧めします</string>\n    <string name=\"player_size_settings\">プレーヤーのサイズ変更ボタン</string>\n    <string name=\"player_size_settings_des\">黒い境界線を削除します</string>\n    <string name=\"player_subtitles_settings_des\">プレーヤーの字幕設定</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecastの字幕</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecastの字幕設定</string>\n    <string name=\"swipe_to_seek_settings\">スワイプして探す</string>\n    <string name=\"autoplay_next_settings\">次のエピソードを自動再生する</string>\n    <string name=\"autoplay_next_settings_des\">現在のエピソードが終了したら次のエピソードを開始する</string>\n    <string name=\"subs_hold_to_reset_to_default\">長押しするとデフォルトにリセットされます</string>\n    <string name=\"popup_resume_download\">ダウンロードを再開</string>\n    <string name=\"filter_bookmarks\">ブックマークのフィルタ</string>\n    <string name=\"normal_no_plot\">プロットが見つかりません</string>\n    <string name=\"double_tap_to_pause_settings\">ダブルタップで一時停止</string>\n    <string name=\"show_trailers_settings\">トレーラーを表示</string>\n    <string name=\"jsdelivr_proxy\">GitHub プロキシ</string>\n    <string name=\"use_system_brightness_settings\">システムの明るさを使用</string>\n    <string name=\"apk_installer_settings\">APKインストーラ</string>\n    <string name=\"pref_category_security\">セキュリティ</string>\n    <string name=\"add_account\">アカウントを追加</string>\n    <string name=\"backup_failed\">ストレージの権限がありません。もう一度試してください。</string>\n    <string name=\"advanced_search\">詳細検索</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"video_skip_op\">OPをスキップ</string>\n    <string name=\"resize_fit\">画面に合わせる</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"tv_layout\">テレビでのレイアウト</string>\n    <string name=\"eigengraumode_settings\">再生速度</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">%s ファイルからデータを復元できませんでした</string>\n    <string name=\"unexpected_error\">予期しないプレーヤーエラー</string>\n    <string name=\"episode_action_play_in_app\">アプリで再生</string>\n    <string name=\"episode_action_download_subtitle\">字幕をダウンロード</string>\n    <string name=\"show_dub\">吹き替えのラベル</string>\n    <string name=\"show_sub\">字幕のラベル</string>\n    <string name=\"skip_update\">この更新をスキップする</string>\n    <string name=\"video_buffer_disk_settings\">ディスク上のビデオキャッシュ</string>\n    <string name=\"video_buffer_size_settings\">ビデオバッファサイズ</string>\n    <string name=\"display_subbed_dubbed_settings\">字幕付きまたは吹き替え済みのアニメを表示</string>\n    <string name=\"pref_category_player_layout\">レイアウト</string>\n    <string name=\"app_layout\">アプリのレイアウト</string>\n    <string name=\"subtitles_encoding\">字幕エンコーディング</string>\n    <string name=\"category_ui\">レイアウト</string>\n    <string name=\"phone_layout\">携帯電話でのレイアウト</string>\n    <string name=\"emulator_layout\">エミュレータでのレイアウト</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"disable\">無効化</string>\n    <string name=\"subtitles_outline\">概要</string>\n    <string name=\"music_singlar\">音楽</string>\n    <string name=\"double_tap_to_pause_settings_des\">中央で２回タップして一時停止</string>\n    <string name=\"episode_action_play_in_format\">%s で再生</string>\n    <string name=\"switch_account\">アカウントを切り替え</string>\n    <string name=\"create_account\">アカウントを作成</string>\n    <string name=\"no_chromecast_support_toast\">このプロバイダはChromecastをサポートしていません</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"play_from_beginning_img_des\">最初から再生する</string>\n    <string name=\"anime_singular\">アニメ</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"delete_message\" formatted=\"true\">%s は完全に削除されます\\n大丈夫ですか？</string>\n    <string name=\"delete_file\">ファイルを削除</string>\n    <string name=\"episode_action_auto_download\">自動ダウンロード</string>\n    <string name=\"no_update_found\">更新が見つかりません</string>\n    <string name=\"dont_show_again\">次回から表示しない</string>\n    <string name=\"video_buffer_length_settings\">ビデオバッファの長さ</string>\n    <string name=\"add_site_summary\">既存のサイトのクローンを異なるURLで追加します</string>\n    <string name=\"pref_category_cache\">キャッシュ</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"subscribe_tooltip\">新しいエピソードの通知</string>\n    <string name=\"recommendations_tooltip\">おすすめを見る</string>\n    <string name=\"repo_copy_label\">リポジトリ名とURL</string>\n    <string name=\"toast_copied\">コピーされました！</string>\n    <string name=\"audio_book_singular\">オーディオブック</string>\n    <string name=\"custom_media_singluar\">メディア</string>\n    <string name=\"limit_title_rez\">プレイヤー情報を表示</string>\n    <string name=\"speed_setting_summary\">プレイヤーに速度オプションを追加</string>\n    <string name=\"downloads_delete_select\">削除する項目を選択</string>\n    <string name=\"offline_file\">オフラインで視聴可能</string>\n    <string name=\"select_all\">全選択</string>\n    <string name=\"deselect_all\">すべて選択解除</string>\n    <string name=\"updates_settings\">アプリの更新を表示</string>\n    <string name=\"copy_link_toast\">コピーされました</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">これらのアイテムを完全に削除しますか？\\n\\n%s</string>\n    <string name=\"nginx_url_pref\">NGINXサーバーのURL</string>\n    <string name=\"restore_settings\">バックアップからデータを復元</string>\n    <string name=\"updates_settings_des\">アプリ起動後に自動的に更新を探します。</string>\n    <string name=\"subs_default_reset_toast\">初期値にリセット</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"no_episodes_found\">エピソードが見つかりません</string>\n    <string name=\"app_theme_settings\">アプリのテーマ</string>\n    <string name=\"error\">エラー</string>\n    <string name=\"setup_done\">完了</string>\n    <string name=\"no_plugins_found_error\">リポジトリにプラグインが見つかりません</string>\n    <string name=\"coming_soon\">近日公開…</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"view_public_repositories_button\">コミュニティのリポジトリを見る</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"poster_image\">ポスター画像</string>\n    <string name=\"error_invalid_id\">無効なID</string>\n    <string name=\"error_invalid_url\">不正なURL</string>\n    <string name=\"plugin_singular\">プラグイン</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (無効)</string>\n    <string name=\"safe_mode_crash_info\">クラッシュ情報を見る</string>\n    <string name=\"app_not_found_error\">アプリが見つかりません</string>\n    <string name=\"plugin\">プラグイン</string>\n    <string name=\"recommended\">おすすめ</string>\n    <string name=\"skip_setup\">セットアップをスキップ</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">%s を読み込めません</string>\n    <string name=\"player_load_subtitles\">ファイルから読み込む</string>\n    <string name=\"player_load_subtitles_online\">インターネットから読み込む</string>\n    <string name=\"quality_blueray\">ブルーレイ</string>\n    <string name=\"quality_webrip\">ウェブ</string>\n    <string name=\"resolution\">解像度</string>\n    <string name=\"delete_plugin\">プラグインを削除</string>\n    <string name=\"audio_tracks\">オーディオトラック</string>\n    <string name=\"video_tracks\">ビデオトラック</string>\n    <string name=\"error_invalid_data\">無効なデータ</string>\n    <string name=\"subscription_episode_released\">エピソード %d がリリース!</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"duplicate_replace_all\">すべて置き換え</string>\n    <string name=\"reset_btn\">リセット</string>\n    <string name=\"select_library\">ライブラリを選択</string>\n    <string name=\"favorites_list_name\">お気に入り</string>\n    <string name=\"favorite_removed\">%s がお気に入りから削除されました</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"auto_rotate_video\">自動回転</string>\n    <string name=\"cs3wiki\">CloudStreamウィキ</string>\n    <string name=\"already_voted\">すでに投票しました</string>\n    <string name=\"duplicate_add\">追加</string>\n    <string name=\"mobile_data\">モバイルデータ</string>\n    <string name=\"app_info_intent_error\">CloudStreamのアプリ情報を開くことができません.</string>\n    <string name=\"update_notification_downloading\">アプリの更新をダウンロード中…</string>\n    <string name=\"apk_installer_legacy\">レガシー</string>\n    <string name=\"profile_background_des\">プロフィールの背景</string>\n    <string name=\"pin_error_incorrect\">PINが違います。もう一度試してください。</string>\n    <string name=\"pin_error_length\">PINは4文字でなければなりません</string>\n    <string name=\"biometric_prompt_description\">数回失敗すると、プロンプトが閉じます。アプリを再起動してもう一度試してください。</string>\n    <string name=\"device_pin_counter_text\">%1$dm %2$ds でコードが切れます</string>\n    <string name=\"preview_seekbar_desc\">シークバー上のプレビューを有効化する</string>\n    <string name=\"confirm_before_exiting_title\">終了前に確認</string>\n    <string name=\"confirm_before_exiting_desc\">アプリを終了する前にダイアログを表示する</string>\n    <string name=\"show\">表示</string>\n    <string name=\"dont_show\">表示しない</string>\n    <string name=\"favorite_added\">%s がお気に入りに追加されました</string>\n    <string name=\"set_default\">デフォルトに設定</string>\n    <string name=\"action_remove_from_favorites\">お気に入りから削除</string>\n    <string name=\"select_an_account\">アカウントを選択</string>\n    <string name=\"sort_alphabetical_a\">アルファベット順 (A ~ Z)</string>\n    <string name=\"sort_alphabetical_z\">アルファベット順 (Z ~ A)</string>\n    <string name=\"duplicate_replace\">置き換え</string>\n    <string name=\"enter_current_pin\">現在のPINを入力してください</string>\n    <string name=\"manage_accounts\">アカウントの管理</string>\n    <string name=\"edit_account\">アカウントを編集</string>\n    <string name=\"logged_account\" formatted=\"true\">%sとしてログインしました</string>\n    <string name=\"skip_startup_account_select_pref\">開始時のアカウント選択をスキップする</string>\n    <string name=\"use_default_account\">デフォルトアカウントを使用する</string>\n    <string name=\"rotate_video\">回転</string>\n    <string name=\"favorite\">お気に入り</string>\n    <string name=\"biometric_unsupported\">生体認証は、このデバイスではサポートされていません</string>\n    <string name=\"biometric_setting_summary\">指紋、顔ID、PIN、パターン、パスワードでアプリをロック解除します.</string>\n    <string name=\"device_pin_url_message\">スマホやPCで<b>%s</b>にアクセスし、上記のコードを入力してください</string>\n    <string name=\"device_pin_expired_message\">PINコードが期限切れになりました！</string>\n    <string name=\"empty_library_no_accounts_message\">ライブラリが空です :(\\nライブラリアカウントにログインするか、ローカルライブラリに表示を追加してください。</string>\n    <string name=\"empty_library_logged_in_message\">このリストは空です。 別のものに切り替えてみてください。</string>\n    <string name=\"edit\">編集</string>\n    <string name=\"help\">ヘルプ</string>\n    <string name=\"action_add_to_favorites\">お気に入りに追加</string>\n    <string name=\"preview_seekbar\">シークバーのプレビュー</string>\n    <string name=\"no_subtitles_loaded\">字幕はまだ読み込まれていません</string>\n    <string name=\"backup_path_title\">バックアップフォルダの場所</string>\n    <string name=\"custom\">カスタム</string>\n    <string name=\"delayed_update_notice\">終了時にアプリが更新されます</string>\n    <string name=\"apk_installer_package_installer\">パッケージインストーラ</string>\n    <string name=\"sort_release_date_new\">リリース日(新着順)</string>\n    <string name=\"duplicate_title\">潜在的な重複が見つかりました</string>\n    <string name=\"plugin_deleted\">プラグインが消されました</string>\n    <string name=\"unfavorite\">お気に入り解除</string>\n    <string name=\"update_notification_failed\">アプリの新しいバージョンをインストールできませんでした</string>\n    <string name=\"backup_frequency\">バックアップ頻度</string>\n    <string name=\"picture_in_picture_des\">他のアプリの上にミニプレイヤーで再生し続ける</string>\n    <string name=\"downloads_empty\">現在ダウンロードはがありません。</string>\n    <string name=\"benene_count_text_none\">ベネネは与えられていません</string>\n    <string name=\"double_tap_to_seek_settings\">ダブルタップでシーク</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">プレーヤーが非表示のときに使用されるシーク量</string>\n    <string name=\"resize_zoom\">ズーム</string>\n    <string name=\"action_subscribe\">購読</string>\n    <string name=\"subtitles_from_embedded\">埋め込み</string>\n    <string name=\"subtitles_from_online\">オンライン</string>\n    <string name=\"lightnovel\">同じ開発者によるライトノベルアプリ</string>\n    <string name=\"add_site_pref\">サイトをクローン</string>\n    <string name=\"actor_main\">メイン</string>\n    <string name=\"subtitles_remove_bloat\">字幕から不要なものを削除</string>\n    <string name=\"safe_mode_file\">セーフモードファイルが見つかりました！\\nファイルが削除されるまで、スタートアップ時に拡張機能は読み込まれません。</string>\n    <string name=\"remove_site_pref\">サイトを削除</string>\n    <string name=\"view_public_repositories_button_short\">公開リスト</string>\n    <string name=\"uppercase_all_subtitles\">すべての字幕を大文字にする</string>\n    <string name=\"enable_skip_op_from_database_des\">オープニング/エンディングのスキップポップアップを表示</string>\n    <string name=\"clipboard_too_large\">テキストが多すぎます。クリップボードに保存できません。</string>\n    <string name=\"sort_episodes_number_desc\">エピソード (降順)</string>\n    <string name=\"sort_episodes_rating_high_low\">評価 (最高)</string>\n    <string name=\"unable_to_inflate\">UIが正しく作成できませんでした。これは重大なバグであり、すぐに報告する必要があります %s</string>\n    <string name=\"update_plugins\">プラグインを更新</string>\n    <string name=\"starting_plugin_update_manually\">プラグインの更新プロセスを開始します！</string>\n    <string name=\"update_plugins_manually\">プラグインを手動で更新</string>\n    <string name=\"episode_sync_settings\">視聴進捗を更新</string>\n    <string name=\"backup_success\">データが保存されました</string>\n    <string name=\"advanced_search_des\">プロバイダごとに分かれた検索結果を提供します</string>\n    <string name=\"watch_quality_pref\">優先視聴品質 (WiFi)</string>\n    <string name=\"auth_locally\">ローカルで認証</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">%s でログインできませんでした</string>\n    <string name=\"pref_category_bypass\">ISPバイパス</string>\n    <string name=\"pref_category_accounts\">アカウント</string>\n    <string name=\"test_extensions\">すべての拡張機能をテスト</string>\n    <string name=\"example_password\">password123</string>\n    <string name=\"restart\">再起動</string>\n    <string name=\"android_tv_interface_on_seek_settings\">プレーヤー表示時 - シーク量</string>\n    <string name=\"random_button_settings_desc\">ホームページとライブラリにランダムボタンを表示</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">すべての %s はすでにダウンロードされています</string>\n    <string name=\"extension_install_first\">最初に拡張機能をインストール</string>\n    <string name=\"player_settings_play_in_app\">内部プレーヤー</string>\n    <string name=\"backup_settings\">データをバックアップ</string>\n    <string name=\"queued\">キューに入れられました</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">プレーヤーが表示されているときに使用されるシーク量</string>\n    <string name=\"extras\">エクストラ</string>\n    <string name=\"skip_type_op\">オープニング</string>\n    <string name=\"subscription_new\">%s を購読しました</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"subs_import_text\" formatted=\"true\">フォントを %s に配置してインポート</string>\n    <string name=\"show_fillers_settings\">アニメのフィラーエピソードを表示</string>\n    <string name=\"automatic_plugin_updates\">自動プラグインアップデート</string>\n    <string name=\"delete_format\" formatted=\"true\">削除 (%1$d | %2$s)</string>\n    <string name=\"render_error\">レンダラーエラー</string>\n    <string name=\"storage_error\">ダウンロードエラー、ストレージの許可を確認してください</string>\n    <string name=\"source_error\">ソースエラー</string>\n    <string name=\"episode_action_chromecast_episode\">エピソードをChromecast</string>\n    <string name=\"video_buffer_clear_settings\">ビデオと画像のキャッシュをクリア</string>\n    <string name=\"primary_color_settings\">プライマリカラー</string>\n    <string name=\"example_site_name\">NewSiteName</string>\n    <string name=\"example_lang_name\">言語コード (en)</string>\n    <string name=\"account\">アカウント</string>\n    <string name=\"delete_repository_plugins\">これにより、リポジトリのすべてのプラグインも削除されます</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">無効: %d</string>\n    <string name=\"player_pref\">優先ビデオプレーヤー</string>\n    <string name=\"skip_type_format\" formatted=\"true\">%s をスキップ</string>\n    <string name=\"skip_type_creddits\">クレジット</string>\n    <string name=\"app_unrestricted_toast\">アプリのバッテリー使用はすでに無制限に設定されています</string>\n    <string name=\"sort\">並べ替え</string>\n    <string name=\"revert\">元に戻す</string>\n    <string name=\"subscription_in_progress_notification\">購読している番組を更新中</string>\n    <string name=\"biometric_authentication_title\">CloudStreamをアンロック</string>\n    <string name=\"apply_on_restart\">変更を反映するにはアプリを再起動してください。</string>\n    <string name=\"benene\">開発者にベネネを与える</string>\n    <string name=\"benene_des\">与えられたベネネ</string>\n    <string name=\"use\">使用</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"apk_installer_settings_des\">一部のスマートフォンは新しいパッケージインストーラをサポートしていません。アップデートがインストールされない場合はレガシーオプションを試してください。</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecastミラー</string>\n    <string name=\"double_tap_to_seek_settings_des\">前後にシークするために右側または左側をダブルタップ</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"anim\">同じ開発者によるアニメアプリ</string>\n    <string name=\"remote_error\">リモートエラー</string>\n    <string name=\"episode_action_download_mirror\">ミラーをダウンロード</string>\n    <string name=\"poster_ui_settings\">ポスター上のUI要素を切り替え</string>\n    <string name=\"dns_pref_summary\">ISPのブロックを回避するのに役立ちます</string>\n    <string name=\"pref_category_looks\">外観</string>\n    <string name=\"example_username\">ユーザー名</string>\n    <string name=\"add_sync\">トラッキングを追加</string>\n    <string name=\"added_sync_format\" formatted=\"true\">%s を追加しました</string>\n    <string name=\"upload_sync\">同期</string>\n    <string name=\"sync_score\">評価済み</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s で認証されました</string>\n    <string name=\"all\">すべて</string>\n    <string name=\"subtitles_shadow\">影</string>\n    <string name=\"subtitles_raised\">浮き上がった</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">字幕が %d ms 早く表示される場合に使用</string>\n    <string name=\"downloaded_file\">ダウンロードしたファイル</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">%s を読み込みました</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"resolution_and_title\">解像度とタイトル</string>\n    <string name=\"title\">タイトル</string>\n    <string name=\"subtitles_filter_lang\">優先メディア言語でフィルタ</string>\n    <string name=\"referer\">リファラー (任意)</string>\n    <string name=\"app_layout_subtext\">デバイスの外観に合わせてアプリのレイアウトを変更</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">%1$d %2$s のダウンロードを開始しました…</string>\n    <string name=\"plugin_loaded\">プラグインが読み込まれました</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">ダウンロード済み: %d</string>\n    <string name=\"tracks\">トラック</string>\n    <string name=\"safe_mode_title\">セーフモードオン</string>\n    <string name=\"extension_description\">説明</string>\n    <string name=\"hls_playlist\">HLSプレイリスト</string>\n    <string name=\"skip_type_ed\">エンディング</string>\n    <string name=\"skip_type_recap\">リキャップ</string>\n    <string name=\"skip_type_mixed_ed\">ミックスエンディング</string>\n    <string name=\"sort_rating_desc\">評価 (高い順)</string>\n    <string name=\"sort_rating_asc\">評価 (低い順)</string>\n    <string name=\"sort_updated_new\">更新日 (新しい順)</string>\n    <string name=\"category_provider_test\">プロバイダテスト</string>\n    <string name=\"stop\">停止</string>\n    <string name=\"profile_number\">プロフィール %d</string>\n    <string name=\"automatic_plugin_download_mode_title\">プラグインダウンロードをフィルタするモードを選択</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">ライブラリに潜在的な重複アイテムがすでに存在します: \\'%s.\\' \\n\\nこのアイテムを追加しますか、既存のものを置き換えますか、それともアクションをキャンセルしますか？</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">%s のPINを入力</string>\n    <string name=\"rotate_video_desc\">画面の向きを切り替えるトグルボタンを表示</string>\n    <string name=\"auto_rotate_video_desc\">ビデオの向きに基づいて画面の向きを自動的に切り替える</string>\n    <string name=\"result_search_tooltip\">他の拡張機能で検索</string>\n    <string name=\"test_extensions_summary\">このテストは開発者専用であり、拡張機能の動作を検証または否定しません。</string>\n    <string name=\"biometric_setting\">生体認証でロック</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\n残り</string>\n    <string name=\"clipboard_unknown_error\">コピー中にエラーが発生しました。logcatをコピーしてアプリサポートに連絡してください。</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"battery_dialog_title\">バッテリー最適化を無効にする</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">%s 後に公開</string>\n    <string name=\"episode_action_cast_mirror\">キャストミラー</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">シーズン %1$d エピソード %2$d は</string>\n    <string name=\"open_local_video\">ローカルビデオを開く</string>\n    <string name=\"test_warning\">警告</string>\n    <string name=\"dismiss\">閉じる</string>\n    <string name=\"open_downloaded_repo\">リポジトリを開く</string>\n    <string name=\"jsdelivr_enabled\">GitHubに接続できません。jsDelivrプロキシをオンにします…</string>\n    <string name=\"jsdelivr_proxy_summary\">jsDelivrを使用して生のGitHub URLのブロックを回避します。アップデートが数日遅れる可能性があります。</string>\n    <string name=\"speech_recognition_unavailable\">音声認識は利用できません</string>\n    <string name=\"begin_speaking\">話し始めてください…</string>\n    <string name=\"torrent_info\">このビデオはトレントのため、ビデオの活動が追跡される可能性があります。\\n続行する前にトレントについて理解してください。</string>\n    <string name=\"watch_quality_pref_data\">優先視聴品質 (モバイルデータ)</string>\n    <string name=\"limit_title\">ビデオプレーヤーのタイトル最大文字数</string>\n    <string name=\"video_disk_description\">ストレージが少ないデバイス（Android TVなど）で高く設定すると問題が発生します。</string>\n    <string name=\"bottom_title_settings\">ポスターのタイトルの位置</string>\n    <string name=\"bottom_title_settings_des\">タイトルをポスターの下に配置</string>\n    <string name=\"subtitles_depressed\">凹んだ</string>\n    <string name=\"qr_image\">QRコード画像</string>\n    <string name=\"previous\">前へ</string>\n    <string name=\"preferred_media_subtext\">表示したいもの</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">%1$d %2$s をダウンロードしました</string>\n    <string name=\"lock_profile\">プロフィールをロック</string>\n    <string name=\"password_pin_authentication_title\">パスワード/PIN認証</string>\n    <string name=\"pref_filter_search_quality\">検索結果で選択したビデオ品質を非表示</string>\n    <string name=\"automatic_plugin_download_summary\">追加されたリポジトリから未インストールのすべてのプラグインを自動的にインストールします。</string>\n    <string name=\"redo_setup_process\">セットアッププロセスを再実行</string>\n    <string name=\"no_links_found_toast\">リンクが見つかりません</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">%1$s の以下のエピソードを永久に削除してもよろしいですか？\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">以下のシリーズのすべてのエピソードも永久に削除されます：\\n\\n%s</string>\n    <string name=\"random_button_settings\">ランダムボタン</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"resize_fill\">引き伸ばす</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"plugin_downloaded\">プラグインがダウンロードされました</string>\n    <string name=\"player_load_one_subtitle_online\">最初に利用可能なものを読み込む</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"subtitles_remove_captions\">字幕からクローズドキャプションを削除</string>\n    <string name=\"setup_extensions_subtext\">使用したいサイトのリストをダウンロード</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">未ダウンロード: %d</string>\n    <string name=\"all_languages_preference\">すべての言語</string>\n    <string name=\"skip_type_mixed_op\">ミックスオープニング</string>\n    <string name=\"sort_by\">並べ替え</string>\n    <string name=\"subs_edge_size\">エッジサイズ</string>\n    <string name=\"swipe_to_seek_settings_des\">ビデオの位置を制御するために左右にスワイプ</string>\n    <string name=\"swipe_to_change_settings_des\">明るさや音量を変更するために左右に上下にスワイプ</string>\n    <string name=\"double_tap_to_seek_amount_settings\">プレーヤーのシーク量（秒）</string>\n    <string name=\"use_system_brightness_settings_des\">アプリプレーヤーで暗いオーバーレイの代わりにシステムの明るさを使用</string>\n    <string name=\"episode_sync_settings_des\">現在のエピソードの進捗を自動的に同期</string>\n    <string name=\"restore_success\">バックアップファイルを読み込みました</string>\n    <string name=\"backup_failed_error_format\">%s のバックアップに失敗しました</string>\n    <string name=\"kitsu_settings\">Kitsuのポスターを表示</string>\n    <string name=\"automatic_plugin_download\">自動的にプラグインをダウンロード</string>\n    <string name=\"delete_files\">ファイルを削除</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">以下のシリーズのすべてのエピソードを永久に削除してもよろしいですか？\\n\\n%s</string>\n    <string name=\"episode_action_reload_links\">リンクをリロード</string>\n    <string name=\"show_hd\">品質ラベル</string>\n    <string name=\"video_ram_description\">メモリが少ないデバイス（Android TVなど）で高く設定するとクラッシュの原因になります。</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"download_path_pref\">ダウンロードパス</string>\n    <string name=\"pref_category_gestures\">ジェスチャー</string>\n    <string name=\"provider_lang_settings\">拡張機能の言語</string>\n    <string name=\"preferred_media_settings\">優先メディア</string>\n    <string name=\"enable_nsfw_on_providers\">サポートされている拡張機能でNSFWを有効にする</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">字幕が %d ms 遅く表示される場合に使用</string>\n    <string name=\"subtitles_example_text\">The quick brown fox jumps over the lazy dog</string>\n    <string name=\"actor_supporting\">サポート</string>\n    <string name=\"actor_background\">背景</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"provider_languages_tip\">これらの言語でビデオを視聴</string>\n    <string name=\"no_repository_found_error\">リポジトリが見つかりません。URLを確認し、VPNを試してください</string>\n    <string name=\"batch_download\">一括ダウンロード</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d 個のプラグインを更新しました</string>\n    <string name=\"safe_mode_description\">トラブルを引き起こすものを特定するのを助けるために、クラッシュのためにすべての拡張機能がオフにされました。</string>\n    <string name=\"extension_types\">サポート</string>\n    <string name=\"player_settings_select_cast_device\">キャストデバイスを選択</string>\n    <string name=\"skip_type_intro\">イントロ</string>\n    <string name=\"clipboard_permission_error\">クリップボードへのアクセスエラー。もう一度お試しください。</string>\n    <string name=\"action_mark_as_watched\">視聴済みとしてマーク</string>\n    <string name=\"action_remove_from_watched\">視聴済みから削除</string>\n    <string name=\"confirm_exit_dialog\">本当に終了しますか？</string>\n    <string name=\"yes\">はい</string>\n    <string name=\"battery_dialog_message\">中断のないダウンロードと購読しているテレビ番組の通知を確実にするために、CloudStreamはバックグラウンドで実行する許可が必要です。\\'OK\\'を押すと、リクエストダイアログが表示されます。\\'許可\\'を押してください。\\n\\nこの許可は、CS3がバッテリーを消耗することを意味するものではありません。通知の受信や公式拡張機能からのビデオのダウンロードなど、必要な場合にのみバックグラウンドで動作します。</string>\n    <string name=\"sort_updated_old\">更新日 (古い順)</string>\n    <string name=\"sort_episodes_number_asc\">エピソード (昇順)</string>\n    <string name=\"sort_episodes_rating_low_high\">評価 (最低)</string>\n    <string name=\"sort_episodes_date_newest\">放映日 (最新)</string>\n    <string name=\"sort_episodes_date_oldest\">放映日 (最古)</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_rating\">評価 %s</string>\n    <string name=\"sort_button_date\">日付 %s</string>\n    <string name=\"subscription_deleted\">%s の購読を解除しました</string>\n    <string name=\"action_unsubscribe\">購読解除</string>\n    <string name=\"profiles\">プロフィール</string>\n    <string name=\"quality_profile_help\">ここでソースの並び順を変更できます。ビデオの優先度が高いほど、ソース選択で上位に表示されます。 ソースの優先度と品質の優先度の合計がビデオの優先度になります。 \\n\\nソース A: 3 \\n品質 B: 7 \\nビデオの優先度は10になります。 \\n\\n注: 合計が10以上の場合、そのリンクが読み込まれたときにプレーヤーは自動的に読み込みをスキップします！</string>\n    <string name=\"qualities\">品質</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">ライブラリに潜在的な重複アイテムが見つかりました: \\n\\n%s \\n\\nこのアイテムを追加しますか、既存のものを置き換えますか、それともアクションをキャンセルしますか？</string>\n    <string name=\"biometric_warning\">CloudStreamのデータは今バックアップされました。非常に低い可能性ですが、すべてのデバイスは異なって動作する可能性があります。まれに、アプリへのアクセスがロックアウトされた場合、アプリのデータを完全にクリアし、バックアップから復元してください。このことで生じる不便についてお詫び申し上げます。</string>\n    <string name=\"device_pin_error_message\">デバイスPINコードを取得できません。ローカル認証を試してください</string>\n    <string name=\"sort_release_date_old\">公開日 (古い順)</string>\n    <string name=\"hide_player_control_names\">プレーヤーのコントロール名を非表示</string>\n    <string name=\"torrent_preferred_media\">設定/プロバイダ/優先メディアでトレントを有効にする</string>\n    <string name=\"torrent_not_accepted\">アプリを再起動し、ポップアップに同意して続行します。</string>\n    <string name=\"software_decoding\">ソフトウェアデコーディング</string>\n    <string name=\"software_decoding_desc\">ソフトウェアデコーディングにより、機器でサポートされていないビデオファイルを再生できますが、高解像度で遅延や不安定な再生を引き起こす可能性があります。</string>\n    <string name=\"plugins_updated_manually\">%d 個のプラグインを正常に更新しました！</string>\n    <string name=\"no_plugins_updated_manually\">更新されたプラグインはありません。</string>\n    <string name=\"player_notification_channel_name\">プレーヤー通知</string>\n    <string name=\"player_notification_channel_description\">バックグラウンドから再生を制御するためのプレーヤー通知</string>\n    <string name=\"audio_singluar\">オーディオ</string>\n    <string name=\"podcast_singluar\">ポッドキャスト</string>\n    <string name=\"android_tv_interface_off_seek_settings\">プレーヤー非表示時 - シーク量</string>\n    <string name=\"encoding_error\">エンコーディングエラー</string>\n    <string name=\"unsupported_error\">サポートされていないエラー</string>\n    <string name=\"pref_category_actions\">アクション</string>\n    <string name=\"pref_category_player_features\">プレーヤー機能</string>\n    <string name=\"all_subtitles_bold\">字幕を太字にする</string>\n    <string name=\"volume_exceeded_100\">ボリュームが100%を越えました</string>\n    <string name=\"slide_up_again_to_exceed_100\">再度上へスライドして100%以上に調整できます</string>\n    <string name=\"all_subtitles_italic\">字幕を斜体にする</string>\n    <string name=\"background_radius\">背景の半径</string>\n    <string name=\"player_settings_always_ask\">常に尋ねること</string>\n    <string name=\"download_parallel_settings_des\">並行してダウンロードできるアイテム</string>\n    <string name=\"parallel_downloads\">並行ダウンロード</string>\n    <string name=\"concurrent_connections\">並行接続</string>\n    <string name=\"concurrent_connections_settings_des\">ダウンロード中に使用できる同時接続数</string>\n    <string name=\"go_to_downloads\">ダウンロードへ</string>\n    <string name=\"no_internet_connection\">インターネットに接続していません。\\n\\nインターネットに接続して再度お試しいただくか、オフラインの状態でダウンロードをご覧ください。</string>\n    <string name=\"overscan_settings_des\">画面の境界を変更する</string>\n    <string name=\"overscan_settings\">オーバースキャン</string>\n    <string name=\"poster_size_settings_des\">ポスターの大きさを変更</string>\n    <string name=\"poster_size_settings\">ポスター</string>\n    <string name=\"speedup_title\">長押し速度トグル</string>\n    <string name=\"speedup_summary\">ホールドで2倍速に</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$d時間 %2$d分 %3$d秒</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$d分 %2$d秒</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d秒</string>\n    <string name=\"episode_action_play_mirror\">ミラーを再生</string>\"\n    <string name=\"show_rating\">評価</string>\n    <string name=\"no_account\">アカウントなし</string>\n    <string name=\"edit_profile_image_title\">プロフィール画像を編集</string>\n    <string name=\"edit_profile_image_hint\">プロフィール画像のURLを入力</string>\n    <string name=\"edit_profile_image_error_empty\">URLが見つかりません</string>\n    <string name=\"edit_profile_image_error_invalid\">無効なURLまたは画像です</string>\n    <string name=\"edit_profile_image_success\">画像を正常に更新しました</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">このエピソードまでを視聴済みにする</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">このエピソードまでの視聴済みマークを解除</string>\n    <string name=\"action_reload\">再読み込みが完了しました</string>\n    <string name=\"reload_provider\">プロバイダーを再読み込み</string>\n    <string name=\"name\">名前</string>\n    <string name=\"resolution_and_name\">解像度と名前</string>\n    <string name=\"subs_subtitle_alignment\">字幕の配置</string>\n    <string name=\"bottom_left\">左下</string>\n    <string name=\"bottom_center\">中央下</string>\n    <string name=\"bottom_right\">右下</string>\n    <string name=\"middle_left\">中央左</string>\n    <string name=\"middle_center\">中央</string>\n    <string name=\"middle_right\">中央右</string>\n    <string name=\"top_left\">左上</string>\n    <string name=\"top_center\">上中央</string>\n    <string name=\"top_right\">右上</string>\n    <string name=\"play_full_series_button\">全シリーズを再生</string>\n    <string name=\"install_prerelease\">プレリリース版をインストール</string>\n    <string name=\"prerelease_already_installed\">プレリリース版は既にインストールされています。</string>\n    <string name=\"prerelease_install_failed\">プレリリース版のインストールに失敗しました。</string>\n    <string name=\"show_episode_text\">エピソードのテキスト</string>\n    <string name=\"search_suggestions\">検索候補</string>\n    <string name=\"search_suggestions_des\">入力中に検索候補を表示する</string>\n    <string name=\"clear_suggestions\">候補を消去</string>\n    <string name=\"show_cast_in_details\">キャストパネルを表示</string>\n    <string name=\"source_name\">ソース名</string>\n    <string name=\"video_info\">メディア情報</string>\n    <string name=\"extra_brightness_settings\">追加の輝度設定</string>\n    <string name=\"extra_brightness_settings_des\">画面の輝度が100%を超えた場合に輝度フィルターを有効にします</string>\n    <string name=\"extra_brightness_key\">追加の輝度を有効化</string>\n    <string name=\"download_queue\">ダウンロードキュー</string>\n    <string name=\"queue_empty_message\">現在、ダウンロードキューは空です。</string>\n    <string name=\"download_all\">すべてダウンロード</string>\n    <string name=\"cancel_all\">すべてキャンセル</string>\n    <string name=\"download_episode_range\">エピソード %s をダウンロードしますか？</string>\n    <string name=\"cancel_queue_message\">ダウンロードキューをすべてキャンセルしますか？</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"other\">%d 件をダウンロード中</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"other\">%d 件が待機中</item>\n    </plurals>\n    <string name=\"source_priority\">ソースの優先順位</string>\n    <string name=\"source_priority_help\">プレイヤーでのビデオソースの並び順を設定します</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+kn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$sಎಪಿ%2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">ಕ್ಯಾಸ್ಟ್:%s</string>\n    <string name=\"go_back_img_des\">ಹಿಂದೆ ಹೋಗು</string>\n    <string name=\"filler\" formatted=\"true\">ಫಿಲ್ಲರ್</string>\n    <string name=\"title_search\">ಹುಡುಕು</string>\n    <string name=\"title_downloads\">ಡೌನ್ಲೋಡ್</string>\n    <string name=\"subs_font\">ಫಾಂಟ್</string>\n    <string name=\"search_provider_text_providers\">ಪೂರೈಕೆದಾರರನ್ನು ಬಳಸಿಕೊಂಡು ಹುಡುಕಿ</string>\n    <string name=\"search_provider_text_types\">ಪ್ರಕಾರಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಹುಡುಕಿ</string>\n    <string name=\"benene_count_text_none\">ಯಾವುದೇ ಬೆನೆನ್ಸ್ ನೀಡಿಲ್ಲ</string>\n    <string name=\"subs_auto_select_language\">ಸ್ವಯಂ-ಆಯ್ಕೆ ಭಾಷೆ</string>\n    <string name=\"action_open_watching\">ಹೆಚ್ಚಿನ ಮಾಹಿತಿ</string>\n    <string name=\"action_open_play\">\\@ಸ್ಟ್ರಿಂಗ್/ಹೋಮ್_ಪ್ಲೇ</string>\n    <string name=\"vpn_might_be_needed\">ಈ ಪೂರೈಕೆದಾರರು ಸರಿಯಾಗಿ ಕೆಲಸ ಮಾಡಲು VPN ಬೇಕಾಗಬಹುದು</string>\n    <string name=\"player_size_settings_des\">ಕಪ್ಪು ಗಡಿಗಳನ್ನು ತೆಗೆದುಹಾಕಿ</string>\n    <string name=\"next_episode_format\" formatted=\"true\">ಸಂಚಿಕೆ%d ಬಿಡುಗಡೆಯಾಗಲಿದೆ</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"result_poster_img_des\">ಪೋಸ್ಟರ್</string>\n    <string name=\"search_poster_img_des\">ಪೋಸ್ಟರ್</string>\n    <string name=\"episode_poster_img_des\">ಸಂಚಿಕೆ ಪೋಸ್ಟರ್</string>\n    <string name=\"home_main_poster_img_des\">ಮೇನ್ ಪೋಸ್ಟರ್</string>\n    <string name=\"update_started\">ಅಪ್ಡೇಟ್ ಪ್ರಾರಂಭವಾಗಿದೆ</string>\n    <string name=\"error_loading_links_toast\">ಲೋಡಿಂಗ್ ಲಿಂಕ್ ಎರರ್ ಬಂದಿದೆ</string>\n    <string name=\"download_storage_text\">ಇಂಟರ್ನಲ್ ಸ್ಟೋರೇಜ್</string>\n    <string name=\"app_dubbed_text\">ಡಬ್</string>\n    <string name=\"app_subbed_text\">ಸಬ್</string>\n    <string name=\"home_expanded_hide\">ಹೈಡ್</string>\n    <string name=\"home_play\">ಪ್ಲೇ</string>\n    <string name=\"home_info\">ಮಾಹಿತಿ</string>\n    <string name=\"action_add_to_bookmarks\">ಸೆಟ್ ವಾಚ್ ಸ್ಟೇಟಸ್</string>\n    <string name=\"sort_apply\">ಅನ್ವಯಿಸು</string>\n    <string name=\"subs_subtitle_elevation\">ಸಬ್ ಟೈಟಲ್ಸ್ ಎಲೆವಷನ್</string>\n    <string name=\"subs_font_size\">ಫಾಂಟ್ ಸೈಜ್</string>\n    <string name=\"subs_subtitle_languages\">ಸಬ್ ಟೈಟಲ್ಸ್ ಭಾಷೆ</string>\n    <string name=\"action_remove_watching\">ತೆಗೆದುಹಾಕಿ</string>\n    <string name=\"vpn_torrent\">ಈ ಪೂರೈಕೆದಾರರು ಟೊರೆಂಟ್ ಆಗಿದೆ, VPN ಅನ್ನು ಶಿಫಾರಸು ಮಾಡಲಾಗಿದೆ</string>\n    <string name=\"normal_no_plot\">ಯಾವುದೇ ಪ್ಲಾಟ್ ಕಂಡುಬಂದಿಲ್ಲ</string>\n    <string name=\"show_log_cat\">ಲಾಗ್‌ಕ್ಯಾಟ್ 🐈 ತೋರಿಸಿ</string>\n    <string name=\"test_log\">ಲಾಗ್</string>\n    <string name=\"picture_in_picture\">ಚಿತ್ರದಲ್ಲಿ-ಚಿತ್ರದಲ್ಲಿ</string>\n    <string name=\"player_size_settings\">ಪ್ಲೇಯರ್ ಮರುಗಾತ್ರಗೊಳಿಸಿ ಬಟನ್</string>\n    <string name=\"player_subtitles_settings\">ಸಬ್ ಟೈಟಲ್ಸ್</string>\n    <string name=\"player_subtitles_settings_des\">ಪ್ಲೇಯರ್ ಸಬ್ ಟೈಟಲ್ಸ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು</string>\n    <string name=\"chromecast_subtitles_settings_des\">ಕ್ರೋಮ್ ಕ್ಯಾಸ್ಟ್ ಸಬ್ ಟೈಟಲ್ಸ್ ಸೆಟ್ಟಿಂಗ್ಸ್</string>\n    <string name=\"go_back\">ಹಿಂದೆ ಹೋಗು</string>\n    <string name=\"popup_pause_download\">ಡೌನ್‌ಲೋಡ್ ವಿರಾಮಗೊಳಿಸಿ</string>\n    <string name=\"error_bookmarks_text\">ಬುಕ್‌ಮಾರ್ಕ್‌</string>\n    <string name=\"subs_background_color\">ಬ್ಯಾಕ್ ಗ್ರೌಂಡ್ ಕಲರ್</string>\n    <string name=\"benene_count_text\">%d ಡೇವ್‌ಗಳಿಗೆ ಬೆನೆನೆಸ್ ನೀಡಲಾಗಿದೆ</string>\n    <string name=\"subs_hold_to_reset_to_default\">ಡೀಫಾಲ್ಟ್‌ಗೆ ಮರುಹೊಂದಿಸಲು ಹಿಡಿದುಕೊಳ್ಳಿ</string>\n    <string name=\"provider_info_meta\">ಸೈಟ್‌ನಿಂದ ಮೆಟಾಡೇಟಾವನ್ನು ಒದಗಿಸಲಾಗಿಲ್ಲ, ಅದು ಸೈಟ್‌ನಲ್ಲಿ ಅಸ್ತಿತ್ವದಲ್ಲಿಲ್ಲದಿದ್ದರೆ ವೀಡಿಯೊ ಲೋಡಿಂಗ್ ವಿಫಲಗೊಳ್ಳುತ್ತದೆ.</string>\n    <string name=\"picture_in_picture_des\">ಇತರ ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಮೇಲೆ ಚಿಕಣಿ ಪ್ಲೇಯರ್‌ನಲ್ಲಿ ಪ್ಲೇಬ್ಯಾಕ್ ಅನ್ನು ಮುಂದುವರಿಸುತ್ತದೆ</string>\n    <string name=\"chromecast_subtitles_settings\">ಕ್ರೋಮ್ ಕ್ಯಾಸ್ಟ್ ಸಬ್ ಟೈಟಲ್ಸ್</string>\n    <string name=\"rated_format\" formatted=\"true\">ರೇಟೆಡ್:%.1f</string>\n    <string name=\"action_remove_from_bookmarks\">ತೆಗೆದುಹಾಕಿ</string>\n    <string name=\"popup_resume_download\">ಡೌನ್‌ಲೋಡ್ ಅನ್ನು ಪುನರಾರಂಭಿಸಿ</string>\n    <string name=\"sort_close\">ಕ್ಲೋಸ್</string>\n    <string name=\"sort_clear\">ಕ್ಲಿಯರ್</string>\n    <string name=\"sort_save\">ಸೇವ್</string>\n    <string name=\"subtitles_settings\">ಸಬ್ ಟೈಟಲ್ಸ್ ಸೆಟ್ಟಿಂಗ್ಸ್</string>\n    <string name=\"popup_play_file\">ಫೈಲ್ ಪ್ಲೇ</string>\n    <string name=\"subs_text_color\">ಟೆಕ್ಸ್ಟ್ ಕಲರ್</string>\n    <string name=\"subs_outline_color\">ಔಟ್ ಲೈನ್ ಕಲರ್</string>\n    <string name=\"subs_window_color\">ವಿಂಡೋ ಕಲರ್</string>\n    <string name=\"subs_edge_type\">ಎಡ್ಜ್ ಟೈಪ್</string>\n    <string name=\"home_change_provider_img_des\">ಪ್ರೊವೈಡರ್ ಬದಲಾಯಿಸಿ</string>\n    <string name=\"duration_format\" formatted=\"true\">%dಮಿನ</string>\n    <string name=\"torrent_plot\">ವಿವರಣೆ</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">ಸ್ಪೀಡ್(%.2fx)</string>\n    <string name=\"title_home\">ಹೋಂ</string>\n    <string name=\"pick_subtitle\">ಸಬ್ ಟೈಟಲ್ಸ್</string>\n    <string name=\"title_settings\">ಸೆಟ್ಟಿಂಗ್ಸ್</string>\n    <string name=\"filter_bookmarks\">ಬುಕ್‌ಮಾರ್ಕ್‌ಗಳನ್ನು ಫಿಲ್ಟರ್ ಮಾಡಿ</string>\n    <string name=\"search_hint\">ಹುಡುಕು…</string>\n    <string name=\"play_movie_button\">ಚಲನಚಿತ್ರವನ್ನು ಪ್ಲೇ ಮಾಡಿ</string>\n    <string name=\"preview_background_img_des\">ಪ್ರಿವ್ಯೂ ಹಿನ್ನೆಲೆ</string>\n    <string name=\"next_episode\">ಮುಂದಿನ ಸಂಚಿಕೆ</string>\n    <string name=\"app_name\">ಕ್ಲೌಡ್ ಸ್ಟ್ರೀಮ್</string>\n    <string name=\"downloading\">ಡೌನ್‌ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ</string>\n    <string name=\"stream\">ಸ್ಟ್ರೀಮ್</string>\n    <string name=\"result_share\">ಶೇರ್</string>\n    <string name=\"popup_delete_file\">ಫೈಲ್ ಅಳಿಸಿ</string>\n    <string name=\"home_more_info\">ಹೆಚ್ಚಿನ ಮಾಹಿತಿ</string>\n    <string name=\"new_update_format\" formatted=\"true\">ಹೊಸ ಅಪ್ಡೇಟ್ ಬಂದಿದೆ\n\\n%1$s-%2$s</string>\n    <string name=\"loading\">ಲೋಡಿಂಗ್…</string>\n    <string name=\"subs_download_languages\">ಡೌನ್‌ಲೋಡ್ ಭಾಷೆಗಳನ್ನು ಮಾಡಿ</string>\n    <string name=\"play_livestream_button\">ಲೈವ್‌ಸ್ಟ್ರೀಮ್ ಪ್ಲೇ ಮಾಡಿ</string>\n    <string name=\"play_with_app_name\">ಕ್ಲೌಡ್ ಸ್ಟ್ರೀಮ್ ಇದರೊಂದಿಗೆ ಪ್ಲೇ ಮಾಡಿ</string>\n    <string name=\"type_plan_to_watch\">ವೀಕ್ಷಿಸಲು ಯೋಜನೆ</string>\n    <string name=\"play_episode\">ಸಂಚಿಕೆಯನ್ನು ಪ್ಲೇ ಮಾಡಿ</string>\n    <string name=\"continue_watching\">ಕಂಟಿನ್ಯೂ ವಾಟಚಿಂಗ್</string>\n    <string name=\"torrent_no_plot\">ಯಾವುದೇ ವಿವರಣೆ ಕಂಡುಬಂದಿಲ್ಲ</string>\n    <string name=\"play_torrent_button\">ಸ್ಟ್ರೀಮ್ ಟೊರೆಂಟ್</string>\n    <string name=\"download\">ಡೌನ್‌ಲೋಡ್</string>\n    <string name=\"sort_copy\">ಕಾಪಿ</string>\n    <string name=\"no_data\">ನೋ ಡೇಟಾ</string>\n    <string name=\"player_speed\">ಪ್ಲೇಯರ್ ಸ್ಪೀಡ್</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d %2$dh %3$dm</string>\n    <string name=\"search_hint_site\" formatted=\"true\">ಹುಡುಕು %s…</string>\n    <string name=\"episode_more_options_des\">ಹೆಚ್ಚಿನ ಆಯ್ಕೆ</string>\n    <string name=\"subs_import_text\" formatted=\"true\">ಫಾಂಟ್‌ಗಳನ್ನು ಇರಿಸುವ ಮೂಲಕ ಆಮದು ಮಾಡಿ %s</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"result_tags\">ಪ್ರಕಾರಗಳು</string>\n    <string name=\"result_open_in_browser\">ಬ್ರೌಸರ್ ತೆರೆಯಿರಿ</string>\n    <string name=\"type_on_hold\">ಆನ್-ಹೋಲ್ಡ್</string>\n    <string name=\"reload_error\">ಸಂಪರ್ಕವನ್ನು ಮರುಪ್ರಯತ್ನಿಸಿ…</string>\n    <string name=\"download_paused\">ಡೌನ್‌ಲೋಡ್ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ</string>\n    <string name=\"download_failed\">ಡೌನ್‌ಲೋಡ್ ವಿಫಲವಾಗಿದೆ</string>\n    <string name=\"download_done\">ಡೌನ್‌ಲೋಡ್ ಮುಗಿದಿದೆ</string>\n    <string name=\"browser\">ಬ್ರೌಸರ್</string>\n    <string name=\"skip_loading\">ಸ್ಕಿಪ್ ಲೋಡಿಂಗ್</string>\n    <string name=\"type_watching\">ವಾಚಿಂಗ್</string>\n    <string name=\"type_completed\">ಪೂರ್ಣಗೊಂಡಿದೆ</string>\n    <string name=\"type_dropped\">ಕೈಬಿಡಲಾಯಿತು</string>\n    <string name=\"type_re_watching\">ಪುನಃ ವೀಕ್ಷಿಸುತ್ತಿದೆ</string>\n    <string name=\"play_trailer_button\">ಟ್ರೈಲರ್ ಪ್ಲೇ ಮಾಡಿ</string>\n    <string name=\"pick_source\">ಮೂಲಗಳು</string>\n    <string name=\"downloaded\">ಡೌನ್‌ಲೋಡ್ ಮಾಡಲಾಗಿದೆ</string>\n    <string name=\"download_started\">ಡೌನ್‌ಲೋಡ್ ಪ್ರಾರಂಭವಾಗಿದೆ</string>\n    <string name=\"download_canceled\">ಡೌನ್‌ಲೋಡ್ ರದ್ದುಗೊಳಿಸಲಾಗಿದೆ</string>\n    <string name=\"home_next_random_img_des\">ಮುಂದಿನ ರಾಂಡಮ್</string>\n    <string name=\"swipe_to_seek_settings\">ಮುಂದಕ್ಕೆ ಹೋಗಲು ಸ್ವೈಪ್ ಮಾಡಿ</string>\n    <string name=\"swipe_to_seek_settings_des\">ವೀಡಿಯೊದಲ್ಲಿ ನಿಮ್ಮ ಸ್ಥಾನವನ್ನು ನಿಯಂತ್ರಿಸಲು ಅಕ್ಕಪಕ್ಕಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ</string>\n    <string name=\"autoplay_next_settings\">ಮುಂದಿನ ಸಂಚಿಕೆಯನ್ನು ಆಟೋ ಪ್ಲೇ ಮಾಡಿ</string>\n    <string name=\"double_tap_to_seek_settings\">ಮುಂದೂಡಲು ಅಥವಾ ಇಂದೂಡಲು ಎರಡು ಬಾರಿ ಟ್ಯಾಪ್ ಮಾಡಿ</string>\n    <string name=\"swipe_to_change_settings_des\">Brightness ಅಥವಾ volume ಬದಲಾಯಿಸಲು ಎಡ ಅಥವಾ ಬಲಭಾಗದಲ್ಲಿ ಮೇಲಕ್ಕೆ ಅಥವಾ ಕೆಳಕ್ಕೆ ಸ್ಲೈಡ್ ಮಾಡಿ</string>\n    <string name=\"autoplay_next_settings_des\">ಈಗಿನ ಎಪಿಸೋಡ್ ಮುಗಿದಾಗ ಮುಂದಿನ ಎಪಿಸೋಡ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಿ</string>\n    <string name=\"swipe_to_change_settings\">ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"cast_format\" formatted=\"true\">출연: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">에피소드 %d이(가) 공개됩니다</string>\n    <string name=\"search_poster_img_des\">포스터</string>\n    <string name=\"episode_poster_img_des\">에피소드 포스터</string>\n    <string name=\"home_main_poster_img_des\">메인 포스터</string>\n    <string name=\"home_next_random_img_des\">다음 랜덤</string>\n    <string name=\"go_back_img_des\">뒤로가기</string>\n    <string name=\"home_change_provider_img_des\">소스 변경</string>\n    <string name=\"preview_background_img_des\">미리보기 배경</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">속도 (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">평점: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">새로운 업데이트!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration_format\" formatted=\"true\">%d분</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">CloudStream에서 재생</string>\n    <string name=\"title_home\">홈</string>\n    <string name=\"title_downloads\">다운로드</string>\n    <string name=\"title_settings\">설정</string>\n    <string name=\"search_hint\">검색…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">검색 %s…</string>\n    <string name=\"no_data\">데이터 없음</string>\n    <string name=\"episode_more_options_des\">기타 옵션</string>\n    <string name=\"next_episode\">다음 에피소드</string>\n    <string name=\"result_tags\">장르</string>\n    <string name=\"result_share\">공유</string>\n    <string name=\"result_open_in_browser\">브라우저에서 열기</string>\n    <string name=\"browser\">브라우저</string>\n    <string name=\"skip_loading\">로딩 건너뛰기</string>\n    <string name=\"loading\">로딩중…</string>\n    <string name=\"type_watching\">시청</string>\n    <string name=\"type_on_hold\">보류</string>\n    <string name=\"type_completed\">시청 완료</string>\n    <string name=\"type_dropped\">포기</string>\n    <string name=\"type_plan_to_watch\">시청 예정</string>\n    <string name=\"type_re_watching\">다시보기</string>\n    <string name=\"play_movie_button\">영화 재생</string>\n    <string name=\"play_trailer_button\">예고편 재생</string>\n    <string name=\"play_torrent_button\">토렌트 재생</string>\n    <string name=\"pick_source\">소스</string>\n    <string name=\"pick_subtitle\">자막</string>\n    <string name=\"reload_error\">연결 재시도…</string>\n    <string name=\"go_back\">뒤로가기</string>\n    <string name=\"play_episode\">에피소드 재생</string>\n    <string name=\"download\">다운로드</string>\n    <string name=\"popup_play_file\">파일 재생</string>\n    <string name=\"popup_resume_download\">계속 다운로드</string>\n    <string name=\"popup_pause_download\">다운로드 일시정지</string>\n    <string name=\"home_more_info\">상세 정보</string>\n    <string name=\"home_expanded_hide\">닫기</string>\n    <string name=\"home_play\">재생</string>\n    <string name=\"home_info\">정보</string>\n    <string name=\"action_add_to_bookmarks\">시청 상태 설정</string>\n    <string name=\"sort_save\">저장</string>\n    <string name=\"player_speed\">재생 속도</string>\n    <string name=\"subs_text_color\">글자 색깔</string>\n    <string name=\"subs_outline_color\">외곽선 색깔</string>\n    <string name=\"subs_background_color\">배경 색깔</string>\n    <string name=\"subs_window_color\">창 색깔</string>\n    <string name=\"subs_edge_type\">가장자리 타입</string>\n    <string name=\"subs_subtitle_elevation\">자막 높이</string>\n    <string name=\"subs_font\">폰트</string>\n    <string name=\"subs_font_size\">폰트 크기</string>\n    <string name=\"downloaded\">다운로드됨</string>\n    <string name=\"downloading\">다운로드중</string>\n    <string name=\"download_paused\">다운로드 일시정지</string>\n    <string name=\"download_started\">다운로드 시작</string>\n    <string name=\"download_failed\">다운로드 실패</string>\n    <string name=\"download_canceled\">다운로드 취소</string>\n    <string name=\"download_done\">다운로드 완료</string>\n    <string name=\"update_started\">업데이트 시작</string>\n    <string name=\"error_loading_links_toast\">링크 로딩 오류</string>\n    <string name=\"download_storage_text\">내부 저장공간</string>\n    <string name=\"subs_auto_select_language\">자동 선택 언어</string>\n    <string name=\"subs_download_languages\">다운로드 언어</string>\n    <string name=\"subs_subtitle_languages\">자막 언어</string>\n    <string name=\"subs_hold_to_reset_to_default\">길게 눌러 기본값으로 재설정</string>\n    <string name=\"subs_import_text\" formatted=\"true\">다음에서 폰트 가져오기 %s</string>\n    <string name=\"continue_watching\">계속 시청</string>\n    <string name=\"action_remove_watching\">제거</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s 에피소드 %2$d</string>\n    <string name=\"result_poster_img_des\">포스터</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d일 %2$d시간 %3$d분</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$d시간 %2$d분</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d분</string>\n    <string name=\"title_search\">검색</string>\n    <string name=\"popup_delete_file\">파일 삭제</string>\n    <string name=\"action_remove_from_bookmarks\">제거</string>\n    <string name=\"category_updates\">업데이트 및 백업</string>\n    <string name=\"pref_category_backup\">백업</string>\n    <string name=\"app_dubbed_text\">더빙</string>\n    <string name=\"app_subbed_text\">자막</string>\n    <string name=\"filter_bookmarks\">북마크 필터</string>\n    <string name=\"error_bookmarks_text\">북마크</string>\n    <string name=\"sort_clear\">제거</string>\n    <string name=\"sort_apply\">적용</string>\n    <string name=\"sort_copy\">복사</string>\n    <string name=\"sort_close\">닫기</string>\n    <string name=\"subtitles_settings\">자막 설정</string>\n    <string name=\"search_provider_text_providers\">소스로 검색</string>\n    <string name=\"test_log\">로그</string>\n    <string name=\"vpn_might_be_needed\">이 소스가 제대로 작동하려면 VPN이 필요할 수 있습니다</string>\n    <string name=\"vpn_torrent\">이 소스는 토렌트이므로 VPN을 사용하는 것이 좋습니다</string>\n    <string name=\"provider_info_meta\">메타데이터는 사이트별로 제공하지 않으며, 메타데이터가 사이트에 없으면 동영상 로딩이 실패합니다.</string>\n    <string name=\"torrent_plot\">설명</string>\n    <string name=\"player_subtitles_settings_des\">플레이어 자막 설정</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast 자막</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast 자막 설정</string>\n    <string name=\"eigengraumode_settings\">Playback 속도</string>\n    <string name=\"swipe_to_seek_settings\">스와이프하여 탐색</string>\n    <string name=\"swipe_to_seek_settings_des\">좌우로 스와이프하여 동영상 위치 제어하기</string>\n    <string name=\"swipe_to_change_settings\">스와이프하여 설정 변경</string>\n    <string name=\"swipe_to_change_settings_des\">왼쪽 또는 오른쪽으로 밀어서 밝기 또는 볼륨을 변경합니다</string>\n    <string name=\"autoplay_next_settings\">다음 에피소드 자동 재생</string>\n    <string name=\"autoplay_next_settings_des\">현재 에피소드가 끝나면 다음 에피소드를 시작합니다</string>\n    <string name=\"double_tap_to_seek_settings\">두 번 탭하여 탐색</string>\n    <string name=\"double_tap_to_pause_settings\">두 번 탭하여 일시정지</string>\n    <string name=\"double_tap_to_seek_amount_settings\">플레이어 탐색 시간 (초)</string>\n    <string name=\"double_tap_to_pause_settings_des\">가운데를 두 번 탭하여 일시중지</string>\n    <string name=\"use_system_brightness_settings\">시스템 밝기 사용</string>\n    <string name=\"use_system_brightness_settings_des\">어두운 오버레이 대신 앱 플레이어의 시스템 밝기를 사용합니다</string>\n    <string name=\"episode_sync_settings\">시청 진행 상황 업데이트</string>\n    <string name=\"episode_sync_settings_des\">현재 에피소드 진행 상황을 자동으로 동기화합니다</string>\n    <string name=\"restore_settings\">백업에서 데이터 복원</string>\n    <string name=\"backup_settings\">데이터 백업</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">파일에서 데이터를 복원하지 못했습니다 %s</string>\n    <string name=\"backup_success\">저장된 데이터</string>\n    <string name=\"backup_failed\">저장소 권한이 없습니다. 다시 시도해 주세요.</string>\n    <string name=\"backup_failed_error_format\">백업 중 오류 %s</string>\n    <string name=\"search\">검색</string>\n    <string name=\"library\">라이브러리</string>\n    <string name=\"category_account\">계정 및 보안</string>\n    <string name=\"advanced_search_des\">소스별로 구분된 검색 결과를 제공합니다</string>\n    <string name=\"show_trailers_settings\">예고편 보기</string>\n    <string name=\"kitsu_settings\">Kitsu에서 포스터 보기</string>\n    <string name=\"pref_filter_search_quality\">검색 결과에서 선택한 동영상 품질 숨기기</string>\n    <string name=\"automatic_plugin_download\">플러그인 자동 다운로드</string>\n    <string name=\"automatic_plugin_updates\">플러그인 자동 업데이트</string>\n    <string name=\"automatic_plugin_download_summary\">추가된 저장소에서 아직 설치되지 않은 모든 플러그인을 자동으로 설치합니다.</string>\n    <string name=\"updates_settings\">앱 업데이트 표시</string>\n    <string name=\"updates_settings_des\">앱을 시작한 후 새 업데이트를 자동으로 검색합니다.</string>\n    <string name=\"apk_installer_settings_des\">일부 장치는 새 패키지 설치 프로그램을 지원하지 않습니다. 업데이트가 설치되지 않으면 레거시 옵션을 사용해보십시오.</string>\n    <string name=\"lightnovel\">같은 개발자가 만든 라이트 노벨 앱</string>\n    <string name=\"anim\">같은 개발자가 만든 애니메이션 앱</string>\n    <string name=\"discord\">Discord에 참여하기</string>\n    <string name=\"benene\">개발자에게 바나나 주기</string>\n    <string name=\"benene_des\">바나나 줌</string>\n    <string name=\"app_language\">앱 언어</string>\n    <string name=\"no_links_found_toast\">링크를 찾을 수 없음</string>\n    <string name=\"copy_link_toast\">클립보드에 링크 복사됨</string>\n    <string name=\"play_episode_toast\">에피소드 재생</string>\n    <string name=\"subs_default_reset_toast\">기본값으로 재설정</string>\n    <string name=\"episodes\">에피소드</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"status_ongoing\">진행중</string>\n    <string name=\"status_completed\">시청 완료</string>\n    <string name=\"status\">상태</string>\n    <string name=\"year\">년</string>\n    <string name=\"rating\">평점</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">%s가 영구 삭제됩니다\n\\n정말 삭제하시겠습니까?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%d분\n\\n남음</string>\n    <string name=\"site\">사이트</string>\n    <string name=\"duration\">시간</string>\n    <string name=\"synopsis\">개요</string>\n    <string name=\"queued\">대기중</string>\n    <string name=\"no_subtitles\">자막 없음</string>\n    <string name=\"action_default\">기본</string>\n    <string name=\"free_storage\">남음</string>\n    <string name=\"used_storage\">사용됨</string>\n    <string name=\"app_storage\">앱</string>\n    <string name=\"movies\">영화</string>\n    <string name=\"tv_series\">TV 시리즈</string>\n    <string name=\"cartoons\">카툰</string>\n    <string name=\"anime\">애니</string>\n    <string name=\"torrent\">토렌트</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast 미러링</string>\n    <string name=\"episode_action_play_in_app\">앱에서 재생</string>\n    <string name=\"episode_action_play_in_format\">%s에서 재생</string>\n    <string name=\"episode_action_auto_download\">자동 다운로드</string>\n    <string name=\"episode_action_download_mirror\">다운로드 미러</string>\n    <string name=\"episode_action_reload_links\">링크 새로고침</string>\n    <string name=\"episode_action_download_subtitle\">자막 다운로드</string>\n    <string name=\"show_hd\">화질 탭</string>\n    <string name=\"show_dub\">더빙 탭</string>\n    <string name=\"show_sub\">자막 탭</string>\n    <string name=\"show_title\">제목</string>\n    <string name=\"check_for_update\">업데이트 확인</string>\n    <string name=\"video_lock\">잠금</string>\n    <string name=\"video_aspect_ratio_resize\">크기 조정</string>\n    <string name=\"video_source\">소스</string>\n    <string name=\"video_skip_op\">오프닝 건너뛰기</string>\n    <string name=\"skip_update\">이 업데이트 건너뛰기</string>\n    <string name=\"watch_quality_pref\">선호하는 화질 (WiFi)</string>\n    <string name=\"watch_quality_pref_data\">선호하는 화질 (모바일 데이터)</string>\n    <string name=\"limit_title_rez\">본문 바로가기</string>\n    <string name=\"video_buffer_size_settings\">동영상 버퍼 크기</string>\n    <string name=\"video_buffer_clear_settings\">동영상 및 이미지 캐시 지우기</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"jsdelivr_enabled\">GitHub에 연결할 수 없습니다. jsDelivr 프록시를 켜는 중…</string>\n    <string name=\"jsdelivr_proxy_summary\">JsDelivr를 사용하여 원시 github URL 차단을 우회하십시오. 몇 일 지연 될 업데이트가 발생할 수 있습니다.</string>\n    <string name=\"add_site_pref\">복제 사이트</string>\n    <string name=\"remove_site_pref\">사이트 삭제</string>\n    <string name=\"add_site_summary\">다른 URL을 사용하여 기존 사이트의 복제본을 추가합니다</string>\n    <string name=\"download_path_pref\">다운로드 경로</string>\n    <string name=\"pref_category_cache\">캐시</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"pref_category_gestures\">제스처</string>\n    <string name=\"pref_category_subtitles\">자막</string>\n    <string name=\"pref_category_player_layout\">레이아웃</string>\n    <string name=\"pref_category_defaults\">기본</string>\n    <string name=\"category_general\">일반</string>\n    <string name=\"pref_category_player_features\">플레이어 기능</string>\n    <string name=\"pref_category_ui_features\">기능</string>\n    <string name=\"provider_lang_settings\">확장 언어</string>\n    <string name=\"app_layout\">앱 레이아웃</string>\n    <string name=\"preferred_media_settings\">선호하는 미디어</string>\n    <string name=\"enable_nsfw_on_providers\">지원된 연장에 NSFW 활성화</string>\n    <string name=\"subtitles_encoding\">자막 인코딩</string>\n    <string name=\"category_providers\">소스</string>\n    <string name=\"category_provider_test\">소스 테스트</string>\n    <string name=\"category_ui\">레이아웃</string>\n    <string name=\"automatic\">자동</string>\n    <string name=\"tv_layout\">TV 레이아웃</string>\n    <string name=\"phone_layout\">휴대폰 레이아웃</string>\n    <string name=\"emulator_layout\">에뮬레이터 레이아웃</string>\n    <string name=\"primary_color_settings\">기본 색상</string>\n    <string name=\"app_theme_settings\">앱 테마</string>\n    <string name=\"bottom_title_settings\">포스터 제목 위치</string>\n    <string name=\"example_email\">이메일</string>\n    <string name=\"example_ip\">IP</string>\n    <string name=\"login\">로그인</string>\n    <string name=\"switch_account\">계정 전환</string>\n    <string name=\"add_account\">계정 추가</string>\n    <string name=\"create_account\">계정 생성</string>\n    <string name=\"add_sync\">트래커 추가</string>\n    <string name=\"added_sync_format\" formatted=\"true\">추가 %s</string>\n    <string name=\"upload_sync\">동기화</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s 인증됨</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">다음에 로그인할 수 없음 %s</string>\n    <string name=\"none\">없음</string>\n    <string name=\"normal\">보통</string>\n    <string name=\"all\">전부</string>\n    <string name=\"max\">최대</string>\n    <string name=\"min\">최소</string>\n    <string name=\"subtitles_outline\">윤곽선</string>\n    <string name=\"subtitles_shadow\">그림자</string>\n    <string name=\"subtitle_offset\">자막 동기화</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">자막 딜레이</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">자막이 %d ms 너무 일찍 표시되는 경우, 이 옵션을 사용하세요</string>\n    <string name=\"actor_main\">주연</string>\n    <string name=\"actor_supporting\">조연</string>\n    <string name=\"actor_background\">출연</string>\n    <string name=\"home_source\">소스</string>\n    <string name=\"home_random\">랜덤</string>\n    <string name=\"poster_image\">포스터 이미지</string>\n    <string name=\"title\">제목</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"resolution_and_title\">해상도 및 제목</string>\n    <string name=\"resolution\">해상도</string>\n    <string name=\"error_invalid_id\">잘못된 ID</string>\n    <string name=\"error_invalid_data\">잘못된 데이터</string>\n    <string name=\"error_invalid_url\">잘못된 URL</string>\n    <string name=\"error\">오류</string>\n    <string name=\"subtitles_remove_captions\">자막에서 선택 캡션 제거</string>\n    <string name=\"subtitles_filter_lang\">선호하는 미디어 언어로 필터링</string>\n    <string name=\"trailer\">예고편</string>\n    <string name=\"next\">다음</string>\n    <string name=\"previous\">이전</string>\n    <string name=\"skip_setup\">설정 건너뛰기</string>\n    <string name=\"app_layout_subtext\">기기에 맞게 앱 모양 변경하기</string>\n    <string name=\"extensions\">확장 기능</string>\n    <string name=\"extension_version\">버전</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">다운로드 시작 %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">다운로드 %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">모든 %s가 이미 다운로드되었습니다</string>\n    <string name=\"batch_download\">일괄 다운로드</string>\n    <string name=\"plugin_singular\">플러그인</string>\n    <string name=\"plugin\">플러그인</string>\n    <string name=\"delete_repository_plugins\">이렇게 하면 모든 저장소의 플러그인도 삭제됩니다</string>\n    <string name=\"delete_repository\">저장소 삭제</string>\n    <string name=\"setup_extensions_subtext\">사용하려는 사이트 목록 다운로드</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">다운로드됨: %d</string>\n    <string name=\"blank_repo_message\">CloudStream에는 기본적으로 설치된 사이트가 없습니다. 저장소에서 사이트를 설치해야 합니다.\n\\n\n\\nSky UK Limited의 무분별한 DMCA 게시 중단으로 인해 앱에서 저장소 사이트를 연결 할 수 없습니다.\n\\n\n\\nDiscord에 가입하거나 온라인으로 검색해 보세요.</string>\n    <string name=\"view_public_repositories_button\">커뮤니티 저장소 보기</string>\n    <string name=\"view_public_repositories_button_short\">공개 목록</string>\n    <string name=\"uppercase_all_subtitles\">모든 자막 대문자화</string>\n    <string name=\"download_all_plugins_from_repo\">경고: CloudStream은 제3자 확장을 이용하여 어떠한 책임도 지지 않습니다!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (사용불가)</string>\n    <string name=\"add_repository\">저장소 추가</string>\n    <string name=\"repository_name_hint\">저장소 이름 (선택 사항)</string>\n    <string name=\"repository_url_hint\">저장소 URL 또는 단축 코드</string>\n    <string name=\"plugin_loaded\">플러그인이 로드됨</string>\n    <string name=\"plugin_downloaded\">플러그인 다운로드</string>\n    <string name=\"plugin_deleted\">플러그인 삭제됨</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">로드할 수 없음 %s</string>\n    <string name=\"audio_tracks\">오디오 트랙</string>\n    <string name=\"video_tracks\">동영상 트랙</string>\n    <string name=\"apply_on_restart\">재 시작 시 적용.</string>\n    <string name=\"safe_mode_title\">안전 모드 켜기</string>\n    <string name=\"safe_mode_description\">충돌로 인해 문제를 일으키는 확장 프로그램을 찾는 데 도움이 되도록 모든 확장 프로그램이 사용 중지되었습니다.</string>\n    <string name=\"safe_mode_crash_info\">충돌 정보 보기</string>\n    <string name=\"extension_language\">언어</string>\n    <string name=\"subscription_episode_released\">에피소드 %d 공개!</string>\n    <string name=\"picture_in_picture\">Picture-in-picture</string>\n    <string name=\"player_size_settings\">플레이어 크기 조정 버튼</string>\n    <string name=\"picture_in_picture_des\">다른 앱 위에 있는 미니어처 플레이어에서 재생을 계속합니다</string>\n    <string name=\"player_size_settings_des\">검은색 테두리 제거</string>\n    <string name=\"double_tap_to_seek_settings_des\">오른쪽 또는 왼쪽을 두 번 탭하여 앞뒤로 탐색하기</string>\n    <string name=\"player_subtitles_settings\">자막</string>\n    <string name=\"restore_success\">로드된 백업 파일</string>\n    <string name=\"settings_info\">정보</string>\n    <string name=\"advanced_search\">고급 검색</string>\n    <string name=\"redo_setup_process\">설정 프로세스 다시 실행</string>\n    <string name=\"apk_installer_settings\">APK 인스톨러</string>\n    <string name=\"github\">Github</string>\n    <string name=\"source_error\">소스 오류</string>\n    <string name=\"no_chromecast_support_toast\">이 소스는 크롬캐스트를 지원하지 않습니다</string>\n    <string name=\"no_season\">시즌 없음</string>\n    <string name=\"season_short\">시즌</string>\n    <string name=\"asian_drama_singular\">아시아 드라마</string>\n    <string name=\"season\">시즌</string>\n    <string name=\"delete\">삭제</string>\n    <string name=\"cancel\">취소</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"delete_file\">파일 삭제</string>\n    <string name=\"pause\">일시정지</string>\n    <string name=\"episode\">에피소드</string>\n    <string name=\"episode_short\">에피소드</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"no_episodes_found\">에피소드를 찾을 수 없음</string>\n    <string name=\"start\">시작</string>\n    <string name=\"test_failed\">실패</string>\n    <string name=\"sync_score\">평점</string>\n    <string name=\"extension_rating\" formatted=\"true\">평점: %s</string>\n    <string name=\"sort_rating_desc\">평점 (높음에서 낮음으로)</string>\n    <string name=\"sort_rating_asc\">평점 (낮음에서 높음으로)</string>\n    <string name=\"nsfw_singular\">19금</string>\n    <string name=\"documentaries\">다큐멘터리</string>\n    <string name=\"livestreams\">라이브 방송</string>\n    <string name=\"nsfw\">19금</string>\n    <string name=\"others\">기타</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">아시아 드라마</string>\n    <string name=\"live_singular\">라이브 방송</string>\n    <string name=\"other_singular\">동영상</string>\n    <string name=\"poster_ui_settings\">포스터의 UI 요소 전환</string>\n    <string name=\"movies_singular\">영화</string>\n    <string name=\"cartoons_singular\">카툰</string>\n    <string name=\"torrent_singular\">토렌트</string>\n    <string name=\"documentaries_singular\">다큐멘터리</string>\n    <string name=\"render_error\">렌더러 오류</string>\n    <string name=\"tv_series_singular\">시리즈</string>\n    <string name=\"anime_singular\">애니</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"remote_error\">원격 오류</string>\n    <string name=\"storage_error\">다운로드 오류, 저장 권한 확인</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast 에피소드</string>\n    <string name=\"unexpected_error\">예기치 않은 플레이어 오류</string>\n    <string name=\"dont_show_again\">다시 표시하지 않음</string>\n    <string name=\"no_update_found\">업데이트를 찾을 수 없음</string>\n    <string name=\"update\">업데이트</string>\n    <string name=\"jsdelivr_proxy\">GitHub 프록시</string>\n    <string name=\"video_buffer_length_settings\">동영상 버퍼 길이</string>\n    <string name=\"video_buffer_disk_settings\">저장소에 동영상 캐시</string>\n    <string name=\"video_ram_description\">Android TV와 같이 메모리가 부족한 디바이스에서 너무 높게 설정하면 충돌이 발생할 수 있습니다.</string>\n    <string name=\"resize_fill\">화면 크기에 맞춤</string>\n    <string name=\"video_disk_description\">Android TV와 같이 저장 공간이 부족한 기기에서 너무 높게 설정하면 문제가 발생할 수 있습니다.</string>\n    <string name=\"nginx_url_pref\">NGINX 서버 URL</string>\n    <string name=\"resize_zoom\">확대</string>\n    <string name=\"pref_category_links\">링크</string>\n    <string name=\"dns_pref_summary\">ISP 차단을 우회하는 데 유용합니다</string>\n    <string name=\"resize_fit\">화면 맞춤</string>\n    <string name=\"display_subbed_dubbed_settings\">더빙/자막 애니메이션 표시</string>\n    <string name=\"legal_notice\">거부</string>\n    <string name=\"pref_category_bypass\">ISP 우회</string>\n    <string name=\"pref_category_app_updates\">앱 업데이트</string>\n    <string name=\"pref_category_extensions\">확장 기능</string>\n    <string name=\"logout\">로그아웃</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_password\">비밀번호</string>\n    <string name=\"account\">계정</string>\n    <string name=\"example_username\">사용자 이름</string>\n    <string name=\"example_lang_name\">언어 코드 (ko)</string>\n    <string name=\"example_site_name\">새사이트이름</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">자막이 %d ms 너무 늦게 표시되는 경우, 사용하세요</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">자막 지연 없음</string>\n    <string name=\"downloaded_file\">다운로드한 파일</string>\n    <string name=\"player_load_subtitles\">파일에서 불러오기</string>\n    <string name=\"recommended\">추천</string>\n    <string name=\"player_load_subtitles_online\">인터넷에서 불러오기</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">로드됨 %s</string>\n    <string name=\"coming_soon\">공개 예정…</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"category_player\">플레이어</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"setup_done\">완료</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">다운로드되지 않음: %d</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"provider_languages_tip\">이 언어로 된 동영상 보기</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">비활성화됨: %d</string>\n    <string name=\"extension_size\">사이즈</string>\n    <string name=\"extension_authors\">제작자</string>\n    <string name=\"preferred_media_subtext\">무엇을 보고 싶으신가요</string>\n    <string name=\"extension_status\">상태</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d 플러그인 업데이트</string>\n    <string name=\"restart\">재시작</string>\n    <string name=\"stop\">정지</string>\n    <string name=\"extension_description\">소개</string>\n    <string name=\"extension_types\">유형</string>\n    <string name=\"extension_install_first\">먼저 확장 프로그램을 설치하세요</string>\n    <string name=\"app_not_found_error\">앱을 찾을 수 없음</string>\n    <string name=\"all_languages_preference\">모든 언어</string>\n    <string name=\"skip_type_format\" formatted=\"true\">건너뛰기 %s</string>\n    <string name=\"skip_type_op\">오프닝</string>\n    <string name=\"skip_type_ed\">엔딩</string>\n    <string name=\"skip_type_mixed_ed\">혼합 엔딩</string>\n    <string name=\"skip_type_mixed_op\">혼합 오프닝</string>\n    <string name=\"skip_type_creddits\">크레딧</string>\n    <string name=\"skip_type_intro\">소개</string>\n    <string name=\"clear_history\">기록 삭제</string>\n    <string name=\"history\">기록</string>\n    <string name=\"enable_skip_op_from_database_des\">오프닝/엔딩 시 건너뛰기 팝업 표시</string>\n    <string name=\"clipboard_too_large\">텍스트가 너무 많습니다. 클립보드에 저장할 수 없습니다.</string>\n    <string name=\"action_remove_from_watched\">시청에서 삭제</string>\n    <string name=\"confirm_exit_dialog\">정말 종료하시겠습니까?</string>\n    <string name=\"yes\">네</string>\n    <string name=\"no\">아니요</string>\n    <string name=\"update_notification_downloading\">앱 업데이트 다운로드 중…</string>\n    <string name=\"update_notification_installing\">앱 업데이트 설치 중…</string>\n    <string name=\"update_notification_failed\">새 버전의 앱을 설치할 수 없습니다</string>\n    <string name=\"apk_installer_legacy\">레거시</string>\n    <string name=\"apk_installer_package_installer\">패키지 인스톨러</string>\n    <string name=\"delayed_update_notice\">앱 종료시 업데이트됩니다</string>\n    <string name=\"sort_by\">정렬 기준</string>\n    <string name=\"sort\">정렬</string>\n    <string name=\"sort_updated_new\">업데이트됨 (새로움에서 오래된 순)</string>\n    <string name=\"sort_updated_old\">업데이트 (오래됨에서 새로운 순)</string>\n    <string name=\"sort_alphabetical_a\">알파벳순 (A에서 Z)</string>\n    <string name=\"sort_alphabetical_z\">알파벳순 (Z에서 A)</string>\n    <string name=\"open_with\">다음으로 열기</string>\n    <string name=\"empty_library_no_accounts_message\">라이브러리가 비어 있습니다 :(\n\\n라이브러리 계정으로 로그인하거나 로컬 라이브러리에 프로그램을 추가하세요.</string>\n    <string name=\"safe_mode_file\">안전 모드 파일을 찾았습니다!\n\\n파일이 제거될 때까지 시작 시 확장 프로그램을 로드하지 않습니다.</string>\n    <string name=\"hls_playlist\">HLS 재생목록</string>\n    <string name=\"player_settings_play_in_app\">내부 플레이어</string>\n    <string name=\"player_pref\">선호하는 동영상 플레이어</string>\n    <string name=\"select_library\">라이브러리 선택</string>\n    <string name=\"empty_library_logged_in_message\">이 목록이 비어 있습니다. 다른 목록으로 전환해 보세요.</string>\n    <string name=\"filler\" formatted=\"true\">필러</string>\n    <string name=\"play_livestream_button\">라이브 스트리밍 재생</string>\n    <string name=\"stream\">네트워크 스트림</string>\n    <string name=\"search_provider_text_types\">유형을 사용하여 검색</string>\n    <string name=\"benene_count_text\">개발자에게 %d 바나나 줌</string>\n    <string name=\"benene_count_text_none\">바나나를 주지 않음</string>\n    <string name=\"action_open_watching\">상세 정보</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"normal_no_plot\">플롯을 찾을 수 없음</string>\n    <string name=\"torrent_no_plot\">설명을 찾을 수 없음</string>\n    <string name=\"show_log_cat\">Logcat 🐈 표시</string>\n    <string name=\"show_fillers_settings\">애니메이션용 필러 에피소드 표시</string>\n    <string name=\"test_passed\">통과</string>\n    <string name=\"resume\">계속</string>\n    <string name=\"limit_title\">동영상 플레이어 제목 최대 글자 수</string>\n    <string name=\"android_tv_interface_on_seek_settings\">표시된 플레이어 - 빨리 감기 및 되감기 초</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">플레이어가 보일 때 사용되는 탐색량</string>\n    <string name=\"android_tv_interface_off_seek_settings\">플레이어 숨김 - 빨리 감기 및 되감기 초</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">플레이어가 숨겨져 있을 때 사용되는 탐색량</string>\n    <string name=\"pref_category_actions\">동작</string>\n    <string name=\"pref_category_looks\">외형</string>\n    <string name=\"random_button_settings\">랜덤 버튼</string>\n    <string name=\"random_button_settings_desc\">홈페이지 및 도서관에서 임의 버튼 표시</string>\n    <string name=\"bottom_title_settings_des\">포스터 아래에 제목을 이동</string>\n    <string name=\"subtitles_depressed\">내려감</string>\n    <string name=\"subtitles_raised\">올라감</string>\n    <string name=\"subtitles_example_text\">다람쥐 헌 쳇바퀴에 타고파</string>\n    <string name=\"subtitles_remove_bloat\">자막에서 부풀림 제거</string>\n    <string name=\"extras\">엑스트라</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"tracks\">트랙</string>\n    <string name=\"referer\">Referer (선택)</string>\n    <string name=\"skip_type_recap\">요약</string>\n    <string name=\"action_mark_as_watched\">시청함으로 표시</string>\n    <string name=\"revert\">되돌리기</string>\n    <string name=\"subscription_in_progress_notification\">구독한 프로그램 업데이트</string>\n    <string name=\"subscription_list_name\">구독중</string>\n    <string name=\"subscription_new\">구독 %s</string>\n    <string name=\"subscription_deleted\">구독 취소 %s</string>\n    <string name=\"pref_category_security\">보안</string>\n    <string name=\"pref_category_accounts\">장부</string>\n    <string name=\"no_plugins_found_error\">리포지토리에서 플러그인을 찾을 수 없습니다</string>\n    <string name=\"toast_copied\">복사됨!</string>\n    <string name=\"repo_copy_label\">레포지토리 이름 및 URL</string>\n    <string name=\"test_extensions_summary\">본 테스트는 개발자만을 대상으로 하며, 확장자의 작업을 확인하거나 거부하지 않습니다.</string>\n    <string name=\"cs3wiki\">클라우스스트림 위키</string>\n    <string name=\"links_reloaded_toast\">다시 기록된 링크</string>\n    <string name=\"backup_frequency\">백업 빈도</string>\n    <string name=\"favorites_list_name\">즐겨찾기</string>\n    <string name=\"qr_image\">QR 이미지</string>\n    <string name=\"test_extensions\">모든 확장프로그램 테스트</string>\n    <string name=\"auth_locally\">로컬 인증</string>\n    <string name=\"clipboard_permission_error\">클립보드에 액세스하는 중 오류가 발생했습니다. 다시 시도하십시오.</string>\n    <string name=\"dismiss\">취소</string>\n    <string name=\"open_downloaded_repo\">저장소 열기</string>\n    <string name=\"enter_current_pin\">현재 PIN 입력</string>\n    <string name=\"auto_rotate_video_desc\">비디오 방향에 따라 화면 방향을 자동으로 전환합니다</string>\n    <string name=\"device_pin_error_message\">장치 PIN 코드를 가져올 수 없습니다, 로컬 인증을 시도하세요</string>\n    <string name=\"device_pin_expired_message\">PIN 코드가 만료되었습니다!</string>\n    <string name=\"device_pin_counter_text\">코드 만료까지 남은 시간: %1$dm %2$ds</string>\n    <string name=\"no_repository_found_error\">리포지토리를 찾을 수 없습니다. URL을 확인하고 VPN을 시도하십시오</string>\n    <string name=\"already_voted\">이미 투표했습니다</string>\n    <string name=\"unable_to_inflate\">UI를 올바르게 만들 수 없습니다. 이것은 주요 버그이며 %s 즉시 보고해야 합니다</string>\n    <string name=\"action_add_to_favorites\">즐겨찾기에 추가</string>\n    <string name=\"wifi\">와이파이</string>\n    <string name=\"help\">도움</string>\n    <string name=\"qualities\">품질</string>\n    <string name=\"edit\">편집</string>\n    <string name=\"profiles\">프로필</string>\n    <string name=\"ok\">확인</string>\n    <string name=\"battery_dialog_title\">배터리 최적화 사용 안 함</string>\n    <string name=\"app_unrestricted_toast\">앱 배터리 사용량이 이미 무제한으로 설정되었습니다</string>\n    <string name=\"app_info_intent_error\">CloudStream의 App 정보를 열 수 없습니다.</string>\n    <string name=\"favorite_added\">즐겨찾기에 %s 추가</string>\n    <string name=\"profile_number\">프로필 %d</string>\n    <string name=\"profile_background_des\">프로필 배경</string>\n    <string name=\"duplicate_replace\">대체</string>\n    <string name=\"enter_pin\">PIN 입력</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"pin_error_length\">PIN은 4자여야 합니다</string>\n    <string name=\"logged_account\" formatted=\"true\">%s으로 로그인 됨</string>\n    <string name=\"skip_startup_account_select_pref\">시작 시 계정 선택 건너뛰기</string>\n    <string name=\"favorite\">즐겨찾기</string>\n    <string name=\"unfavorite\">즐겨찾기 해제</string>\n    <string name=\"biometric_authentication_title\">잠금 해제</string>\n    <string name=\"biometric_setting\">생체 인식으로 잠금</string>\n    <string name=\"music_singlar\">음악</string>\n    <string name=\"audio_book_singular\">오디오책</string>\n    <string name=\"auto_rotate_video\">자동 회전</string>\n    <string name=\"mobile_data\">모바일 데이터</string>\n    <string name=\"disable\">사용 불가능</string>\n    <string name=\"player_settings_select_cast_device\">캐스트 장치 선택</string>\n    <string name=\"clipboard_unknown_error\">복사하는 중 오류가 발생했습니다. 로그캣을 복사하고 문의하십시오.</string>\n    <string name=\"action_unsubscribe\">구독 취소</string>\n    <string name=\"set_default\">기본값 설정</string>\n    <string name=\"action_subscribe\">구독</string>\n    <string name=\"use\">사용</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">당신의 라이브러리에 이미 잠재적으로 중복된 항목이 존재합니다: \\'%s\\'.\n\\n\n\\n이 항목을 그래도 추가하시겠습니까, 기존 항목을 교체하시겠습니까, 아니면 작업을 취소하시겠습니까?</string>\n    <string name=\"duplicate_replace_all\">전부 대체</string>\n    <string name=\"duplicate_add\">추가</string>\n    <string name=\"favorite_removed\">즐겨찾기에서 %s 제거</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">당신의 라이브러리에 잠재적으로 중복된 항목이 발견되었습니다:\n\\n\n\\n%s\n\\n\n\\n이 항목을 그래도 추가하시겠습니까, 기존 항목을 교체하시겠습니까, 아니면 작업을 취소하시겠습니까?</string>\n    <string name=\"select_an_account\">계정 선택</string>\n    <string name=\"use_default_account\">기본 계정 사용</string>\n    <string name=\"rotate_video\">회전</string>\n    <string name=\"rotate_video_desc\">화면 방향을 전환할 토글 버튼 표시</string>\n    <string name=\"manage_accounts\">계정 관리</string>\n    <string name=\"lock_profile\">프로필 잠금</string>\n    <string name=\"pin_error_incorrect\">잘못된 PIN입니다. 다시 시도하세요.</string>\n    <string name=\"edit_account\">계정 편집</string>\n    <string name=\"custom_media_singluar\">미디어</string>\n    <string name=\"password_pin_authentication_title\">비밀번호/PIN 인증</string>\n    <string name=\"biometric_unsupported\">이 장치에서는 생체 인식이 지원되지 않습니다</string>\n    <string name=\"biometric_setting_summary\">지문, 얼굴 ID, PIN, 패턴 또는 비밀번호로 앱을 잠급니다.</string>\n    <string name=\"biometric_prompt_description\">여러 번 실패하면 프롬프트가 닫힙니다. 다시 시도하려면 앱을 다시 시작하세요.</string>\n    <string name=\"reset_btn\">재설정</string>\n    <string name=\"automatic_plugin_download_mode_title\">플러그인 다운로드를 필터링할 모드 선택</string>\n    <string name=\"biometric_warning\">데이터가 백업되었습니다. 장치에 따라 동작이 다를 수 있으며 앱 접근이 차단될 경우 앱 데이터를 완전히 지우고 백업에서 복원하세요. 이로 인해 발생하는 불편을 사과드립니다.</string>\n    <string name=\"device_pin_url_message\">스마트폰이나 컴퓨터에서 <b>%s</b>를 방문하여 위의 코드를 입력하세요</string>\n    <string name=\"battery_dialog_message\">구독 된 TV 프로그램에 대한 특이성 다운로드 및 알림을 보려면 클라우드 스트림은 배경에서 오른쪽으로 실행할 권리가 필요합니다. 확인을 눌러 요청 대화 상자를 표시하십시오. 필요한 경우 필요에 따라 CP3에 제한되지 않고 공식을 다운로드하거나 공식화에서 확대를 누릴 필요가 있습니다.</string>\n    <string name=\"quality_profile_help\">여기서 소스의 순서를 변경할 수 있습니다. 비디오의 우선 순위가 높은 경우에는 소스 선택에 더 높게 나타납니다. 소스 우선 순위와 품질 우선 순위의 합이 비디오 우선 순위입니다.\n\\n\n\\n참고 A: 3\n\\n품질 B: 7\n\\n총 비디오 우선 순위는 10입니다.\n\\n\n\\n참고: 합이 10 이상이면 해당 링크가 로드되면 플레이어는 자동으로 로드를 건너뜁니다!</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">시즌 %1$d 에피소드 %2$d이(가) 출시됩니다</string>\n    <string name=\"result_search_tooltip\">다른 확장자에서 검색</string>\n    <string name=\"subscribe_tooltip\">새로운 에피소드 알림</string>\n    <string name=\"recommendations_tooltip\">권장 사항 표시</string>\n    <string name=\"speed_setting_summary\">플레이어에 속도 옵션을 추가합니다</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">%s로 출시 예정</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\n남음</string>\n    <string name=\"duplicate_title\">잠재적 중복 발견</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">%s의 PIN 입력</string>\n    <string name=\"action_remove_from_favorites\">즐겨찾기에서 제거</string>\n    <string name=\"episode_action_cast_mirror\">캐스트미러</string>\n    <string name=\"delete_plugin\">플러그인 삭제</string>\n    <string name=\"test_warning\">경고</string>\n    <string name=\"preview_seekbar\">탐색바 미리보기</string>\n    <string name=\"preview_seekbar_desc\">탐색바에서 미리보기 화면 활성화</string>\n    <string name=\"play_from_beginning_img_des\">처음부터 시작</string>\n    <string name=\"downloads_empty\">현재 다운로드가 없습니다.</string>\n    <string name=\"downloads_delete_select\">삭제할 항목을 선택하십시오</string>\n    <string name=\"offline_file\">오프라인 시청가능</string>\n    <string name=\"select_all\">모두 선택</string>\n    <string name=\"deselect_all\">모두 선택해제</string>\n    <string name=\"open_local_video\">로컬 비디오 열기</string>\n    <string name=\"delete_files\">파일 삭제</string>\n    <string name=\"delete_format\" formatted=\"true\">삭제 (%1$d | %2$s)</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">다음 항목을 영구적으로 삭제 하시겠습니까??\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">다음 에피소드를 영구적으로 삭제 하시겠습니까? %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">또한 다음 시리즈의 모든 에피소드를 영구적으로 삭제합니다:\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">다음 시리즈의 모든 에피소드를 영구적으로 삭제 하시겠습니까??\n\\n\n\\n%s</string>\n    <string name=\"sort_release_date_new\">출시일 (새로운 것부터 오래된 것)</string>\n    <string name=\"sort_release_date_old\">출시일 (오래된것부터 새로운것)</string>\n    <string name=\"hide_player_control_names\">플레이어 컨트롤 이름 숨기기</string>\n    <string name=\"torrent_info\">이 동영상은 토렌트이므로 동영상 활동이 추적될 수 있습니다.\\n계속하기 전에 토렌트에 대해 충분히 이해했는지 확인하세요.</string>\n    <string name=\"audio_singluar\">오디오</string>\n    <string name=\"podcast_singluar\">팟캐스트</string>\n    <string name=\"begin_speaking\">시작하기 …</string>\n    <string name=\"encoding_error\">인코딩 오류</string>\n    <string name=\"unsupported_error\">지원되지 않는 오류</string>\n    <string name=\"speech_recognition_unavailable\">음성 인식 사용 불가</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$d시간 %2$d분 %3$d초</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$d분 %2$d초</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d초</string>\n    <string name=\"play_full_series_button\">전체 시리즈 재생하기</string>\n    <string name=\"install_prerelease\">출시 전 버전 설치</string>\n    <string name=\"prerelease_already_installed\">출시 전 버전이 이미 설치되어 있습니다.</string>\n    <string name=\"prerelease_install_failed\">출시 전 버전 설치 실패.</string>\n    <string name=\"episode_action_play_mirror\">미러 재생</string>\"\n    <string name=\"show_rating\">평가 라벨</string>\n    <string name=\"show_episode_text\">에피소드 본문</string>\n    <string name=\"player_load_one_subtitle_online\">사용 가능한 자막 불러오기</string>\n    <string name=\"player_settings_always_ask\">항상 묻기</string>\n    <string name=\"sort_episodes_number_asc\">에피소드 (오름차순)</string>\n    <string name=\"sort_episodes_number_desc\">에피소드 (내림차순)</string>\n    <string name=\"sort_episodes_rating_high_low\">평가 (높은순)</string>\n    <string name=\"sort_episodes_rating_low_high\">평가 (낮은순)</string>\n    <string name=\"sort_episodes_date_newest\">방영 날짜 (최신순)</string>\n    <string name=\"sort_episodes_date_oldest\">방영 날짜 (오래된순)</string>\n    <string name=\"sort_button_episode\">에피소드 %s</string>\n    <string name=\"sort_button_rating\">평가 %s</string>\n    <string name=\"sort_button_date\">날짜 %s</string>\n    <string name=\"no_account\">계정 없음</string>\n    <string name=\"no_subtitles_loaded\">자막을 아직 불러오지 않았습니다</string>\n    <string name=\"backup_path_title\">백업 폴더 위치</string>\n    <string name=\"custom\">커스텀</string>\n    <string name=\"confirm_before_exiting_title\">나가기 전에 확인</string>\n    <string name=\"confirm_before_exiting_desc\">이 문항을 앱에서 나가기 전에 보이기</string>\n    <string name=\"show\">보이기</string>\n    <string name=\"dont_show\">보이지 않기</string>\n    <string name=\"subs_edge_size\">테두리 크기</string>\n    <string name=\"torrent_preferred_media\">Settings/Providers/Preferred media 에서 토렌트 활성화</string>\n    <string name=\"torrent_not_accepted\">진행하려면 앱 재시작 후 토렌트 스트리밍 팝업란의 수락이 필요합니다.</string>\n    <string name=\"software_decoding\">소프트웨어 디코딩</string>\n    <string name=\"software_decoding_desc\">소프트웨어 디코딩은 당신의 기기에서 지원되지 않는 영상 파일들을 재생할 수 있지만, 높은 화질에서 렉 또는 불안정한 재생을 유발할 수 있습니다.</string>\n    <string name=\"volume_exceeded_100\">볼륨이 100%를 초과하였습니다</string>\n    <string name=\"slide_up_again_to_exceed_100\">100% 너머로 높이려면 한번 더 슬라이드 하십시오</string>\n    <string name=\"update_plugins\">플러그인 업데이트하기</string>\n    <string name=\"update_plugins_manually\">수동으로 플러그인 업데이트 하기</string>\n    <string name=\"starting_plugin_update_manually\">플러그인 업데이트 절차를 시작합니다!</string>\n    <string name=\"plugins_updated_manually\">성공적으로 %d 플러그인을 업데이트 하였습니다!</string>\n    <string name=\"no_plugins_updated_manually\">업데이트 된 플러그인이 없습니다.</string>\n    <string name=\"player_notification_channel_name\">플레이어 알림</string>\n    <string name=\"player_notification_channel_description\">백그라운드에서 재생을 조종할 수 있는 플레이어 알림</string>\n    <string name=\"subtitles_from_embedded\">내장된</string>\n    <string name=\"subtitles_from_online\">온라인</string>\n    <string name=\"all_subtitles_bold\">모든 자막 굵게</string>\n    <string name=\"all_subtitles_italic\">모든 자막 기울기</string>\n    <string name=\"download_parallel_settings_des\">병렬로 다운로드 할 수 있는 아이템의 수</string>\n    <string name=\"parallel_downloads\">병렬 다운로드</string>\n    <string name=\"concurrent_connections\">동시 연결수</string>\n    <string name=\"concurrent_connections_settings_des\">다운로드 시 각 항목마다 사용할 수 있는 동시 연결의 수</string>\n    <string name=\"go_to_downloads\">다운로드로 가기</string>\n    <string name=\"no_internet_connection\">인터넷 연결 없음.\\n\\n인터넷에 연결 한 후 재시도 하거나, 혹은 이미 다운로드 된 항목을 재생하십시오.</string>\n    <string name=\"overscan_settings_des\">화면 경계 조정</string>\n    <string name=\"poster_size_settings_des\">포스터 크기 변경</string>\n    <string name=\"poster_size_settings\">포스터 크기</string>\n    <string name=\"speedup_title\">길게 눌러 배속 활성화</string>\n    <string name=\"speedup_summary\">길게 눌러 2배속</string>\n    <string name=\"edit_profile_image_title\">프로필 사진 변경</string>\n    <string name=\"edit_profile_image_hint\">프로필 사진 URL 입력</string>\n    <string name=\"edit_profile_image_error_empty\">URL을 찾을 수 없습니다</string>\n    <string name=\"edit_profile_image_error_invalid\">잘못된 URL 혹은 이미지 입니다</string>\n    <string name=\"edit_profile_image_success\">이미지 업데이트 성공</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">이 에피소드 까지 봤음 표시</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">이 에피소드 까지 봤음 표시 제거</string>\n    <string name=\"name\">이름</string>\n    <string name=\"resolution_and_name\">해상도 및 이름</string>\n    <string name=\"subs_subtitle_alignment\">자막 정렬</string>\n    <string name=\"bottom_left\">왼쪽 아래</string>\n    <string name=\"bottom_center\">중앙 아래</string>\n    <string name=\"bottom_right\">오른쪽 아래</string>\n    <string name=\"middle_left\">왼쪽 중앙</string>\n    <string name=\"middle_center\">정중앙</string>\n    <string name=\"middle_right\">오른쪽 중앙</string>\n    <string name=\"top_left\">왼쪽 위</string>\n    <string name=\"top_center\">중앙 위</string>\n    <string name=\"top_right\">오른쪽 위</string>\n    <string name=\"source_priority_help\">비디오 소스가 플레이어에서 정렬되어야하는 방법 결정</string>\n    <string name=\"extra_brightness_settings_des\">100% 표시 광도가 초과될 때 Enable 광도 여과기</string>\n    <string name=\"cancel_queue_message\">모든 퀴즈 다운로드를 취소하시겠습니까?</string>\n    <string name=\"download_episode_range\">에피소드를 다운로드 하시겠습니까 %s?</string>\n    <string name=\"queue_empty_message\">현재 누락된 다운로드가 없습니다.</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"other\">%d 활성 다운로드</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"other\">%d 다운로드</item>\n    </plurals>\n    <string name=\"search_suggestions_des\">검색 결과 표시</string>\n    <string name=\"show_cast_in_details\">회사 소개</string>\n    <string name=\"background_radius\">배경 반경</string>\n    <string name=\"reload_provider\">Reload 공급자</string>\n    <string name=\"search_suggestions\">검색 제안</string>\n    <string name=\"clear_suggestions\">자주 묻는 질문</string>\n    <string name=\"video_info\">미디어 정보</string>\n    <string name=\"source_name\">근원 이름</string>\n    <string name=\"extra_brightness_settings\">추가 밝기</string>\n    <string name=\"download_queue\">다운로드 queue</string>\n    <string name=\"download_all\">다운로드</string>\n    <string name=\"cancel_all\">모든 것</string>\n    <string name=\"source_priority\">근원 우선권</string>\n    <string name=\"overscan_settings\">구름 많음</string>\n    <string name=\"action_reload\">관련 상품</string>\n    <string name=\"extra_brightness_key\">추가_brightness_enabled</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+lt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"delete_file\">Ištrinti failą</string>\n    <string name=\"action_remove_from_bookmarks\">Pašalinti</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Greitis (%.2fx)</string>\n    <string name=\"error_bookmarks_text\">Žymos</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"download_started\">Siuntimas pradėtas</string>\n    <string name=\"home_next_random_img_des\">Sekantis atsitiktinai</string>\n    <string name=\"preview_background_img_des\">Peržiūros fonas</string>\n    <string name=\"play_movie_button\">Paleisti filmą</string>\n    <string name=\"subs_default_reset_toast\">Atstatyti į numatytą reikšmę</string>\n    <string name=\"sort_clear\">Išvalyti</string>\n    <string name=\"search_poster_img_des\">Plakatas</string>\n    <string name=\"filter_bookmarks\">Filtruoti žymas</string>\n    <string name=\"update_notification_failed\">Nepavyko įrašyti naujos programos versijos</string>\n    <string name=\"updates_settings_des\">Automatiškai ieškoti atnaujinimų, kai paleidžiama programa.</string>\n    <string name=\"movies_singular\">Filmas</string>\n    <string name=\"torrent_singular\">Torrentas</string>\n    <string name=\"show_fillers_settings\">Rodyti tarpines serijas animei</string>\n    <string name=\"subs_font_size\">Šrifto dydis</string>\n    <string name=\"no_links_found_toast\">Nuorodos ne rastos</string>\n    <string name=\"type_plan_to_watch\">Planuojama žiūrėti</string>\n    <string name=\"update_started\">Atnaujinimas pradėtas</string>\n    <string name=\"sort_copy\">Kopijuoti</string>\n    <string name=\"benene_des\">Duoti bananai</string>\n    <string name=\"home_more_info\">Daugiau informacijos</string>\n    <string name=\"title_downloads\">Atsiuntimai</string>\n    <string name=\"subs_auto_select_language\">Automatiškai pasirinkti kalbą</string>\n    <string name=\"error_loading_links_toast\">Klaida kraunant nuorodas</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"download_done\">Atsiuntimas baigtas</string>\n    <string name=\"continue_watching\">Tęsti žiūrėjimą</string>\n    <string name=\"new_update_format\" formatted=\"true\">Rastas atnaujinimas!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"subs_download_languages\">Atsisiųsti kalbas</string>\n    <string name=\"search_provider_text_providers\">Ieškoti naudojant tiekėjus</string>\n    <string name=\"go_back_img_des\">Grįžti atgal</string>\n    <string name=\"downloading\">Siunčiama</string>\n    <string name=\"episode_more_options_des\">Daugiau pasirinkčiu</string>\n    <string name=\"play_episode\">Paleisti seriją</string>\n    <string name=\"player_speed\">Grotuvo greitis</string>\n    <string name=\"benene_count_text\">%d Bananai duoti kūrėjams</string>\n    <string name=\"type_watching\">Žiūrima</string>\n    <string name=\"pause\">Pauzė</string>\n    <string name=\"result_tags\">Žanrai</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"episode_poster_img_des\">Serijos plakatas</string>\n    <string name=\"vpn_might_be_needed\">Gali reikėti VPN šitam tiekėjui, kad veiktų teisingai</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Ieškoti %s…</string>\n    <string name=\"github\">Github</string>\n    <string name=\"benene_count_text_none\">Nėra duotu bananų</string>\n    <string name=\"subs_subtitle_languages\">Subtitrų kalba</string>\n    <string name=\"home_change_provider_img_des\">Keisti teikėją</string>\n    <string name=\"subs_background_color\">Fono spalva</string>\n    <string name=\"search_hint\">Ieškoti…</string>\n    <string name=\"no_season\">Nėra Sezonų</string>\n    <string name=\"play_episode_toast\">Leisti seriją</string>\n    <string name=\"category_account\">Paskyros</string>\n    <string name=\"popup_pause_download\">Sustabdyti siuntimą</string>\n    <string name=\"app_dubbed_text\">Įgarsinimas</string>\n    <string name=\"subtitles_settings\">Subtitrų nustatymai</string>\n    <string name=\"subs_window_color\">Lango spalva</string>\n    <string name=\"documentaries\">Dokumentika</string>\n    <string name=\"play_torrent_button\">Transliuoti Torrentą</string>\n    <string name=\"delete\">Ištrinti</string>\n    <string name=\"cancel\">Atšaukti</string>\n    <string name=\"start\">Pradėti</string>\n    <string name=\"cartoons_singular\">Filmukas</string>\n    <string name=\"download_canceled\">Atsiuntimas atšauktas</string>\n    <string name=\"advanced_search\">Išplėstinė paieška</string>\n    <string name=\"empty_library_logged_in_message\">Tuščias sąrašas. Pabandykite pasirinkti kitą sąrašą.</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast subtitrai</string>\n    <string name=\"rated_format\" formatted=\"true\">Įvertinimas: %.1f</string>\n    <string name=\"home_expanded_hide\">Slėpti</string>\n    <string name=\"sort_apply\">Pritaikyti</string>\n    <string name=\"browser\">Naršyklė</string>\n    <string name=\"pick_subtitle\">Subtitrai</string>\n    <string name=\"next_episode\">Kita serija</string>\n    <string name=\"download_paused\">Siuntimas sustabdytas</string>\n    <string name=\"updates_settings\">Rodyti programos atnaujinimus</string>\n    <string name=\"download\">Atsisiųsti</string>\n    <string name=\"library\">Biblioteka</string>\n    <string name=\"video_disk_description\">Kelią problemas jei nustatytas per didelis ant prietaisų su mažai turymos vietos, tokiu kaip Android TV.</string>\n    <string name=\"others\">Kita</string>\n    <string name=\"popup_delete_file\">Ištrinti failą</string>\n    <string name=\"downloaded\">Atsisiųsta</string>\n    <string name=\"popup_resume_download\">Pratęsti siuntimą</string>\n    <string name=\"asian_drama\">Azijietiškos dramos</string>\n    <string name=\"episode\">Serija</string>\n    <string name=\"empty_library_no_accounts_message\">Jūsų biblioteka tuščia :(\n\\nPrisijunkite prie bibliotekos paskyros arba pridėkite laidas prie vietinės bibliotekos.</string>\n    <string name=\"autoplay_next_settings_des\">Pradėti sekančia seriją, kai dabartinė baigsis</string>\n    <string name=\"subs_text_color\">Teksto spalva</string>\n    <string name=\"type_completed\">Užbaigta</string>\n    <string name=\"use_system_brightness_settings_des\">Naudoti sistemos ryškumą programos grotuve vietoj tamsumo</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Nepavyko atstatyti duomenis iš failo %s</string>\n    <string name=\"play_trailer_button\">Paleisti anonsa</string>\n    <string name=\"play_livestream_button\">Paleisti gyva transliacija</string>\n    <string name=\"no_episodes_found\">Nerasta serijų</string>\n    <string name=\"vpn_torrent\">Šis tiekėjas yra iš Torrentų, VPN rekomenduojama naudoti</string>\n    <string name=\"test_failed\">Nepavyko</string>\n    <string name=\"result_poster_img_des\">Plakatas</string>\n    <string name=\"popup_play_file\">Paleisti failą</string>\n    <string name=\"type_re_watching\">Peržiūrima</string>\n    <string name=\"result_open_in_browser\">Atidaryti Naršyklėje</string>\n    <string name=\"use_system_brightness_settings\">Naudoti sistemos ryškumą</string>\n    <string name=\"no_data\">Nėra duomenų</string>\n    <string name=\"subs_font\">Šriftas</string>\n    <string name=\"redo_setup_process\">Perdaryti nustatymo procesą</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"benene\">Duoti bananą kūrėjams</string>\n    <string name=\"go_back\">Sugryšti</string>\n    <string name=\"copy_link_toast\">Nuoroda nukopijuota į iškarpinę</string>\n    <string name=\"search\">Paieška</string>\n    <string name=\"settings_info\">Informacija</string>\n    <string name=\"skip_loading\">Praleisti įkėlima</string>\n    <string name=\"home_info\">Informacija</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Serija %d bus išleista</string>\n    <string name=\"sort_save\">Išsaugoti</string>\n    <string name=\"clipboard_too_large\">Perdaug teksto. Nepavyko išsaugoti i iškarpynę.</string>\n    <string name=\"download_failed\">Atsiuntimas nepavyko</string>\n    <string name=\"result_share\">Pasidalinti</string>\n    <string name=\"home_main_poster_img_des\">Pagrindinis Plakatas</string>\n    <string name=\"pick_source\">Šaltiniai</string>\n    <string name=\"title_settings\">Nustatymai</string>\n    <string name=\"title_search\">Ieškoti</string>\n    <string name=\"loading\">Kraunama…</string>\n    <string name=\"action_remove_watching\">Pašalinti</string>\n    <string name=\"action_open_watching\">Daugiau informacijos</string>\n    <string name=\"type_on_hold\">Sustabdyta</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"home_play\">Paleisti</string>\n    <string name=\"livestreams\">Gyvos transliacijos</string>\n    <string name=\"apk_installer_settings\">APK įrašymas</string>\n    <string name=\"download_storage_text\">Vidinė atmintis</string>\n    <string name=\"autoplay_next_settings\">Automatiškai paleisti kitą seriją</string>\n    <string name=\"player_subtitles_settings_des\">Grotuvo subtitrų nustatymai</string>\n    <string name=\"app_language\">Programos kalba</string>\n    <string name=\"sort_close\">Uždaryti</string>\n    <string name=\"action_add_to_bookmarks\">Nustatyti žiūrėjimo statusą</string>\n    <string name=\"play_with_app_name\">Paleisti su CloudStream</string>\n    <string name=\"subs_subtitle_elevation\">Subtitrų iškėlimas</string>\n    <string name=\"episodes\">Serijos</string>\n    <string name=\"cast_format\" formatted=\"true\">Skleisti: %s</string>\n    <string name=\"season\">Sezonas</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Pridėta %s</string>\n    <string name=\"video_source\">Šaltinis</string>\n    <string name=\"pref_category_app_updates\">Programos atnaujinimai</string>\n    <string name=\"no_update_found\">Nerasta atnaujinimų</string>\n    <string name=\"show_title\">Pavadinimas</string>\n    <string name=\"download_path_pref\">Atsiuntimo kelias</string>\n    <string name=\"normal\">Normalu</string>\n    <string name=\"add_site_pref\">Klonuoti puslapį</string>\n    <string name=\"update\">Atnaujinimas</string>\n    <string name=\"episode_action_download_subtitle\">Atsisiųsti subtitrus</string>\n    <string name=\"dont_show_again\">Ne rodyti dar kartą</string>\n    <string name=\"video_skip_op\">Praleisti OP</string>\n    <string name=\"live_singular\">Gyva transliacija</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"unexpected_error\">Netikėta grotuvo klaida</string>\n    <string name=\"sync_score\">Įvertinta</string>\n    <string name=\"skip_update\">Praleisti šį atnaujinimą</string>\n    <string name=\"pref_category_actions\">Veiksmai</string>\n    <string name=\"episode_action_play_in_app\">Paleisti programoje</string>\n    <string name=\"upload_sync\">Sinchronizuoti</string>\n    <string name=\"remove_site_pref\">Pašalinti puslapį</string>\n    <string name=\"episode_action_reload_links\">Perkrauti nuorodos</string>\n    <string name=\"disable\">Išjungti</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"pref_category_links\">Nuorodos</string>\n    <string name=\"resize_zoom\">Pritraukti</string>\n    <string name=\"resize_fit\">Sutalpinti į ekraną</string>\n    <string name=\"video_lock\">Užrakinti</string>\n    <string name=\"storage_error\">Atsiuntimo klaida, patikrinkite atminties leidimus</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"asian_drama_singular\">Azijietiška drama</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"source_error\">Šaltinio klaida</string>\n    <string name=\"view_public_repositories_button_short\">Viešas sąrašas</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Atsiųsta %1$d %2$s</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Praleisti %s</string>\n    <string name=\"blank_repo_message\">Pagal numatytuosius nustatymus „CloudStream“ neturi įdiegtų svetainių. Turite įdiegti svetaines iš saugyklų.\n\\n\n\\nDėl beprotiško DMCA reikalavimų, kurios atliko Sky UK Limited 🤮, negalime susieti saugyklos svetainės programoje.\n\\n\n\\nPrisijunkite prie mūsų Discord arba ieškokite internete.</string>\n    <string name=\"mobile_data\">Mobilūs duomenys</string>\n    <string name=\"example_username\">šaunusPrisijungimoVardas</string>\n    <string name=\"extension_authors\">Autoriai</string>\n    <string name=\"all_languages_preference\">Visos kalbos</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Pradėta siųsti %1$d %2$s…</string>\n    <string name=\"extension_description\">Aprašymas</string>\n    <string name=\"safe_mode_title\">Saugus režimas įjungtas</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Ne atsiųsta: %d</string>\n    <string name=\"next\">Kitas</string>\n    <string name=\"select_library\">Pasirinkti biblioteką</string>\n    <string name=\"no\">Ne</string>\n    <string name=\"example_lang_name\">Kalbos kodas (lt)</string>\n    <string name=\"setup_done\">Baigta</string>\n    <string name=\"clear_history\">Išvalyti istoriją</string>\n    <string name=\"edit\">Redaguoti</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"coming_soon\">Greitai būs…</string>\n    <string name=\"yes\">Taip</string>\n    <string name=\"help\">Pagalba</string>\n    <string name=\"app_not_found_error\">Programa nerasta</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Išjungta: %d</string>\n    <string name=\"sort_by\">Rūšiuoti pagal</string>\n    <string name=\"skip_type_op\">Atidarymas</string>\n    <string name=\"example_password\">Slaptazodis123</string>\n    <string name=\"open_with\">Atidaryti su</string>\n    <string name=\"extension_language\">Kalba</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"example_email\">sveikas@pasauli.com</string>\n    <string name=\"use\">Naudoti</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"example_site_url\">Pavyzdys.com</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"extension_size\">Dydis</string>\n    <string name=\"extension_types\">Palaikoma</string>\n    <string name=\"example_site_name\">ManoŠaunusPuslapis</string>\n    <string name=\"trailer\">Anonsas</string>\n    <string name=\"history\">Istorija</string>\n    <string name=\"subscription_episode_released\">Serija %d išleista!</string>\n    <string name=\"update_notification_downloading\">Atsiunčiamas programos atnaujinimas…</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Atsiųsta: %d</string>\n    <string name=\"error\">Klaida</string>\n    <string name=\"logout\">Atsijungti</string>\n    <string name=\"sort\">Rūšiuoti</string>\n    <string name=\"video_tracks\">Vaizdo takelis</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"delayed_update_notice\">Programa bus atnaujinta išėjus</string>\n    <string name=\"primary_color_settings\">Pagrindinė kalba</string>\n    <string name=\"login\">Prisijungti</string>\n    <string name=\"action_mark_as_watched\">Pažymėti kaip žiūrima</string>\n    <string name=\"preferred_media_subtext\">Ką norite matyti</string>\n    <string name=\"update_notification_installing\">Įrašomas programos atnaujinimas…</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Nepavyko įkelti %s</string>\n    <string name=\"extension_rating\" formatted=\"true\">Įvertinimas: %s</string>\n    <string name=\"extension_status\">Statusas</string>\n    <string name=\"skip_type_ed\">Pabaiga</string>\n    <string name=\"error_invalid_url\">Klaidingas URL</string>\n    <string name=\"extension_version\">Versija</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (išjungta)</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"player_settings_play_in_app\">Integruotas grotuvas</string>\n    <string name=\"setup_extensions_subtext\">Atsisiųskite sąrašą puslapiu jūs norite naudoti</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ser %2$d</string>\n    <string name=\"confirm_exit_dialog\">Ar tikrai norite išeiti?</string>\n    <string name=\"action_remove_from_watched\">Pašalinti iš žiūrimų</string>\n    <string name=\"audio_tracks\">Garso takelis</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"search_poster_img_des\">Plakāts</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Cast: %s</string>\n    <string name=\"result_poster_img_des\">Plakāts</string>\n    <string name=\"episode_poster_img_des\">Epizodes plakāts</string>\n    <string name=\"home_main_poster_img_des\">Galvenais plakāts</string>\n    <string name=\"home_next_random_img_des\">Nākamais random</string>\n    <string name=\"go_back_img_des\">Iet atpakaļ</string>\n    <string name=\"home_change_provider_img_des\">Nomainīt dvēju</string>\n    <string name=\"preview_background_img_des\">Apskatīt background</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Ātrums (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Lidzīgi: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Jauns atjauninājums atrasts!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration_format\" formatted=\"true\">%d galvenais</string>\n    <string name=\"app_name\">Claudstream</string>\n    <string name=\"play_with_app_name\">Atskaņo ar cloudstream</string>\n    <string name=\"title_home\">Mājas</string>\n    <string name=\"title_search\">Meklēt</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Meklēt %s…</string>\n    <string name=\"no_data\">Nav datu</string>\n    <string name=\"episode_more_options_des\">Vairāk opcijas</string>\n    <string name=\"next_episode\">Nākamā epizode</string>\n    <string name=\"browser\">Internets</string>\n    <string name=\"skip_loading\">Izlaist ladešanos</string>\n    <string name=\"loading\">Lādējas…</string>\n    <string name=\"type_watching\">Skaties</string>\n    <string name=\"type_on_hold\">Aizturēts</string>\n    <string name=\"type_completed\">Pabeigts</string>\n    <string name=\"type_dropped\">Atmests</string>\n    <string name=\"type_plan_to_watch\">Plāno skatīties</string>\n    <string name=\"type_re_watching\">Atkārtoti skatities</string>\n    <string name=\"play_movie_button\">Palaist Filmu</string>\n    <string name=\"play_trailer_button\">Palaist Trelleri</string>\n    <string name=\"play_livestream_button\">Palaist Livestreamu</string>\n    <string name=\"play_torrent_button\">Skatities Torrentu</string>\n    <string name=\"pick_source\">Devēji</string>\n    <string name=\"pick_subtitle\">Subtitri</string>\n    <string name=\"reload_error\">Atkārtot pieslēgumu…</string>\n    <string name=\"go_back\">Iet atpakaļ</string>\n    <string name=\"play_episode\">Palaist epizodi</string>\n    <string name=\"download\">Ieladēt</string>\n    <string name=\"download_paused\">Lādēšana pauzēta</string>\n    <string name=\"download_started\">Lādēšana sakās</string>\n    <string name=\"download_failed\">Ielādēt neizdevās</string>\n    <string name=\"download_canceled\">Ielādēšana atcelta</string>\n    <string name=\"download_done\">Pabeidza ieladēt</string>\n    <string name=\"update_started\">Atjauninājums sakās</string>\n    <string name=\"stream\">Tīkla plūsma</string>\n    <string name=\"error_loading_links_toast\">Kļūda padejot linkus</string>\n    <string name=\"download_storage_text\">Iekšējā atmiņa</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"popup_delete_file\">Dzēst datni</string>\n    <string name=\"popup_play_file\">Atskaņot datni</string>\n    <string name=\"popup_resume_download\">Atsākt ielādi</string>\n    <string name=\"popup_pause_download\">Pauzēt ielādi</string>\n    <string name=\"home_more_info\">Vairāk informācijas</string>\n    <string name=\"home_expanded_hide\">Slēpt</string>\n    <string name=\"home_play\">Atskaņot</string>\n    <string name=\"home_info\">Informācija</string>\n    <string name=\"filter_bookmarks\">Filtra bookmarks</string>\n    <string name=\"error_bookmarks_text\">Bookmarks</string>\n    <string name=\"action_remove_from_bookmarks\">Noņemt</string>\n    <string name=\"action_add_to_bookmarks\">Ieliec skatīšanās statusu</string>\n    <string name=\"sort_apply\">Apstiprināt</string>\n    <string name=\"sort_copy\">Kopēt</string>\n    <string name=\"sort_save\">Saglabāt</string>\n    <string name=\"player_speed\">Atskaņošanas ātrums</string>\n    <string name=\"subtitles_settings\">Subtitru iestatījumi</string>\n    <string name=\"subs_outline_color\">Apkārt krāsa</string>\n    <string name=\"subs_background_color\">Backgrounds krāsa</string>\n    <string name=\"subs_window_color\">Līga krāsa</string>\n    <string name=\"subs_edge_type\">Stūra tips</string>\n    <string name=\"subs_font\">Fonts</string>\n    <string name=\"subs_font_size\">Fonta lielums</string>\n    <string name=\"search_provider_text_providers\">Meklēt izmantojot devējus</string>\n    <string name=\"search_provider_text_types\">Meklēt izmantojot tipus</string>\n    <string name=\"benene_count_text\">%d Banāni iedoti veidotājiem</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episode %d būs izlaista</string>\n    <string name=\"filler\" formatted=\"true\">Filtrs</string>\n    <string name=\"title_downloads\">Ieladētas</string>\n    <string name=\"search_hint\">Meklēt…</string>\n    <string name=\"title_settings\">Settingi</string>\n    <string name=\"result_tags\">Žanrs</string>\n    <string name=\"result_share\">Dalities</string>\n    <string name=\"result_open_in_browser\">Atvērt pārlūkā</string>\n    <string name=\"downloaded\">Ieladēts</string>\n    <string name=\"downloading\">Lādējas</string>\n    <string name=\"sort_close\">Aizvērt</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"benene_count_text_none\">Nav banāni iedoti</string>\n    <string name=\"subs_subtitle_elevation\">Subtitru paaugstinājums</string>\n    <string name=\"sort_clear\">Iztīrīt</string>\n    <string name=\"subs_text_color\">Teksta krāsa</string>\n    <string name=\"subs_auto_select_language\">Automātiski-iestādīt valodu</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"subs_download_languages\">Ielādēt valodas</string>\n    <string name=\"subs_subtitle_languages\">Subtitru valoda</string>\n    <string name=\"subs_hold_to_reset_to_default\">Tūri lai restartētu uz sākumu</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importēt fontus ieliekot iekšā %s</string>\n    <string name=\"continue_watching\">Turpini skatīties</string>\n    <string name=\"action_remove_watching\">Noņemt</string>\n    <string name=\"action_open_watching\">Vairāk informācijas</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">VPNs varētu būt vajadzīgs lai šis devējs strādātu pareizi</string>\n    <string name=\"vpn_torrent\">Šis devējs ir Torrents vpn ir rekomendēts</string>\n    <string name=\"provider_info_meta\">Dati nav doti no saites, video lādēšanas neizdosies ja neiksestē saitē.</string>\n    <string name=\"torrent_plot\">Apraksts</string>\n    <string name=\"normal_no_plot\">Nav apraksts atrasts</string>\n    <string name=\"torrent_no_plot\">Apraksts nav atrasts</string>\n    <string name=\"show_log_cat\">Rādīt Logcat 🐈</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"picture_in_picture\">Bilde bildē</string>\n    <string name=\"picture_in_picture_des\">Turpina spēlēt mazā lodziņā virs aplikācijām</string>\n    <string name=\"player_size_settings\">Players izmēra poga</string>\n    <string name=\"player_size_settings_des\">Noņemt melnās malas</string>\n    <string name=\"player_subtitles_settings\">Subtitri</string>\n    <string name=\"player_subtitles_settings_des\">Atskaņotāja subtitru iestatījumi</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast subtitri</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast subtitru iestatījumi</string>\n    <string name=\"eigengraumode_settings\">Atskaņošanas ātrums</string>\n    <string name=\"swipe_to_seek_settings\">Novelc lai paradītu</string>\n    <string name=\"swipe_to_seek_settings_des\">Novelc no māla lidz malai lai pozicionētu video</string>\n    <string name=\"swipe_to_change_settings\">Novēlu lai mainītu iestādījums</string>\n    <string name=\"swipe_to_change_settings_des\">Novēlu uz augšu vai apakšu pa labi un pa kreisi lai nomainītu gaišumu un skaņu</string>\n    <string name=\"autoplay_next_settings\">Automātiski nākamo epizodi</string>\n    <string name=\"autoplay_next_settings_des\">Sākt nākamo epizodi kad šis bridzas</string>\n    <string name=\"double_tap_to_seek_settings\">Divreiz uzpied lai paslēptu</string>\n    <string name=\"double_tap_to_pause_settings\">Divreiz uzpied lai pauzētu</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Players meklēšanas daudzums (sekundes)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Uzpied divreiz pa labi vai kreisi lai palaistu atpakaļ vai uz priekšu</string>\n    <string name=\"double_tap_to_pause_settings_des\">Uzpied divreiz vidū lai pauzētu</string>\n    <string name=\"use_system_brightness_settings\">Lietot sistēmas gaišums</string>\n    <string name=\"use_system_brightness_settings_des\">Lietot sistēmas gaišumu aplikācijas playerī nevis tumšunu</string>\n    <string name=\"episode_sync_settings\">Atjaunināt skatīšanos progresu</string>\n    <string name=\"episode_sync_settings_des\">Automātiski sync savu pašreizējo epizodes progresu</string>\n    <string name=\"restore_settings\">Atgūt datus no backupa</string>\n    <string name=\"backup_settings\">Saglabāt datus</string>\n    <string name=\"restore_success\">Atjaunots no dublējuma</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Neizdevās atjaunot datus no %s datnes</string>\n    <string name=\"backup_success\">Dati saglabāti</string>\n    <string name=\"backup_failed\">Krātuves atļaujas nav. Lūdzu mēģiniet vēlreiz.</string>\n    <string name=\"backup_failed_error_format\">Kļūda meiģinot saglabāt %s</string>\n    <string name=\"search\">Meklēt</string>\n    <string name=\"library\">Library</string>\n    <string name=\"category_account\">Konti un drošība</string>\n    <string name=\"category_updates\">Atjauninājumi un dublēšana</string>\n    <string name=\"settings_info\">Informācija</string>\n    <string name=\"advanced_search\">Advancēta meklēšana</string>\n    <string name=\"advanced_search_des\">Dod tev meklēšanas rezultātus citus no devēja</string>\n    <string name=\"show_fillers_settings\">Rādīt anime papilda epizodi</string>\n    <string name=\"show_trailers_settings\">Rādīt reklāmkadrus</string>\n    <string name=\"kitsu_settings\">Rādīt Kitsu vietnes plakātus</string>\n    <string name=\"pref_filter_search_quality\">Slēpt izvēlētos video kvalitāti meklēšanas rezultātus</string>\n    <string name=\"automatic_plugin_updates\">Automātiska papildinājumu atjaunināšana</string>\n    <string name=\"automatic_plugin_download\">Automātiski lejupielādēt papildinājumus</string>\n    <string name=\"automatic_plugin_download_summary\">Automātiski uzstāda visus vēl neuzstādītos papildinājumus no pievienotajiem repozitorijiem.</string>\n    <string name=\"updates_settings\">Rādīt lietotņu atjauninājumus</string>\n    <string name=\"updates_settings_des\">Automātiski meklēt jaunus atjauninājumus kad palaiž aplikāciju.</string>\n    <string name=\"redo_setup_process\">Atsākt uzstādīšanas procesu</string>\n    <string name=\"apk_installer_settings_des\">Dažas ierīces neatbalsta jauno pakotnes uzstādītāju. Izmantojiet legacy (veco) uzstādītāju, ja atjauninājumus nevar uzstādīt.</string>\n    <string name=\"lightnovel\">Noveles aplikācija no šiem izstrādātājiem</string>\n    <string name=\"anim\">Anime aplikāciju no tiem pašiem izstradatājiem</string>\n    <string name=\"discord\">Ienāc discordā</string>\n    <string name=\"benene\">Iedot banānu izstrādātājiem</string>\n    <string name=\"benene_des\">Iedotie banāni</string>\n    <string name=\"app_language\">Aplikācijas valoda</string>\n    <string name=\"no_chromecast_support_toast\">Šim devējam nav Chromecast pieņemšana</string>\n    <string name=\"no_links_found_toast\">Nav linku strastu</string>\n    <string name=\"copy_link_toast\">Links kopēts cliobordā</string>\n    <string name=\"subs_default_reset_toast\">Restartēt uz parasto value</string>\n    <string name=\"season\">Sezona</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Nav sezonas</string>\n    <string name=\"episode\">Epizode</string>\n    <string name=\"episodes\">Epizodes</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Epizodes netika atrastas</string>\n    <string name=\"delete_file\">Dzēst datni</string>\n    <string name=\"delete\">Dzēst</string>\n    <string name=\"cancel\">Atcelt</string>\n    <string name=\"pause\">Pauzēt</string>\n    <string name=\"start\">Sākt</string>\n    <string name=\"test_failed\">Neizdevās</string>\n    <string name=\"test_passed\">Nokārtojāt</string>\n    <string name=\"resume\">Atsākt</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Šis pilnibā dzesīs %s\n\\nEsat parliecināts?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\natlikušas</string>\n    <string name=\"status_completed\">Pabeigts</string>\n    <string name=\"status\">Statuss</string>\n    <string name=\"year\">gads</string>\n    <string name=\"rating\">Reitings</string>\n    <string name=\"duration\">Ilgums</string>\n    <string name=\"site\">Saite</string>\n    <string name=\"synopsis\">Synopsis</string>\n    <string name=\"queued\">Gaida</string>\n    <string name=\"used_storage\">Lietotie</string>\n    <string name=\"app_storage\">Aplikācija</string>\n    <string name=\"movies\">Filmas</string>\n    <string name=\"tv_series\">Seriāli</string>\n    <string name=\"cartoons\">Animācija</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrenti</string>\n    <string name=\"documentaries\">Dokumentārija</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Āzijas Drāma</string>\n    <string name=\"livestreams\">Livestreami</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Citi</string>\n    <string name=\"movies_singular\">Filmas</string>\n    <string name=\"tv_series_singular\">Sērijas</string>\n    <string name=\"cartoons_singular\">Animācija</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrenti</string>\n    <string name=\"documentaries_singular\">Documentarijas</string>\n    <string name=\"asian_drama_singular\">Āzijas drāma</string>\n    <string name=\"live_singular\">Livestreami</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"source_error\">Devēja kļūda</string>\n    <string name=\"remote_error\">Remote kļūda</string>\n    <string name=\"unexpected_error\">Negaidīta atskaņotāja kļūda</string>\n    <string name=\"storage_error\">Ielādēšanas kļūda, pārbaudi atmiņas atļauju</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast epizode</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast morror</string>\n    <string name=\"episode_action_play_in_app\">Palaist aplikācijā</string>\n    <string name=\"episode_action_play_in_format\">Atskaņot uekšā %s</string>\n    <string name=\"episode_action_auto_download\">Automātiski ielādēt</string>\n    <string name=\"episode_action_download_mirror\">Ielādēt spoguli</string>\n    <string name=\"episode_action_reload_links\">Pārlādēt saites</string>\n    <string name=\"episode_action_download_subtitle\">Lejupielādēt subtitrus</string>\n    <string name=\"show_hd\">Kvalitātes zīme</string>\n    <string name=\"show_dub\">Dub lable</string>\n    <string name=\"show_sub\">Subtirti</string>\n    <string name=\"show_title\">Nosaukums</string>\n    <string name=\"render_error\">Render kļūda</string>\n    <string name=\"check_for_update\">Pārbaudīt atjauninājumus</string>\n    <string name=\"video_lock\">Slēgt</string>\n    <string name=\"video_aspect_ratio_resize\">Mainīt lielumu</string>\n    <string name=\"video_source\">Devējs</string>\n    <string name=\"video_skip_op\">Izlaist OP</string>\n    <string name=\"dont_show_again\">Nerādīt atkal</string>\n    <string name=\"skip_update\">Izlaist šo atjauninājumu</string>\n    <string name=\"update\">Atjauninājums</string>\n    <string name=\"watch_quality_pref\">Izvēlētā skatīšanās kvalitāte (WiFi)</string>\n    <string name=\"limit_title\">Video players nosaukuma maksimālie burti</string>\n    <string name=\"limit_title_rez\">Video atskaņotāja kvalitāte</string>\n    <string name=\"video_buffer_size_settings\">Video buffer izmērs</string>\n    <string name=\"video_buffer_length_settings\">Video buffering garums</string>\n    <string name=\"video_buffer_disk_settings\">Video atkritne diskā</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Atskaņotājs rāda - seek smount</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Meklēšanas summa, kas tiek izmantota, kad spēlētājs ir redzams</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Atskaņotājs paslēpts — meklēšanas summa</string>\n    <string name=\"video_ram_description\">Izraisa avārijas, ja ierīcēs ar mazu atmiņu ir iestatīta pārāk augsta vērtība, piemēram, Android TV.</string>\n    <string name=\"dns_pref_summary\">Izdevīgs lai izlaistu ISO aizturi</string>\n    <string name=\"jsdelivr_proxy\">GitHub starpniekserveris</string>\n    <string name=\"jsdelivr_proxy_summary\">Apiet tiešo GitHub URL saišu piekļuves ierobežojumus, izmantojot jsDelivr. Tādēļ atjauninājumi var aizkavēties vairākas dienas.</string>\n    <string name=\"add_site_pref\">Klonēt saiti</string>\n    <string name=\"remove_site_pref\">Noņemt saiti</string>\n    <string name=\"add_site_summary\">Pievienojiet esošas vietnes klonu ar citu URL</string>\n    <string name=\"download_path_pref\">Ielādēšanas ceļš</string>\n    <string name=\"nginx_url_pref\">NGINX servera URL</string>\n    <string name=\"display_subbed_dubbed_settings\">Radīt Dubbed/Subbed Anime</string>\n    <string name=\"resize_fit\">Ietilpt ekranā</string>\n    <string name=\"legal_notice\">Atruna</string>\n    <string name=\"pref_category_bypass\">ISP Izlaists</string>\n    <string name=\"pref_category_links\">Links</string>\n    <string name=\"pref_category_app_updates\">Aplikācijas atjauninājumus</string>\n    <string name=\"pref_category_backup\">Dublējums</string>\n    <string name=\"pref_category_extensions\">Papildinājumi</string>\n    <string name=\"pref_category_actions\">Akcijas</string>\n    <string name=\"pref_category_cache\">Atkritne</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"pref_category_gestures\">Žesti</string>\n    <string name=\"pref_category_player_features\">Atskaņošanas funkcijas</string>\n    <string name=\"pref_category_subtitles\">Subtitri</string>\n    <string name=\"pref_category_player_layout\">Iskats</string>\n    <string name=\"pref_category_defaults\">Parasts</string>\n    <string name=\"pref_category_looks\">Izskats</string>\n    <string name=\"pref_category_ui_features\">Funkcijas</string>\n    <string name=\"category_general\">Ģenerāls</string>\n    <string name=\"random_button_settings\">Randomā poga</string>\n    <string name=\"random_button_settings_desc\">Rādīt izlases pogu Sākums un Bibliotēka sadaļās</string>\n    <string name=\"provider_lang_settings\">Papildinājuma valodas</string>\n    <string name=\"app_layout\">Aplikācijas izskats</string>\n    <string name=\"preferred_media_settings\">Izvēlētā media</string>\n    <string name=\"enable_nsfw_on_providers\">Iespējot nepiedienīgu, izaicinošu saturu (NSFW) atbalstītajos papildinājumos</string>\n    <string name=\"subtitles_encoding\">Subtitru kodējums</string>\n    <string name=\"category_providers\">Devēji</string>\n    <string name=\"category_provider_test\">Devēju tests</string>\n    <string name=\"category_ui\">Izskats</string>\n    <string name=\"automatic\">Automātiski</string>\n    <string name=\"tv_layout\">Televizora izskats</string>\n    <string name=\"phone_layout\">Telefona izskats</string>\n    <string name=\"emulator_layout\">Emulators izskats</string>\n    <string name=\"bottom_title_settings\">Plakāta virsraksta lokācija</string>\n    <string name=\"example_password\">Parole123</string>\n    <string name=\"example_username\">Lietotājvārds</string>\n    <string name=\"example_email\">Sveiki@pasaule.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">JaunāsVietnesNosaukums</string>\n    <string name=\"example_site_url\">https://piemērs.com</string>\n    <string name=\"example_lang_name\">Valodas kods (lv)</string>\n    <string name=\"account\">Konts</string>\n    <string name=\"logout\">Iziet</string>\n    <string name=\"login\">Ieiet</string>\n    <string name=\"switch_account\">Mainīt kontu</string>\n    <string name=\"add_account\">Pievienot kontu</string>\n    <string name=\"create_account\">Veidot kontu</string>\n    <string name=\"add_sync\">Pievienot izsekošanu</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Pievienot %s</string>\n    <string name=\"upload_sync\">Sync</string>\n    <string name=\"sync_score\">Lidzīgi</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s autentificēts</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Nevarēja ieiet %s</string>\n    <string name=\"none\">Nekas</string>\n    <string name=\"normal\">Normāls</string>\n    <string name=\"all\">Viss</string>\n    <string name=\"max\">Maksimālais</string>\n    <string name=\"min\">Minimālais</string>\n    <string name=\"subtitles_outline\">Kontūrs</string>\n    <string name=\"subtitles_depressed\">Iespiests</string>\n    <string name=\"subtitles_shadow\">Ēna</string>\n    <string name=\"subtitles_raised\">Izvirzīts</string>\n    <string name=\"subtitle_offset\">Subtitru sinhronizācija</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Subtitru nobīde</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Ja subtitri steidzas pa %d ms</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Nav subtitru nobīdes - kavēšanās vai apsteigšana</string>\n    <string name=\"subtitles_example_text\">Fogts čuhņā mīļi lenc - ģērbj, žvadz, pūkšķ</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Ielādēti %s</string>\n    <string name=\"player_load_subtitles\">Ielādēt no datnes</string>\n    <string name=\"app_theme_settings\">Aplikācijas theme</string>\n    <string name=\"player_load_subtitles_online\">Lejupielādēt no interneta</string>\n    <string name=\"downloaded_file\">Lejupielādēta datne</string>\n    <string name=\"actor_main\">Galvenais</string>\n    <string name=\"actor_supporting\">Atbalsta</string>\n    <string name=\"actor_background\">Aizmugure</string>\n    <string name=\"home_source\">Devējs</string>\n    <string name=\"home_random\">Randoms</string>\n    <string name=\"quality_cam\">Camera</string>\n    <string name=\"quality_cam_rip\">Kamera</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"poster_image\">Plakāta bilde</string>\n    <string name=\"category_player\">Atskaņotājs</string>\n    <string name=\"resolution_and_title\">Rezolūcija un tituls</string>\n    <string name=\"error_invalid_id\">Nederīgs ID</string>\n    <string name=\"error_invalid_data\">Nederīgi dati</string>\n    <string name=\"error_invalid_url\">Nederīgs URL</string>\n    <string name=\"error\">Kļūda</string>\n    <string name=\"subtitles_remove_captions\">Noņemt slēgtos parakstus no subtitriem</string>\n    <string name=\"subtitles_remove_bloat\">Noņemt lieko no subtitriem (piemēram, reklāmu)</string>\n    <string name=\"subtitles_filter_lang\">Filtrēt pēc vēlamās multivides valodas</string>\n    <string name=\"extras\">Ekstras</string>\n    <string name=\"trailer\">Treileris</string>\n    <string name=\"network_adress_example\">https://piemērs.com/piemērs.mp4</string>\n    <string name=\"referer\">Referents</string>\n    <string name=\"next\">Nākamais</string>\n    <string name=\"provider_languages_tip\">Skatieties videoklipus šajās valodās</string>\n    <string name=\"previous\">Iepriekšējais</string>\n    <string name=\"skip_setup\">Izlaist uzstādīšanu</string>\n    <string name=\"app_layout_subtext\">Mainiet lietotnes izskatu, lai tā atbilstu savai ierīcei</string>\n    <string name=\"preferred_media_subtext\">Ko tu vēlies redzēt</string>\n    <string name=\"setup_done\">Pabeigts</string>\n    <string name=\"extensions\">Papildinājumi</string>\n    <string name=\"add_repository\">Pievienot repozitoriju</string>\n    <string name=\"repository_url_hint\">Repozitorija URL vai īsskods</string>\n    <string name=\"plugin_loaded\">Papildinājums ielādēts</string>\n    <string name=\"plugin_deleted\">Papildinājums dzēsts</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Nevarēja ielādēt %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Sākta %1$d %2$s lejupielāde…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Lejuplādēts %1$d %2$s</string>\n    <string name=\"batch_download\">Pakešu lejupielāde</string>\n    <string name=\"plugin_singular\">papildinājums</string>\n    <string name=\"plugin\">papildinājumi</string>\n    <string name=\"delete_repository_plugins\">Tiks izdzēsti arī visi repozitorija papildinājumi</string>\n    <string name=\"delete_repository\">Dzēst repozitoriju</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Lejupielādēts: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Atspējots: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Nelejupielādēts: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Atjaunināti %d papildinājumi</string>\n    <string name=\"view_public_repositories_button\">Skatīt kopienas repozitorijus</string>\n    <string name=\"view_public_repositories_button_short\">Publiskais saraksts</string>\n    <string name=\"uppercase_all_subtitles\">Visi subtitri ar lielajiem burtiem</string>\n    <string name=\"download_all_plugins_from_repo\">Uzmanību: CloudStream neuzņemas nekādu atbildību par trešo pušu papildinājumu izmantošanu un nesniedz nekādu tā atbalstu!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (atspējots)</string>\n    <string name=\"tracks\">Tracks</string>\n    <string name=\"audio_tracks\">Audio dziesmas</string>\n    <string name=\"video_tracks\">Video tracks</string>\n    <string name=\"apply_on_restart\">Palaist pa jaunu lietotni, lai redzētu izmaiņas.</string>\n    <string name=\"restart\">Restartēt</string>\n    <string name=\"stop\">Pārtraukt</string>\n    <string name=\"safe_mode_title\">Drošais režīms ieslēgts</string>\n    <string name=\"safe_mode_description\">Visi papildinājumi tika izslēgti avārijas dēļ, lai palīdzētu jums atrast to, kurš rada problēmas.</string>\n    <string name=\"safe_mode_crash_info\">Skatīt avārijas informāciju</string>\n    <string name=\"extension_rating\" formatted=\"true\">Vērtējums: %s</string>\n    <string name=\"extension_description\">Apraksts</string>\n    <string name=\"extension_version\">Versija</string>\n    <string name=\"extension_status\">Statuss</string>\n    <string name=\"extension_size\">Izmērs</string>\n    <string name=\"extension_authors\">Autori</string>\n    <string name=\"extension_types\">Atbalstīts</string>\n    <string name=\"extension_language\">Valoda</string>\n    <string name=\"hls_playlist\">HLS atskaņošanas saraksts</string>\n    <string name=\"player_pref\">Vēlamais video atskaņotājs</string>\n    <string name=\"player_settings_play_in_app\">Iekšējais atskaņotājs</string>\n    <string name=\"app_not_found_error\">Aplikācijs nav atrasta</string>\n    <string name=\"all_languages_preference\">Visas valodas</string>\n    <string name=\"skip_type_ed\">Beigas</string>\n    <string name=\"skip_type_recap\">Kopsavilkums</string>\n    <string name=\"skip_type_mixed_ed\">Jauktas beigas</string>\n    <string name=\"skip_type_mixed_op\">Jauktais sākums</string>\n    <string name=\"skip_type_creddits\">Kredīts</string>\n    <string name=\"clear_history\">Notīrīt vēsturi</string>\n    <string name=\"history\">Vēsture</string>\n    <string name=\"enable_skip_op_from_database_des\">Rādīt izlaižamos uznirstošos logus atvēršanai/beigšanai</string>\n    <string name=\"clipboard_too_large\">Pārāk daudz teksta. Nevar saglabāt starpliktuvē.</string>\n    <string name=\"yes\">Jā</string>\n    <string name=\"no\">Nē</string>\n    <string name=\"update_notification_downloading\">Notiek lietotnes atjauninājuma lejupielāde…</string>\n    <string name=\"update_notification_installing\">Notiek lietotnes atjauninājuma instalēšana…</string>\n    <string name=\"update_notification_failed\">Nevarēja instalēt jauno lietotnes versiju</string>\n    <string name=\"apk_installer_legacy\">Mantojums</string>\n    <string name=\"apk_installer_package_installer\">Insteletājs</string>\n    <string name=\"delayed_update_notice\">Lietotne tiks atjaunināta pēc iziešanas</string>\n    <string name=\"sort_by\">Kārtot pēc</string>\n    <string name=\"sort\">Kārtot</string>\n    <string name=\"sort_rating_desc\">Vērtējums (no augsta līdz zemam)</string>\n    <string name=\"sort_updated_new\">Atjaunināts (no jauna uz veco)</string>\n    <string name=\"sort_updated_old\">Atjaunināts (no vecā uz jauno)</string>\n    <string name=\"sort_alphabetical_a\">Alfabētiskā secībā (A līdz Z)</string>\n    <string name=\"sort_alphabetical_z\">Alfabētiskā secībā (Z līdz A)</string>\n    <string name=\"select_library\">Atlasiet Bibliotēka</string>\n    <string name=\"open_with\">Atvērt ar</string>\n    <string name=\"empty_library_no_accounts_message\">Šķiet, ka jūsu bibliotēka ir tukša :(\n\\nPiesakieties bibliotēkas kontā vai pievienojiet pārraides savai vietējai bibliotēkai.</string>\n    <string name=\"revert\">Atgriest</string>\n    <string name=\"subscription_deleted\">Anulēts %s abonements</string>\n    <string name=\"subscription_episode_released\">%d sērija izlaista!</string>\n    <string name=\"apk_installer_settings\">Apk insteletājs</string>\n    <string name=\"github\">Github</string>\n    <string name=\"no_subtitles\">Nav subtitru</string>\n    <string name=\"play_episode_toast\">Atskaņot epizodi</string>\n    <string name=\"status_ongoing\">Iet</string>\n    <string name=\"free_storage\">Bezmaksas</string>\n    <string name=\"poster_ui_settings\">Ieslēgt elementus uz plakātiem</string>\n    <string name=\"action_default\">Parastais</string>\n    <string name=\"no_update_found\">Nav atjauninājumi atrasti</string>\n    <string name=\"video_buffer_clear_settings\">Izdzēst video un bildes atkritne</string>\n    <string name=\"watch_quality_pref_data\">Izvēlētā skatīšanās kvalitāte (Mobilie Dati)</string>\n    <string name=\"video_disk_description\">Rada problēmas, ja ierīcēs ar maz vietas krātuvē ir iestatīts pārāk augsts, piemēram, Android TV.</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Meklēšanas summa, kas tiek izmantota, kad spēlētājs ir paslēpts</string>\n    <string name=\"dns_pref\">DNS virs HTTPS</string>\n    <string name=\"resize_zoom\">Tuvināt</string>\n    <string name=\"jsdelivr_enabled\">Neizdevās sasniegt GitHub. Pieslēdzas starpniekserverim caur jsDelivr…</string>\n    <string name=\"resize_fill\">Iztiept</string>\n    <string name=\"primary_color_settings\">Galvenā krāsa</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"bottom_title_settings_des\">Likt nosaukumu zem plakāta</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Ja subtitri kavējas pa %d ms</string>\n    <string name=\"recommended\">Rekomendācijas</string>\n    <string name=\"coming_soon\">Drīzumā…</string>\n    <string name=\"quality_cam_hd\">Kamera</string>\n    <string name=\"title\">Virsraksts</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"resolution\">Rezulūcija</string>\n    <string name=\"blank_repo_message\">CloudStream pēc noklusējuma nesatur, nav uzstādīts neviens repozitorijs. Lai izmantotu lietotni, obligāti jāpievieno vismaz viens repozitorijs, kas satur vismaz vienu papildinājumu. Repozitorijus var uzstādīt zem Iestatījumi. Tas viss pateicoties Sky UK Limited 🤮 bezsmadzeņu DMCA noņemšanas rīkojumam, kas liedz iekļaut repozitorijus lietotnē.\\n\\nPievienojieties mūsu Discord serverim vai meklējiet tiešsaistē.</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Viss %s jau ir lejupielādēts</string>\n    <string name=\"repository_name_hint\">Repozitorija nosaukums (pēc izvēles, neobligāti)</string>\n    <string name=\"plugin_downloaded\">Papildinājums lejupielādēts</string>\n    <string name=\"setup_extensions_subtext\">Lejupielādējiet to vietņu sarakstu, kuras vēlaties izmantot</string>\n    <string name=\"extension_install_first\">Vispirms uzstādīt papildinājumu</string>\n    <string name=\"skip_type_op\">Atvēršana</string>\n    <string name=\"skip_type_intro\">Sākums</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Izlaist %s</string>\n    <string name=\"action_remove_from_watched\">Noņemt no skatītajiem</string>\n    <string name=\"action_mark_as_watched\">Atzīmēt kā skatītu</string>\n    <string name=\"confirm_exit_dialog\">Vai tiešām vēlaties iziet?</string>\n    <string name=\"empty_library_logged_in_message\">Šķiet, ka šis saraksts ir tukšs, mēģiniet pārslēgties uz citu.</string>\n    <string name=\"safe_mode_file\">Atrasta drošā režīma datne!\\nPalaišanas laikā neviens papildinājums netiek ielādēts, kamēr datne nav izdzēsta.</string>\n    <string name=\"sort_rating_asc\">Vērtējums (no zema līdz augstam)</string>\n    <string name=\"subscription_in_progress_notification\">Abonēto šovu atjaunināšana</string>\n    <string name=\"subscription_list_name\">Abonēts</string>\n    <string name=\"subscription_new\">Abonēts %s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">%1$d. sezona un %2$d. sērija tiks izlaista pēc</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"play_from_beginning_img_des\">Atskaņot no sākuma</string>\n    <string name=\"speech_recognition_unavailable\">Runas atpazīšana nav pieejama</string>\n    <string name=\"begin_speaking\">Sāciet runāt…</string>\n    <string name=\"torrent_info\">Šis video ir torrenta fails, kas nozīmē, ka jūsu video aktivitātes var izsekot.\\nPirms turpināt, pārliecinieties, ka saprotat torrenta failu lietošanu.</string>\n    <string name=\"downloads_delete_select\">Atlasiet dzēšamos vienumus</string>\n    <string name=\"downloads_empty\">Pašlaik nav lejupielāžu.</string>\n    <string name=\"offline_file\">Pieejams skatīšanai bezsaistē</string>\n    <string name=\"wifi\">Bezvadu (Wi-Fi)</string>\n    <string name=\"use\">Izmantot</string>\n    <string name=\"edit\">Rediģēt</string>\n    <string name=\"profiles\">Profili</string>\n    <string name=\"help\">Palīdzība</string>\n    <string name=\"qualities\">Kvalitāte</string>\n    <string name=\"disable\">Atspējot</string>\n    <string name=\"favorites_list_name\">Iecienītākie</string>\n    <string name=\"action_subscribe\">Abonēt</string>\n    <string name=\"action_unsubscribe\">Pārtraukt abonēt</string>\n    <string name=\"duplicate_add\">Pievienot</string>\n    <string name=\"duplicate_replace\">Aizstāt</string>\n    <string name=\"pin\">PIN kods</string>\n    <string name=\"rotate_video\">Pagriezt</string>\n    <string name=\"unfavorite\">Noņemt no iecienītajiem</string>\n    <string name=\"favorite\">Pievienot iecienītajiem</string>\n    <string name=\"toast_copied\">nokopēts!</string>\n    <string name=\"ok\">Labi</string>\n    <string name=\"music_singlar\">Mūzika</string>\n    <string name=\"reset_btn\">Atiestatīt</string>\n    <string name=\"pref_category_security\">Drošība</string>\n    <string name=\"pref_category_accounts\">Konti</string>\n    <string name=\"test_warning\">Brīdinājums</string>\n    <string name=\"show\">Rādīt</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"podcast_singluar\">Raidieraksts</string>\n    <string name=\"subtitles_from_embedded\">Iegultie</string>\n    <string name=\"subtitles_from_online\">No interneta</string>\n    <string name=\"name\">Nosaukums</string>\n    <string name=\"profile_number\">Profils %d</string>\n    <string name=\"mobile_data\">Mobilie dati</string>\n    <string name=\"profile_background_des\">Profila fons</string>\n    <string name=\"backup_frequency\">Rezerves kopijas izveides biežums</string>\n    <string name=\"duplicate_replace_all\">Aizstāt visus</string>\n    <string name=\"enter_pin\">Ievadiet PIN kodu</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Ievadiet %s PIN kodu</string>\n    <string name=\"enter_current_pin\">Ievadiet pašreizējo PIN kodu</string>\n    <string name=\"lock_profile\">Aizslēgt profilu</string>\n    <string name=\"pin_error_incorrect\">Nepareizs PIN kods. Lūdzu, ievadiet to no jauna.</string>\n    <string name=\"pin_error_length\">PIN kods satur 4 rakstzīmes</string>\n    <string name=\"select_an_account\">Atlasiet kontu</string>\n    <string name=\"no_account\">Nav konta</string>\n    <string name=\"manage_accounts\">Pārvaldīt kontus</string>\n    <string name=\"edit_account\">Rediģēt kontu</string>\n    <string name=\"repo_copy_label\">Repozitorija nosaukums un URL</string>\n    <string name=\"no_plugins_found_error\">Repozitorijā nav atrasts neviens papildinājums</string>\n    <string name=\"no_repository_found_error\">Repozitorijs nav atrasts, pārbaudiet URL un izmēģiniet ar ieslēgtu VPN</string>\n    <string name=\"open_downloaded_repo\">Atvērt repozitoriju</string>\n    <string name=\"unable_to_inflate\">Lietotāja saskarni nevarēja izveidot pareizi, tā ir NOPIETNA KĻŪDA, un par to jāziņo nekavējoties %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Atlasiet režīmu pēc kā filtrēt papildinājumu lejupielādi</string>\n    <string name=\"delete_plugin\">Dzēst papildinājumu</string>\n    <string name=\"update_plugins\">Atjaunināt papildinājumus</string>\n    <string name=\"update_plugins_manually\">Atjaunināt papildinājumus manuāli</string>\n    <string name=\"starting_plugin_update_manually\">Sāk papildinājuma atjaunināšanas procesu!</string>\n    <string name=\"plugins_updated_manually\">Veiksmīgi atjaunināts(-i) %d papildinājums(-i)!</string>\n    <string name=\"no_plugins_updated_manually\">Neviens papildinājums netika atjaunināts.</string>\n    <string name=\"result_search_tooltip\">Meklēt citos papildinājumos</string>\n    <string name=\"test_extensions\">Pārbaudīt visus papildinājumus</string>\n    <string name=\"test_extensions_summary\">Šis tests ir paredzēts tikai izstrādātājiem, un tas neapstiprina vai nenoliedz papildinājumu funkcionalitāti.</string>\n    <string name=\"battery_dialog_message\">Lai nodrošinātu nepārtrauktu abonēto TV pārraižu (seriālu un raidījumu) lejupielādi un paziņojumu saņemšanu, CloudStream nepieciešama darboties fonā atļauja. Noklikšķinot uz 𝙇𝙖𝙗𝙞, tiks parādīts vaicājumlogs. Lūdzu, noklikšķiniet uz \\'Atļaut\\'.\\n\\nLūdzu, nesatraucieties, ka piešķirot šo atļauja, CloudStream 3 sāks veikt pastāvīgu akumulatora izlādi. Tas tiks palaists fonā tikai nepieciešamības gadījumā, piemēram, saņemot paziņojumus vai lejupielādējot video no oficiālajiem papildinājumiem.</string>\n    <string name=\"delete_files\">Dzēst datnes</string>\n    <string name=\"quality_profile_help\">Šeit jūs varat mainīt avotu atlases secību. Ja video ir augstāka prioritāte, tad tas tiks parādīts augstāk avotu atlases sarakstā. Avota prioritātes un kvalitātes prioritātes summa ir video prioritāte.\\n\\nAvots A: 3\\nKvalitāte B: 7\\nRezultātā kopējā video prioritātes summa ir 10.\\n\\nPIEZĪME: Ja kopējā summa ir vienāda ar 10 vai vairāk, atskaņotājs automātiski izlaidīs atskaņot, lejupielādēt video, kad šī saite ir ielādēta!</string>\n    <string name=\"software_decoding_desc\">Programmatūras (procesora) dekodēšana ļauj atskaņot video datnes, kuras jūsu ierīce neatbalsta. Taču var izraisīt aizkavētu vai nestabilu atskaņošanu video ar augstu izšķirtspēju, ja procesora veiktspēja ir neadekvāta.</string>\n    <string name=\"edit_profile_image_title\">Nomainīt profila attēlu</string>\n    <string name=\"edit_profile_image_hint\">Ievadiet profila attēla URL</string>\n    <string name=\"edit_profile_image_error_empty\">URL nav norādīts vai atrodams</string>\n    <string name=\"edit_profile_image_error_invalid\">Nepareizs URL vai nederīgs attēls</string>\n    <string name=\"edit_profile_image_success\">Profila attēls veiksmīgi nomainīts</string>\n    <string name=\"recommendations_tooltip\">Rādīt ieteikumus</string>\n    <string name=\"resolution_and_name\">Izšķirtspēja un nosaukums</string>\n    <string name=\"player_load_one_subtitle_online\">Lejupielādēt pirmo pieejamo</string>\n    <string name=\"no_subtitles_loaded\">Neviens subtitrs vēl nav ielādēts</string>\n    <string name=\"all_subtitles_bold\">Padarīt visus subtitrus treknrakstā</string>\n    <string name=\"all_subtitles_italic\">Padarīt visus subtitrus slīprakstā</string>\n    <string name=\"speed_setting_summary\">Pievieno atskaņošanas ātruma izvēli atskaņotājā</string>\n    <string name=\"delete_format\" formatted=\"true\">Dzēst (%1$d | %2$s)</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+mk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Брзина (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Оценето: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Пронајдена нова верзија!\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Филтер</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Дома</string>\n    <string name=\"title_search\">Барај</string>\n    <string name=\"title_downloads\">Преземања</string>\n    <string name=\"title_settings\">Поставки</string>\n    <string name=\"search_hint\">Барај…</string>\n    <string name=\"no_data\">Нема податоци</string>\n    <string name=\"episode_more_options_des\">Повеќе опции</string>\n    <string name=\"next_episode\">Следна епизода</string>\n    <string name=\"result_tags\">Жанрови</string>\n    <string name=\"result_share\">Сподели</string>\n    <string name=\"result_open_in_browser\">Отвори во прелистувач</string>\n    <string name=\"skip_loading\">Прескокни вчитување</string>\n    <string name=\"loading\">Вчитување…</string>\n    <string name=\"type_watching\">Се гледа</string>\n    <string name=\"type_on_hold\">Паузирано</string>\n    <string name=\"type_completed\">Изгледанo</string>\n    <string name=\"type_dropped\">Прекинато</string>\n    <string name=\"type_plan_to_watch\">За гледање</string>\n    <string name=\"type_re_watching\">Повторно гледање</string>\n    <string name=\"play_movie_button\">Пушти филм</string>\n    <string name=\"play_torrent_button\">Стримај торент</string>\n    <string name=\"pick_source\">Извор на видео</string>\n    <string name=\"pick_subtitle\">Преводи</string>\n    <string name=\"reload_error\">Повтори конекција…</string>\n    <string name=\"go_back\">Оди назад</string>\n    <string name=\"play_episode\">Вклучи епизода</string>\n    <!--<string name=\"need_storage\">Allow to download episodes</string>-->\n    <string name=\"download\">Преземи</string>\n    <string name=\"downloaded\">Преземено</string>\n    <string name=\"downloading\">Преземање</string>\n    <string name=\"download_paused\">Преземањето е паузирано</string>\n    <string name=\"download_started\">Преземањето започна</string>\n    <string name=\"download_failed\">Преземањето е неуспешно</string>\n    <string name=\"download_canceled\">Преземањето е откажано</string>\n    <string name=\"download_done\">Преземањето е готово</string>\n    <string name=\"error_loading_links_toast\">Грешка при вчитување на линковите</string>\n    <string name=\"download_storage_text\">Внатрешна меморија</string>\n    <string name=\"popup_delete_file\">Избриши датотека</string>\n    <string name=\"popup_play_file\">Пушти датотека</string>\n    <string name=\"popup_resume_download\">Продолжи со преземање</string>\n    <string name=\"popup_pause_download\">Паузирај со преземање</string>\n    <string name=\"home_more_info\">Повеќе информации</string>\n    <string name=\"home_expanded_hide\">Скриј</string>\n    <string name=\"home_play\">Пушти</string>\n    <string name=\"home_info\">Информации</string>\n    <string name=\"filter_bookmarks\">Филтрирај ги обележувачите</string>\n    <string name=\"error_bookmarks_text\">Обележувачи</string>\n    <string name=\"action_remove_from_bookmarks\">Отстрани</string>\n    <string name=\"sort_apply\">Активирај</string>\n    <string name=\"player_speed\">Брзина на плеер</string>\n    <string name=\"subtitles_settings\">Поставки за преводи</string>\n    <string name=\"subs_text_color\">Боја на текстот</string>\n    <string name=\"subs_outline_color\">Боја на надворешна линија од текстот</string>\n    <string name=\"subs_background_color\">Позадинска боја</string>\n    <string name=\"subs_window_color\">Боја на прозорец</string>\n    <string name=\"subs_edge_type\">Тип на раб</string>\n    <string name=\"subs_subtitle_elevation\">Висина на превод</string>\n    <string name=\"subs_font\">Фонт</string>\n    <string name=\"subs_font_size\">Големина на фонт</string>\n    <string name=\"search_provider_text_providers\">Пребарувај користејќи провајдери</string>\n    <string name=\"search_provider_text_types\">Пребарувај користејќи типови</string>\n    <string name=\"benene_count_text\">%d крем банани дадени на девелоперите</string>\n    <string name=\"benene_count_text_none\">Нема дадени крем банани</string>\n    <string name=\"subs_auto_select_language\">Авто одбирање на јазик</string>\n    <string name=\"subs_download_languages\">Преземи јазици</string>\n    <string name=\"subs_hold_to_reset_to_default\">Држи за да се ресетираш на стандардно</string>\n    <string name=\"continue_watching\">Продолжи со гледање</string>\n    <string name=\"action_remove_watching\">Избриши</string>\n    <string name=\"action_open_watching\">Повеќе информации</string>\n    <string name=\"vpn_might_be_needed\">Можеби ќе биде потребен VPN за да работи правилно овој провајдер</string>\n    <string name=\"vpn_torrent\">Овој провајдер е торент, се препорачува VPN</string>\n    <string name=\"provider_info_meta\">Метаподатоците не се обезбедени од страната, вчитувањето на видеото може да не успее.</string>\n    <string name=\"torrent_plot\">Опис</string>\n    <string name=\"normal_no_plot\">Не е пронајден заговор</string>\n    <string name=\"torrent_no_plot\">Не е пронајден опис</string>\n    <string name=\"picture_in_picture\">Слика-во-слика</string>\n    <string name=\"picture_in_picture_des\">Продолжува со репродукција во минијатурен плеер над другите апликации</string>\n    <string name=\"player_size_settings\">Копче за промена на големината на плеерот</string>\n    <string name=\"player_size_settings_des\">Острани ги црните граници</string>\n    <string name=\"player_subtitles_settings\">Преводи</string>\n    <string name=\"player_subtitles_settings_des\">Поставки на плеерот за преводи</string>\n    <string name=\"eigengraumode_settings\">Брзина на репродукција</string>\n    <string name=\"swipe_to_seek_settings\">Повлечи за премотување</string>\n    <string name=\"swipe_to_seek_settings_des\">Повлечи од страна до страна за да ја контролираш твојата позиција во видеото</string>\n    <string name=\"swipe_to_change_settings\">Повлечи за да ги промениш поставките</string>\n    <string name=\"swipe_to_change_settings_des\">Лизгај нагоре или надолу на левата или десната страна за да ја промениш осветленоста или јачината на звукот</string>\n    <string name=\"double_tap_to_seek_settings\">Допри двапати за премотување</string>\n    <string name=\"double_tap_to_seek_settings_des\">Допри двапати на десната или левата страна за да бараш напред или назад</string>\n    <string name=\"use_system_brightness_settings\">Користи ја осветленоста на системот</string>\n    <string name=\"use_system_brightness_settings_des\">Користи ја системската осветленост во плеерот на апликацијата наместо темен прекривач</string>\n    <string name=\"search\">Барај</string>\n    <string name=\"settings_info\">Информации</string>\n    <string name=\"advanced_search\">Напредно пребарување</string>\n    <string name=\"advanced_search_des\">Ви ги дава резултатите од пребарувањето одделени по провајдер</string>\n    <string name=\"show_fillers_settings\">Прикажи епизода за полнење за аниме</string>\n    <string name=\"updates_settings\">Прикажи ажурирања на апликации</string>\n    <string name=\"updates_settings_des\">Автоматски пребарувај нови ажурирања откако ќе ја стартуваш апликацијата.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Едноставна апликација за новели од истите развивачи</string>\n    <string name=\"anim\">Апликација за аниме од истите развивачи</string>\n    <string name=\"discord\">Придружи се на Discord</string>\n    <string name=\"benene\">Дај им крем банана на развивачите</string>\n    <string name=\"benene_des\">Дадени крем банани</string>\n    <string name=\"app_language\">Јазик на апликацијата</string>\n    <string name=\"no_chromecast_support_toast\">Овој провајдер нема поддршка за Chromecast</string>\n    <string name=\"no_links_found_toast\">Не се пронајдени линкови</string>\n    <string name=\"copy_link_toast\">Линкот е копиран во таблата со исечоци</string>\n    <string name=\"play_episode_toast\">Пушти ја епизодата</string>\n    <string name=\"subs_default_reset_toast\">Ресетирање на стандардните вредности</string>\n    <string name=\"season\">Сезона</string>\n    <string name=\"no_season\">Нема сезона</string>\n    <string name=\"episode\">Епизода</string>\n    <string name=\"episodes\">Епизоди</string>\n    <string name=\"season_short\">С</string>\n    <string name=\"episode_short\">Е</string>\n    <string name=\"delete_file\">Избриши датотека</string>\n    <string name=\"delete\">Избриши</string>\n    <string name=\"cancel\">Откажи</string>\n    <string name=\"pause\">Паузирај</string>\n    <string name=\"resume\">Продолжи</string>\n    <string name=\"delete_message\">Ова трајно ќе го избрише %s\n\\nДали си сигурен?</string>\n    <string name=\"status_ongoing\">Во тек</string>\n    <string name=\"status_completed\">Изгледанo</string>\n    <string name=\"status\">Статус</string>\n    <string name=\"year\">Година</string>\n    <string name=\"rating\">Рејтинг</string>\n    <string name=\"duration\">Времетраење</string>\n    <string name=\"site\">Страница</string>\n    <string name=\"synopsis\">Крат</string>\n    <string name=\"queued\">во редица</string>\n    <string name=\"no_subtitles\">Нема преводи</string>\n    <string name=\"action_default\">Стандардно</string>\n    <string name=\"free_storage\">Слободен простор</string>\n    <string name=\"used_storage\">Искористен простор</string>\n    <string name=\"app_storage\">Апликациски простор</string>\n    <string name=\"movies\">Филмови</string>\n    <string name=\"tv_series\">Серии</string>\n    <string name=\"cartoons\">Цртани</string>\n    <string name=\"anime\">Аниме</string>\n    <string name=\"torrent\">Торент</string>\n    <string name=\"source_error\">Неуспешно вчитување на извор</string>\n    <string name=\"remote_error\">Грешка</string>\n    <string name=\"render_error\">Грешка</string>\n    <string name=\"unexpected_error\">Неочекувана грешка со плеерот</string>\n    <string name=\"storage_error\">Грешка при преземање, провери ги дозволите за складирање</string>\n    <string name=\"episode_action_chromecast_episode\">Епизода на Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Огледало на Chromecastr</string>\n    <string name=\"episode_action_play_in_app\">Пушти во апликацијата</string>\n    <string name=\"episode_action_play_in_format\">Пушти на %s</string>\n    <string name=\"episode_action_auto_download\">Автоматско преземање</string>\n    <string name=\"episode_action_download_mirror\">Преземи Mirror</string>\n    <string name=\"episode_action_reload_links\">Вчитај ги повторно линковите</string>\n    <string name=\"no_update_found\">Не е пронајдено ажурирање</string>\n    <string name=\"check_for_update\">Провери дали има нови верзии за апликацијата</string>\n    <string name=\"video_lock\">Заклучи</string>\n    <string name=\"video_aspect_ratio_resize\">Промени ја големината</string>\n    <string name=\"video_source\">Извор</string>\n    <string name=\"video_skip_op\">Прескокни ОП</string>\n    <string name=\"dont_show_again\">Не прикажувај повторно</string>\n    <string name=\"update\">Ажурирај</string>\n    <string name=\"watch_quality_pref\">Префериран квалитет на гледање (WiFi)</string>\n    <string name=\"dns_pref\">DNS преку HTTPS</string>\n    <string name=\"dns_pref_summary\">Корисно за заобиколување на блоковите на интернет провајдерите</string>\n    <string name=\"download_path_pref\">Патека на преземање</string>\n    <string name=\"display_subbed_dubbed_settings\">Прикажи синхронизирано/сублирано аниме</string>\n    <string name=\"resize_fit\">Прилагоди на екранот</string>\n    <string name=\"resize_fill\">Истегни</string>\n    <string name=\"resize_zoom\">Зумирај</string>\n    <string name=\"legal_notice\">Disclaimer</string>\n    <string name=\"category_general\">Општи поставки</string>\n    <string name=\"provider_lang_settings\">Јазици на екстензиите</string>\n    <string name=\"app_layout\">Распоред на апликацијата</string>\n    <string name=\"preferred_media_settings\">Претпочитани медиуми</string>\n    <string name=\"automatic\">Автоматски</string>\n    <string name=\"tv_layout\">Изглед за гледање на телевизор</string>\n    <string name=\"phone_layout\">Изглед за гледање на телефон</string>\n    <string name=\"primary_color_settings\">Примарна боја</string>\n    <string name=\"app_theme_settings\">Тема на апликацијата</string>\n    <string name=\"login_format\">%1$s %2$s</string>\n    <string name=\"account\">Корисничко име</string>\n    <string name=\"logout\">Одјави се</string>\n    <string name=\"login\">Најави се</string>\n    <string name=\"switch_account\">Промени корисничка сметка</string>\n    <string name=\"add_account\">Додади корисничка сметка</string>\n    <!-- ============ -->\n    <string name=\"none\">Ништо</string>\n    <string name=\"normal\">Нормално</string>\n    <string name=\"all\">Сите</string>\n    <string name=\"max\">Максимум</string>\n    <string name=\"min\">Минимум</string>\n    <string name=\"subtitles_outline\">Надворешна контура</string>\n    <string name=\"subtitles_depressed\">Депресиран</string>\n    <string name=\"subtitles_shadow\">Сенка</string>\n    <string name=\"subtitles_raised\">Подигнат</string>\n    <string name=\"history\">Историја</string>\n    <string name=\"uppercase_all_subtitles\">Голема буква на сите преводи</string>\n    <string name=\"automatic_plugin_download_summary\">Автоматски инсталирај ги сите сè уште неинсталирани приклучоци од додадените извори.</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"livestreams\">Преноси во живо</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Други</string>\n    <string name=\"remove_site_pref\">Отстрани ја страницата</string>\n    <string name=\"example_password\">password123</string>\n    <string name=\"example_lang_name\">Јазичен код (мк)</string>\n    <string name=\"subtitle_offset_title\">Задоцнување на преводот</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Вчитан %s</string>\n    <string name=\"home_source\">Извор на видео и превод</string>\n    <string name=\"home_random\">Случајно</string>\n    <string name=\"error\">Грешка</string>\n    <string name=\"view_public_repositories_button\">Прикажи складишта на заедницата</string>\n    <string name=\"skip_update\">Прескокни го ова ажурирање</string>\n    <string name=\"batch_download\">Групно преземање</string>\n    <string name=\"actor_background\">Позадина</string>\n    <string name=\"documentaries\">Документарни филмови</string>\n    <string name=\"next\">Следно</string>\n    <string name=\"nginx_url_pref\">Линк на серверот NGINX</string>\n    <string name=\"stop\">Стоп</string>\n    <string name=\"show_sub\">Подознака</string>\n    <string name=\"emulator_layout\">Изглед на емулатор</string>\n    <string name=\"other_singular\">Видео</string>\n    <string name=\"sort_clear\">Исчисти</string>\n    <string name=\"test_passed\">Успешна верификација</string>\n    <string name=\"example_site_name\">Име на сајт</string>\n    <string name=\"error_invalid_data\">Неважечки податоци</string>\n    <string name=\"actor_supporting\">Поддршка</string>\n    <string name=\"pref_category_player_features\">Функции на плеерот</string>\n    <string name=\"tv_series_singular\">Серија</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Сите %s веќе се преземени</string>\n    <string name=\"pref_category_actions\">Дејства</string>\n    <string name=\"subs_subtitle_languages\">Јазик на преводот</string>\n    <string name=\"extension_description\">Опис</string>\n    <string name=\"delayed_update_notice\">Апликацијата ќе се ажурира по излегувањето</string>\n    <string name=\"subscription_deleted\">Отпишана е од %s</string>\n    <string name=\"jsdelivr_proxy\">GitHub прокси</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"subscription_new\">Претплатен на %s</string>\n    <string name=\"pref_category_subtitles\">Преводи</string>\n    <string name=\"download_all_plugins_from_repo\">Предупредување: CloudStream 3 не презема никаква одговорност за користење на екстензии од трети страни и не обезбедува никаква поддршка за нив!</string>\n    <string name=\"backup_failed\">Недостасуваат дозволи за складирање. Обиди се повторно.</string>\n    <string name=\"sort_save\">Зачувај</string>\n    <string name=\"player_load_subtitles\">Вчитај од датотека</string>\n    <string name=\"pref_category_app_updates\">Ажурирања на апликацијата</string>\n    <string name=\"browser\">Прелистувач</string>\n    <string name=\"restore_success\">Вчитана резервна датотека</string>\n    <string name=\"pref_category_gestures\">Гестови</string>\n    <string name=\"double_tap_to_pause_settings\">Двоен допир за да паузираш</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Прескокни %s</string>\n    <string name=\"safe_mode_file\">Најдена е датотека во безбеден режим!\\nНе се вчитуваат екстензии при стартување додека датотеката не се отстрани.</string>\n    <string name=\"revert\">Врати</string>\n    <string name=\"sort\">Подреди</string>\n    <string name=\"player_settings_play_in_app\">Внатрешен плеер</string>\n    <string name=\"resolution\">Резолуција</string>\n    <string name=\"skip_type_creddits\">Кредити</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Пребарај %s…</string>\n    <string name=\"plugin_deleted\">Приклучокот е избришан</string>\n    <string name=\"extension_status\">Статус</string>\n    <string name=\"extension_authors\">Автори</string>\n    <string name=\"start\">Започни</string>\n    <string name=\"pref_category_looks\">Изглед</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Без задоцнување на преводот</string>\n    <string name=\"subscription_in_progress_notification\">Ажурирање претплатени емисии</string>\n    <string name=\"upload_sync\">Синхронизирај</string>\n    <string name=\"player_load_subtitles_online\">Вчитај од Интернет</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (оневозможено)</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"sort_close\">Затвори</string>\n    <string name=\"coming_soon\">Наскоро…</string>\n    <string name=\"extension_version\">Верзија</string>\n    <string name=\"show_hd\">Ознака за квалитет</string>\n    <string name=\"plugin_singular\">приклучок</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"provider_languages_tip\">Гледај видеа на овие јазици</string>\n    <string name=\"extension_install_first\">Прво инсталирај ја екстензијата</string>\n    <string name=\"episode_sync_settings\">Ажурирај го напредокот на гледање</string>\n    <string name=\"library\">Библиотека</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Износот на барањето што се користи кога плеерот е скриен</string>\n    <string name=\"episode_action_download_subtitle\">Преземи преводи</string>\n    <string name=\"view_public_repositories_button_short\">Јавна листа</string>\n    <string name=\"apk_installer_package_installer\">Инсталатор на пакети</string>\n    <string name=\"ova_singular\">ОВА</string>\n    <string name=\"category_updates\">Ажурирање и резервна копија</string>\n    <string name=\"empty_library_no_accounts_message\">Твојата библиотека е празна :(\\nНајави се на корисничка сметка или додади серии во твојата локална библиотека.</string>\n    <string name=\"no_episodes_found\">Не се пронајдени епизоди</string>\n    <string name=\"subtitles_example_text\">Брзата кафеава лисица го прескокнува мрзливото куче</string>\n    <string name=\"poster_image\">Слика на постер</string>\n    <string name=\"video_buffer_length_settings\">Должина на видео баферот</string>\n    <string name=\"delete_repository\">Избриши извор</string>\n    <string name=\"add_site_pref\">Клонирај ја страницата</string>\n    <string name=\"bottom_title_settings_des\">Стави го насловот под постерот</string>\n    <string name=\"safe_mode_crash_info\">Прикажи информации за падот на апликацијата</string>\n    <string name=\"extension_language\">Јазик</string>\n    <string name=\"torrent_singular\">Торент</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Скриен плеер - Износ за пребарување</string>\n    <string name=\"episode_sync_settings_des\">Автоматски синхронизирај го напредокот на твојата тековна епизода</string>\n    <string name=\"pref_category_bypass\">Бајпас на интернет провајдерот</string>\n    <string name=\"recommended\">Препорачано</string>\n    <string name=\"show_title\">Наслов</string>\n    <string name=\"watch_quality_pref_data\">Префериран квалитет на гледање (мобилни податоци)</string>\n    <string name=\"category_provider_test\">Тест за провајдер</string>\n    <string name=\"select_library\">Избери библиотека</string>\n    <string name=\"video_tracks\">Видео резолуција</string>\n    <string name=\"asian_drama\">Азиски драми</string>\n    <string name=\"plugin_loaded\">Приклучокот е вчитан</string>\n    <string name=\"subtitles_remove_bloat\">Отстрани непотребен текст од преводите</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Не е преземено: %d</string>\n    <string name=\"subtitles_remove_captions\">Remove closed captions from subtitles</string>\n    <string name=\"audio_tracks\">Аудио јазик</string>\n    <string name=\"poster_ui_settings\">Вклучи ги елементите на корисничкиот интерфејс на постерот</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Оневозможено: %d</string>\n    <string name=\"apk_installer_legacy\">Легаси</string>\n    <string name=\"autoplay_next_settings\">Автоматска репродукција на следната епизода</string>\n    <string name=\"video_buffer_clear_settings\">Исчисти го кешот на видео и слики</string>\n    <string name=\"pref_category_ui_features\">Карактеристики</string>\n    <string name=\"asian_drama_singular\">Азиска драма</string>\n    <string name=\"extras\">Додатоци</string>\n    <string name=\"random_button_settings_desc\">Прикажи случајно копче на почетната страница и библиотеката</string>\n    <string name=\"extension_types\">Поддржано</string>\n    <string name=\"category_account\">Сметки и безбедност</string>\n    <string name=\"skip_type_intro\">Вовед</string>\n    <string name=\"create_account\">Креирај сметка</string>\n    <string name=\"action_remove_from_watched\">Отстрани од гледаното</string>\n    <string name=\"double_tap_to_pause_settings_des\">Допри двапати во средината за да паузираш</string>\n    <string name=\"pref_category_backup\">Резервна копија</string>\n    <string name=\"ova\">ОВА</string>\n    <string name=\"live_singular\">Пренос во живо</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Ажурирани %d приклучоци</string>\n    <string name=\"skip_type_mixed_op\">Мешано отворање</string>\n    <string name=\"pref_category_extensions\">Екстензии</string>\n    <string name=\"enable_nsfw_on_providers\">Овозможи NSFW на поддржаните екстензии</string>\n    <string name=\"jsdelivr_enabled\">Не успеа да стигне до GitHub. Вклучувам jsDelivr прокси…</string>\n    <string name=\"subtitles_filter_lang\">Филтрирај по претпочитан медиумски јазик</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"movies_singular\">Филм</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Додаден %s</string>\n    <string name=\"plugin\">приклучоци</string>\n    <string name=\"sort_by\">Подреди по</string>\n    <string name=\"empty_library_logged_in_message\">Оваа листа е празна. Обиди се да преминеш на друга.</string>\n    <string name=\"anime_singular\">Аниме</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Износот на барањето што се користи кога плеерот е видлив</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"automatic_plugin_download\">Автоматско преземање приклучоци</string>\n    <string name=\"actor_main\">Главна</string>\n    <string name=\"pref_category_cache\">Кеш меморија</string>\n    <string name=\"trailer\">Трејлер</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Не можев да се најавам на %s</string>\n    <string name=\"clipboard_too_large\">Премногу текст. Не може да се зачува во таблата со исечоци.</string>\n    <string name=\"error_invalid_id\">Неважечки ID</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Преземено %1$d %2$s</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Користи го ова ако преводите се прикажани %d ms порано</string>\n    <string name=\"error_invalid_url\">Неважечки линк</string>\n    <string name=\"safe_mode_title\">Безбедниот режим е вклучен</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"backup_success\">Зачувани податоци</string>\n    <string name=\"video_ram_description\">Предизвикува падови ако е превисоко поставено на уреди со слаба меморија, како што е Android TV.</string>\n    <string name=\"update_notification_installing\">Се инсталира ажурирање на апликацијата…</string>\n    <string name=\"repository_url_hint\">URL на изворот или краток код</string>\n    <string name=\"update_notification_failed\">Не може да се инсталира новата верзија на апликацијата</string>\n    <string name=\"kitsu_settings\">Прикажи постери од Kitsu</string>\n    <string name=\"confirm_exit_dialog\">Дали си сигурен дека сакаш да изглезеш?</string>\n    <string name=\"video_disk_description\">Предизвикува проблеми ако е превисоко поставено на уреди со мал простор за складирање, како што е Android TV.</string>\n    <string name=\"jsdelivr_proxy_summary\">Заобиколи го блокирањето на необработени линкови на github користејќи jsDelivr. Ова може да предизвика ажурирањата да се одложат за неколку дена.</string>\n    <string name=\"yes\">Да</string>\n    <string name=\"sort_alphabetical_z\">Азбучно (Ш до А)</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"add_site_summary\">Додај клон на постоечка страница, со различен линк</string>\n    <string name=\"downloaded_file\">Преземена датотека</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Износ на бараниот плеер (секунди)</string>\n    <string name=\"show_log_cat\">Прикажи Logcat 🐈</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Преземено: %d</string>\n    <string name=\"resolution_and_title\">Резолуција и наслов</string>\n    <string name=\"update_started\">Ажурирањето започна</string>\n    <string name=\"chromecast_subtitles_settings\">Преводи на Chromecast</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Користи го ова ако преводите се прикажуваат %d ms подоцна</string>\n    <string name=\"random_button_settings\">Случајно копче</string>\n    <string name=\"apk_installer_settings\">Инсталатор на APK</string>\n    <string name=\"extensions\">Екстензии</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"referer\">Референт (опционално)</string>\n    <string name=\"skip_type_op\">Се отвора</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"delete_repository_plugins\">Ова исто така ќе ги избрише сите приклучоци</string>\n    <string name=\"backup_settings\">Направи резервна копија од податоците</string>\n    <string name=\"show_dub\">Етикета за Dub</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Прикажан плеер - Барај износ</string>\n    <string name=\"pref_category_android_tv\">Андроид ТВ</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Не успеа да ги врати податоците од датотеката %s</string>\n    <string name=\"test_failed\">Неуспешна верификација</string>\n    <string name=\"documentaries_singular\">Документарец</string>\n    <string name=\"stream\">Мрежен проток</string>\n    <string name=\"duration_format\" formatted=\"true\">%d мин</string>\n    <string name=\"play_with_app_name\">Играј со CloudStream</string>\n    <string name=\"play_trailer_button\">Пушти трејлер</string>\n    <string name=\"chromecast_subtitles_settings_des\">Поставки за преводи на Chromecast</string>\n    <string name=\"title\">Наслов</string>\n    <string name=\"sort_copy\">Копирај</string>\n    <string name=\"category_player\">Плеер</string>\n    <string name=\"subscription_list_name\">Претплатени</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"restart\">Рестартирај</string>\n    <string name=\"cartoons_singular\">Цртан филм</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Почна да презема %1$d %2$s…</string>\n    <string name=\"automatic_plugin_updates\">Автоматски ажурирања на приклучоци</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nпреостанува</string>\n    <string name=\"video_buffer_disk_settings\">Видео кеш на дискот</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"setup_done\">Готово</string>\n    <string name=\"add_repository\">Додај извор</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"hls_playlist\">ХЛС плејлиста</string>\n    <string name=\"player_pref\">Префериран видео плеер</string>\n    <string name=\"show_trailers_settings\">Прикажи трејлери</string>\n    <string name=\"subtitles_encoding\">Енкодирање на превод</string>\n    <string name=\"category_ui\">Изглед</string>\n    <string name=\"add_sync\">Додај тракинг</string>\n    <string name=\"sync_score\">Оценет</string>\n    <string name=\"quality_cam_rip\">Камера</string>\n    <string name=\"quality_cam_hd\">Камера</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"app_not_found_error\">Апликацијата не е пронајдена</string>\n    <string name=\"example_username\">Корисничко име</string>\n    <string name=\"open_with\">Отвори со</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"redo_setup_process\">Повтори го процесот на поставување опции на апликацијата</string>\n    <string name=\"pref_category_links\">Линкови</string>\n    <string name=\"skip_type_recap\">Повторување</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"autoplay_next_settings_des\">Започни ја следната епизода кога ќе заврши тековната</string>\n    <string name=\"backup_failed_error_format\">Грешка при правење резервна копија на %s</string>\n    <string name=\"pref_filter_search_quality\">Сокриј го избраниот квалитет на видеото во резултатите од пребарувањето</string>\n    <string name=\"apk_installer_settings_des\">Некои уреди не го поддржуваат новиот инсталатор на пакети. Испробај ја легаси(старата) опција, ако ажурирањата не се инсталираат.</string>\n    <string name=\"limit_title_rez\">Резолуција на видео плеер</string>\n    <string name=\"video_buffer_size_settings\">Големина на видео баферот</string>\n    <string name=\"pref_category_player_layout\">Распоред</string>\n    <string name=\"pref_category_defaults\">Стандардно</string>\n    <string name=\"category_providers\">Провајдери</string>\n    <string name=\"bottom_title_settings\">Локација на насловот на постерот</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"previous\">Претходно</string>\n    <string name=\"skip_setup\">Прескокни го поставувањето</string>\n    <string name=\"app_layout_subtext\">Промени го изгледот на апликацијата за да одговара на твојот уред</string>\n    <string name=\"preferred_media_subtext\">Што сакате да видите</string>\n    <string name=\"repository_name_hint\">Име на изворот (Опционално)</string>\n    <string name=\"plugin_downloaded\">Приклучокот е преземен</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Не може да се вчита %s</string>\n    <string name=\"setup_extensions_subtext\">Преземи ја листата на сајтови што сакаш да ги користиш</string>\n    <string name=\"blank_repo_message\">CloudStream нема стандардно инсталирани приклучоци. Треба сам да инсталираш приклучоци.\\n\\nПридружи се на нашиот Discord и дознај повеќе или барај онлајн.</string>\n    <string name=\"tracks\">Видео резолуција и аудио јазик</string>\n    <string name=\"safe_mode_description\">Сите екстензии беа исклучени поради пад за да ти помогне да ја пронајдеш причината што предизвикува проблем.</string>\n    <string name=\"extension_rating\" formatted=\"true\">Оцена: %s</string>\n    <string name=\"extension_size\">Големина</string>\n    <string name=\"all_languages_preference\">Сите јазици</string>\n    <string name=\"clear_history\">Исчисти историја</string>\n    <string name=\"action_mark_as_watched\">Обележи како гледано</string>\n    <string name=\"enable_skip_op_from_database_des\">Прикажи скокачки прозорци за отворање/завршување</string>\n    <string name=\"no\">Не</string>\n    <string name=\"update_notification_downloading\">Се презема ажурирање на апликацијата…</string>\n    <string name=\"sort_rating_desc\">Оцена (висока до ниска)</string>\n    <string name=\"sort_rating_asc\">Оцена (ниска до висока)</string>\n    <string name=\"sort_updated_new\">Ажурирано (ново на старо)</string>\n    <string name=\"sort_updated_old\">Ажурирано (старо во ново)</string>\n    <string name=\"sort_alphabetical_a\">Азбучно (А до Ш)</string>\n    <string name=\"subscription_episode_released\">Епизодата %d е објавена!</string>\n    <string name=\"quality_cam\">Камера</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"skip_type_ed\">Завршува</string>\n    <string name=\"skip_type_mixed_ed\">Измешан крај</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"subtitle_offset\">Синхронизирај преводи</string>\n    <string name=\"apply_on_restart\">Рестартирај ја апликацијата за да ги видиш промените.</string>\n    <string name=\"limit_title\">Наслов на видео плеер максимални знаци</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Увези фонтови ставајќи ги во %s</string>\n    <string name=\"restore_settings\">Врати ги податоците од резервна копија</string>\n    <string name=\"action_add_to_bookmarks\">Постави статус на пратење</string>\n    <string name=\"play_livestream_button\">Пушти Livestream</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s е автентициран</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$sЕп.%2$d</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dч%2$dм</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dм</string>\n    <string name=\"home_next_random_img_des\">Следен рандом</string>\n    <string name=\"result_poster_img_des\">Постер</string>\n    <string name=\"search_poster_img_des\">Постер</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dч%2$dд%3$dм</string>\n    <string name=\"home_main_poster_img_des\">Главен постер</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Епизодата %d ќе биде објавена на</string>\n    <string name=\"episode_poster_img_des\">Постер за епизода</string>\n    <string name=\"preview_background_img_des\">Прегледај позадина</string>\n    <string name=\"home_change_provider_img_des\">Смени провајдер</string>\n    <string name=\"go_back_img_des\">Оди назад</string>\n    <string name=\"cast_format\" formatted=\"true\">Актери: %s</string>\n    <string name=\"favorite_added\">%s е додаден во омилени</string>\n    <string name=\"favorite_removed\">%s е отстранета од омилените</string>\n    <string name=\"automatic_plugin_download_mode_title\">Одбери опција за селектирање на преземените приклучоци</string>\n    <string name=\"no_repository_found_error\">Изворот не е пронајден, провери го линкот повторно и пробај со VPN</string>\n    <string name=\"favorites_list_name\">Фаворити</string>\n    <string name=\"action_add_to_favorites\">Додади во омилени</string>\n    <string name=\"action_remove_from_favorites\">Отстрани од омилените</string>\n    <string name=\"duplicate_replace_all\">Замени ги сите</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Се чини дека потенцијален дупликат веќе постои во твојата библиотека: „%s“.\\n\\nДали сепак сакаш да ја додадеш оваа ставка, да ја замениш постојната или да го откажеш дејството?</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Пронајдени се потенцијални дупликатни ставки во твојата библиотека:\\n\\n%s\\n\\nДали сакаш да ја додадеш оваа ставка, да ги замениш постојните или да ја откажеш акцијата?</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Внеси PIN за %s</string>\n    <string name=\"pin_error_length\">ПИН-кодот мора да има 4 знаци</string>\n    <string name=\"manage_accounts\">Менаџирај корисници</string>\n    <string name=\"edit_account\">Уреди корисници</string>\n    <string name=\"logged_account\" formatted=\"true\">Најавен како %s</string>\n    <string name=\"skip_startup_account_select_pref\">Прескокни го изборот на корисник при стартување</string>\n    <string name=\"use_default_account\">Користи го стандардниот корисник</string>\n    <string name=\"rotate_video\">Ротирај</string>\n    <string name=\"rotate_video_desc\">Прикажи копче за префрлување за ориентација на екранот</string>\n    <string name=\"already_voted\">Веќе гласавте</string>\n    <string name=\"quality_profile_help\">Овде можеш да го промениш начинот на кој се подредуваат изворите. Ако видеото има повисок приоритет, ќе се појави повисоко во изборот на изворот. Збирот на приоритетот на изворот и приоритетот на квалитетот е приоритет на видеото.\\n\\nИзвор А: 3\\nКвалитет Б: 7\\nЌе има комбиниран приоритет на видеото од 10.\\n\\nЗАБЕЛЕШКА: Ако сумата е 10 или повеќе, плеерот автоматски ќе го прескокне вчитувањето кога ќе се вчита тој линк!</string>\n    <string name=\"select_an_account\">Одбери корисник</string>\n    <string name=\"links_reloaded_toast\">Повторно се вчитани линковите</string>\n    <string name=\"disable\">Оневозможи</string>\n    <string name=\"enter_pin\">Внеси PIN</string>\n    <string name=\"enter_current_pin\">Внеси го тековниот PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"lock_profile\">Заклучи профил</string>\n    <string name=\"pin_error_incorrect\">Неточен ПИН. Обиди се повторно.</string>\n    <string name=\"action_unsubscribe\">Исклучи ја претплатата</string>\n    <string name=\"profile_number\">Профил %d</string>\n    <string name=\"action_subscribe\">Претплати се</string>\n    <string name=\"profile_background_des\">Позадина на профил</string>\n    <string name=\"mobile_data\">Мобилен интернет</string>\n    <string name=\"set_default\">Постави како стандардно</string>\n    <string name=\"qualities\">Квалитети</string>\n    <string name=\"duplicate_title\">Пронајден е потенцијален дупликат</string>\n    <string name=\"duplicate_add\">Додади</string>\n    <string name=\"duplicate_replace\">Замени</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"no_plugins_found_error\">Не се пронајдени приклучоци во изворот</string>\n    <string name=\"use\">Користи</string>\n    <string name=\"edit\">Уреди</string>\n    <string name=\"profiles\">Профили</string>\n    <string name=\"help\">Помош</string>\n    <string name=\"unable_to_inflate\">UI не можеше да се креира правилно, ова е ГОЛЕМА ГРЕШКА и треба веднаш да се пријави %s</string>\n    <string name=\"backup_frequency\">Фрекфенција на бекап</string>\n    <string name=\"auto_rotate_video_desc\">Овозможи автоматско префрлување на ориентацијата на екранот врз основа на видео ориентација</string>\n    <string name=\"auto_rotate_video\">Автоматско ротирање</string>\n    <string name=\"repo_copy_label\">Име и URL на изворот</string>\n    <string name=\"toast_copied\">копирано!</string>\n    <string name=\"test_extensions\">Тестирај ги сите екстензии</string>\n    <string name=\"ok\">ОК</string>\n    <string name=\"app_unrestricted_toast\">Користењето на батеријата на апликацијата е веќе поставено на неограничено</string>\n    <string name=\"unfavorite\">Неомилен</string>\n    <string name=\"favorite\">Омилен</string>\n    <string name=\"biometric_setting\">Заклучување со биометрика</string>\n    <string name=\"music_singlar\">Музика</string>\n    <string name=\"subscribe_tooltip\">Известување за нова епизода</string>\n    <string name=\"result_search_tooltip\">Пребарај во други екстензии</string>\n    <string name=\"recommendations_tooltip\">Прикажи препораки</string>\n    <string name=\"speed_setting_summary\">Додава опција за брзина во плеерот</string>\n    <string name=\"episode_action_cast_mirror\">Cast mirror</string>\n    <string name=\"test_extensions_summary\">Овој тест е наменет само за програмери и не ја потврдува или негира работата на која било екстензија.</string>\n    <string name=\"app_info_intent_error\">Не може да се отворат информациите за апликацијата CloudStream.</string>\n    <string name=\"password_pin_authentication_title\">Лозинка/ПИН автентикација</string>\n    <string name=\"biometric_setting_summary\">Отклучи ја апликацијата со отпечаток од прст, ID на лице, PIN, шема и лозинка.</string>\n    <string name=\"biometric_warning\">Сега е направена резервна копија на твоите податоци на CloudStream. Иако можноста за ова е многу мала, сите уреди можат да се однесуваат поинаку. Во ретки случаи, кога ќе се изгубиш пристап до апликацијата, целосно исчисти ги податоците на апликацијата и врати ги од резервната копија. Многу ни е жал за какви било непријатности што произлегуваат од ова.</string>\n    <string name=\"reset_btn\">Ресетирај</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Сезона %1$d Епизода %2$d ќе биде објавена за</string>\n    <string name=\"player_settings_select_cast_device\">Одбери уред да кастираш</string>\n    <string name=\"battery_dialog_title\">Оневозможи оптимизација на батерија</string>\n    <string name=\"biometric_authentication_title\">Отклучи CloudStream</string>\n    <string name=\"biometric_unsupported\">Биометриската автентикација не е поддржана на овој уред</string>\n    <string name=\"biometric_prompt_description\">По неколку неуспешни обиди, известувањето ќе се затвори. Едноставно вклучи ја апликацијата повторно за да се обидеш повторно.</string>\n    <string name=\"custom_media_singluar\">Медиуми</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Претстои во %s</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nпреостанати</string>\n    <string name=\"battery_dialog_message\">За да се обезбедат непрекинати преземања и известувања за претплатените ТВ серии, CloudStream треба дозвола за работа во позадина. Со притискање на „ОК“, ќе ви биде прикажан дијалог за барање дозвола. Ве молиме, притиснете „Дозволи“.\\n\\nИмајте предвид дека оваа дозвола не значи дека CS3 ќе ја троши вашата батерија. Ќе работи во позадина само кога е потребно, како на пример при примање известувања или преземање видеа од официјални екстензии.</string>\n    <string name=\"clipboard_permission_error\">Грешка при пристапот до таблата со исечоци, обиди се повторно.</string>\n    <string name=\"clipboard_unknown_error\">Грешка при копирање, молам копирај го логот и контактирај ја поддршката на апликацијата.</string>\n    <string name=\"audio_book_singular\">Аудио книга</string>\n    <string name=\"pref_category_security\">Безбедност</string>\n    <string name=\"dismiss\">Отфрли</string>\n    <string name=\"open_downloaded_repo\">Отвори извор</string>\n    <string name=\"preview_seekbar\">Преглед на лентата за пребарување</string>\n    <string name=\"device_pin_url_message\">Посети го <b>%s</b> на твојот паметен телефон или компјутер и внеси го горниот код</string>\n    <string name=\"subs_edge_size\">Големина на раб</string>\n    <string name=\"delete_files\">Избриши ги податоците</string>\n    <string name=\"delete_format\" formatted=\"true\">Избриши (%1$d | %2$s)</string>\n    <string name=\"sort_release_date_old\">Датум на издавање (најстари до најнови)</string>\n    <string name=\"no_subtitles_loaded\">Сè уште не е вчитан преводот</string>\n    <string name=\"backup_path_title\">Локација на бекап</string>\n    <string name=\"custom\">Прилагодено</string>\n    <string name=\"confirm_before_exiting_title\">Потврди пред да излезеш</string>\n    <string name=\"confirm_before_exiting_desc\">Прикажи го дијалог прозорецот пред да излезеш од апликацијата</string>\n    <string name=\"show\">Прикажи</string>\n    <string name=\"dont_show\">Не прикажувај</string>\n    <string name=\"preview_seekbar_desc\">Вклучи преглед на слика на траката за премотување</string>\n    <string name=\"pref_category_accounts\">Кориснички сметки</string>\n    <string name=\"auth_locally\">Локална автентикација</string>\n    <string name=\"qr_image\">Слика со QR код</string>\n    <string name=\"play_from_beginning_img_des\">Пушти од почеток</string>\n    <string name=\"open_local_video\">Отвори локално видео</string>\n    <string name=\"test_warning\">Предупредување</string>\n    <string name=\"downloads_empty\">Во моментов нема преземања.</string>\n    <string name=\"deselect_all\">Деселектирај сѐ</string>\n    <string name=\"select_all\">Одбери ги сите</string>\n    <string name=\"offline_file\">Достапно за гледање офлајн</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Ќе ги избришеш и сите епизоди од следниве серии трајно:\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Дали си сигурен дека сакаш трајно да ги избришеш сите епизоди во следните серии?\\n\\n%s</string>\n    <string name=\"device_pin_expired_message\">ПИН-кодот сега е истечен!</string>\n    <string name=\"sort_release_date_new\">Датум на издавање (најнови до најстари)</string>\n    <string name=\"torrent_info\">Ова видео е Torrent, тоа значи дека твојата видео активност може да се следи.\\nУвери се дека разбираш Torrenting пред да продолжиш.</string>\n    <string name=\"downloads_delete_select\">Одбери ставки за бришење</string>\n    <string name=\"hide_player_control_names\">Сокриј ги имињата на контролите на корисникот</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Дали си сигурен дека сакаш трајно да ги избришеш следните ставки?\\n\\n%s</string>\n    <string name=\"delete_plugin\">Избриши го приклучокот</string>\n    <string name=\"device_pin_error_message\">Не може да се добие PIN-кодот на уредот, обиди се со локална автентикација</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Дали си сигурен дека сакаш трајно да ги избришеш следните епизоди во %1$s?\\n\\n%2$s</string>\n    <string name=\"device_pin_counter_text\">Кодот истекува за %1$d минута/и и %2$d секунда/и</string>\n    <string name=\"audio_singluar\">Аудио</string>\n    <string name=\"podcast_singluar\">Поткаст</string>\n    <string name=\"encoding_error\">Грешка при кодирање на преводот</string>\n    <string name=\"unsupported_error\">Неподдржана грешка</string>\n    <string name=\"player_load_one_subtitle_online\">Вчитај прво достапно</string>\n    <string name=\"torrent_not_accepted\">Рестартирај ја апликацијата и прифати го Stream Torrent искачувачкиот прозорец за да продолжиш.</string>\n    <string name=\"torrent_preferred_media\">Овозможи torrent во Поставки/Провајдери/Претпочитани медиуми</string>\n    <string name=\"software_decoding_desc\">Софтверското декодирање овозможува плеерот да воспоставува видео фајлови кои не се поддржани од вашиот уред, но може да предизвика застој или нестабилно репродуцирање при висока резолуција.</string>\n    <string name=\"software_decoding\">Софтверско декодирање</string>\n    <string name=\"starting_plugin_update_manually\">Започнување на процесот на ажурирање на приклучоци!</string>\n    <string name=\"update_plugins\">Ажурирај приклучоци</string>\n    <string name=\"no_plugins_updated_manually\">Ниту еден приклучок не е ажуриран.</string>\n    <string name=\"plugins_updated_manually\">Успешно ажурирани %d приклучоци!</string>\n    <string name=\"sort_episodes_number_asc\">Епизода (Растечки)</string>\n    <string name=\"sort_episodes_number_desc\">Епизода (Опаѓачки)</string>\n    <string name=\"sort_episodes_rating_high_low\">Рејтинг (Највисок)</string>\n    <string name=\"sort_episodes_rating_low_high\">Рејтинг (Најнизок)</string>\n    <string name=\"sort_episodes_date_newest\">Датум на емитување (Најнов)</string>\n    <string name=\"sort_episodes_date_oldest\">Датум на емитување (Најстар)</string>\n    <string name=\"sort_button_episode\">Еп %s</string>\n    <string name=\"sort_button_rating\">Рејтинг %s</string>\n    <string name=\"sort_button_date\">Датум %s</string>\n    <string name=\"update_plugins_manually\">Ажурирај ги приклучоците рачно</string>\n    <string name=\"volume_exceeded_100\">Јачината на звукот ја надмина 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Повлечи повторно нагоре за да надминеш 100%</string>\n    <string name=\"player_notification_channel_name\">Известувања од плеерот</string>\n    <string name=\"player_notification_channel_description\">Известување од плеерот за контрола на репродукцијата од позадина</string>\n    <string name=\"subtitles_from_embedded\">Вграден</string>\n    <string name=\"subtitles_from_online\">Онлајн</string>\n    <string name=\"all_subtitles_bold\">Направи ги сите преводи со задебелен фонт</string>\n    <string name=\"all_subtitles_italic\">Направи ги сите преводи со закосен фонт</string>\n    <string name=\"speech_recognition_unavailable\">Препознавањето на говор не е достапно</string>\n    <string name=\"begin_speaking\">Започни со зборување…</string>\n    <string name=\"background_radius\">Радиус на позадина</string>\n    <string name=\"download_parallel_settings_des\">Колку различни содржини можат да се симнуваат паралелно</string>\n    <string name=\"parallel_downloads\">Паралелни симнувања</string>\n    <string name=\"concurrent_connections\">Истовремени конекции</string>\n    <string name=\"concurrent_connections_settings_des\">Колку истовремени конекции може да користи секое симнување додека се симнува</string>\n    <string name=\"go_to_downloads\">Оди во Симнувања</string>\n    <string name=\"no_internet_connection\">Нема интернет конекција.\\n\\nПоврзете се на интернет и обидете се повторно, или гледајте ги симнатите содржини додека сте офлајн.</string>\n    <string name=\"overscan_settings_des\">Ги менува границите на екранот</string>\n    <string name=\"overscan_settings\">Оверскен</string>\n    <string name=\"poster_size_settings_des\">Менување на големината на постерите</string>\n    <string name=\"poster_size_settings\">Големина на постер</string>\n    <string name=\"player_settings_always_ask\">Секогаш прашувај</string>\n    <string name=\"speedup_title\">Префрлувач на брзина со долго притискање</string>\n    <string name=\"speedup_summary\">Држи за да добиеш 2x брзина</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dч %2$dм %3$dс</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dм %2$dс</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$dс</string>\n    <string name=\"show_rating\">Ознака за рејтинг</string>\n    <string name=\"no_account\">Нема корисничка сметка</string>\n    <string name=\"edit_profile_image_title\">Измени профилна слика</string>\n    <string name=\"edit_profile_image_hint\">Внеси линк на профилна слика</string>\n    <string name=\"edit_profile_image_error_empty\">Линкот не е пронајден</string>\n    <string name=\"edit_profile_image_error_invalid\">Неважечки линк или слика</string>\n    <string name=\"edit_profile_image_success\">Успешно прикачена слика</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Означи изгледано до оваа епизода</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Избриши изгледано до оваа епизода</string>\n    <string name=\"action_reload\">Повторно вчитано</string>\n    <string name=\"reload_provider\">Повторно вчитај провајдер</string>\n    <string name=\"episode_action_play_mirror\">Пушти друг линк</string>\"\n    <string name=\"name\">Име</string>\n    <string name=\"resolution_and_name\">Резолуција и име</string>\n    <string name=\"subs_subtitle_alignment\">Усогласување на превод</string>\n    <string name=\"bottom_left\">Доле на лево</string>\n    <string name=\"bottom_center\">Доле во центар</string>\n    <string name=\"bottom_right\">Доле на десно</string>\n    <string name=\"middle_left\">Средина на лево</string>\n    <string name=\"middle_center\">Средина во центар</string>\n    <string name=\"middle_right\">Средина на десно</string>\n    <string name=\"top_left\">Горе на лево</string>\n    <string name=\"top_center\">Горе во центар</string>\n    <string name=\"top_right\">Горе на десно</string>\n    <string name=\"play_full_series_button\">Пушти ја целата серија</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ml/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">വേഗം (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">റേറ്റിംഗ്: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">പുതിയ അപ്ഡേറ്റ്!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"app_name\">ക്ലൗഡ് സ്ട്രീം</string>\n    <string name=\"title_home\">ഹോം</string>\n    <string name=\"title_search\">തിരയുക</string>\n    <string name=\"title_downloads\">ഡൗൺലോഡ്സ്</string>\n    <string name=\"title_settings\">സെറ്റിങ്‌സ്</string>\n    <string name=\"search_hint\">തിരയുക…</string>\n    <string name=\"no_data\">ടാറ്റ ലഭ്യമല്ല</string>\n    <string name=\"episode_more_options_des\">കൂടുതൽ ഓപ്ഷൻസ്</string>\n    <string name=\"next_episode\">അടുത്ത എപ്പിസോഡ്</string>\n    <string name=\"result_tags\">തരം</string>\n    <string name=\"result_share\">ഷെയർ</string>\n    <string name=\"result_open_in_browser\">ബ്രൗസറിൽ തുറക്കുക</string>\n    <string name=\"type_watching\">കാണുന്നു</string>\n    <string name=\"type_on_hold\">കണ്ടു നിർത്തി</string>\n    <string name=\"type_completed\">കണ്ടു തീർന്നു</string>\n    <string name=\"type_dropped\">കണ്ടു മതിയാക്കി</string>\n    <string name=\"type_plan_to_watch\">കാണാൻ പോകുന്നു</string>\n    <string name=\"play_movie_button\">സിനിമ പ്ലേ ചെയ്യുക</string>\n    <string name=\"play_torrent_button\">ടോറൻറ് സ്ട്രീം ചെയ്യുക</string>\n    <string name=\"pick_source\">സ്രോതസുകൾ</string>\n    <string name=\"pick_subtitle\">സബ്ടൈറ്റിലുകൾ</string>\n    <string name=\"reload_error\">വീണ്ടും കണക്ട് ചെയ്യുക…</string>\n    <string name=\"go_back\">പിന്നോട്ട് പോകുക</string>\n    <string name=\"play_episode\">എപ്പിസോഡ് പ്ലേയ് ചെയ്യുക</string>\n    <string name=\"download\">ഡൌൺലോഡ്</string>\n    <string name=\"downloaded\">ഡൌൺലോഡ് ചെയ്തവ</string>\n    <string name=\"downloading\">ഡൌൺലോഡ് ചെയ്യുന്നു</string>\n    <string name=\"download_paused\">ഡൌൺലോഡ് നിർത്തി</string>\n    <string name=\"download_started\">ഡൌൺലോഡ് ആരംഭിച്ചു</string>\n    <string name=\"download_failed\">ഡൌൺലോഡ് മുടങ്ങി</string>\n    <string name=\"download_canceled\">ഡൌൺലോഡ് റദ്ദാക്കി</string>\n    <string name=\"download_done\">ഡൌൺലോഡ് പൂർത്തിയായി</string>\n    <string name=\"error_loading_links_toast\">ലിങ്കിൽ തകരാർ</string>\n    <string name=\"download_storage_text\">ആന്തരിക സ്റ്റോറേജ്</string>\n    <string name=\"app_dubbed_text\">ഡബ്</string>\n    <string name=\"app_subbed_text\">സബ്</string>\n    <string name=\"popup_delete_file\">ഫയൽ ഡിലീറ്റ് ചെയ്യുക</string>\n    <string name=\"popup_play_file\">ഫയൽ പ്ലേയ് ചെയ്യുക</string>\n    <string name=\"popup_resume_download\">ഡൌൺലോഡ് തുടരുക</string>\n    <string name=\"popup_pause_download\">ഡൌൺലോഡ് നിർത്തുക</string>\n    <string name=\"home_more_info\">കൂടുതൽ വിവരം</string>\n    <string name=\"home_expanded_hide\">ഒളിക്കുക</string>\n    <string name=\"home_play\">പ്ലേയ്</string>\n    <string name=\"home_info\">വിവരം</string>\n    <string name=\"filter_bookmarks\">ബുക്മാർക് ഫിൽറ്റർ ചെയ്യുക</string>\n    <string name=\"error_bookmarks_text\">ബുക്മാർക്</string>\n    <string name=\"action_remove_from_bookmarks\">നീക്കം ചെയ്യുക</string>\n    <string name=\"sort_apply\">പ്രയോഗിക്കുക</string>\n    <string name=\"player_speed\">പ്ലേയർ വേഗത</string>\n    <!-- <string name=\"subtitles_settings\">Subtitle Settings</string>\n    <string name=\"subs_text_color\">Text Color</string>\n    <string name=\"subs_outline_color\">Outline Color</string>\n    <string name=\"subs_background_color\">Background Color</string>\n    <string name=\"subs_window_color\">Window Color</string>\n    <string name=\"subs_edge_type\">Edge Type</string>\n    <string name=\"subs_subtitle_elevation\">Subtitle Elevation</string>\n    <string name=\"subs_font\">Font</string> -->\n    <string name=\"search_provider_text_providers\">സ്രോതസ് അടിസ്ഥാനത്തിൽ തിരയുക</string>\n    <string name=\"search_provider_text_types\">തരം അടിസ്ഥാനത്തിൽ തിരയുക</string>\n    <string name=\"benene_count_text\">%d പഴം കൊടുത്തു</string>\n    <string name=\"benene_count_text_none\">പഴം കൊടുത്തിട്ടില്ല</string>\n    <!-- <string name=\"subs_auto_select_language\">Auto Select Language</string>\n    <string name=\"subs_download_languages\">Download Languages</string> -->\n    <string name=\"subs_hold_to_reset_to_default\">റീസെറ് ചെയ്യാൻ അമർത്തിപ്പിടിക്കുക</string>\n    <string name=\"continue_watching\">തുടർന്നു കാണുക</string>\n    <string name=\"action_remove_watching\">നീക്കം ചെയ്യുക</string>\n    <string name=\"action_open_watching\">കൂടുതൽ വിവരം</string>\n    <string name=\"vpn_might_be_needed\">ഈ സ്രോതസ് പ്രവൃത്തിക്കാൻ VPN ഉപയോഗിക്കേണ്ടിവന്നേക്കാം</string>\n    <string name=\"vpn_torrent\">ഈ ടോറന്റ് സ്രോതസ് ഉപയോഗിക്കാൻ VPN ശുപാർശചെയ്യുന്നു</string>\n    <string name=\"torrent_plot\">വിവരണം</string>\n    <string name=\"normal_no_plot\">വിവരണം ലഭ്യമല്ല</string>\n    <string name=\"torrent_no_plot\">വിവരണം ലഭ്യമല്ല</string>\n    <!-- <string name=\"picture_in_picture\">Picture-in-picture</string> -->\n    <string name=\"picture_in_picture_des\">മറ്റ് ആപ്പുകളുടെ മുകളിൽ ഒരു മിനിയേച്ചർ പ്ലെയറിൽ പ്ലേബാക്ക് തുടരുക</string>\n    <!-- <string name=\"player_size_settings\">Player resize button</string> -->\n    <string name=\"player_size_settings_des\">കറുത്ത അതിർത്തി നീക്കംചെയ്യുക</string>\n    <!-- <string name=\"player_subtitles_settings\">Subtitles</string> -->\n    <string name=\"player_subtitles_settings_des\">പ്ലേയർ സബ്‌ടൈറ്റിലുകളുടെ സെറ്റിങ്‌സ്</string>\n    <!-- <string name=\"swipe_to_seek_setthings\">Swipe to seek</string> -->\n    <string name=\"swipe_to_seek_settings_des\">വീഡിയോപ്ലേയറിൽ സമയം നിയന്ത്രിക്കാൻ ഇടത്തോട്ടോ വലത്തോട്ടോ സ്വൈപ്പുചെയ്യുക</string>\n    <!-- <string name=\"swipe_to_change_settings\">Swipe to change settings</string> -->\n    <string name=\"swipe_to_change_settings_des\">തെളിച്ചം അല്ലെങ്കിൽ വോളിയം മാറ്റാൻ ഇടത്തോട്ടോ വലത്തോട്ടോ സ്വൈപ്പുചെയ്യുക</string>\n    <!-- <string name=\"double_tap_to_seek_setthings\">Double tap to seek</string> -->\n    <string name=\"double_tap_to_seek_settings_des\">മുന്നോട്ട് അല്ലെങ്കിൽ പിന്നിലേക്ക് നീങ്ങാൻ വലത്തോട്ടോ ഇടത്തോട്ടോ രണ്ടുതവണ ടാപ്പുചെയ്യുക</string>\n    <string name=\"search\">തിരയുക</string>\n    <string name=\"settings_info\">വിവരം</string>\n    <!-- <string name=\"advanced_search\">Advanced Search</string> -->\n    <string name=\"advanced_search_des\">സ്ട്രോതസായി തിരിച്ച ഫലം തരുക</string>\n    <string name=\"updates_settings\">അപ്ഡേറ്റുകൾ അറിയിക്കുക</string>\n    <string name=\"updates_settings_des\">ആരംഭത്തിൽ അപ്ഡേറ്റുകൾ തിരയുക</string>\n    <string name=\"github\">ഗിറ്റ്ഹബ്</string>\n    <string name=\"lightnovel\">നമ്മുടെ ലൈറ്റ് നോവൽ ആപ്പ്</string>\n    <string name=\"anim\">നമ്മുടെ ആനിമേ ആപ്പ്</string>\n    <string name=\"discord\">ഡിസ്‌കോർഡിലേക്ക് സ്വാഗതം</string>\n    <string name=\"benene\">പഴം കൊടുക്കു</string>\n    <string name=\"benene_des\">പഴം കൊടുത്ത എണ്ണം</string>\n    <string name=\"app_language\">ആപ്പിന്റെ ഭാഷ</string>\n    <string name=\"no_chromecast_support_toast\">ഈ സ്രോതസ് ക്രോംകാസ്റ് അനുവദിക്കുന്നില്ല</string>\n    <string name=\"no_links_found_toast\">ലിങ്കുകൾ ലഭ്യമല്ല</string>\n    <string name=\"copy_link_toast\">ലിങ്ക് പകർത്തിയിരിക്കുന്നു</string>\n    <string name=\"play_episode_toast\">എപ്പിസോഡ് പ്ലേയ് ചെയ്യുക</string>\n    <string name=\"season\">സീസൺ</string>\n    <string name=\"no_season\">സീസണില്ല</string>\n    <string name=\"episode\">എപ്പിസോഡ്</string>\n    <string name=\"episodes\">എപ്പിസോഡുകൾ</string>\n    <string name=\"delete_file\">ഫയൽ ഡിലീറ്റ് ചെയ്യുക</string>\n    <string name=\"delete\">ഡിലീറ്റ്</string>\n    <string name=\"cancel\">റദ്ദാക്കുക</string>\n    <string name=\"pause\">നിർത്തുക</string>\n    <string name=\"resume\">തുടരുക</string>\n    <string name=\"delete_message\">സ്ഥിരമായി %sനെ ഡിലീറ്റ് ചെയ്യുക\n\\nഉറപ്പാണോ?</string>\n    <string name=\"status_ongoing\">തുടരുന്നു</string>\n    <string name=\"status_completed\">പൂർത്തിയായി</string>\n    <string name=\"status\">അവസ്ഥ</string>\n    <string name=\"year\">വർഷം</string>\n    <string name=\"rating\">റേറ്റിംഗ്</string>\n    <string name=\"duration\">ദൈര്ഘം</string>\n    <string name=\"site\">സ്രോതസ്</string>\n    <string name=\"synopsis\">സംഗ്രഹം</string>\n    <!-- <string name=\"queued\">queued</string>\n    <string name=\"no_subtitles\">No Subtitles</string>\n    <string name=\"action_default\">Default</string> -->\n    <string name=\"free_storage\">ഒഴിവ്</string>\n    <string name=\"used_storage\">ഉപയോഗത്തിൽ</string>\n    <string name=\"app_storage\">ആപ്പ്</string>\n    <string name=\"movies\">സിനിമ</string>\n    <string name=\"tv_series\">ടീവീ സീരീസ്</string>\n    <string name=\"cartoons\">കാർട്ടൂൺസ്</string>\n    <string name=\"anime\">ആനിമേ</string>\n    <string name=\"torrent\">ടോറൻറ്</string>\n    <!-- <string name=\"source_error\">Source error</string>\n    <string name=\"remote_error\">Remote error</string>\n    <string name=\"render_error\">Renderer error</string>\n    <string name=\"unexpected_error\">Unexpected player error</string>\n    <string name=\"storage_error\">Download error, check storage permissions</string> -->\n    <!-- <string name=\"episode_action_chomecast_episode\">Chromecast Episode</string>\n    <string name=\"episode_action_chomecast_mirror\">Chromecast Mirror</string> -->\n    <string name=\"episode_action_play_in_app\">ആപ്പിൽ പ്ലേയ് ചെയ്യുക</string>\n    <string name=\"episode_action_play_in_format\">%sയിൽ പ്ലേയ് ചെയ്യുക</string>\n    <string name=\"episode_action_auto_download\">ഡൌൺലോഡ് ചെയ്യൂ</string>\n    <string name=\"episode_action_download_mirror\">മിറർ ഡൗണ്ലോഡ്</string>\n    <string name=\"episode_action_reload_links\">ലിങ്ക്സ് വീണ്ടും ലോഡുചെയ്യുക</string>\n    <string name=\"no_update_found\">അപ്ഡേറ്റ് ലഭ്യമല്ല</string>\n    <string name=\"check_for_update\">അപ്ഡേറ്റിനായി തിരയുക</string>\n    <string name=\"video_lock\">പൂട്ടുക</string>\n    <string name=\"video_aspect_ratio_resize\">വലുപ്പം മാറ്റുക</string>\n    <string name=\"video_source\">സ്രോതസ്</string>\n    <string name=\"video_skip_op\">OP ഒഴിവാക്കു</string>\n    <string name=\"dont_show_again\">ഇനിയും കാണിക്കരുത്</string>\n    <string name=\"update\">അപ്ഡേറ്റ്</string>\n    <string name=\"watch_quality_pref\">ഔചിത്യ വീഡിയോ ക്വാളിറ്റി</string>\n    <string name=\"history\">ചരിത്രം</string>\n    <string name=\"action_mark_as_watched\">കണ്ടതാണെന്ന് അടയാളപ്പെടുത്തുക</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d ദിവസങ്ങൾ %2$d മണിക്കൂർ %3$d മിനിറ്റ്</string>\n    <string name=\"next_episode_format\" formatted=\"true\">അധ്യായം%dൽ റിലീസ് ചെയ്യും</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$d മണിക്കൂർ %2$d മിനിറ്റ്</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$sഅധ്യാ%2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">കാസ്റ്റ്:%s</string>\n    <string name=\"create_account\">അക്കൗണ്ട് ഉണ്ടാക്കുക</string>\n    <string name=\"delayed_update_notice\">പുറത്ത്പോകുന്നതോടുകൂടി ആപ് അപ്ഡേറ്റ് ആവുന്നതാണ്</string>\n    <string name=\"select_library\">ലൈബ്രറി തിരഞ്ഞെടുക്കുക</string>\n    <string name=\"open_with\">ഇത് ഉപയോഗിച്ച് തുറക്കുക</string>\n    <string name=\"play_trailer_button\">ട്രെയിലർ പ്ലേ ചെയ്യുക</string>\n    <string name=\"play_livestream_button\">ലൈവ് സ്ട്രീം പ്ലേ ചെയ്യുക</string>\n    <string name=\"filler\" formatted=\"true\">ഫില്ലർ</string>\n    <string name=\"duration_format\" formatted=\"true\">%d മിനിറ്റ്</string>\n    <string name=\"play_with_app_name\">ക്ലൗഡ് സ്ട്രീം ഉപയോഗിച്ച് പ്രവർത്തിപ്പിക്കുക</string>\n    <string name=\"home_next_random_img_des\">അടുത്ത ക്രമരഹിതമായ</string>\n    <string name=\"episode_poster_img_des\">എപ്പിസോഡ് പോസ്റ്റർ</string>\n    <string name=\"update_started\">അപ്ഡേറ്റ് ആരംഭിച്ചു</string>\n    <string name=\"home_main_poster_img_des\">പ്രധാന പോസ്റ്റർ</string>\n    <string name=\"search_poster_img_des\">പോസ്റ്റർ</string>\n    <string name=\"skip_loading\">ലോഡിംഗ് ഒഴിവാക്കുക</string>\n    <string name=\"search_hint_site\" formatted=\"true\">തിരയുക %s…</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dമിനിറ്റ്</string>\n    <string name=\"go_back_img_des\">മടങ്ങിപ്പോവുക</string>\n    <string name=\"preview_background_img_des\">പശ്ചാത്തല പ്രിവ്യൂ</string>\n    <string name=\"result_poster_img_des\">പോസ്റ്റർ</string>\n    <string name=\"home_change_provider_img_des\">ദാതാവിനെ മാറ്റുക</string>\n    <string name=\"loading\">ലോഡിംഗ്…</string>\n    <string name=\"browser\">ബ്രൗസർ</string>\n    <string name=\"type_re_watching\">വീണ്ടും കാണുക</string>\n    <string name=\"stream\">സ്ട്രീം</string>\n    <string name=\"subs_import_text\" formatted=\"true\">%s ൽ ഫോൻ്റ്‌സ് വെച്ചു കൊണ്ട് ഇംപോർട്ട് ചെയ്യുക</string>\n    <string name=\"safe_mode_description\">പ്രശ്‌നമുണ്ടാക്കുന്ന ഒന്ന് കണ്ടെത്താൻ നിങ്ങളെ സഹായിക്കുന്നതിന് ഒരു ക്രാഷ് കാരണം എല്ലാ വിപുലീകരണങ്ങളും ഓഫാക്കി.</string>\n    <string name=\"view_public_repositories_button_short\">പൊതു പട്ടിക</string>\n    <string name=\"blank_repo_message\">CloudStream-ന് സ്ഥിരസ്ഥിതിയായി സൈറ്റുകളൊന്നും ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല. നിങ്ങൾ റിപ്പോസിറ്ററികളിൽ നിന്ന് സൈറ്റുകൾ ഇൻസ്റ്റാൾ ചെയ്യേണ്ടതുണ്ട്.\n\\n\n\\nഞങ്ങളുടെ ഡിസ്കോർഡിൽ ചേരുക അല്ലെങ്കിൽ ഓൺലൈനിൽ തിരയുക.</string>\n    <string name=\"sort_copy\">പകർത്തുക</string>\n    <string name=\"uppercase_all_subtitles\">എല്ലാ സബ്‌ടൈറ്റിലുകളും വലിയക്ഷരമാക്കുക</string>\n    <string name=\"render_error\">റെൻഡറർ പിശക്</string>\n    <string name=\"lock_profile\">പ്രൊഫൈൽ ലോക്ക് ചെയ്യുക</string>\n    <string name=\"view_public_repositories_button\">കമ്മ്യൂണിറ്റി റിപ്പോസിറ്ററികൾ കാണുക</string>\n    <string name=\"safe_mode_title\">സുരക്ഷിത മോഡ് ഓണാണ്</string>\n    <string name=\"manage_accounts\">അക്കൗണ്ടുകൾ കൈകാര്യം ചെയ്യുക</string>\n    <string name=\"coming_soon\">ഉടൻ വരുന്നു…</string>\n    <string name=\"apply_on_restart\">പുനരാരംഭിക്കുമ്പോൾ പ്രയോഗിക്കുക</string>\n    <string name=\"edit_account\">അക്കൗണ്ട് തിരുത്തുക</string>\n    <string name=\"pin_error_incorrect\">തെറ്റായ പിൻ. ദയവായി വീണ്ടും ശ്രമിക്കുക.</string>\n    <string name=\"stop\">നിർത്തുക</string>\n    <string name=\"tracks\">ട്രാക്കുകൾ</string>\n    <string name=\"pin_error_length\">പിൻ 4 പ്രതീകങ്ങൾ ആയിരിക്കണം</string>\n    <string name=\"unexpected_error\">അപ്രതീക്ഷിത പ്ലെയർ പിശക്</string>\n    <string name=\"previous\">മുമ്പത്തെ</string>\n    <string name=\"delete_repository_plugins\">ഇത് എല്ലാ റിപ്പോസിറ്ററി പ്ലഗിന്നുകളും ഇല്ലാതാക്കും</string>\n    <string name=\"restart\">പുനരാരംഭിക്കുക</string>\n    <string name=\"safe_mode_crash_info\">ക്രാഷ് വിവരം കാണുക</string>\n    <string name=\"provider_languages_tip\">ഈ ഭാഷകളിലെ വീഡിയോകൾ കാണുക</string>\n    <string name=\"select_an_account\">ഒരു അക്കൗണ്ട് തിരഞ്ഞെടുക്കുക</string>\n    <string name=\"home_source\">ഉറവിടം</string>\n    <string name=\"video_tracks\">വീഡിയോ ട്രാക്കുകൾ</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast മിറർ</string>\n    <string name=\"download_all_plugins_from_repo\">ഈ ശേഖരത്തിൽ നിന്ന് എല്ലാ പ്ലഗിന്നുകളും ഡൗൺലോഡ് ചെയ്യണോ?</string>\n    <string name=\"delete_repository\">ശേഖരം ഇല്ലാതാക്കുക</string>\n    <string name=\"home_random\">ക്രമരഹിതം</string>\n    <string name=\"quality_cam\">ക്യാമറ</string>\n    <string name=\"storage_error\">ഡൗൺലോഡ് പിശക്, സംഭരണ അനുമതികൾ പരിശോധിക്കുക</string>\n    <string name=\"remote_error\">റിമോട്ട് പിശക്</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast എപ്പിസോഡ്</string>\n    <string name=\"setup_extensions_subtext\">നിങ്ങൾ ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്ന സൈറ്റുകളുടെ ലിസ്റ്റ് ഡൗൺലോഡ് ചെയ്യുക</string>\n    <string name=\"enter_pin\">പിൻ നൽകുക</string>\n    <string name=\"sort_close\">അടയ്ക്കുക</string>\n    <string name=\"action_add_to_bookmarks\">വാച്ച് സ്റ്റാറ്റസ് സജ്ജീകരിക്കുക</string>\n    <string name=\"pin\">പിൻ</string>\n    <string name=\"links_reloaded_toast\">ലിങ്കുകൾ വീണ്ടും ലോഡുചെയ്‌തു</string>\n    <string name=\"source_error\">ഉറവിട പിശക്</string>\n    <string name=\"enter_current_pin\">നിലവിലെ പിൻ നൽകുക</string>\n    <string name=\"audio_tracks\">ഓഡിയോ ട്രാക്കുകൾ</string>\n    <string name=\"picture_in_picture\">ചിത്രം-ഇൻ-ചിത്രം</string>\n    <string name=\"sort_updated_old\">പുതുക്കിയത് (പഴയത് മുതൽ പുതിയത് വരെ)</string>\n    <string name=\"sort_rating_desc\">റേറ്റിംഗ് (ഉയർന്നത് മുതൽ താഴ്ന്നത്)</string>\n    <string name=\"apk_installer_legacy\">പാരമ്പര്യം</string>\n    <string name=\"subs_window_color\">വിൻഡോ നിറം</string>\n    <string name=\"sort_clear\">ക്ലിയർ</string>\n    <string name=\"test_log\">ലോഗ്</string>\n    <string name=\"recommendations_tooltip\">ശുപാർശകൾ കാണിക്കുക</string>\n    <string name=\"logged_account\" formatted=\"true\">%s ആയി ലോഗിൻ ചെയ്തു</string>\n    <string name=\"sort_by\">ഇങ്ങനെ അടുക്കുക</string>\n    <string name=\"sort\">അടുക്കുക</string>\n    <string name=\"edit\">തിരുത്തുക</string>\n    <string name=\"sort_updated_new\">പുതുക്കിയത് (പുതിയത് മുതൽ പഴയത് വരെ)</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"update_notification_installing\">ആപ്പ് അപ്ഡേറ്റ് ഇൻസ്റ്റാൾ ചെയ്യുന്നു…</string>\n    <string name=\"category_updates\">അപ്ഡേറ്റുകളും ഒപ്പം ബാക്കപ്പും</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s(അപ്രാപ്തമാക്കി)</string>\n    <string name=\"sort_rating_asc\">റേറ്റിംഗ് (താഴ്ന്നത് മുതൽ ഉയർന്നത് വരെ)</string>\n    <string name=\"subs_text_color\">വാചക നിറം</string>\n    <string name=\"update_notification_failed\">ആപ്പിൻ്റെ പുതിയ പതിപ്പ് ഇൻസ്റ്റാൾ ചെയ്യാനായില്ല</string>\n    <string name=\"apk_installer_package_installer\">പാക്കേജ് ഇൻസ്റ്റാളർ</string>\n    <string name=\"sort_alphabetical_a\">അക്ഷരമാലാക്രമം (A മുതൽ Z വരെ)</string>\n    <string name=\"sort_alphabetical_z\">അക്ഷരമാലാക്രമം (Z മുതൽ A വരെ)</string>\n    <string name=\"empty_library_logged_in_message\">ഈ ലിസ്റ്റ് ശൂന്യമാണ്. മറ്റൊന്നിലേക്ക് മാറാൻ ശ്രമിക്കുക.</string>\n    <string name=\"clear_history\">ചരിത്രം മായ്ക്കുക</string>\n    <string name=\"show_log_cat\">ലോഗ്കാറ്റ് കാണിക്കുക 🐈</string>\n    <string name=\"empty_library_no_accounts_message\">നിങ്ങളുടെ ലൈബ്രറി ശൂന്യമാണ് :(\n\\nഒരു ലൈബ്രറി അക്കൗണ്ടിൽ ലോഗിൻ ചെയ്യുക അല്ലെങ്കിൽ നിങ്ങളുടെ പ്രാദേശിക ലൈബ്രറിയിലേക്ക് ഷോകൾ ചേർക്കുക.</string>\n    <string name=\"other_singular\">വീഡിയോ</string>\n    <string name=\"repo_copy_label\">റിപ്പോസിറ്ററി നാമവും URL ഉം</string>\n    <string name=\"toast_copied\">പകർത്തി!</string>\n    <string name=\"subscribe_tooltip\">പുതിയ എപ്പിസോഡ് അറിയിപ്പ്</string>\n    <string name=\"result_search_tooltip\">മറ്റ് വിപുലീകരണങ്ങളിൽ തിരയുക</string>\n    <string name=\"subtitles_settings\">ഉപശീർഷകം ക്രമീകരണങ്ങൾ</string>\n    <string name=\"subs_edge_type\">എഡ്ജ് തരം</string>\n    <string name=\"subs_outline_color\">ഔട്ട്ലൈൻ നിറം</string>\n    <string name=\"subs_background_color\">പശ്ചാത്തല നിറം</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ms/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"all_languages_preference\">Semua bahasa</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Langkau %s</string>\n    <string name=\"history\">Sejarah</string>\n    <string name=\"clear_history\">Kosongkan sejarah</string>\n    <string name=\"skip_type_intro\">Pengenalan</string>\n    <string name=\"skip_type_creddits\">Kredit</string>\n    <string name=\"skip_type_mixed_op\">Pembukaan bercampur</string>\n    <string name=\"skip_type_ed\">Penamat</string>\n    <string name=\"skip_type_op\">Pembukaan</string>\n    <string name=\"update_notification_installing\">Memasang kemaskini aplikasi…</string>\n    <string name=\"update_notification_downloading\">Memuat turun kemaskini aplikasi…</string>\n    <string name=\"no\">Tidak</string>\n    <string name=\"yes\">Ya</string>\n    <string name=\"confirm_exit_dialog\">Adakah anda pasti anda ingin keluar?</string>\n    <string name=\"action_remove_from_watched\">Keluarkan daripada ditonton</string>\n    <string name=\"action_mark_as_watched\">Tanda sebagai sudah ditonton</string>\n    <string name=\"enable_skip_op_from_database_des\">Tunjukkan pop timbul yang dilangkau untuk pembukaan/pengakhiran</string>\n    <string name=\"update_notification_failed\">Tidak dapat memasang versi aplikasi terkini</string>\n    <string name=\"clipboard_too_large\">Terlalu banyak perkataan. Tidak dapat disimpan di papan klip.</string>\n    <string name=\"app_not_found_error\">Aplikasi tidak ditemui</string>\n    <string name=\"skip_type_mixed_ed\">Penamat bercampur</string>\n    <string name=\"skip_type_recap\">Imbas kembali</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episod %d akan disiarkan dalam</string>\n    <string name=\"cast_format\" formatted=\"true\">Pelakon:%s</string>\n    <string name=\"safe_mode_title\">Mod Selamat Hidup</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"episode_poster_img_des\">Poster Episod</string>\n    <string name=\"home_main_poster_img_des\">Poster Utama</string>\n    <string name=\"go_back_img_des\">Pergi Kembali</string>\n    <string name=\"home_next_random_img_des\">Seterusnya Rawak</string>\n    <string name=\"home_change_provider_img_des\">Tukar Pembekal</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Kelajuan (%.2fx)</string>\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Poster</string>\n    <string name=\"sort_copy\">Salin</string>\n    <string name=\"title_downloads\">Muat Turun</string>\n    <string name=\"result_tags\">Genre</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Cari %s…</string>\n    <string name=\"edit\">Sunting</string>\n    <string name=\"search_hint\">Carian…</string>\n    <string name=\"browser\">Pelayar</string>\n    <string name=\"next_episode\">Episod seterusnya</string>\n    <string name=\"download\">Muat Turun</string>\n    <string name=\"open_with\">Buka dengan</string>\n    <string name=\"popup_delete_file\">Padam Fail</string>\n    <string name=\"result_open_in_browser\">Buka Dalam Pelayar</string>\n    <string name=\"no_data\">Tiada Data</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"sort_save\">Simpan</string>\n    <string name=\"result_share\">Kongsi</string>\n    <string name=\"title_settings\">Tetapan</string>\n    <string name=\"sort_close\">Tutup</string>\n    <string name=\"preview_background_img_des\">Pratonton</string>\n    <string name=\"rated_format\" formatted=\"true\">Resensi:%.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Kemas kini baru dijumpai!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"play_from_beginning_img_des\">Main dari mula</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Musim %1$d Episod %2$d akan dikeluarkan di</string>\n    <string name=\"popup_pause_download\">Henti muat turun</string>\n    <string name=\"sort_clear\">Buang</string>\n    <string name=\"toast_copied\">disalin!</string>\n    <string name=\"player_speed\">Kelajuan Pemain</string>\n    <string name=\"action_remove_from_bookmarks\">Buang</string>\n    <string name=\"autoplay_next_settings_des\">Mulakan episod seterusnya apabila episod semasa tamat</string>\n    <string name=\"open_local_video\">Buka video tempatan</string>\n    <string name=\"subtitles_settings\">Tetapan Sari Kata</string>\n    <string name=\"subscribe_tooltip\">Pemberitahuan episod baru</string>\n    <string name=\"result_search_tooltip\">Carian dalam sambungan lain</string>\n    <string name=\"recommendations_tooltip\">Paparkan cadangan</string>\n    <string name=\"error_bookmarks_text\">Penanda halaman</string>\n    <string name=\"home_play\">Pasang</string>\n    <string name=\"torrent_no_plot\">Tiada penerangan dijumpai</string>\n    <string name=\"play_with_app_name\">Pasang dengan CloudStream</string>\n    <string name=\"title_home\">Halaman Utama</string>\n    <string name=\"play_movie_button\">Pasang Wayang</string>\n    <string name=\"update_started\">Kemas kini bermula</string>\n    <string name=\"subs_font\">Teks</string>\n    <string name=\"chromecast_subtitles_settings_des\">Tetapan Sari kata Chromecast</string>\n    <string name=\"play_episode\">Pasang Episod</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"type_completed\">Selesai</string>\n    <string name=\"search_provider_text_types\">Carian mengikut jenis</string>\n    <string name=\"title_search\">Carian</string>\n    <string name=\"episode_more_options_des\">Lebih Pilihan</string>\n    <string name=\"filler\" formatted=\"true\">Pengisi</string>\n    <string name=\"type_watching\">Menonton</string>\n    <string name=\"type_plan_to_watch\">Dirancang untuk ditonton</string>\n    <string name=\"type_re_watching\">Tonton semula</string>\n    <string name=\"pick_source\">Sumber</string>\n    <string name=\"pick_subtitle\">Sarikata</string>\n    <string name=\"go_back\">Kembali</string>\n    <string name=\"downloading\">Memuat turun</string>\n    <string name=\"download_canceled\">Muat turun dibatalkan</string>\n    <string name=\"download_failed\">Muat turun gagal</string>\n    <string name=\"download_started\">Muat turun dimulakan</string>\n    <string name=\"downloaded\">Dimuat turun</string>\n    <string name=\"download_done\">Muat turun selesai</string>\n    <string name=\"popup_play_file\">Pasang fail</string>\n    <string name=\"popup_resume_download\">Sambung muat turun</string>\n    <string name=\"download_storage_text\">Storan dalaman</string>\n    <string name=\"search_provider_text_providers\">Carian mengikut sumber</string>\n    <string name=\"benene_count_text\">%d Pisang yang diberikan kepada pemaju</string>\n    <string name=\"subs_font_size\">Saiz Teks</string>\n    <string name=\"sort_apply\">Mohon</string>\n    <string name=\"subs_text_color\">Warna teks</string>\n    <string name=\"subs_background_color\">Warna latar belakang</string>\n    <string name=\"benene_count_text_none\">Tiada Benenes diberikan</string>\n    <string name=\"subs_auto_select_language\">Auto-Pilih Bahasa</string>\n    <string name=\"subs_download_languages\">Muat turun Bahasa</string>\n    <string name=\"subs_subtitle_languages\">Bahasa Sari kata</string>\n    <string name=\"continue_watching\">Sambung tonton</string>\n    <string name=\"action_remove_watching\">Buang</string>\n    <string name=\"action_open_watching\">Lebih Maklumat</string>\n    <string name=\"vpn_torrent\">Sumber ini adalah torrent, penggunaan VPN digalakkan</string>\n    <string name=\"provider_info_meta\">Metadata tidak diberikan oleh laman web, video lalai akan gagala sekiranya tidak wujud di laman web.</string>\n    <string name=\"torrent_plot\">Penerangan</string>\n    <string name=\"show_log_cat\">Papar Logcat🐈</string>\n    <string name=\"player_size_settings\">Saiz butang pemain</string>\n    <string name=\"links_reloaded_toast\">Pautan dimuat semula</string>\n    <string name=\"repo_copy_label\">Nama repositori dan URL</string>\n    <string name=\"speed_setting_summary\">Tambah pilihan kelajuan dalam pemain</string>\n    <string name=\"downloads_empty\">Tiada yang dimuat turun.</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"home_expanded_hide\">Sembunyi</string>\n    <string name=\"home_more_info\">Lebih maklumat</string>\n    <string name=\"filter_bookmarks\">Penapis penanda halaman</string>\n    <string name=\"action_add_to_bookmarks\">Tetapkan status tontonan</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"offline_file\">Sedia untuk dipasang luar talian</string>\n    <string name=\"select_all\">Pilih semua</string>\n    <string name=\"deselect_all\">Nyahpilih semua</string>\n    <string name=\"vpn_might_be_needed\">VPN mungkin diperlukan untuk sumber ini berjalan dengan lancar</string>\n    <string name=\"picture_in_picture_des\">Sambung Rakaman didalam pemain mini di atas aplikasi lain</string>\n    <string name=\"player_subtitles_settings\">Sari kata</string>\n    <string name=\"player_subtitles_settings_des\">Tetapan sari kata pemain</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast Sari kata</string>\n    <string name=\"eigengraumode_settings\">Kelajuan pemain</string>\n    <string name=\"autoplay_next_settings\">Auto-pasang episod seterusnya</string>\n    <string name=\"use_system_brightness_settings\">Gunakan keterangan sistem</string>\n    <string name=\"reload_error\">Cuba sambungan talian…</string>\n    <string name=\"settings_info\">Informasi</string>\n    <string name=\"safe_mode_crash_info\">Lihat info ralat</string>\n    <string name=\"limit_title\">char maximum tajuk pemain video</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"extension_size\">Saiz</string>\n    <string name=\"sort_by\">Isih ikut</string>\n    <string name=\"sort\">Susun mengikut</string>\n    <string name=\"revert\">Kembali ke asal</string>\n    <string name=\"profile_background_des\">Profil latar belakang</string>\n    <string name=\"favorites_list_name\">Kegemaran</string>\n    <string name=\"pin_error_length\">PIN perlu mempunyai 4 aksara</string>\n    <string name=\"delete_file\">Padam Fail</string>\n    <string name=\"resume\">Sambung</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"category_player\">Pemain</string>\n    <string name=\"delayed_update_notice\">Aplikasi akan dikemas kini ketika keluar</string>\n    <string name=\"player_settings_play_in_app\">Pemain dalaman</string>\n    <string name=\"duration\">Durasi</string>\n    <string name=\"site\">Laman web</string>\n    <string name=\"synopsis\">Sinopsis</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"tv_series_singular\">Bersiri</string>\n    <string name=\"cartoons_singular\">Kartun</string>\n    <string name=\"unexpected_error\">Pemain tidak jangka gagal</string>\n    <string name=\"episode_action_chromecast_mirror\">Cermin Chromecast</string>\n    <string name=\"dns_pref\">DNS atas HTTPS</string>\n    <string name=\"pref_category_actions\">Tindakan</string>\n    <string name=\"example_password\">password123</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"backup_failed\">Keizinan storan hilang. Cuba sekali lagi.</string>\n    <string name=\"pause\">Henti</string>\n    <string name=\"free_storage\">Bebas</string>\n    <string name=\"app_storage\">Aplikasi</string>\n    <string name=\"show_dub\">Label dub</string>\n    <string name=\"episode_action_auto_download\">Muat turun automatik</string>\n    <string name=\"check_for_update\">Semak kemas kini</string>\n    <string name=\"video_lock\">Kunci</string>\n    <string name=\"update\">Kemas kini</string>\n    <string name=\"jsdelivr_proxy\">Proksi Github</string>\n    <string name=\"remove_site_pref\">Padam laman web</string>\n    <string name=\"legal_notice\">Penafian</string>\n    <string name=\"pref_category_links\">Pautan</string>\n    <string name=\"pref_category_backup\">Sandaran</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"random_button_settings\">Butang Rawak</string>\n    <string name=\"pref_category_player_layout\">Susun atur</string>\n    <string name=\"pref_category_looks\">Tengok</string>\n    <string name=\"provider_lang_settings\">Bahasa tambahan</string>\n    <string name=\"app_layout\">Susun atur App</string>\n    <string name=\"enable_nsfw_on_providers\">Aktifkan NSFW pada tambahan yang disokong</string>\n    <string name=\"category_providers\">Sumber</string>\n    <string name=\"add_account\">Tambah akaun</string>\n    <string name=\"switch_account\">Tukar akaun</string>\n    <string name=\"create_account\">Buat akaun</string>\n    <string name=\"none\">Tiada</string>\n    <string name=\"subtitles_outline\">Rangka</string>\n    <string name=\"actor_supporting\">Menyokong</string>\n    <string name=\"actor_background\">Latar Belakang</string>\n    <string name=\"home_source\">Sumber</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Mula muat turun %1$d%2$s…</string>\n    <string name=\"dismiss\">Tolak</string>\n    <string name=\"subscription_in_progress_notification\">Mengemas kini cerita dilanggan</string>\n    <string name=\"subscription_episode_released\">Episod %d telah keluar!</string>\n    <string name=\"device_pin_url_message\">Lawati <b>%s</b> di telefon pintar atau komputer dan masukkan kod diatas</string>\n    <string name=\"device_pin_error_message\">Tidak dapat Kod PIN peranti, cuba pengesahan lokal</string>\n    <string name=\"backup_success\">Data disimpan</string>\n    <string name=\"library\">Perpustakaan</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"episode_action_play_in_app\">Main dalam app</string>\n    <string name=\"add_site_pref\">Klon laman web</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"bottom_title_settings\">Lokasi tajuk poster</string>\n    <string name=\"cs3wiki\">Wiki CloudStream</string>\n    <string name=\"delete\">Padam</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Drama Asia</string>\n    <string name=\"normal_no_plot\">Tiada plot dijumpai</string>\n    <string name=\"limit_title_rez\">Resolusi pemain video</string>\n    <string name=\"logout\">Log keluar</string>\n    <string name=\"quality_cam\">Kamera</string>\n    <string name=\"subtitles_raised\">Dinaikkan</string>\n    <string name=\"provider_languages_tip\">Lihat video dalam bahasa-bahasa ini</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"duplicate_add\">Tambah</string>\n    <string name=\"used_storage\">Diguna</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"pref_category_subtitles\">Sari kata</string>\n    <string name=\"error_loading_links_toast\">Gagal Memuatkan Pautan</string>\n    <string name=\"cancel\">Batal</string>\n    <string name=\"start\">Mula</string>\n    <string name=\"test_failed\">Gagal</string>\n    <string name=\"status_completed\">Selesai</string>\n    <string name=\"status\">Status</string>\n    <string name=\"others\">Selain itu</string>\n    <string name=\"pref_category_app_updates\">Kemas kini aplikasi</string>\n    <string name=\"pref_category_ui_features\">Fitur</string>\n    <string name=\"phone_layout\">Susun atur telefon</string>\n    <string name=\"preferred_media_subtext\">Apa yang anda mahu lihat</string>\n    <string name=\"example_username\">Nama Pengguna</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Tidak dapat log masuk di %s</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Gambar Poster</string>\n    <string name=\"resolution_and_title\">Resolusi dan tajuk</string>\n    <string name=\"error_invalid_id\">ID tidak sah</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"min\">Min</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Dilumpuhkan: %d</string>\n    <string name=\"extension_language\">Bahasa</string>\n    <string name=\"login\">Log masuk</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"ok\">Setuju</string>\n    <string name=\"battery_dialog_title\">Nyahdaya pengoptimuman bateri</string>\n    <string name=\"app_info_intent_error\">Tidak dapat membuka info aplikasi CloudStream.</string>\n    <string name=\"use\">Guna</string>\n    <string name=\"duplicate_replace\">Tukar</string>\n    <string name=\"enter_pin\">Masukkan PIN</string>\n    <string name=\"lock_profile\">Kunci Profil</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"rotate_video\">Putar</string>\n    <string name=\"biometric_authentication_title\">Buka CloudStream</string>\n    <string name=\"biometric_setting\">Kunci dengan biometrik</string>\n    <string name=\"audio_book_singular\">Buku Audio</string>\n    <string name=\"all\">Semua</string>\n    <string name=\"subscription_list_name\">Dilanggan</string>\n    <string name=\"subscription_new\">Dilanggan kepada %s</string>\n    <string name=\"profile_number\">Profil %d</string>\n    <string name=\"help\">Bantuan</string>\n    <string name=\"favorite_added\">%s ditambah ke kegemaran</string>\n    <string name=\"favorite_removed\">%s dialih keluar dari kegemaran</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Masukkan PIN untuk %s</string>\n    <string name=\"enter_current_pin\">Masukkan PIN Semasa</string>\n    <string name=\"pin_error_incorrect\">PIN salah. Sila cuba sekali lagi.</string>\n    <string name=\"select_an_account\">Sila pilih Akaun</string>\n    <string name=\"manage_accounts\">Urus akaun</string>\n    <string name=\"edit_account\">Sunting Akaun</string>\n    <string name=\"logged_account\" formatted=\"true\">Log masuk sebagai %s</string>\n    <string name=\"search\">Carian</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Gunakan ini sekiranya sari kata yang dipaparkan awal sebanyak %d</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"tv_layout\">Susun atur TV</string>\n    <string name=\"tv_series\">TV Bersiri</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Tidak dapat papar %s</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Dimuat turun: %d</string>\n    <string name=\"qr_image\">Gambar Kod QR</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"select_library\">Pilih Perpustakaan</string>\n    <string name=\"resolution\">Resolusi</string>\n    <string name=\"profiles\">Profil</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"show_title\">Tajuk</string>\n    <string name=\"add_sync\">Tambah penjejakan</string>\n    <string name=\"loading\">Memuatkan…</string>\n    <string name=\"download_paused\">Muat turun dihentikan</string>\n    <string name=\"stream\">Rangkaian penstriman</string>\n    <string name=\"app_dubbed_text\">Alih suara</string>\n    <string name=\"app_subbed_text\">Sari kata</string>\n    <string name=\"subs_subtitle_elevation\">Timbul Sari kata</string>\n    <string name=\"show_fillers_settings\">Papar episod pengisi untuk anime</string>\n    <string name=\"github\">Github</string>\n    <string name=\"episode\">Episod</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Episod tidak dijumpai</string>\n    <string name=\"year\">Tahun</string>\n    <string name=\"no_subtitles\">Tiada Sari kata</string>\n    <string name=\"cartoons\">Kartun</string>\n    <string name=\"asian_drama_singular\">Drama Asia</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"source_error\">Sumber gagal</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast episod</string>\n    <string name=\"episode_action_play_in_format\">Main dalam %s</string>\n    <string name=\"storage_error\">Muat turun gagal, cek keizinan storan</string>\n    <string name=\"episode_action_download_mirror\">Muat turun cermin</string>\n    <string name=\"episode_action_download_subtitle\">Muat turun sari kata</string>\n    <string name=\"show_sub\">Label sub</string>\n    <string name=\"video_aspect_ratio_resize\">Saiz semula</string>\n    <string name=\"video_source\">Sumber</string>\n    <string name=\"dont_show_again\">Jangan tunjuk lagi</string>\n    <string name=\"add_site_summary\">Tambah klon laman web wujud dengan URL berbeza</string>\n    <string name=\"download_path_pref\">Laluan muat turun</string>\n    <string name=\"display_subbed_dubbed_settings\">Paparkan Anime Dubbed/Subbed</string>\n    <string name=\"pref_category_player_features\">FItur pemain</string>\n    <string name=\"category_provider_test\">Periksa sumber</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"category_ui\">Susun atur</string>\n    <string name=\"primary_color_settings\">Warna primer</string>\n    <string name=\"bottom_title_settings_des\">Letak tajuk di bawah poster</string>\n    <string name=\"example_site_name\">NewSiteName</string>\n    <string name=\"example_lang_name\">Kod bahasa (en)</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Ditambah %s</string>\n    <string name=\"recommended\">Disaran</string>\n    <string name=\"actor_main\">Utama</string>\n    <string name=\"home_random\">Rawak</string>\n    <string name=\"coming_soon\">Akan datang…</string>\n    <string name=\"quality_cam_rip\">Kamera</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"error_invalid_data\">Data tidak sah</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"error_invalid_url\">URL tidak sah</string>\n    <string name=\"error\">Ralat</string>\n    <string name=\"title\">Tajuk</string>\n    <string name=\"subtitles_filter_lang\">Tapis bahasa media mengikut pilihan</string>\n    <string name=\"extras\">Ekstra</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"next\">Seterusnya</string>\n    <string name=\"batch_download\">Muat turun kelompok</string>\n    <string name=\"delete_repository\">Padam repositori</string>\n    <string name=\"backup_frequency\">Frekuensi sandaran</string>\n    <string name=\"disable\">Lumpuhkan</string>\n    <string name=\"no_repository_found_error\">Repositori tidak dijumpai, cek URL dan cuba VPN</string>\n    <string name=\"action_unsubscribe\">Nyahlanggan</string>\n    <string name=\"duplicate_title\">Potensi Duplikasi Dijumpai</string>\n    <string name=\"duplicate_replace_all\">Tukar Semua</string>\n    <string name=\"action_subscribe\">Langgani</string>\n    <string name=\"test_extensions\">Periksa semua tambahan</string>\n    <string name=\"auto_rotate_video\">Auto putar</string>\n    <string name=\"favorite\">Kegemaran</string>\n    <string name=\"biometric_unsupported\">Pengesahan biometric tidak disokong oleh peranti anda</string>\n    <string name=\"test_extensions_summary\">Pemeriksaan ini ditujukan untuk pembangun sahaja dan tidak mengesahkan bahawa tambahan berjalan.</string>\n    <string name=\"unfavorite\">Tidak digemar</string>\n    <string name=\"pref_category_accounts\">Akaun</string>\n    <string name=\"device_pin_expired_message\">Kod PIN telah luput!</string>\n    <string name=\"pref_category_security\">Keselamatan</string>\n    <string name=\"open_downloaded_repo\">Buka repositori</string>\n    <string name=\"device_pin_counter_text\">Kod luput dalam %1$dm%2$ds</string>\n    <string name=\"jsdelivr_enabled\">Github tidak dapat dicapai. Menghidupkan proksi jsDelivr…</string>\n    <string name=\"random_button_settings_desc\">Papar butang rawak di laman utama dan perpustakaan</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Dilumpuhkan)</string>\n    <string name=\"empty_library_no_accounts_message\">Perpustakaan anda kosong :(\\nLog masuk dalam akaun perpustakaan atau tambah cerita di perpustakaan lokal.</string>\n    <string name=\"subtitle_offset_title\">Kelewatan sari kata</string>\n    <string name=\"sort_release_date_old\">Tarikh Keluar (Tua ke Baru)</string>\n    <string name=\"sort_release_date_new\">Tarikh Keluar (Baru ke Tua)</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"double_tap_to_pause_settings\">Tekan dua kali untuk henti</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"downloaded_file\">Fail dimuat turun</string>\n    <string name=\"stop\">Berhenti</string>\n    <string name=\"already_voted\">Anda telah mengundi</string>\n    <string name=\"action_remove_from_favorites\">Alih keluar dari Kegemaran</string>\n    <string name=\"music_singlar\">Musik</string>\n    <string name=\"downloads_delete_select\">Pilih benda untuk dibuang</string>\n    <string name=\"player_size_settings_des\">Buang sempadan hitam</string>\n    <string name=\"category_account\">Akaun dan Sekuriti</string>\n    <string name=\"advanced_search\">Carian Bestari</string>\n    <string name=\"advanced_search_des\">Beri hasil carian dipisah mengikut pelbagai sumber</string>\n    <string name=\"lightnovel\">Aplikasi Light novel oleh pembangun sama</string>\n    <string name=\"anim\">Aplikasi Anime oleh pembangun sama</string>\n    <string name=\"discord\">Menyertai Discord</string>\n    <string name=\"delete_files\">Padam Fail</string>\n    <string name=\"delete_format\" formatted=\"true\">Padam (%1$d | %2$s)</string>\n    <string name=\"resize_fit\">Muatkan ke skrin</string>\n    <string name=\"resize_fill\">Regang</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"subtitles_shadow\">Bayang</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Gunakan ini sekiranya sari kata yang dipaparkan lewat sebanyak %d</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Tiada kelewatan sari kata</string>\n    <string name=\"quality_cam_hd\">Kamera</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"previous\">Sebelum</string>\n    <string name=\"app_layout_subtext\">Tukar kelihatan aplikasi mengikut peranti</string>\n    <string name=\"setup_done\">Tamat</string>\n    <string name=\"extensions\">Tambahan</string>\n    <string name=\"add_repository\">Tambah repositori</string>\n    <string name=\"repository_name_hint\">Nama repositori (Pilihan)</string>\n    <string name=\"repository_url_hint\">Arkibkan URL atau Kod Pendek</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Dimuat turun %1$d%2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Semua %s telah dimuat turun</string>\n    <string name=\"setup_extensions_subtext\">Muat turun senarai laman web yang anda ingin gunakan</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Tidak dimuat turun: %d</string>\n    <string name=\"view_public_repositories_button\">Lihat repositori komuniti</string>\n    <string name=\"view_public_repositories_button_short\">Senarai awam</string>\n    <string name=\"uppercase_all_subtitles\">Huruf besar semua sari kata</string>\n    <string name=\"restart\">Mula semula</string>\n    <string name=\"safe_mode_description\">Semua tambahan telah dilumpuhkan disebabkan ralat untuk menolong anda mencari mana satu yang bermasalah.</string>\n    <string name=\"extension_description\">Penghuraian</string>\n    <string name=\"extension_version\">Versi</string>\n    <string name=\"extension_authors\">Pengarang</string>\n    <string name=\"extension_install_first\">Tetapkan tambahan dahulu</string>\n    <string name=\"biometric_setting_summary\">Buka aplikasi dengan Cap Jari, Pengesahan Muka, PIN, Corak dan Password.</string>\n    <string name=\"resize_zoom\">Zum</string>\n    <string name=\"category_general\">Umum</string>\n    <string name=\"pref_category_extensions\">Tambahan</string>\n    <string name=\"app_theme_settings\">Tema aplikasi</string>\n    <string name=\"apk_installer_legacy\">Legasi</string>\n    <string name=\"reset_btn\">Tetap Semula</string>\n    <string name=\"password_pin_authentication_title\">Pengesahan Password/PIN</string>\n    <string name=\"no_subtitles_loaded\">Sari kata belum tetapkan lagi</string>\n    <string name=\"extension_types\">Disokong</string>\n    <string name=\"clipboard_permission_error\">Ralat tidak dapat akses Clipboard, Sila cuba sekali lagi.</string>\n    <string name=\"clipboard_unknown_error\">Ralat menyalin, Sila salin logcat dan hubungi penyokong aplikasi.</string>\n    <string name=\"test_warning\">Amaran</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"show_hd\">Label Kualiti</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"test_passed\">Lepas</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"max\">Maks</string>\n    <string name=\"download_all_plugins_from_repo\">Amaran: CloudStream 3 tidak bertanggungjawab atas penggunaan tambahan pihak ketiga dan tidak memberi sumbang kepada mereka!</string>\n    <string name=\"apply_on_restart\">Mula semula aplikasi untuk lihat perubahan.</string>\n    <string name=\"empty_library_logged_in_message\">Senarai ini kosong. Sila tukar yang lain.</string>\n    <string name=\"mobile_data\">Data mudah alih</string>\n    <string name=\"action_add_to_favorites\">Tambah ke kegemaran</string>\n    <string name=\"account\">akaun</string>\n    <string name=\"subs_outline_color\">Warna Garis Luar</string>\n    <string name=\"subs_window_color\">Warna Tetingkap</string>\n    <string name=\"type_dropped\">Diabaikan</string>\n    <string name=\"skip_loading\">Langkau Memuat</string>\n    <string name=\"type_on_hold\">Tangguh</string>\n    <string name=\"play_trailer_button\">Main Pra-tonton</string>\n    <string name=\"play_livestream_button\">Main Strim Langsung</string>\n    <string name=\"play_torrent_button\">Strim Torrent</string>\n    <string name=\"subs_edge_type\">Jenis Bucu</string>\n    <string name=\"subs_hold_to_reset_to_default\">Tekan lama-lama untuk set semula kepada asal</string>\n    <string name=\"kitsu_settings\">Tunjuk poster dari Kitsu</string>\n    <string name=\"episode_sync_settings\">Kemaskini kemajuan tontonan</string>\n    <string name=\"pref_filter_search_quality\">Sembunyi kualiti video pilihan dalam carian</string>\n    <string name=\"automatic_plugin_updates\">Kemaskini \\'plugin\\' automatik</string>\n    <string name=\"swipe_to_seek_settings\">Sapu untuk percepat</string>\n    <string name=\"automatic_plugin_download_mode_title\">Pilih mod untuk tapis \\'plugin\\' perlu dimuat turun</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Import tulisan dengan meletakkan di %s</string>\n    <string name=\"picture_in_picture\">Gambar dalam gambar</string>\n    <string name=\"automatic_plugin_download\">Muat turun \\'plugin\\' secara automatik</string>\n    <string name=\"show_trailers_settings\">Tunjuk pra-tonton</string>\n    <string name=\"double_tap_to_seek_settings_des\">Tekan dua kali di kanan atau kiri untuk kehadapan atau kebelakang</string>\n    <string name=\"swipe_to_seek_settings_des\">Sapu dari sisi ke sisi untuk mengawal minit video</string>\n    <string name=\"swipe_to_change_settings\">Sapu untuk ubah tetapan</string>\n    <string name=\"swipe_to_change_settings_des\">Sapu atas atau bawah di kiri atau kanan untuk ubah kecerahan atau kekuatan suara</string>\n    <string name=\"double_tap_to_pause_settings_des\">Tekan dua kali di tengah-tengah untuk jeda</string>\n    <string name=\"episode_sync_settings_des\">Selaraskan kemajuan episod secara automatik</string>\n    <string name=\"restore_success\">Memuatkan fail sandaran</string>\n    <string name=\"category_updates\">Kemaskini dan sandaran</string>\n    <string name=\"double_tap_to_seek_settings\">Ketik dua kali untuk mencari</string>\n    <string name=\"use_system_brightness_settings_des\">Gunakan kecerahan sistem dalam pemain apl dan bukannya tindanan gelap</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"speech_recognition_unavailable\">Pengecaman pertuturan tidak tersedia</string>\n    <string name=\"begin_speaking\">Mula Bercakap…</string>\n    <string name=\"torrent_info\">Video ini adalah torrent, ini bermakna aktiviti video anda dapat dikesan.\\nPastikan anda memahami torrenting sebelum meneruskan.</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Pemain Mencari Amaun (Seconds)</string>\n    <string name=\"automatic_plugin_download_summary\">Secara automatik memasang semua plugin yang belum dipasang dari repositori yang ditambah.</string>\n    <string name=\"updates_settings\">Tunjukkan kemas kini aplikasi</string>\n    <string name=\"updates_settings_des\">Secara automatik cari kemas kini baru selepas memulakan aplikasi.</string>\n    <string name=\"redo_setup_process\">Redo Proses Persediaan</string>\n    <string name=\"apk_installer_settings\">Pemasang APK</string>\n    <string name=\"apk_installer_settings_des\">Sesetengah telefon tidak menyokong pemasang pakej baru. Cuba pilihan Legacy jika kemas kini tidak dipasang.</string>\n    <string name=\"benene\">Berikan benen kepada devs</string>\n    <string name=\"benene_des\">Diberi pisang</string>\n    <string name=\"app_language\">Bahasa App</string>\n    <string name=\"no_chromecast_support_toast\">Penyedia ini tidak mempunyai sokongan Chromecast</string>\n    <string name=\"no_links_found_toast\">Tiada pautan yang dijumpai</string>\n    <string name=\"copy_link_toast\">Pautan disalin ke papan klip</string>\n    <string name=\"play_episode_toast\">Main episod</string>\n    <string name=\"subs_default_reset_toast\">Tetapkan semula ke nilai lalai</string>\n    <string name=\"season\">Musim</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Tiada musim</string>\n    <string name=\"restore_settings\">Pulihkan data dari sandaran</string>\n    <string name=\"backup_settings\">Sandarkan data</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Gagal pulihkan data dari fail %s</string>\n    <string name=\"backup_failed_error_format\">Ralat sandaran %s</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Akan datang pada %s</string>\n    <string name=\"delete_message\" formatted=\"true\">Ini akan memadamkan secara kekal %s\\nAdakah anda pasti?</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Adakah anda pasti mahu memadamkan item berikut secara kekal?\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Adakah anda pasti mahu memadamkan episod berikut secara kekal %1$s?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Anda juga akan memadamkan semua episod dalam siri berikut secara kekal:\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Adakah anda pasti mahu memadamkan semua episod dalam siri berikut secara kekal?\\n\\n%s</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\nyang tinggal</string>\n    <string name=\"status_ongoing\">Sedang berlangsung</string>\n    <string name=\"rating\">Penilaian</string>\n    <string name=\"movies\">Filem</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"documentaries\">Dokumentari</string>\n    <string name=\"livestreams\">Siaran Langsung</string>\n    <string name=\"movies_singular\">Movie</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Dokumentari</string>\n    <string name=\"live_singular\">Siaran Langsung</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+mt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"subtitles_settings\">Preferenzi tas-sottotitli</string>\n    <string name=\"subs_text_color\">Kulur tal-kitba</string>\n    <string name=\"subs_window_color\">Kulur tat-Tieqa</string>\n    <string name=\"search_provider_text_types\">Fittex bl-użu ta \\'tipi</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importa fonts billi tpoġġihom ġo %s</string>\n    <string name=\"vpn_torrent\">Dan il-fornitur huwa torrent, VPN huwa rakkomandat</string>\n    <string name=\"cast_format\" formatted=\"true\">Atturi: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">L-episodju %d ha johrog fil</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"result_poster_img_des\">Kartellun</string>\n    <string name=\"search_poster_img_des\">Kartellun</string>\n    <string name=\"episode_poster_img_des\">Kartellun tal-episodju</string>\n    <string name=\"home_main_poster_img_des\">Kartellun Principali</string>\n    <string name=\"home_next_random_img_des\">Li jmiss bl\\'addoċċ</string>\n    <string name=\"home_change_provider_img_des\">Ibdel Il-fornitur</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">veloċità (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Klassifikazzjoni: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Aġġornament ġdid misjub!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Ara bil-CloudStream</string>\n    <string name=\"title_home\">Dar</string>\n    <string name=\"title_search\">Fittex</string>\n    <string name=\"title_downloads\">Imnizzel</string>\n    <string name=\"title_settings\">Preferenzi</string>\n    <string name=\"search_hint\">Fittex…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Fittex%s…</string>\n    <string name=\"no_data\">Bla dejta</string>\n    <string name=\"episode_more_options_des\">Iktar Preferenzi</string>\n    <string name=\"next_episode\">L-episodju li\\'jmiss</string>\n    <string name=\"result_tags\">Ġeneri</string>\n    <string name=\"result_share\">Aqsam</string>\n    <string name=\"result_open_in_browser\">Iftah fil-brawser</string>\n    <string name=\"browser\">Brawser</string>\n    <string name=\"skip_loading\">Aqbez it-tagħbija</string>\n    <string name=\"loading\">Tagħbija…</string>\n    <string name=\"type_watching\">Jaraw</string>\n    <string name=\"type_on_hold\">Stenna ftit</string>\n    <string name=\"type_completed\">Lest</string>\n    <string name=\"type_dropped\">Imwaqqa</string>\n    <string name=\"type_plan_to_watch\">Pjana biex tara</string>\n    <string name=\"type_re_watching\">Terġa\\' tara</string>\n    <string name=\"play_trailer_button\">Ibda t-trejler</string>\n    <string name=\"play_livestream_button\">Ibda l-livestream</string>\n    <string name=\"play_torrent_button\">Stream Torrent</string>\n    <string name=\"pick_source\">Sorsi</string>\n    <string name=\"reload_error\">Erġa\\' pprova l-konnessjoni…</string>\n    <string name=\"go_back\">Mur lura</string>\n    <string name=\"play_episode\">Ibda l-episodju</string>\n    <string name=\"download_paused\">Tniżżila ppawzata</string>\n    <string name=\"downloading\">Qed jinżlu</string>\n    <string name=\"downloaded\">Imniżżel</string>\n    <string name=\"download_canceled\">Tniżżil ikkanċellat</string>\n    <string name=\"download_done\">Lest it-tniżżil</string>\n    <string name=\"update_started\">Beda l-aġġornament</string>\n    <string name=\"stream\">Network stream</string>\n    <string name=\"error_loading_links_toast\">Tagħbija tal-Links falliet</string>\n    <string name=\"links_reloaded_toast\">Links regaw gew mogħbija</string>\n    <string name=\"download_storage_text\">Ħażna Interna</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"home_play\">Ibda</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"action_add_to_bookmarks\">Issettja l-istatus ta-rajtux</string>\n    <string name=\"sort_apply\">Applika</string>\n    <string name=\"sort_copy\">Ikkopja</string>\n    <string name=\"sort_close\">Għalaq</string>\n    <string name=\"sort_clear\">Neħħi</string>\n    <string name=\"sort_save\">Issevja</string>\n    <string name=\"repo_copy_label\">Isem tar-repożitorju u URL</string>\n    <string name=\"toast_copied\">Ikkupjat!</string>\n    <string name=\"subscribe_tooltip\">Notifika ta\\' episodju ġdid</string>\n    <string name=\"result_search_tooltip\">Fittex f\\'estensjonijiet oħra</string>\n    <string name=\"recommendations_tooltip\">Uri r-rakkomandazzjonijiet</string>\n    <string name=\"player_speed\">Veloċità tal-Plejer</string>\n    <string name=\"subs_outline_color\">Kulur tal-Kontorn</string>\n    <string name=\"subs_background_color\">Kulur tal-Isfond</string>\n    <string name=\"subs_edge_type\">Tip tat-tarf</string>\n    <string name=\"subs_subtitle_elevation\">Elevazzjoni tas-Sottotitolu</string>\n    <string name=\"subs_font\">Font</string>\n    <string name=\"subs_font_size\">Daqs tal-font</string>\n    <string name=\"search_provider_text_providers\">Fittex bl-użu ta\\' fornituri</string>\n    <string name=\"benene_count_text\">%d Benenes mogħtija lil devs</string>\n    <string name=\"benene_count_text_none\">Ebda Benenes mogħtija</string>\n    <string name=\"subs_auto_select_language\">Agħżel il-Lingwa Awtomatikament</string>\n    <string name=\"subs_download_languages\">Niżżel Lingwi</string>\n    <string name=\"subs_subtitle_languages\">Lingwa tas-sottotitolu</string>\n    <string name=\"subs_hold_to_reset_to_default\">Żomm biex tirrisettja għal default</string>\n    <string name=\"continue_watching\">Kompli Ara</string>\n    <string name=\"action_remove_watching\">Neħħi</string>\n    <string name=\"action_open_watching\">Iktar informazzjoni</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Jista\\' jkun hemm bżonn ta\\' VPN biex dan il-fornitur jaħdem b\\'mod korrett</string>\n    <string name=\"provider_info_meta\">Il-metadata mhix ipprovduta mis-sit, it-tagħbija tal-vidjo se tfalli jekk ma teżistix fuq is-sit.</string>\n    <string name=\"torrent_plot\">Deskrizzjoni</string>\n    <string name=\"normal_no_plot\">Lebda Plot misjub</string>\n    <string name=\"torrent_no_plot\">Lebda Deskrizzjoni misjuba</string>\n    <string name=\"show_log_cat\">Uri Logcat 🐈</string>\n    <string name=\"test_log\">ġurnal</string>\n    <string name=\"picture_in_picture\">Stampa f-istampa</string>\n    <string name=\"picture_in_picture_des\">Ikompli d-daqq fi player minjatura fuq apps oħra</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"go_back_img_des\">Mur Lura</string>\n    <string name=\"preview_background_img_des\">Ara l\\'isfond</string>\n    <string name=\"filler\" formatted=\"true\">Mili</string>\n    <string name=\"play_movie_button\">Ibda l-film</string>\n    <string name=\"pick_subtitle\">Sottotitli</string>\n    <string name=\"app_subbed_text\">Sut</string>\n    <string name=\"popup_play_file\">Ibda l-fajl</string>\n    <string name=\"download\">Niżżel</string>\n    <string name=\"popup_delete_file\">Hassar il-fajl</string>\n    <string name=\"popup_resume_download\">Kompli Nizzel</string>\n    <string name=\"popup_pause_download\">Ieqaf Nizzel</string>\n    <string name=\"home_more_info\">Iktar Informazzjoni</string>\n    <string name=\"home_expanded_hide\">Aħbi</string>\n    <string name=\"filter_bookmarks\">Iffiltra l-Bookmarks</string>\n    <string name=\"download_started\">Beda t-tniżżil</string>\n    <string name=\"error_bookmarks_text\">Bookmarks</string>\n    <string name=\"action_remove_from_bookmarks\">Neħħi</string>\n    <string name=\"download_failed\">Falla t-tniżżil</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+my/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"cast_format\" formatted=\"true\">သရုပ်ဆောင်များ: %s</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dရက် %2$ddနာရီ %3$ddမိနစ်</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$ddနာရီ %2$ddမိနစ်</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%ddမိနစ်</string>\n    <string name=\"search_poster_img_des\">ပိုစတာ</string>\n    <string name=\"episode_poster_img_des\">အပိုင်း ပိုစတာ</string>\n    <string name=\"home_main_poster_img_des\">မိန်း ပိုစတာ</string>\n    <string name=\"home_next_random_img_des\">နောက် ကျပန်း</string>\n    <string name=\"go_back_img_des\">နောက်သို့</string>\n    <string name=\"preview_background_img_des\">နောက်ခံပုံရိပ်ကို အကြိုကြည့်ရန်</string>\n    <string name=\"rated_format\" formatted=\"true\">အဆင့်: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">အပ်ဒိတ်အသစ်!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">စစ်ထုတ်မှု</string>\n    <string name=\"duration_format\" formatted=\"true\">%d မိနစ်</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">CloudStream ဖြင့်ကြည့်ရန်</string>\n    <string name=\"title_home\">ပင်မ</string>\n    <string name=\"title_search\">ရှာရန်</string>\n    <string name=\"search_hint\">ရှာရန်…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">ရှာရန် %s…</string>\n    <string name=\"no_data\">အချက်အလက်မရှိပါ</string>\n    <string name=\"episode_more_options_des\">အခြားရွေးစရာများ</string>\n    <string name=\"next_episode\">နောက်အပိုင်း</string>\n    <string name=\"result_tags\">ကဏ္ဍများ</string>\n    <string name=\"result_share\">မျှဝေမည်</string>\n    <string name=\"result_open_in_browser\">ဘရောက်ဇာတွင်ဖွင့်ရန်</string>\n    <string name=\"browser\">ဘရောက်ဇာ</string>\n    <string name=\"skip_loading\">မစောင့်တော့ပါ</string>\n    <string name=\"type_watching\">ကြည့်နေသည်</string>\n    <string name=\"type_completed\">ကြည့်ပြီး</string>\n    <string name=\"type_dropped\">ကြည့်ခြင်းရပ်ထားသော</string>\n    <string name=\"error_loading_links_toast\">လင့်များချိတ်ဆက်ရာတွင်အချို့အယွင်း</string>\n    <string name=\"download_storage_text\">ဖုန်း သိုလှောင်ရုံ</string>\n    <string name=\"filter_bookmarks\">စာမှတ်များ စစ်ထုတ်မှု</string>\n    <string name=\"error_bookmarks_text\">စာမှတ်များ</string>\n    <string name=\"action_remove_from_bookmarks\">ဖယ်ရှားရန်</string>\n    <string name=\"action_add_to_bookmarks\">ကြည့်ရှုမှုအခြေအနေသတ်မှတ်ခြင်း</string>\n    <string name=\"sort_copy\">မိတ္တူကူးရန်</string>\n    <string name=\"sort_close\">ပိတ်ရန်</string>\n    <string name=\"sort_clear\">ရှင်းလင်းရန်</string>\n    <string name=\"sort_save\">သိမ်းဆည်းရန်</string>\n    <string name=\"player_speed\">ကြည့်ရှုမှုအရှိန်</string>\n    <string name=\"subs_background_color\">နောက်ခံ အရောင်</string>\n    <string name=\"subs_window_color\">ဝင်းဒိုး အရောင်</string>\n    <string name=\"subs_edge_type\">အစွန်းနားပုံစံ</string>\n    <string name=\"subs_subtitle_elevation\">စာတန်းထိုး အမြင့်</string>\n    <string name=\"subs_font\">ဖောင့်</string>\n    <string name=\"subs_font_size\">ဖောင့် အရွယ်အစား</string>\n    <string name=\"search_provider_text_types\">အမျိုးအစားများအသုံးပြု၍ရှာရန်</string>\n    <string name=\"benene_count_text\">%d အက်ပ်ဖန်တီးသူတွေကိုကျေးဇူးတင်ကြောင်းပို့မည်</string>\n    <string name=\"subs_auto_select_language\">အလိုအလျောက် ဘာသာစကားရွေးချယ်ခြင်း</string>\n    <string name=\"subs_download_languages\">ဒေါင်းလုဒ် လုပ်ထားသော ဘာသာစကားများ</string>\n    <string name=\"subs_hold_to_reset_to_default\">မူရင်းပုံစံအတိုင်းပြန်ထားရန်ဖိထားပါ</string>\n    <string name=\"continue_watching\">ဆက်လက်ကြည့်ရှုမည်</string>\n    <string name=\"action_remove_watching\">ဖယ်ရှားရန်</string>\n    <string name=\"action_open_watching\">ပိုမို၍</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_torrent\">ဒီဟာကတောရပ်တစ်ခုပါ ဗီပီအန်တစ်ခုသုံးဖို့အကြံပြုပါတယ်</string>\n    <string name=\"torrent_plot\">ဖော်ပြချက်</string>\n    <string name=\"normal_no_plot\">ဇာတ်လမ်းသွား မတွေ့ပါ</string>\n    <string name=\"torrent_no_plot\">ဖော်ပြချက် မရိှပါ</string>\n    <string name=\"show_log_cat\">Logcat ပြရန် 🐈</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"picture_in_picture\">ရုပ်ပုံထပ်</string>\n    <string name=\"player_size_settings\">ကြည့်ရှုမှု စခရင်အရွယ်အစားချိန်ညိှမှု</string>\n    <string name=\"player_subtitles_settings\">စာတန်းထိုးများ</string>\n    <string name=\"player_subtitles_settings_des\">ကြည့်ရှုမှုစာတန်းထိုးပြုပြင်စရာများ</string>\n    <string name=\"eigengraumode_settings\">Eigengravy လုပ်ဆောင်မှု</string>\n    <string name=\"swipe_to_seek_settings\">ရစ်ရန်ဘယ်ညာဆွဲပါ</string>\n    <string name=\"swipe_to_seek_settings_des\">သင်ရောက်နေတဲ့နေရာပြောင်းရန်ဘယ်ညာဆွဲပါ</string>\n    <string name=\"swipe_to_change_settings\">ပြုပြင်စရာရိှပါက ပွတ်ဆွဲပါ</string>\n    <string name=\"autoplay_next_settings\">နောက်အပိုင်းကို အလိုအလျောက် ဖွင့်ပါ</string>\n    <string name=\"double_tap_to_seek_settings\">ကျော်ရန်နှစ်ချက်နှိပ်ပါ</string>\n    <string name=\"double_tap_to_pause_settings\">ရပ်ရန်နှစ်ချက်နှိပ်ပါ</string>\n    <string name=\"double_tap_to_seek_amount_settings\">ကျော်လိုသောပမာဏ (စက္ကန့်များ)</string>\n    <string name=\"double_tap_to_seek_settings_des\">ရှေ့သို့ကျော်ရန် သို့ နောက်သို့ရစ်ရန် ဘယ် သို့ ညာ ပေါ်မှာနှစ်ချက်နှိပ်ပါ</string>\n    <string name=\"double_tap_to_pause_settings_des\">ရပ်ရန် အလယ်တွင်နှစ်ချက်နှိပ်ပါ</string>\n    <string name=\"use_system_brightness_settings\">ဖုန်းအလင်းအမှောင်အတိုင်းသုံးမည်</string>\n    <string name=\"use_system_brightness_settings_des\">အက်ပ်ကြည့်ရှုမှုထဲမှာ ဖုန်းအလင်းအမှောင်အတိုင်းသုံးမည်</string>\n    <string name=\"episode_sync_settings\">ကြည့်ရှုမှုတိုးတက်ခြင်းကိုအပ်ဒိတ်လုပ်ပါ</string>\n    <string name=\"restore_settings\">အရန်သိမ်းဖိုင်မှပြန်သိုလှောင်မည်</string>\n    <string name=\"backup_settings\">အရန်သိမ်းမည်</string>\n    <string name=\"restore_success\">အရန်သိမ်းဖိုင်များရယူပြီး</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">အရန်သိမ်းဖိုင်မှပြန်သိုလှောငးခြင်မအောင်မြင်ပါ %s</string>\n    <string name=\"backup_success\">သိုလှောင်ပြီး</string>\n    <string name=\"backup_failed\">သိုလှောင်ရုံခွင့်ပြုချက်မရိှပါ။ပြန်ကြိုးစားပါ။</string>\n    <string name=\"backup_failed_error_format\">အရန်သိမ်းနေစဥ်အချို့အယွင်း %s</string>\n    <string name=\"library\">လိုက်ဘရီ</string>\n    <string name=\"category_updates\">အပ်ဒိတ်များနှင့်အရန်သိမ်းဆည်းမှု</string>\n    <string name=\"advanced_search\">နက်နက်ရှိုင်းရှိုင်းရှာခြင်း</string>\n    <string name=\"advanced_search_des\">သင့်ကိုဝန်ဆောင်မှုပေးသူအလိုက်ရှာဖွေမှုရလဒ်များပေးမည်</string>\n    <string name=\"show_fillers_settings\">anime များအတွက်ဖြည့်စွက်အပိုင်းကိုပြရန်</string>\n    <string name=\"show_trailers_settings\">ထွေလာများကိုပြရန်</string>\n    <string name=\"kitsu_settings\">Kitsu မှ ပိုစတာများကိုပြရန်</string>\n    <string name=\"automatic_plugin_updates\">အလိုအလျောက် ဖြည့်စွက်လုပ်ဆောင်ချက်များကိုအပ်ဒိတ်တင်ခြင်း</string>\n    <string name=\"automatic_plugin_download_mode_title\">အပိုလုပ်ဆောင်ချက်များကိုစစ်ထုတ်ရန်မုဒ်ရွေးပါ</string>\n    <string name=\"updates_settings\">အက်ပ်အပ်ဒိတ်များပြရန်</string>\n    <string name=\"redo_setup_process\">အစီအစဥ်ချခြင်းကိုပြန်စမည်</string>\n    <string name=\"apk_installer_settings\">အက်ပ်ထည့်သွင်းခြင်း</string>\n    <string name=\"apk_installer_settings_des\">အချို့ဖုန်းတွေက အက်ပ်ထည့်သွင်းခြင်းလုပ်ဆောင်ချက်အသစ်ကို မပံ့ပိုးပါဘူး။အကယ်၍အလုပ်မဖြစ်ပါကသမားရိုးကျနည်းလမ်းကိုအသုံးပြုပါ။</string>\n    <string name=\"github\">Github</string>\n    <string name=\"no_chromecast_support_toast\">ဤဝန်ဆောင်မှုပေးသူသည် Chromecast ကိုမပံ့ပိုးပါ</string>\n    <string name=\"no_links_found_toast\">လင့်များမတွေ့ပါ</string>\n    <string name=\"copy_link_toast\">ကလစ်ဘုတ်သို့မိတ္တူကူးပြီး</string>\n    <string name=\"play_episode_toast\">အပိုင်းကြည့်မည်</string>\n    <string name=\"season\">အတွဲ</string>\n    <string name=\"no_season\">အတွဲမရှိပါ</string>\n    <string name=\"episode\">အပိုင်း</string>\n    <string name=\"episodes\">အပိုင်းများ</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"delete_message\" formatted=\"true\">ဒါကအပြီးဖျက်ခြင်းဖြစ်ပါသည် %s\n\\nသင်သေချာပါသလား။</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dမိနစ်\n\\nကျန်ရိှသည်</string>\n    <string name=\"status_ongoing\">ထုတ်လွှင့်နေဆဲ</string>\n    <string name=\"status_completed\">ထုတ်လွှင့်မှုပြီးဆုံး</string>\n    <string name=\"status\">အခြေအနေ</string>\n    <string name=\"year\">ခုနစ်</string>\n    <string name=\"rating\">အဆင့်သတ်မှတ်ချက်</string>\n    <string name=\"duration\">ကြာချိန်</string>\n    <string name=\"site\">ဆိုဒ်</string>\n    <string name=\"synopsis\">အကျဥ်းချုပ်</string>\n    <string name=\"queued\">နောက်အစီအစဥ်</string>\n    <string name=\"no_subtitles\">စာတန်းထိုးမထည့်</string>\n    <string name=\"action_default\">ပုံသေ</string>\n    <string name=\"free_storage\">ကျန်ရှိသော</string>\n    <string name=\"app_storage\">အက်ပ်</string>\n    <string name=\"movies\">ရုပ်ရှင်များ</string>\n    <string name=\"tv_series\">ဇာတ်လမ်းတွဲများ</string>\n    <string name=\"cartoons\">ကာတွန်းများ</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">ေတာရပ်များ</string>\n    <string name=\"documentaries\">မှတ်တမ်းရုပ်ရှင်များ</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">အာရှ ဒရာမာများ</string>\n    <string name=\"livestreams\">တိုက်ရိုက်ထုတ်လွှင်မှုများ</string>\n    <string name=\"nsfw\">အပြာဗီဒီယိုများ</string>\n    <string name=\"others\">အခြား</string>\n    <string name=\"movies_singular\">ရုပ်ရှင်</string>\n    <string name=\"tv_series_singular\">ဇာတ်လမ်းတွဲ</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">တောရပ်</string>\n    <string name=\"documentaries_singular\">မှတ်တမ်းရုပ်ရှင်</string>\n    <string name=\"asian_drama_singular\">အာရှ ဒရာမာ</string>\n    <string name=\"live_singular\">တိုက်ရိုက်ထုတ်လွှင့်မှု</string>\n    <string name=\"nsfw_singular\">အပြာဗီဒီယို</string>\n    <string name=\"other_singular\">ဗီဒီယို</string>\n    <string name=\"source_error\">ရင်းမြစ်အချို့အယွင်း</string>\n    <string name=\"remote_error\">အဝေးထိန်းချုပ်မှုအချို့အယွင်း</string>\n    <string name=\"render_error\">တင်ဆက်သူ အချို့အယွင်း</string>\n    <string name=\"unexpected_error\">မျှော်လင့်မထားသော အချို့အယွင်း</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast အပိုင်း</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast ဖန်သားပြင်</string>\n    <string name=\"episode_action_play_in_app\">အက်ပ်တွင်းဖွင့်</string>\n    <string name=\"episode_action_play_in_format\">ဖွင့်ရန် %s</string>\n    <string name=\"episode_action_auto_download\">အလိုအလျောက်ဒေါင်းလုဒ်</string>\n    <string name=\"episode_action_reload_links\">လင့်များကို ပြန်စစ်ရန်</string>\n    <string name=\"show_hd\">အရည်အသွေး အမှတ်အသား</string>\n    <string name=\"show_dub\">နောက်ခံအသံ အမှတ်အသား</string>\n    <string name=\"show_sub\">စာတန်း အမှတ်အသား</string>\n    <string name=\"show_title\">ခေါင်းစဥ်</string>\n    <string name=\"no_update_found\">အပ်ဒိတ်မရှိပါ</string>\n    <string name=\"check_for_update\">အပ်ဒိတ်စစ်ရန်</string>\n    <string name=\"video_lock\">လော့ခ်ခတ်ရန်</string>\n    <string name=\"video_source\">ရင်းမြစ်</string>\n    <string name=\"video_skip_op\">OPကိုကျော်ရန်</string>\n    <string name=\"skip_update\">ဒီအပ်ဒိတ်ကိုကျော်ပါ</string>\n    <string name=\"update\">အပ်ဒိတ်</string>\n    <string name=\"limit_title\">ခေါင်းစဥ်အတွက်စာလုံးရေပြည့်ခြင်း</string>\n    <string name=\"limit_title_rez\">ကြည့်ရှုမှု အရည်အသွေး</string>\n    <string name=\"video_buffer_size_settings\">ဗီဒီယိုရှေ့ပြေးသိမ်းဆည်းမှုပမာဏ</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">ကြည့်ရှုမှုဘားမြင်တွေ့ရချိန်တွင်ပြသသောပမာဏ</string>\n    <string name=\"android_tv_interface_off_seek_settings\">ဝှက်ထားသောကြည့်ရှုပြီးသောပမာဏ</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">ဝှက်ထားသည့်အခါ အသုံးပြုသည့် ရှာဖွေမှုပမာဏ</string>\n    <string name=\"video_ram_description\">Android TV ကဲ့သို့သော မမ်မိုရီနည်းသော စက်ပစ္စည်းများတွင် သတ်မှတ်နှုန်း အလွန်မြင့်မားပါက ပျက်စီးမှုများ ဖြစ်စေသည်။</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"jsdelivr_proxy\">raw.githubusercontent.com ပရောက်စီ</string>\n    <string name=\"jsdelivr_enabled\">GitHub သို့ မရောက်ရှိနိုင်ပါ။ jsDelivr ပရောက်စီကို ဖွင့်နေသည်…</string>\n    <string name=\"add_site_pref\">ကလုန်း ဆိုဒ်</string>\n    <string name=\"remove_site_pref\">ဆိုဒ်ကိုဖယ်ရှားရန်</string>\n    <string name=\"add_site_summary\">မတူညီသော URL တစ်ခုဖြင့် ရှိပြီးသား ဝဘ်ဆိုက်တစ်ခု၏ ပုံတူတစ်ခုကို ထည့်ပါ</string>\n    <string name=\"download_path_pref\">ဒေါင်းလုဒ်လမ်းကြောင်း</string>\n    <string name=\"nginx_url_pref\">NGINX ဆာဗာ URL</string>\n    <string name=\"display_subbed_dubbed_settings\">Dubbed/Subbed Anime ကိုပြသပါ</string>\n    <string name=\"resize_fit\">မျက်နှာပြင်နှင့် အံကိုက်</string>\n    <string name=\"resize_fill\">ဆန့်သည်</string>\n    <string name=\"resize_zoom\">ချဲ့သည်</string>\n    <string name=\"legal_notice\">ရှင်းလင်းချက်</string>\n    <string name=\"pref_category_bypass\">ISP ရှောင်လွှဲမှုများ</string>\n    <string name=\"pref_category_links\">လင့်များ</string>\n    <string name=\"pref_category_app_updates\">အက်ပ်အပ်ဒိတ်များ</string>\n    <string name=\"pref_category_extensions\">Extensions</string>\n    <string name=\"pref_category_actions\">ဆောင်ရွက်ချက်များ</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_android_tv\">Android တီဗွီ</string>\n    <string name=\"pref_category_subtitles\">စာတန်းထိုးများ</string>\n    <string name=\"pref_category_defaults\">ပုံသေများ</string>\n    <string name=\"pref_category_looks\">ပုံပန်းသဏ္ဌာန်</string>\n    <string name=\"category_general\">အထွေထွေ</string>\n    <string name=\"random_button_settings_desc\">ပင်မစာမျက်နှာမှာကျပန်းခလုတ်ကိုပြပါ</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s အပိုင်း %2$d</string>\n    <string name=\"next_episode_format\" formatted=\"true\">အပိုင်း %d ထုတ်လွှင့်ပြသမည်</string>\n    <string name=\"result_poster_img_des\">ပိုစတာ</string>\n    <string name=\"home_change_provider_img_des\">ပံ့ပိုးပေးသောဝန်ဆောင်မှုပြောင်းရန်</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">အရှိန် (%.2fx)</string>\n    <string name=\"title_downloads\">ဒေါင်းလုဒ်များ</string>\n    <string name=\"title_settings\">ပြင်ဆင်ရန်</string>\n    <string name=\"loading\">ခဏစောင့်ပါ…</string>\n    <string name=\"type_on_hold\">ကြည့်ဆဲ</string>\n    <string name=\"type_plan_to_watch\">ကြည့်ရန်</string>\n    <string name=\"type_re_watching\">ပြန်ကြည့်နေသည်</string>\n    <string name=\"pick_subtitle\">စာတန်းထိုး</string>\n    <string name=\"play_movie_button\">ရုပ်ရှင်ကြည့်မည်</string>\n    <string name=\"play_trailer_button\">ထွေလာ ကြည့်မည်</string>\n    <string name=\"play_livestream_button\">လိုက်ခ် ကြည့်မည်</string>\n    <string name=\"play_torrent_button\">တောရပ် ကြည့်မည်</string>\n    <string name=\"pick_source\">ရင်းမြစ်များ</string>\n    <string name=\"reload_error\">ချိတ်ဆက်မှုပြန်ကြိုးစား…</string>\n    <string name=\"go_back\">နောက်သို့</string>\n    <string name=\"play_episode\">အပိုင်း ကြည့်မည်</string>\n    <string name=\"download\">ဒေါင်းလုဒ်</string>\n    <string name=\"downloaded\">ဒေါင်းလုဒ် လုပ်ပြီး</string>\n    <string name=\"downloading\">ဒေါင်းလုဒ် လုပ်နေသည်</string>\n    <string name=\"download_paused\">ဒေါင်းလုဒ် ရပ်ထား</string>\n    <string name=\"download_started\">ဒေါင်းလုဒ်စတင်</string>\n    <string name=\"download_failed\">ဒေါင်းလုဒ် မအောင်မြင်</string>\n    <string name=\"download_canceled\">ဒေါင်းလုဒ် ပယ်ဖျက်ပြီး</string>\n    <string name=\"download_done\">ဒေါင်းလုဒ်ပြီးစီး</string>\n    <string name=\"update_started\">အပ်ဒိတ်စတင်</string>\n    <string name=\"stream\">တိုက်ရိုက်ကြည့်မည်</string>\n    <string name=\"app_dubbed_text\">နောက်ခံအသံ</string>\n    <string name=\"pref_filter_search_quality\">ရှာဖွေမှုရလဒ်များတွင်ရွေးချယ်ထားသောဗီဒီယိုအရည်အသွေးကိုဝှက်ထားရန်</string>\n    <string name=\"app_subbed_text\">စာတန်းထိုး</string>\n    <string name=\"popup_delete_file\">ဖိုင်ဖျက်ရန်</string>\n    <string name=\"popup_play_file\">ဖိုင်ကို ဖွင့်ရန်</string>\n    <string name=\"popup_resume_download\">ဒေါင်းလုဒ် ဆက်လုပ်ရန်</string>\n    <string name=\"popup_pause_download\">ဒေါင်းလုဒ် ရပ်ရန်</string>\n    <string name=\"home_more_info\">ပိုမို၍</string>\n    <string name=\"search_provider_text_providers\">ပ့ံပိုးပေးသောဝန်ဆောင်မှုများအသုံးပြု၍ရှာရန်</string>\n    <string name=\"home_expanded_hide\">ဝုက်ရန်</string>\n    <string name=\"benene_count_text_none\">ကျေးဇူးတင်ကြောင်းမပို့ရသေး</string>\n    <string name=\"home_play\">ကြည့်မည်</string>\n    <string name=\"home_info\">အချက်အလက်</string>\n    <string name=\"subs_subtitle_languages\">စာတန်းထိုး ဘာသာစကား</string>\n    <string name=\"subs_import_text\" formatted=\"true\">ဒီမှာနေရာချခြင်းဖြင့်ဖောင့်များကိုသွင်းပါ %s</string>\n    <string name=\"sort_apply\">အတည်ပြု</string>\n    <string name=\"subtitles_settings\">စာတန်းထိုး ပြုပြင်ခြင်း</string>\n    <string name=\"subs_text_color\">စာသား အရောင်</string>\n    <string name=\"subs_outline_color\">အနားကွပ် အရောင်</string>\n    <string name=\"vpn_might_be_needed\">ဒီပံ့ပိုးမှုကောင်းမွန်စွာအလုပ်လုပ်ရန်ဗီပီအန်တစ်ခုလိုနိုင်ပါတယ်</string>\n    <string name=\"provider_info_meta\">အသေးစိတ်အချက်အလက်များပြမထားပါ။ဝဘ်ဆိုဒ်ပေါ်မှာမရှိလျှင်ကြည့်ရှု၍မရနိုင်ပါ။</string>\n    <string name=\"automatic_plugin_download\">ဖြည့်စွက်လုပ်ဆောင်ချက်များကို အလိုအလျောက်ဒေါင်းလုဒ်လုပ်ခြင်း</string>\n    <string name=\"automatic_plugin_download_summary\">ရီပိုစစ်ထရီများမှမထည့်သွင်းရသေးသောဖြည့်စွက်လုပ်ဆောင်ချက်များအားလုံးကိုထည့်သွင်းပါ။</string>\n    <string name=\"picture_in_picture_des\">ပြန်ကြည့်ခြင်းကိုအသေးစား ကြည့်ရှုမှုတွင်ဆက်ပြပါ</string>\n    <string name=\"player_size_settings_des\">အနက်ရောင်ဘောင်များကို ဖယ်ရှားရန်</string>\n    <string name=\"updates_settings_des\">အက်ပ်ထဲဝင်လိုက်သည့်နှင့်အက်ပ်အပ်ဒိတ်ကိုစစ်ဆေးပါ။</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast စာတန်းထိုးများ</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast စာတန်းထိုး ပြုပြင်ရန်</string>\n    <string name=\"swipe_to_change_settings_des\">အသံအတိုးအကျယ်နှင့်အလင်းအမှောင်များကိုချိန်ညိှရန် ဘယ် သို့ ညာ ဘက်တွင် အပေါ်အောက်ဆွဲပါ</string>\n    <string name=\"autoplay_next_settings_des\">ယခုကြည့်နေသောအပိုင်းပြီးပါကနောက်အပိုင်းကိုဖွင့်ပါ</string>\n    <string name=\"episode_sync_settings_des\">သင့်၏အပိုင်းကြည်ရှုမှုရောက်ရှိနေရာကိုအလိုအလျောက်သိမ်းဆည်းပါ</string>\n    <string name=\"search\">ရှာရန်</string>\n    <string name=\"category_account\">အကောင့်များ</string>\n    <string name=\"settings_info\">အချက်အလက်</string>\n    <string name=\"android_tv_interface_on_seek_settings\">ကြည့်ရှုပြီးသောအချိန်ပမာဏ</string>\n    <string name=\"video_disk_description\">Android TV ကဲ့သို့သော သိုလှောင်မှုနေရာနည်းပါးသော စက်ပစ္စည်းများတွင် အလွန်မြင့်မားစွာ သတ်မှတ်ပါက ပြဿနာများ ဖြစ်လာနိုင်သည်။</string>\n    <string name=\"dns_pref_summary\">ISP ပိတ်ဆို့ခြင်းကို ကျော်လွှားရန်အတွက် အသုံးဝင်သည်</string>\n    <string name=\"jsdelivr_proxy_summary\">jsDelivr ကို အသုံးပြု၍ GitHub ပိတ်ဆို့ခြင်းကို ကျော်ဖြတ်သည်။ အပ်ဒိတ်များကို ရက်အနည်းငယ်ကြာအောင် နှောင့်နှေးစေနိုင်သည်။</string>\n    <string name=\"pref_category_backup\">အရန်သိမ်းထားသော</string>\n    <string name=\"pref_category_gestures\">လက်ဟန်များ</string>\n    <string name=\"pref_category_player_features\">ကြည့်ရှုမှုလုပ်ဆောင်ချက်များ</string>\n    <string name=\"pref_category_player_layout\">အပြင်အဆင်</string>\n    <string name=\"pref_category_ui_features\">လုပ်ဆောင်ချက်များ</string>\n    <string name=\"random_button_settings\">ကျပန်းခလုတ်</string>\n    <string name=\"lightnovel\">တူညီသောအက်ပ်ရေးသားသူများ၏ ဝတ္ထုရှည်များဖတ်နိုင်သည့် အက်ပ်</string>\n    <string name=\"anim\">တူညီသောအက်ပ်ရေးသားသူများ၏ Anime အက်ပ်</string>\n    <string name=\"discord\">Discord ကိုဝင်ရန်</string>\n    <string name=\"benene\">အက်ပ်ရေးသားသူများထံ ကျေးဇူးတင်စာပို့မည်</string>\n    <string name=\"benene_des\">ပေးခဲ့သောစာအရေအတွက်</string>\n    <string name=\"app_language\">အက်ပ်ဘာသာစကား</string>\n    <string name=\"subs_default_reset_toast\">မူလအခြေအနေများကိုပြန်ထားပါ</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"season_short\">အတွဲ</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"episode_short\">အပိုင်း</string>\n    <string name=\"no_episodes_found\">အပိုင်းများမတွေ့ပါ</string>\n    <string name=\"delete_file\">ဖိုင်ကိုဖျက်ရန်</string>\n    <string name=\"delete\">ဖျက်ရန်</string>\n    <string name=\"cancel\">ပယ်ဖျက်ရန်</string>\n    <string name=\"pause\">ရပ်ရန်</string>\n    <string name=\"start\">စရန်</string>\n    <string name=\"test_failed\">မအောင်မြင်ပါ</string>\n    <string name=\"test_passed\">ကျော်ဖြတ်ပြီး</string>\n    <string name=\"resume\">ကြည့်လက်စ</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"used_storage\">အသုံးပြုပြီးသော</string>\n    <string name=\"cartoons_singular\">ကာတွန်း</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"storage_error\">ဒေါင်းလုဒ် အချို့အယွင်း၊သိုလှောင်ရုံခွင့်ပြုချက်တွေကိုစစ်ဆေးပါ</string>\n    <string name=\"episode_action_download_mirror\">ဒေါင်းလုဒ် ကြေးမုံ</string>\n    <string name=\"episode_action_download_subtitle\">စာတန်းထိုးများကို ဒေါင်းလုဒ်လုပ်ရန်</string>\n    <string name=\"poster_ui_settings\">ပိုစတာပေါ်ရှိ UI အစိတ်အပိုင်းများကို ပြောင်းပါ</string>\n    <string name=\"video_aspect_ratio_resize\">ပြန်ညိှ</string>\n    <string name=\"dont_show_again\">နောက်ထပ်မပြရန်</string>\n    <string name=\"watch_quality_pref\">ဝိုင်ဖိုင်ဖြင့်ကြည့်စဥ်ဗီဒီယိုအရည်အသွေး</string>\n    <string name=\"watch_quality_pref_data\">မိုဘိုင်းဒေတာဖြင့်ကြည့်စဥ်ဗီဒီယိုအရည်အသွေး</string>\n    <string name=\"video_buffer_length_settings\">ဗီဒီယိုရှေ့ပြေးသိမ်းဆည်းမှုအကွာအဝေး</string>\n    <string name=\"video_buffer_disk_settings\">ဗီဒီယိုcacheအများ</string>\n    <string name=\"video_buffer_clear_settings\">ဗီဒီယို cache နှင့် ရုပ်ပုံ cache များကိူရှင်းလင်းရန်</string>\n    <string name=\"enable_nsfw_on_providers\">ပံ့ပိုးပေးထားသည့် ဝန်ဆောင်မှုများပေါ်တွင် အပြာဗီဒီယို ကို ဖွင့်ပါ</string>\n    <string name=\"provider_lang_settings\">ဝန်ဆောင်မှုပံ့ပိုးသူဘာသာစကား</string>\n    <string name=\"app_layout\">အက်ပ်အပြင်အဆင်</string>\n    <string name=\"preferred_media_settings\">ဦးစားပေးမီဒီယာ</string>\n    <string name=\"app_theme_settings\">အက်ပ် အပြင်အဆင်</string>\n    <string name=\"bottom_title_settings\">ပိုစတာခေါင်းစဉ်တည်နေရာ</string>\n    <string name=\"bottom_title_settings_des\">ခေါင်းစဉ်ကို ပိုစတာအောက်မှာ ထားပါ</string>\n    <string name=\"phone_layout\">ဖုန်းအပြင်အဆင်</string>\n    <string name=\"emulator_layout\">အင်မြူလိတ်တာ အပြင်အဆင်</string>\n    <string name=\"primary_color_settings\">အဓိကအရောင်</string>\n    <string name=\"recommended\">အကြံပြုသည်</string>\n    <string name=\"quality_dvd\">ဒီဗွီဒီ</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"network_adress_example\">ထုတ်လွှင့်ရန် လင့်ခ် နှင့်ချိတ်ပါ</string>\n    <string name=\"referer\">ရည်ညွှန်းသည်</string>\n    <string name=\"next\">ရှေ့သို့</string>\n    <string name=\"previous\">နောက်သို့</string>\n    <string name=\"plugins_updated\" formatted=\"true\">အပ်ဒိတ်လုပ်ပြီး %d ဖြည့်စွက်များ</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">ဒေါင်းလုဒ်မလုပ်ရသေး: %d</string>\n    <string name=\"app_not_found_error\">အက်ပ်မတွေ့ပါ</string>\n    <string name=\"all_languages_preference\">ဘာသာစကားအားလုံး</string>\n    <string name=\"skip_type_format\" formatted=\"true\">ကျော်ရန် %s</string>\n    <string name=\"skip_type_recap\">အစမှပြန်စ</string>\n    <string name=\"skip_type_mixed_ed\">ရောထားသောအဆုံးပိုင်း</string>\n    <string name=\"skip_type_mixed_op\">ရောထားသောအစပိုင်း</string>\n    <string name=\"skip_type_creddits\">ခရက်ဒစ်များ</string>\n    <string name=\"skip_type_intro\">အစ</string>\n    <string name=\"yes\">သေချာသည်</string>\n    <string name=\"apk_installer_legacy\">သမားရိုးကျ</string>\n    <string name=\"apk_installer_package_installer\">ထည့်သွင်းသူ</string>\n    <string name=\"delayed_update_notice\">ထွက်ချိန်တွင် အက်ပ်ကို အပ်ဒိတ်လုပ်ပါမည်</string>\n    <string name=\"blank_repo_message\">CloudStream တွင် မူရင်းအတိုင်း ထည့်သွင်းထားသည့်ဆိုက်များ မရှိပါ။ ရီပိုစစ်ထရီများ မှ ဆိုဒ် များကို ထည့်သွင်းရန်လိုအပ်သည်။\n\\n\n\\nSky UK Limited မှ ဦးနှောက်မဲ့ DMCA ကို ဖယ်ရှားလိုက်ခြင်းကြောင့် 🤮 ကျွန်ုပ်တို့သည် ရီပိုစစ်ထရီဆိုဒ်ကို အက်ပ်တွင် ချိတ်ဆက်၍မရပါ။\n\\n\n\\nကျွန်ုပ်တို့၏ Discord တွင်ပါဝင်ပါ သို့မဟုတ် အွန်လိုင်းတွင်ရှာဖွေပါ။</string>\n    <string name=\"view_public_repositories_button\">အခြားသူများ၏ရီပိုစစ်ထရီများကိုရှာဖွေမည်</string>\n    <string name=\"tracks\">အသံများ</string>\n    <string name=\"audio_tracks\">အသံဖိုင်များ</string>\n    <string name=\"video_tracks\">ဗီဒီယိုအသံဖိုင်များ</string>\n    <string name=\"apply_on_restart\">ပြန်စတင်ချိန်မှာအသုံးပြုပါ</string>\n    <string name=\"stop\">ရပ်ရန်</string>\n    <string name=\"safe_mode_title\">လုံခြုံသောမုဖွင့်ရန်</string>\n    <string name=\"player_settings_play_in_app\">ဖုန်းတွင်းကြည့်ရှုမှု</string>\n    <string name=\"player_pref\">ဦးစားပေး ဗီဒီယိုဖွင့်စက်</string>\n    <string name=\"safe_mode_description\">ပြဿနာဖြစ်စေသည့်အရာကို သင်ရှာဖွေရာတွင် အထောက်အကူဖြစ်စေရန်အတွက် ပျက်စီးမှုတစ်ခုကြောင့် အဆက်များအားလုံးကို ပိတ်ထားသည်။</string>\n    <string name=\"extension_rating\" formatted=\"true\">အဆင့်သတ်မှတ်ချက်များ: %s</string>\n    <string name=\"safe_mode_crash_info\">ပျက်စီးမှုအချက်အလက်ကို ကြည့်ပါ</string>\n    <string name=\"extension_description\">ဖော်ပြချက်</string>\n    <string name=\"extension_version\">ဗားရှင်း</string>\n    <string name=\"extension_status\">အခြေအနေ</string>\n    <string name=\"extension_size\">အရွယ်အစား</string>\n    <string name=\"extension_authors\">ရေးသားသူများ</string>\n    <string name=\"hls_playlist\">HLS ဖွင့်စဥ်</string>\n    <string name=\"history\">ကြည့်ရှုခဲ့သည်များ</string>\n    <string name=\"update_notification_failed\">အက်ပ်၏ ဗားရှင်းအသစ်ကို ထည့်သွင်း၍မရပါ</string>\n    <string name=\"enable_skip_op_from_database_des\">အစပိုင်း/အဆုံးပိုင်းအတွက် ကျော်နိုင်သော ပေါ့ပ်အပ်များကို ပြပါ</string>\n    <string name=\"clipboard_too_large\">စာသားအလွန်များသဖြင့်ကလစ်ဘုတ်တွင် သိမ်းဆည်း၍မရပါ။</string>\n    <string name=\"category_providers\">ပံ့ပိုးပေးသူများ</string>\n    <string name=\"category_ui\">အပြင်အဆင်</string>\n    <string name=\"automatic\">အလိုအလျောက်</string>\n    <string name=\"tv_layout\">တီဗွီအပြင်အဆင်</string>\n    <string name=\"example_password\">သင့်စကားဝှက်</string>\n    <string name=\"example_username\">သင့်ယူဇာနိမ်း</string>\n    <string name=\"example_email\">သင့်အီးမေးလ် လိပ်စာ</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">သင့်ဆိုဒ်</string>\n    <string name=\"example_site_url\">example.com</string>\n    <string name=\"subtitles_shadow\">အရိပ်</string>\n    <string name=\"subtitles_raised\">ထမြောက်မှု</string>\n    <string name=\"subtitle_offset\">စာတန်းထိုးများ ထပ်တူပြုရန်</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">စာတန်းထိုးများ အလွန်စောနေပါက %d ms ဒီဟာကိုသုံးပါ</string>\n    <string name=\"subtitles_example_text\">The quick brown fox jumps over the lazy dog</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">တင်ပြီး %s</string>\n    <string name=\"player_load_subtitles\">ဖိုင်မှတင်သွင်းပြီး</string>\n    <string name=\"quality_cam_hd\">ရုံရိုက်</string>\n    <string name=\"quality_hq\">အကြည်</string>\n    <string name=\"quality_hd\">အကြည်</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"category_player\">ကြည့်ရှုမှု</string>\n    <string name=\"poster_image\">ပိုစတာပုံရိပ်</string>\n    <string name=\"subtitles_remove_bloat\">စာတန်းထိုးများမှ bloat ကိုဖယ်ရှားပါ</string>\n    <string name=\"subtitles_filter_lang\">နှစ်သက်ရာ မီဒီယာဘာသာစကားဖြင့် စစ်ထုတ်ပါ</string>\n    <string name=\"extras\">အပိုများ</string>\n    <string name=\"error_invalid_data\">ဒေတာမမှန်ပါ</string>\n    <string name=\"error_invalid_url\">URL မမှန်ပါ</string>\n    <string name=\"error\">အချို့အယွင်း</string>\n    <string name=\"subtitles_remove_captions\">စာတန်းထိုးများမှ ပိတ်ထားသော စာတန်းများကို ဖယ်ရှားပါ</string>\n    <string name=\"trailer\">ထွေလာ</string>\n    <string name=\"plugin\">ဖြည့်စွက်များ</string>\n    <string name=\"delete_repository_plugins\">ရီပိုစစ်ထရီ ဖြည့်စွက်များအားလုံးကိုဖျက်မည်ဖြစ်သည်</string>\n    <string name=\"delete_repository\">ရီပိုစစ်ထရီ ကိုဖျက်ရန်</string>\n    <string name=\"download_all_plugins_from_repo\">ဤရီပိုစစ်ထရီမှ ဖြည့်စွက်များအားလုံးကို ဒေါင်းလုဒ်လုပ်မှာလား?</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (ပိတ်ပြီး)</string>\n    <string name=\"extension_types\">ထောက်ပံ့ထားသော</string>\n    <string name=\"extension_language\">ဘာသာစကား</string>\n    <string name=\"extension_install_first\">အဆက်များကိုအရင်သွင်းပါ</string>\n    <string name=\"skip_type_op\">အစပိုင်း</string>\n    <string name=\"skip_type_ed\">အဆုံးပိုင်း</string>\n    <string name=\"clear_history\">ကြည့်ရှုခဲ့သည်များကိုရှင်းရန်</string>\n    <string name=\"action_remove_from_watched\">ကြည့်ပြီးသည်မှဖယ်ရှားရန်</string>\n    <string name=\"confirm_exit_dialog\">သင်ထွက်ရန်သေချာပြီလား</string>\n    <string name=\"no\">မသေချာပါ</string>\n    <string name=\"update_notification_downloading\">အက်ပ်အပ်ဒိတ်အားဒေါင်းလုဒ်လုပ်နေသည်…</string>\n    <string name=\"update_notification_installing\">အက်ပ်အပ်ဒိတ်အားသွင်းနေသည်…</string>\n    <string name=\"sort_updated_new\">အပ်ဒိတ်ဖြစ်မှု (အသစ် မှ အဟောင်း)</string>\n    <string name=\"empty_library_no_accounts_message\">သင့်လိုက်ဘရီသည် ဗလာဖြစ်နေသည် :(\n\\nအကောင့်ဝင်ပါ သို့မဟုတ် သင့်ဖုန်းလိုက်ဘရီတွင် ကြည့်စရာများထည့်ပါ။</string>\n    <string name=\"use\">သုံးရန်</string>\n    <string name=\"edit\">တည်းဖြတ်ရန်</string>\n    <string name=\"qualities\">အရည်အသွေးများ</string>\n    <string name=\"subtitles_encoding\">စာတန်းထိုး ကုဒ်လုပ်ခြင်း</string>\n    <string name=\"category_provider_test\">ပံ့ပိုးပေးသူ စစ်ဆေးမှု</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"login\">အကောင့်ဝင်မည်</string>\n    <string name=\"switch_account\">အကောင့်ပြောင်းမည်</string>\n    <string name=\"upload_sync\">ချိန်ညိှခြင်း</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"player_load_subtitles_online\">အင်တာနက်မှ တင်သွင်းမည်</string>\n    <string name=\"actor_background\">နောက်ခံ</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">အကောင့်မဝင်ရောက်နိုင်ပါ %s</string>\n    <string name=\"none\">ဘာမျှ</string>\n    <string name=\"min\">အနည်းဆုံး</string>\n    <string name=\"subtitles_outline\">အနားကွပ်</string>\n    <string name=\"home_random\">ကျပန်း</string>\n    <string name=\"subtitles_depressed\">ချုံ့ပြီး</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">စာတန်းထိုး ကြန့်ကြာမှု</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">စာတန်းထိုးများအလွန်နောက်ကျနေပါက %d ms ဒီဟာကိုသုံးပါ</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">စာတန်းထိုး ကြန့်ကြာမှု သတ်မှတ်ထားခြင်းမရှိ</string>\n    <string name=\"quality_cam\">ရုံရိုက်</string>\n    <string name=\"quality_cam_rip\">ရုံရိုက်</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"resolution\">အရည်အသွေး</string>\n    <string name=\"skip_setup\">အစီအစဥ်ချခြင်းကိုကျော်မည်</string>\n    <string name=\"preferred_media_subtext\">ဘာတွေကြည့်ချင်လဲ</string>\n    <string name=\"setup_done\">ပြီးပြီ</string>\n    <string name=\"extensions\">အဆက်များ</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">မသွင်းနိုင်ပါ %s</string>\n    <string name=\"app_layout_subtext\">သင့်စက်ပစ္စည်းနှင့် ကိုက်ညီစေရန် အက်ပ်၏အသွင်အပြင်ကို ပြောင်းလဲပါ</string>\n    <string name=\"add_repository\">ရီပိုစစ်ထရီထည့်ရန်</string>\n    <string name=\"is_adult\">အသက်ပြည့်ပြီးသူများသာ</string>\n    <string name=\"repository_name_hint\">ရီပိုစစ်ထရီအမည်</string>\n    <string name=\"repository_url_hint\">ရီပိုစစ်ထရီ URL</string>\n    <string name=\"plugin_loaded\">ဖြည့်စွက်များ ထည့်ပြီး</string>\n    <string name=\"provider_languages_tip\">ဤဘာသာစကားများဖြင့် ဗီဒီယိုများကို ကြည့်ရှုပါ</string>\n    <string name=\"plugin_downloaded\">ဖြည့်စွက်များ ဒေါင်းလုဒ်လုပ်ပြီး</string>\n    <string name=\"plugin_deleted\">ဖြည့်စွက်များဖျက်ပြီး</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">ဒေါင်းလုဒ်လုပ်ခြင်း စတင်သည် %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">ဒေါင်းလုဒ်လုပ်ပြီး %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">အားလုံး %s ဒေါင်းလုဒ်လုပ်ပြီးသား</string>\n    <string name=\"no_plugins_found_error\">ရီပိုစစ်ထရီထဲတွင်ဖြည့်စွက်များမတွေ့ပါ</string>\n    <string name=\"no_repository_found_error\">ရီပိုစစ်ထရီမတွေ့ပါ၊URLကိုပြန်စစ်ပြီးဗီပီအန်ဖြင့်ကြိုးစားကြည့်ပါ</string>\n    <string name=\"batch_download\">အသုတ်လိုက် ဒေါင်းလုဒ်</string>\n    <string name=\"plugin_singular\">ဖြည့်စွက်</string>\n    <string name=\"setup_extensions_subtext\">သင်အသုံးပြုလိုသောဆိုက်များစာရင်းကို ဒေါင်းလုဒ်လုပ်ပါ</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">ဒေါင်းလုဒ်လုပ်ပြီး: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">ပိတ်ပြီး: %d</string>\n    <string name=\"example_lang_name\">ဘာသာစကားကုဒ် (en)</string>\n    <string name=\"account\">အကောင့်</string>\n    <string name=\"logout\">အကောင့်ထွက်မည်</string>\n    <string name=\"add_account\">အကောင့်ထည့်မည်</string>\n    <string name=\"create_account\">အကောင့်ဖွင့်မည်</string>\n    <string name=\"add_sync\">စောင့်ကြည့်ခြင်းထည့်မည်</string>\n    <string name=\"added_sync_format\" formatted=\"true\">ထည့်ပြီး %s</string>\n    <string name=\"sync_score\">အဆင့်သတ်မှတ်ထားပြီး</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s ချိတ်ဆက်ပြီး</string>\n    <string name=\"disable\">ပိတ်ပါ</string>\n    <string name=\"normal\">ပုံမှန်</string>\n    <string name=\"all\">အားလုံး</string>\n    <string name=\"max\">အပြည့်</string>\n    <string name=\"downloaded_file\">ဖိုင်ဒေါင်းလုဒ်လုပ်ပြီး</string>\n    <string name=\"actor_main\">အဓိက</string>\n    <string name=\"actor_supporting\">ထောက်ပံ့သည်</string>\n    <string name=\"home_source\">ရင်းမြစ်</string>\n    <string name=\"coming_soon\">မကြာမီလာမည်…</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"resolution_and_title\">အရည်အသွေးနှင့်ခေါင်းစဥ်</string>\n    <string name=\"title\">ခေါင်းစဥ်</string>\n    <string name=\"error_invalid_id\">အိုင်ဒီမမှန်ပါ</string>\n    <string name=\"view_public_repositories_button_short\">အများမြင်နိုင်သော</string>\n    <string name=\"uppercase_all_subtitles\">စာတန်းထိုးအားလုံးကို စာလုံးအကြီးပြောင်းပါ</string>\n    <string name=\"restart\">ပြန်စတင်မည်</string>\n    <string name=\"action_mark_as_watched\">ကြည့်ပြီးအဖြစ်မှတ်ရန်</string>\n    <string name=\"sort_by\">အစီအစဥ်ချမှု</string>\n    <string name=\"sort\">အစီအစဥ်</string>\n    <string name=\"sort_rating_desc\">အဆင့်သတ်မှတ်ချက် (အမြင့်ဆုံးမှအနိမ့်ဆုံးသို့)</string>\n    <string name=\"sort_rating_asc\">အဆင့်သတ်မှတ်ချက် (အနိမ့်ဆုံး မှ အမြင့်ဆုံးသို့)</string>\n    <string name=\"sort_updated_old\">အပ်ဒိတ်ဖြစ်မှု (အဟောင် မှ အသစ်)</string>\n    <string name=\"sort_alphabetical_a\">အက္ခရာစဥ်လိုက် (A မှ Z)</string>\n    <string name=\"sort_alphabetical_z\">အက္ခရာစဥ်လိုက် (Z မှ A)</string>\n    <string name=\"revert\">ပြောင်းပြန်</string>\n    <string name=\"subscription_in_progress_notification\">စာရင်းသွင်းထားသောရှိုးများကိုအပ်ဒိတ်လုပ်နေသည်</string>\n    <string name=\"subscription_list_name\">စာရင်းသွင်းပြီး</string>\n    <string name=\"subscription_new\">စာရင်းသွင်းပြီး %s</string>\n    <string name=\"subscription_deleted\">စာရင်းသွင်းမှုပယ်ဖျက်ပြီး %s</string>\n    <string name=\"empty_library_logged_in_message\">ဤစာရင်းသည် ဗလာဖြစ်နေသည်။ အခြားတစ်ခုသို့ ပြောင်းကြည့်ပါ။</string>\n    <string name=\"safe_mode_file\">Safe mode ဖိုင်ကို တွေ့ရှိခဲ့သည်။\n\\nဖိုင်ကိုမဖယ်ရှားမချင်း စတင်ဖွင့်စတွင် မည်သည့် extension များကိုမျှ မတင်ပါ။</string>\n    <string name=\"subscription_episode_released\">အပိုင်းသစ် %d ထွက်ပြီ</string>\n    <string name=\"profile_number\">ပရိုဖိုင် %d</string>\n    <string name=\"wifi\">ဝိုင်ဖိုင်</string>\n    <string name=\"mobile_data\">မိုဘိုင်းဒေတာ</string>\n    <string name=\"set_default\">ပုံသေထားရန်</string>\n    <string name=\"profiles\">ပရိုဖိုင်များ</string>\n    <string name=\"help\">အကူအညီ</string>\n    <string name=\"quality_profile_help\">ဤနေရာတွင် သင်သည် အရင်းအမြစ်များကို မည်ကဲ့သို့ အစီအစဥ်ချမည်ကို ပြောင်းလဲနိုင်သည်။ ဗီဒီယိုတစ်ခုတွင် ပိုမိုဦးစားပေးပါက ရင်းမြစ်ရွေးချယ်မှုတွင် ပိုမိုမြင့်မားလာမည်ဖြစ်သည်။ အရင်းအမြစ် ဦးစားပေးနှင့် အရည်အသွေး ဦးစားပေး၏ ပေါင်းစုသည် ဗီဒီယို ဦးစားပေးဖြစ်သည်။\n\\n\n\\nအရင်းအမြစ် A: 3\n\\nအရည်အသွေး B: 7\n\\nပေါင်းစပ်ဗီဒီယို ဦးစားပေး 10 ခု ရှိပါမည်။\n\\n\n\\nမှတ်ချက်- ပေါင်းလဒ်သည် 10 သို့မဟုတ် ထို့ထက်ပိုပါက ထိုလင့်ခ်ကို တင်သည့်အခါ ဗီဒီယိုဖွင့်စက်သည် အလိုအလျောက် ဒေါင်းလုဒ်ကို ကျော်သွားမည်ဖြစ်သည်</string>\n    <string name=\"profile_background_des\">ပရိုဖိုင်နောက်ခံ</string>\n    <string name=\"unable_to_inflate\">UI ကို မှန်ကန်စွာ ဖန်တီး၍မရပါ၊ ၎င်းသည် အဓိက ချို့ယွင်းချက်တစ်ခုဖြစ်ပြီး ချက်ချင်းသတင်းပို့သင့်သည်။ %s</string>\n    <string name=\"already_voted\">သင်နဂိုတည်းကသတ်မှတ်ပြီး</string>\n    <string name=\"select_library\">လိုက်ဘရီရွေးချယ်ရန်</string>\n    <string name=\"open_with\">ဖြင့်ဖွင့်မည်</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ne/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"player_speed_text_format\" formatted=\"true\">गति (%.2fx)</string>\n    <string name=\"home_next_random_img_des\">अर्को अनियमित</string>\n    <string name=\"preview_background_img_des\">पृष्ठभूमि देखाउनुहोस्</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"search_poster_img_des\">पोस्टर</string>\n    <string name=\"go_back_img_des\">पछाडी जाउ</string>\n    <string name=\"episode_poster_img_des\">एपिसोडको पोस्टर</string>\n    <string name=\"home_change_provider_img_des\">प्रोवाइडर परिवर्तन गर्नुहोस्</string>\n    <string name=\"rated_format\" formatted=\"true\">रेटिंग: %.1f</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"result_poster_img_des\">विज्ञापन</string>\n    <string name=\"home_main_poster_img_des\">मुख्य पोस्टर</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">अभिनेता:%s</string>\n    <string name=\"new_update_format\" formatted=\"true\">नयाँ अपडेट भेटियो!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">फिलर</string>\n    <string name=\"duration_format\" formatted=\"true\">%d मिनेट</string>\n    <string name=\"app_name\">क्लाउडस्ट्रीम</string>\n    <string name=\"play_with_app_name\">क्लाउडस्ट्रीममा प्ले गर्नुहोस्</string>\n    <string name=\"title_home\">होम्</string>\n    <string name=\"title_search\">खोजी</string>\n    <string name=\"title_downloads\">डाउनलोडस</string>\n    <string name=\"title_settings\">सेटिङह</string>\n    <string name=\"search_hint\">खोज्नुहोस्…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">%s खोज्नुहोस्…</string>\n    <string name=\"episode_more_options_des\">थप विकल्पहरू</string>\n    <string name=\"result_tags\">विधाहरू</string>\n    <string name=\"result_share\">सेयर गर्नुहोस्</string>\n    <string name=\"result_open_in_browser\">ब्राउजरमा खाेल्नुहाेस्</string>\n    <string name=\"browser\">ब्राउजर</string>\n    <string name=\"skip_loading\">लोड गर्न छोड्नुहोस्</string>\n    <string name=\"loading\">लोड हुँदै…</string>\n    <string name=\"type_on_hold\">होल्डमा भएको</string>\n    <string name=\"type_dropped\">अधुरै छाडेको</string>\n    <string name=\"type_plan_to_watch\">हेर्ने योजना</string>\n    <string name=\"play_movie_button\">चलचित्र प्ले गर्नुहोस्</string>\n    <string name=\"play_trailer_button\">ट्रेलर प्ले गर्नुहोस्</string>\n    <string name=\"play_livestream_button\">लाइभस्ट्रिम प्ले गर्नुहोस्</string>\n    <string name=\"pick_subtitle\">उपशीर्षक</string>\n    <string name=\"reload_error\">पुनः प्रयास गर्नुहोस…</string>\n    <string name=\"go_back\">पछाडि जानुहोस्</string>\n    <string name=\"play_episode\">एपिसोड प्ले गर्नुहोस्</string>\n    <string name=\"download\">डाउनलोड</string>\n    <string name=\"downloaded\">डाउनलोड भयो</string>\n    <string name=\"downloading\">डाउनलोड हुदैछ</string>\n    <string name=\"download_paused\">डाउनलोड रोकियो</string>\n    <string name=\"download_started\">डाउनलोड सुरु भयो</string>\n    <string name=\"download_failed\">डाउनलोड असफल भयो</string>\n    <string name=\"download_canceled\">डाउनलोड रद्द गरियो</string>\n    <string name=\"download_done\">डाउनलोड भयो</string>\n    <string name=\"update_started\">अपडेट सुरु</string>\n    <string name=\"stream\">नेटवर्क स्ट्रीम</string>\n    <string name=\"error_loading_links_toast\">लिङ्क लोड गर्दा त्रुटि भयो</string>\n    <string name=\"links_reloaded_toast\">लिङ्कहरू रिलोड गरियो</string>\n    <string name=\"download_storage_text\">भित्री स्टोरेज</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">फाइल मेट्नुहोस्</string>\n    <string name=\"popup_play_file\">फाइल प्ले गर्नुहोस्</string>\n    <string name=\"popup_resume_download\">डाउनलोड सुचारु गर्नुहोस्</string>\n    <string name=\"popup_pause_download\">डाउनलोड रोक्नुहोस्</string>\n    <string name=\"home_more_info\">थप जानकारी</string>\n    <string name=\"home_expanded_hide\">लुकाउनुहोस्</string>\n    <string name=\"home_play\">प्ले</string>\n    <string name=\"home_info\">जानकारी</string>\n    <string name=\"filter_bookmarks\">बुकमार्कहरू फिल्टर गर्नुहोस्</string>\n    <string name=\"error_bookmarks_text\">बुकमार्कहरू</string>\n    <string name=\"action_remove_from_bookmarks\">हटाउनुहोस्</string>\n    <string name=\"action_add_to_bookmarks\">हेरेको स्थिति निर्धारण गर्नुहोस्</string>\n    <string name=\"sort_copy\">कपी</string>\n    <string name=\"sort_close\">बन्द</string>\n    <string name=\"sort_clear\">खाली गर्नुहोस्</string>\n    <string name=\"sort_save\">सेव</string>\n    <string name=\"next_episode_format\" formatted=\"true\">एपिसोड %d रिलीज हुने समय</string>\n    <string name=\"no_data\">डाटा छैन</string>\n    <string name=\"next_episode\">अर्को एपिसोड</string>\n    <string name=\"type_watching\">हेर्दै गरेको</string>\n    <string name=\"type_completed\">पुरा भएको</string>\n    <string name=\"type_re_watching\">पुन: हेर्दै</string>\n    <string name=\"play_torrent_button\">स्ट्रिम टोरेन्ट</string>\n    <string name=\"pick_source\">स्रोतहरू</string>\n    <string name=\"sort_apply\">लागू गर्नुहोस्</string>\n    <string name=\"provider_info_meta\">साइट ले मेटाडाटा दिएको छैन,मेटाडाटा बिना भिडियो लोड नहुन सक्छ।</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">प्रकरण %1$d प्रसङ्ग %2$d प्रशारण हुनेवाला छ</string>\n    <string name=\"search_provider_text_providers\">प्रोभाईडर उपयोग गरी खोज्नुहोस्</string>\n    <string name=\"subs_download_languages\">भाषा डाउनलाेड गर्नुहोस्</string>\n    <string name=\"subs_subtitle_languages\">उपशीर्षकको भाषा</string>\n    <string name=\"vpn_torrent\">यो प्रोभाईडर torrent हो त्यसैले VPN प्रयाेग गर्नुहुन सिफारिश गरिन्छ</string>\n    <string name=\"torrent_plot\">वर्णन</string>\n    <string name=\"normal_no_plot\">केही विषय भेटिएन</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast को उपशीर्षकहरु</string>\n    <string name=\"torrent_no_plot\">केहीपनि वर्णन भेटिएन</string>\n    <string name=\"show_log_cat\">Logcat देखाउनुहोस</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"picture_in_picture\">Picture-in-picture</string>\n    <string name=\"picture_in_picture_des\">अरु एप माथी सानो प्लेयरमा पलेब्याक जारी राख्दछ</string>\n    <string name=\"player_speed\">प्लेयर स्पीड</string>\n    <string name=\"subtitles_settings\">उपशीर्षकको सेटिङ</string>\n    <string name=\"subs_window_color\">विन्डोको रंग</string>\n    <string name=\"subs_subtitle_elevation\">उपशीर्षक ऊंचाई</string>\n    <string name=\"subs_font_size\">अक्षरको नाप</string>\n    <string name=\"subs_font\">फन्ट</string>\n    <string name=\"search_provider_text_types\">प्रकारको उपयोग गरी खोज्नुहोस्</string>\n    <string name=\"benene_count_text\">%d केरा डेभलपर लाई दिइयो</string>\n    <string name=\"benene_count_text_none\">एउटै पनी केरा दिइएन</string>\n    <string name=\"continue_watching\">हेर्न सुचारु राख्नुहोस</string>\n    <string name=\"action_remove_watching\">हटाउनुहोस्</string>\n    <string name=\"player_size_settings_des\">कालो सीमा हटाउनुहोस</string>\n    <string name=\"player_subtitles_settings\">उपशीर्षक</string>\n    <string name=\"subscribe_tooltip\">नयाँ प्रसङ्ग को सूचना</string>\n    <string name=\"result_search_tooltip\">अन्य एक्सटेन्सन मा खोज्नुहोस्</string>\n    <string name=\"recommendations_tooltip\">सुुझाव हरु</string>\n    <string name=\"subs_text_color\">अक्षरको रंग</string>\n    <string name=\"subs_outline_color\">बाहिरी रेखा को रंग</string>\n    <string name=\"subs_background_color\">पृष्ठभूमिको रंग</string>\n    <string name=\"subs_edge_type\">धारको प्रकार</string>\n    <string name=\"subs_auto_select_language\">भाषा अटो छनौट</string>\n    <string name=\"subs_hold_to_reset_to_default\">रिसेट गर्न स्क्रिनमा थिचिराख्नुहोस्</string>\n    <string name=\"subs_import_text\" formatted=\"true\">फन्ट देखाउन %s मा राख्नुहोस्</string>\n    <string name=\"action_open_watching\">अधिक जानकारी</string>\n    <string name=\"vpn_might_be_needed\">यो प्रोभाईडर सही ढंगले प्रयोग गर्न VPN प्रयोग गर्नुपर्ने हुन सक्छ</string>\n    <string name=\"player_size_settings\">प्लेयर resize गर्ने वटन</string>\n    <string name=\"player_subtitles_settings_des\">प्लेयरको उपशीर्षकको सेटिङ</string>\n    <string name=\"repo_copy_label\">रिपोजिटरी को नाम र यूआरएल</string>\n    <string name=\"toast_copied\">कपी गरियो!</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Cast: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Aflevering %d zal worden uitgebracht in</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Poster</string>\n    <string name=\"episode_poster_img_des\">Aflevering Poster</string>\n    <string name=\"home_main_poster_img_des\">Hoofdposter</string>\n    <string name=\"home_next_random_img_des\">Volgende willekeurig</string>\n    <string name=\"go_back_img_des\">Ga terug</string>\n    <string name=\"home_change_provider_img_des\">Wijzig provider</string>\n    <string name=\"preview_background_img_des\">Voorbeeld Achtergrond</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Snelheid (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Beoordeeld: %.1fAls</string>\n    <string name=\"new_update_format\" formatted=\"true\">Nieuwe update gevonden!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Filler</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Afspelen met CloudStream</string>\n    <string name=\"title_home\">Home</string>\n    <string name=\"title_search\">Zoeken</string>\n    <string name=\"title_downloads\">Downloads</string>\n    <string name=\"title_settings\">Instellingen</string>\n    <string name=\"search_hint\">Zoeken…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Zoeken %s…</string>\n    <string name=\"no_data\">Geen gegevens</string>\n    <string name=\"episode_more_options_des\">Meer Opties</string>\n    <string name=\"next_episode\">Volgende aflevering</string>\n    <string name=\"result_tags\">Genres</string>\n    <string name=\"result_share\">Deel</string>\n    <string name=\"result_open_in_browser\">Openen in Browser</string>\n    <string name=\"skip_loading\">Laden overslaan</string>\n    <string name=\"loading\">Laden…</string>\n    <string name=\"type_watching\">Aan het kijken</string>\n    <string name=\"type_on_hold\">In de wacht</string>\n    <string name=\"type_completed\">Voltooid</string>\n    <string name=\"type_dropped\">Dropped</string>\n    <string name=\"type_plan_to_watch\">Plan om te kijken</string>\n    <string name=\"type_re_watching\">Opnieuw kijken</string>\n    <string name=\"play_movie_button\">Film afspelen</string>\n    <string name=\"play_livestream_button\">Livestream afspelen</string>\n    <string name=\"play_torrent_button\">Stream Torrent</string>\n    <string name=\"pick_source\">Bronnen</string>\n    <string name=\"pick_subtitle\">Ondertitels</string>\n    <string name=\"reload_error\">Opnieuw proberen…</string>\n    <string name=\"go_back\">Ga terug</string>\n    <string name=\"play_episode\">Aflevering afspelen</string>\n    <!--<string name=\"need_storage\">Allow to download episodes</string>-->\n    <string name=\"download\">Download</string>\n    <string name=\"downloaded\">Gedownload</string>\n    <string name=\"downloading\">Downloaden</string>\n    <string name=\"download_paused\">Downloaden Gepauzeerd</string>\n    <string name=\"download_started\">Download Begonnen</string>\n    <string name=\"download_failed\">Download Mislukt</string>\n    <string name=\"download_canceled\">Download Geannuleerd</string>\n    <string name=\"download_done\">Download Gereed</string>\n    <string name=\"stream\">Netwerkstream</string>\n    <string name=\"error_loading_links_toast\">Fout bij laden links</string>\n    <string name=\"download_storage_text\">Interne opslag</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Bestand verwijderen</string>\n    <string name=\"popup_play_file\">Bestand afspelen</string>\n    <string name=\"popup_resume_download\">Download hervatten</string>\n    <string name=\"popup_pause_download\">Download pauzeren</string>\n    <string name=\"home_more_info\">Meer info</string>\n    <string name=\"home_expanded_hide\">Verberg</string>\n    <string name=\"home_play\">Speel</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"filter_bookmarks\">Bladwijzers filteren</string>\n    <string name=\"error_bookmarks_text\">Bladwijzers</string>\n    <string name=\"action_remove_from_bookmarks\">Verwijder</string>\n    <string name=\"action_add_to_bookmarks\">Zet kijkstatus</string>\n    <string name=\"sort_apply\">Toepassen</string>\n    <string name=\"sort_copy\">Kopiëren</string>\n    <string name=\"sort_close\">Sluit</string>\n    <string name=\"sort_clear\">Wissen</string>\n    <string name=\"sort_save\">Opslaan</string>\n    <string name=\"player_speed\">Afspelen Snelheid</string>\n    <string name=\"subtitles_settings\">Ondertiteling</string>\n    <string name=\"subs_text_color\">Tekst kleur</string>\n    <string name=\"subs_outline_color\">Omtrekkleur</string>\n    <string name=\"subs_background_color\">Achtergrond kleur</string>\n    <string name=\"subs_window_color\">Vensterkleur</string>\n    <string name=\"subs_edge_type\">Randtype</string>\n    <string name=\"subs_subtitle_elevation\">Ondertitelhoogte</string>\n    <string name=\"subs_font\">Lettertype</string>\n    <string name=\"subs_font_size\">Lettergrootte</string>\n    <string name=\"search_provider_text_providers\">Zoeken met providers</string>\n    <string name=\"search_provider_text_types\">Zoeken met types</string>\n    <string name=\"benene_count_text\">%d Bananen gegeven aan ontwikkelaars</string>\n    <string name=\"benene_count_text_none\">Geen Bananen gegeven</string>\n    <string name=\"subs_auto_select_language\">Taal automatisch selecteren</string>\n    <string name=\"subs_download_languages\">Talen downloaden</string>\n    <string name=\"subs_subtitle_languages\">Ondertiteltaal</string>\n    <string name=\"subs_hold_to_reset_to_default\">Houd ingedrukt om naar standaard instellingen gaan</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importeer lettertypes door ze in %s</string>\n    <string name=\"continue_watching\">Doorgaan met kijken</string>\n    <string name=\"action_remove_watching\">Verwijder</string>\n    <string name=\"action_open_watching\">Meer Info</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Een VPN kan nodig zijn om deze provider correct te laten werken</string>\n    <string name=\"vpn_torrent\">Deze provider is een torrent, een VPN wordt aanbevolen</string>\n    <string name=\"provider_info_meta\">Metadata wordt niet geleverd door de site, het laden van video\\'s zal mislukken als deze niet op de site bestaat.</string>\n    <string name=\"torrent_plot\">Beschrijving</string>\n    <string name=\"normal_no_plot\">Geen plot gevonde</string>\n    <string name=\"torrent_no_plot\">Geen Beschrijving Gevonden</string>\n    <string name=\"show_log_cat\">Toon Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Beeld-in-beeld</string>\n    <string name=\"picture_in_picture_des\">Blijft afspelen in een miniatuurspeler bovenop andere apps</string>\n    <string name=\"player_size_settings\">Afspeel knop wijzig</string>\n    <string name=\"player_size_settings_des\">Verwijder de zwarte randen</string>\n    <string name=\"player_subtitles_settings\">Ondertitels</string>\n    <string name=\"player_subtitles_settings_des\">Speler Ondertiteling instellingen</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast Ondertitels</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast ondertitels instellingen</string>\n    <string name=\"eigengraumode_settings\">Afspeelsnelheid</string>\n    <string name=\"swipe_to_seek_settings\">Swipe to seek</string>\n    <string name=\"swipe_to_seek_settings_des\">Veeg naar links of rechts om de tijd in de videospeler te regelen</string>\n    <string name=\"swipe_to_change_settings\">Veeg om instellingen te wijzigen</string>\n    <string name=\"swipe_to_change_settings_des\">Veeg omhoog of omlaag aan de linker- of rechterkant om de helderheid of het volume te wijzigen</string>\n    <string name=\"double_tap_to_seek_settings\">Dubbeltik om te zien</string>\n    <string name=\"double_tap_to_pause_settings\">Dubbeltik om te pauzeren</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Videospeler aantal zoeken</string>\n    <string name=\"double_tap_to_seek_settings_des\">Tik twee keer aan de rechter- of linkerkant om vooruit of achteruit te zoeken</string>\n    <string name=\"double_tap_to_pause_settings_des\">Tik twee keer in het midden om te pauzeren</string>\n    <string name=\"use_system_brightness_settings\">Systeemhelderheid gebruiken</string>\n    <string name=\"use_system_brightness_settings_des\">Gebruik systeemhelderheid in de app-speler in plaats van een donkere overlay</string>\n    <string name=\"episode_sync_settings\">Kijkvoortgang bijwerken</string>\n    <string name=\"episode_sync_settings_des\">Automatisch synchroniseren van je huidige episode vooruitgang</string>\n    <string name=\"restore_settings\">Gegevens herstellen vanaf back-up</string>\n    <string name=\"backup_settings\">Back-up gegevens</string>\n    <string name=\"restore_success\">Geladen back-up bestand</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Kan gegevens uit bestand niet herstellen %s</string>\n    <string name=\"backup_success\">De gegevens zijn opgeslagen</string>\n    <string name=\"backup_failed\">Opslagrechten ontbreken. Probeer het opnieuw.</string>\n    <string name=\"backup_failed_error_format\">Fout bij het maken van een back-up %s</string>\n    <string name=\"search\">Zoeken</string>\n    <string name=\"category_account\">Accounts en Beveiliging</string>\n    <string name=\"category_updates\">Updates en back-up</string>\n    <string name=\"settings_info\">Info</string>\n    <string name=\"advanced_search\">Geavanceerd zoeken</string>\n    <string name=\"advanced_search_des\">Geeft u de zoekresultaten gescheiden door provider</string>\n    <string name=\"show_fillers_settings\">Toon filler episode voor anime</string>\n    <string name=\"show_trailers_settings\">Toon trailers</string>\n    <string name=\"kitsu_settings\">Toon posters van Kitsu</string>\n    <string name=\"updates_settings\">App-updates tonen</string>\n    <string name=\"updates_settings_des\">Automatisch zoeken naar nieuwe updates na het starten van de app.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Light novel app van dezelfde ontwikkelaars</string>\n    <string name=\"anim\">Anime app by the same devs</string>\n    <string name=\"discord\">Word lid van ons Discord kanaal</string>\n    <string name=\"benene\">Geef een banaan aan de ontwikkelaars</string>\n    <string name=\"benene_des\">Gegeven banaan</string>\n    <string name=\"app_language\">App Taal</string>\n    <string name=\"no_chromecast_support_toast\">Deze provider heeft geen Chromecast-ondersteuning</string>\n    <string name=\"no_links_found_toast\">Geen links gevonden</string>\n    <string name=\"copy_link_toast\">Link gekopieerd naar klembord</string>\n    <string name=\"play_episode_toast\">Aflevering afspelen</string>\n    <string name=\"subs_default_reset_toast\">Reset naar standaardwaarde</string>\n    <string name=\"season\">Seizoen</string>\n    <string name=\"no_season\">Geen seizoen</string>\n    <string name=\"episode\">Aflevering</string>\n    <string name=\"episodes\">afleveringen</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Geen afleveringen gevonden</string>\n    <string name=\"delete_file\">Verwijder bestand</string>\n    <string name=\"delete\">Verwijder</string>\n    <string name=\"cancel\">annuleer</string>\n    <string name=\"pause\">Pauze</string>\n    <string name=\"resume\">Hervatten</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Dit wordt zeker permanent verwijderd %s\n\\nWeet u het zeker?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nremaining</string>\n    <string name=\"status_ongoing\">Voortdurende</string>\n    <string name=\"status_completed\">Voltooid</string>\n    <string name=\"status\">Status</string>\n    <string name=\"year\">Jaar</string>\n    <string name=\"rating\">Beoordeling</string>\n    <string name=\"duration\">Duur</string>\n    <string name=\"site\">Site</string>\n    <string name=\"synopsis\">Korte inhoud</string>\n    <string name=\"queued\">wachtrij</string>\n    <string name=\"no_subtitles\">Geen ondertiteling</string>\n    <string name=\"action_default\">Standaard</string>\n    <string name=\"free_storage\">Vrij</string>\n    <string name=\"used_storage\">Gebruikt</string>\n    <string name=\"app_storage\">App</string>\n    <!--plural-->\n    <string name=\"movies\">Films</string>\n    <string name=\"tv_series\">TV series</string>\n    <string name=\"cartoons\">tekenfilms</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"documentaries\">Documentaires</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Aziatische drama\\'s</string>\n    <string name=\"livestreams\">Livestreams</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Serie</string>\n    <string name=\"cartoons_singular\">Tekenfilm</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Documentaire</string>\n    <string name=\"asian_drama_singular\">Aziatisch drama</string>\n    <string name=\"live_singular\">Livestream</string>\n    <string name=\"source_error\">Bronfout</string>\n    <string name=\"remote_error\">Externe fout</string>\n    <string name=\"render_error\">Renderer fout</string>\n    <string name=\"unexpected_error\">Onverwachte speler fout</string>\n    <string name=\"storage_error\">Downloadfout, controleer opslagrechten</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast aflevering</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast mirror</string>\n    <string name=\"episode_action_play_in_app\">Speel in app</string>\n    <string name=\"episode_action_play_in_format\">Speel in %s</string>\n    <string name=\"episode_action_auto_download\">Automatisch downloaden</string>\n    <string name=\"episode_action_download_mirror\">Download mirror</string>\n    <string name=\"episode_action_reload_links\">Herlaad Linkss</string>\n    <string name=\"episode_action_download_subtitle\">Ondertitels downloaden</string>\n    <string name=\"show_hd\">Kwaliteitslabel</string>\n    <string name=\"show_dub\">Dub label</string>\n    <string name=\"show_sub\">Sub label</string>\n    <string name=\"show_title\">Titel</string>\n    <string name=\"poster_ui_settings\">Schakel UI-elementen op poster</string>\n    <string name=\"no_update_found\">Geen update gevonden</string>\n    <string name=\"check_for_update\">Controleren op updates</string>\n    <string name=\"video_lock\">Slot</string>\n    <string name=\"video_aspect_ratio_resize\">Formaat wijzigen</string>\n    <string name=\"video_source\">Bron</string>\n    <string name=\"video_skip_op\">OP overslaan</string>\n    <string name=\"dont_show_again\">Niet meer weergeven</string>\n    <string name=\"skip_update\">Deze update overslaan</string>\n    <string name=\"update\">Update</string>\n    <string name=\"watch_quality_pref\">Voorkeurskwaliteit voor kijken (WiFi)</string>\n    <string name=\"limit_title\">Maximaal aantal tekens voor titel van videospeler</string>\n    <string name=\"limit_title_rez\">Toon spelerinformatie</string>\n    <string name=\"video_buffer_size_settings\">Grootte videobuffer</string>\n    <string name=\"video_buffer_length_settings\">Lengte videobuffer</string>\n    <string name=\"video_buffer_disk_settings\">Video cache op schijf</string>\n    <string name=\"video_buffer_clear_settings\">Wis video en beeld cache</string>\n    <string name=\"video_ram_description\">Veroorzaakt storingen indien te hoog ingesteld op toestellen met weinig geheugen, zoals Android TV.</string>\n    <string name=\"video_disk_description\">Veroorzaakt problemen indien te hoog ingesteld op toestellen met weinig opslagruimte, zoals Android TV.</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"dns_pref_summary\">Handig om ISP-blokkades te omzeilen</string>\n    <string name=\"add_site_pref\">Kloon site</string>\n    <string name=\"remove_site_pref\">Site verwijderen</string>\n    <string name=\"add_site_summary\">Voeg een kloon toe van een bestaande site, met een andere URL</string>\n    <string name=\"download_path_pref\">Downloadpad</string>\n    <string name=\"nginx_url_pref\">NGINX server URL</string>\n    <string name=\"display_subbed_dubbed_settings\">Weergave Dubbed/Subbed Anime</string>\n    <string name=\"resize_fit\">Pas aan het scherm</string>\n    <string name=\"resize_fill\">Uitgerekt</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"legal_notice\">Disclaimer</string>\n    <string name=\"category_general\">Algemeen</string>\n    <string name=\"random_button_settings\">Willekeurige knop</string>\n    <string name=\"random_button_settings_desc\">Toon willekeurige knop op Homepage en Bibliotheek</string>\n    <string name=\"provider_lang_settings\">Extensietalen</string>\n    <string name=\"app_layout\">App Layout</string>\n    <string name=\"preferred_media_settings\">Preferred media</string>\n    <string name=\"subtitles_encoding\">Subtitle encoding</string>\n    <string name=\"category_ui\">Layout</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"tv_layout\">TV layout</string>\n    <string name=\"phone_layout\">Telefoon layout</string>\n    <string name=\"emulator_layout\">emulator layout</string>\n    <string name=\"primary_color_settings\">Primaire kleur</string>\n    <string name=\"app_theme_settings\">App thema</string>\n    <string name=\"bottom_title_settings\">Locatie van de titel van de poster</string>\n    <string name=\"bottom_title_settings_des\">Zet de titel onder de poster</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">wachtwoord123</string>\n    <string name=\"example_username\">Gebruikersnaam</string>\n    <string name=\"example_email\">hello@Wereld.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NieuweSiteNaam</string>\n    <string name=\"example_site_url\">https://voorbeeld.com</string>\n    <string name=\"example_lang_name\">Taalcode (nl)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">account</string>\n    <string name=\"logout\">Log uit</string>\n    <string name=\"login\">Log in</string>\n    <string name=\"switch_account\">Wissel account</string>\n    <string name=\"add_account\">Account toevoegen</string>\n    <string name=\"create_account\">Maak account</string>\n    <string name=\"add_sync\">Tracking toevoegen</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Toegevoegd %s</string>\n    <string name=\"upload_sync\">Sync</string>\n    <string name=\"sync_score\">gewaardeerd</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s geverifieerd</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Kon niet inloggen op %s</string>\n    <!-- ============ -->\n    <string name=\"none\">Geen</string>\n    <string name=\"normal\">normaal</string>\n    <string name=\"all\">Allemaal</string>\n    <string name=\"max\">Max</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Overzicht</string>\n    <string name=\"subtitles_depressed\">Depressed</string>\n    <string name=\"subtitles_shadow\">Schaduw</string>\n    <string name=\"subtitles_raised\">Verhoogd</string>\n    <string name=\"subtitle_offset\">Sync subs</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Subtitle vertraging</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Gebruik dit als de ondertitels %d ms te vroeg worden getoond</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Gebruik dit als de ondertitels %d ms te laat worden getoond</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Geen ondertitelvertragin</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">De snelle bruine vos springt over de luie hond</string>\n    <string name=\"recommended\">Aanbevolen</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Geladen %s</string>\n    <string name=\"player_load_subtitles\">Laden uit bestand</string>\n    <string name=\"player_load_subtitles_online\">Laden vanaf internet</string>\n    <string name=\"downloaded_file\">Gedownload bestand</string>\n    <string name=\"actor_main\">Hoofd</string>\n    <string name=\"actor_supporting\">Ondersteuning</string>\n    <string name=\"actor_background\">Achtergrond</string>\n    <string name=\"home_source\">Bron</string>\n    <string name=\"home_random\">Willekeurig</string>\n    <string name=\"coming_soon\">Binnenkort…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Posterafbeelding</string>\n    <string name=\"category_player\">Player</string>\n    <string name=\"resolution_and_title\">Resolutie en titel</string>\n    <string name=\"title\">Titel</string>\n    <string name=\"resolution\">Resolutie</string>\n    <string name=\"error_invalid_id\">Ongeldige ID</string>\n    <string name=\"error_invalid_data\">Onjuiste data</string>\n    <string name=\"error_invalid_url\">Ongeldige URL</string>\n    <string name=\"error\">Fout</string>\n    <string name=\"subtitles_remove_captions\">Ondertiteling van ondertitels verwijderen</string>\n    <string name=\"subtitles_remove_bloat\">Opgeblazen ondertitels verwijderen</string>\n    <string name=\"extras\">Extra\\'s</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"network_adress_example\">https://voorbeeld.com/voorbeeld.mp4</string>\n    <string name=\"referer\">Verwijzer (optioneel)</string>\n    <string name=\"next\">Volgende</string>\n    <string name=\"provider_languages_tip\">Bekijk video\\'s in deze talen</string>\n    <string name=\"previous\">Vorige</string>\n    <string name=\"skip_setup\">Instelling overslaan</string>\n    <string name=\"app_layout_subtext\">Pas het uiterlijk van de app aan uw apparaat aan</string>\n    <string name=\"preferred_media_subtext\">Wat wil je zien</string>\n    <string name=\"setup_done\">Klaar</string>\n    <string name=\"action_mark_as_watched\">Markeer als bekeken</string>\n    <string name=\"history\">Geschiedenis</string>\n    <string name=\"play_trailer_button\">Speel Trailer</string>\n    <string name=\"autoplay_next_settings_des\">Start de volgende episode wanneer deze afgelopen is</string>\n    <string name=\"autoplay_next_settings\">Volgende episode automatisch afspelen</string>\n    <string name=\"update_started\">Update Gestart</string>\n    <string name=\"library\">Bibliotheek</string>\n    <string name=\"browser\">Browser</string>\n    <string name=\"test_log\">Logboek</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Kan %s niet laden</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Alle %s reeds gedownload</string>\n    <string name=\"plugin_singular\">plugin</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Sla %s over</string>\n    <string name=\"pref_category_links\">Links</string>\n    <string name=\"pref_category_app_updates\">App updates</string>\n    <string name=\"pref_category_gestures\">Handelingen</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"pref_category_ui_features\">Eigenschappen</string>\n    <string name=\"add_repository\">Repository toevoegen</string>\n    <string name=\"extension_version\">Versie</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"jsdelivr_proxy\">GitHub Proxy</string>\n    <string name=\"pref_category_bypass\">ISP Omleidingen</string>\n    <string name=\"pref_category_defaults\">Standaardinstellingen</string>\n    <string name=\"app_not_found_error\">App niet gevonden</string>\n    <string name=\"pref_category_subtitles\">Ondertitels</string>\n    <string name=\"subtitles_filter_lang\">Filter op gewenste mediataal</string>\n    <string name=\"plugin_loaded\">Plugin Geladen</string>\n    <string name=\"category_provider_test\">Aanbieder test</string>\n    <string name=\"test_passed\">Geslaagd</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">De zoekhoeveelheid gebruikt als de speler onzichtbaar is</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">De gebruikte zoekhoeveelheid wanneer de speler zichtbaar is</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Speler Verborgen - Zoekhoeveelheid</string>\n    <string name=\"extension_authors\">Auteurs</string>\n    <string name=\"pref_category_player_layout\">Layout</string>\n    <string name=\"extension_language\">Taal</string>\n    <string name=\"extension_install_first\">Installeer eerst de uitbreiding</string>\n    <string name=\"all_languages_preference\">Alle Talen</string>\n    <string name=\"automatic_plugin_download_summary\">Installeer automatisch alle nog niet geïnstalleerde plugins uit toegevoegde repositories.</string>\n    <string name=\"jsdelivr_enabled\">Kan GitHub niet bereiken, schakel jsDelivr proxy in…</string>\n    <string name=\"apk_installer_settings\">APK Installatie</string>\n    <string name=\"automatic_plugin_download\">Download plugins automatisch</string>\n    <string name=\"extensions\">Uitbreidingen</string>\n    <string name=\"skip_type_op\">Openen</string>\n    <string name=\"plugin\">plugins</string>\n    <string name=\"watch_quality_pref_data\">Voorkeurskwaliteit voor kijken (Mobiele Data)</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Speler Weergegeven - Zoekhoeveelheid</string>\n    <string name=\"pref_category_actions\">Acties</string>\n    <string name=\"repository_name_hint\">Repository naam (Optioneel)</string>\n    <string name=\"plugin_downloaded\">Plugin Gedownload</string>\n    <string name=\"test_failed\">Mislukt</string>\n    <string name=\"jsdelivr_proxy_summary\">Omzeil de blokkering van ruwe GitHub-URL’s via jsDelivr. Hierdoor kunnen updates enkele dagen vertraagd zijn.</string>\n    <string name=\"repository_url_hint\">Repository URL of Shortcode</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Download %1$d %2$s voltooid</string>\n    <string name=\"hls_playlist\">HLS Afspeellijst</string>\n    <string name=\"pref_category_player_features\">Speler eigenschappen</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"plugin_deleted\">Plugin Verwijderd</string>\n    <string name=\"extension_types\">Ondersteund</string>\n    <string name=\"category_providers\">Aanbieders</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Gestart met downloaden van %1$d %2$s…</string>\n    <string name=\"player_pref\">Gewenste videospeler</string>\n    <string name=\"pref_category_looks\">Lijkt</string>\n    <string name=\"enable_nsfw_on_providers\">NSFW inschakelen op ondersteunde extensies</string>\n    <string name=\"others\">Andere</string>\n    <string name=\"redo_setup_process\">Herhaal installatieproces</string>\n    <string name=\"automatic_plugin_updates\">Automatisch bijwerken plugin</string>\n    <string name=\"apk_installer_settings_des\">Sommige apparaten ondersteunen het nieuwe installatieprogramma niet. Probeer de oude optie als de updates niet worden geïnstalleerd.</string>\n    <string name=\"player_settings_play_in_app\">Interne speler</string>\n    <string name=\"skip_type_mixed_ed\">Gemengd einde</string>\n    <string name=\"skip_type_recap\">Herhaling</string>\n    <string name=\"start\">Start</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_backup\">Backup</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"extension_size\">Grootte</string>\n    <string name=\"skip_type_ed\">Einde</string>\n    <string name=\"delete_repository_plugins\">Dit zal ook alle repository plugins verwijderen</string>\n    <string name=\"pref_filter_search_quality\">Verberg geselecteerde videokwaliteit in zoekresultaten</string>\n    <string name=\"batch_download\">Batch download</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"pref_category_extensions\">Uitbreidingen</string>\n    <string name=\"skip_type_intro\">Intro</string>\n    <string name=\"view_public_repositories_button_short\">Publieke lijst</string>\n    <string name=\"extension_rating\" formatted=\"true\">Beoordeling: %s</string>\n    <string name=\"safe_mode_description\">Alle extensies zijn uitgeschakeld door een crash om u te helpen degene te vinden die problemen veroorzaakt.</string>\n    <string name=\"safe_mode_crash_info\">Bekijk de crash info</string>\n    <string name=\"empty_library_logged_in_message\">Deze lijst is leeg. Probeer een andere.</string>\n    <string name=\"sort_alphabetical_a\">Alfabetisch (A tot Z)</string>\n    <string name=\"confirm_exit_dialog\">Weet je zeker dat je wilt afsluiten?</string>\n    <string name=\"sort_updated_old\">Bijgewerkt (Oud naar Nieuw)</string>\n    <string name=\"sort_rating_desc\">Beoordeling ( Hoog naar Laag)</string>\n    <string name=\"apk_installer_legacy\">Erfenis</string>\n    <string name=\"select_library\">Kies Bibliotheek</string>\n    <string name=\"yes\">Ja</string>\n    <string name=\"video_tracks\">Videosporen</string>\n    <string name=\"tracks\">Sporen</string>\n    <string name=\"view_public_repositories_button\">Bekijk gemeenschap repositories</string>\n    <string name=\"sort_updated_new\">Bijgewerkt ( Nieuw naar Oud)</string>\n    <string name=\"action_remove_from_watched\">Verwijderen uit bekeken</string>\n    <string name=\"delayed_update_notice\">App wordt bijgewerkt bij afsluiten</string>\n    <string name=\"sort\">Gesorteerd</string>\n    <string name=\"empty_library_no_accounts_message\">Je bibliotheek is leeg :(\n\\nLog in op een bibliotheekaccount of voeg voorstellingen toe aan uw lokale bibliotheek.</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Uitgeschakeld: %d</string>\n    <string name=\"stop\">Stop</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Niet gedownload: %d</string>\n    <string name=\"sort_alphabetical_z\">Alfabetisch (Z tot A)</string>\n    <string name=\"subscription_new\">Ingeschreven op %s</string>\n    <string name=\"apk_installer_package_installer\">PakketInstallatie</string>\n    <string name=\"subscription_in_progress_notification\">Bijwerken geabonneerde shows</string>\n    <string name=\"setup_extensions_subtext\">Download de lijst met sites die je wilt gebruiken</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Bijgewerkte %d plugins</string>\n    <string name=\"clipboard_too_large\">Te veel tekst. Kan niet opslaan naar klembord.</string>\n    <string name=\"subscription_episode_released\">Aflevering %d uitgebracht!</string>\n    <string name=\"enable_skip_op_from_database_des\">Toon skip popups voor openen/einde</string>\n    <string name=\"uppercase_all_subtitles\">Alle ondertitels in hoofdletters</string>\n    <string name=\"update_notification_downloading\">App update downloaden…</string>\n    <string name=\"update_notification_installing\">App update installeren…</string>\n    <string name=\"update_notification_failed\">Kan de nieuwe versie van de app niet installeren</string>\n    <string name=\"skip_type_mixed_op\">Gemengde opening</string>\n    <string name=\"open_with\">Open met</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s ( Uitgeschakeld)</string>\n    <string name=\"apply_on_restart\">Herstart de app om veranderingen te zien.</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Gedownload: %d</string>\n    <string name=\"safe_mode_file\">Veilige mode bestand gevonden!\n\\nGeen extensies laden bij het opstarten totdat het bestand is verwijderd.</string>\n    <string name=\"no\">Nee</string>\n    <string name=\"sort_rating_asc\">Beoordeling ( Hoog naar Laag)</string>\n    <string name=\"safe_mode_title\">Veilige mode aan</string>\n    <string name=\"restart\">Herstart</string>\n    <string name=\"extension_description\">Beschrijving</string>\n    <string name=\"skip_type_creddits\">Waardering</string>\n    <string name=\"clear_history\">Wis geschiedenis</string>\n    <string name=\"subscription_list_name\">Ingeschreven</string>\n    <string name=\"delete_repository\">Wis repository</string>\n    <string name=\"subscription_deleted\">Uitgeschreven bij %s</string>\n    <string name=\"revert\">Terugkeren</string>\n    <string name=\"blank_repo_message\">CloudStream heeft standaard geen sites geïnstalleerd. U moet de sites uit repositories installeren.\n\\n\n\\nVanwege een hersenloze DMCA verwijdering door Sky UK Limited 🤮 kunnen we de repository site niet linken in de app.\n\\n\n\\nWord lid van onze Discord of zoek online.</string>\n    <string name=\"audio_tracks\">Audiosporen</string>\n    <string name=\"sort_by\">Gesorteerd op</string>\n    <string name=\"wifi\">Wifi</string>\n    <string name=\"mobile_data\">Mobiele data</string>\n    <string name=\"set_default\">Maak standaard</string>\n    <string name=\"edit\">Aanpassen</string>\n    <string name=\"profiles\">Profielen</string>\n    <string name=\"help\">Help</string>\n    <string name=\"qualities\">Kwaliteiten</string>\n    <string name=\"profile_background_des\">Profiel achtergrond</string>\n    <string name=\"use\">Gebruik</string>\n    <string name=\"quality_profile_help\">Hier kan je de volgorde van de bronnen veranderen. Als een video een hogere prioriteit heeft zal het hoger in de bronnenlijst staan. De som van de prioriteit van de bron en de prioriteit van de kwaliteit is de prioriteit van de video.\n\\n\n\\nBron A: 3\n\\nKwaliteit B: 7\n\\nHeeft een totale prioriteit van de video van 10.\n\\n\n\\nNOTITIE: Als de som 10 of hoger is zal de speler automatisch het laden overslaan wanneer die link is geladen!</string>\n    <string name=\"profile_number\">Profiel %d</string>\n    <string name=\"no_repository_found_error\">Repository niet gevonden, controleer de URL en probeer een VPN</string>\n    <string name=\"no_plugins_found_error\">Geen plug-ins gevonden in de repository</string>\n    <string name=\"automatic_plugin_download_mode_title\">Selecteer een modus om het downloaden van plug-ins te filteren</string>\n    <string name=\"disable\">Uitzetten</string>\n    <string name=\"unable_to_inflate\">De gebruikersinterface kon niet correct worden gemaakt, dit is een ERNSTIG PROBLEEM en moet onmiddellijk gerapporteerd worden %s</string>\n    <string name=\"already_voted\">Je hebt al gestemd</string>\n    <string name=\"favorite_removed\">%s verwijderd uit favorieten</string>\n    <string name=\"favorites_list_name\">Favorieten</string>\n    <string name=\"favorite_added\">%s toegevoegd aan favorieten</string>\n    <string name=\"logged_account\" formatted=\"true\">Aangemeld als %s</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Er zijn mogelijk dubbele items gevonden in uw bibliotheek:\n\\n\n\\n%s\n\\n\n\\nWilt u dit item toch toevoegen, de bestaande vervangen of de actie annuleren?</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Voer PIN in voor %s</string>\n    <string name=\"backup_frequency\">Backupfrequentie</string>\n    <string name=\"duplicate_title\">Mogelijk Duplicaat Gevonden</string>\n    <string name=\"lock_profile\">Profiel vergrendelen</string>\n    <string name=\"use_default_account\">Standaardaccount gebruiken</string>\n    <string name=\"skip_startup_account_select_pref\">Accountselectie overslaan bij opstarten</string>\n    <string name=\"action_add_to_favorites\">Voeg toe aan favorieten</string>\n    <string name=\"manage_accounts\">Beheer Accounts</string>\n    <string name=\"duplicate_replace_all\">Alles Vervangen</string>\n    <string name=\"edit_account\">Account bewerken</string>\n    <string name=\"pin_error_incorrect\">Onjuiste PIN. Probeer het opnieuw.</string>\n    <string name=\"action_unsubscribe\">Afmelden</string>\n    <string name=\"pin_error_length\">PIN moet 4 teken bevatten</string>\n    <string name=\"duplicate_replace\">Vervangen</string>\n    <string name=\"duplicate_add\">Toevoegen</string>\n    <string name=\"action_subscribe\">Abonneer</string>\n    <string name=\"action_remove_from_favorites\">Verwijder uit favorieten</string>\n    <string name=\"select_an_account\">Selecteer een Account</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Het lijkt erop dat er al een mogelijk duplicaat bestaat in uw bibliotheek: \\'%s.\\'\n\\n\n\\nWilt u dit item toch toevoegen, het bestaande item vervangen of de actie annuleren?</string>\n    <string name=\"enter_pin\">PIN invoeren</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">Huidige PIN invoeren</string>\n    <string name=\"links_reloaded_toast\">Link opnieuw geladen</string>\n    <string name=\"auto_rotate_video\">Autoroteer</string>\n    <string name=\"rotate_video\">Roteer</string>\n    <string name=\"downloads_empty\">Er zijn momenteel geen downloads beschikbaar.</string>\n    <string name=\"toast_copied\">Gekopieerd!</string>\n    <string name=\"dont_show\">Verbergen</string>\n    <string name=\"show\">Tonen</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Seizoen %1$d Aflevering %2$d zal worden uitgebracht in</string>\n    <string name=\"play_from_beginning_img_des\">Speel van het begin</string>\n    <string name=\"repo_copy_label\">Repositorynaam en URL</string>\n    <string name=\"recommendations_tooltip\">Aanbevelingen tonen</string>\n    <string name=\"downloads_delete_select\">Selecteer items om te verwijderen</string>\n    <string name=\"torrent_info\">Deze video is een Torrent, dit betekent dat je videoactiviteit kan worden gevolgd.\\nZorg ervoor dat je Torrenting begrijpt voordat je doorgaat.</string>\n    <string name=\"speed_setting_summary\">Voegt een snelheidsoptie toe in de speler</string>\n    <string name=\"open_local_video\">Open lokale video</string>\n    <string name=\"speech_recognition_unavailable\">Spraakherkenning is niet beschikbaar</string>\n    <string name=\"begin_speaking\">Begin met praten…</string>\n    <string name=\"offline_file\">Beschikbaar om offline te kijken</string>\n    <string name=\"select_all\">Selecteer alles</string>\n    <string name=\"deselect_all\">Deselecteer alles</string>\n    <string name=\"subscribe_tooltip\">Bericht voor nieuwe afleveringen</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$d u %2$d m %3$d s</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$d m %2$d s</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d s</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Binnenkort beschikbaar in %s</string>\n    <string name=\"delete_files\">Verwijder bestanden</string>\n    <string name=\"delete_format\" formatted=\"true\">Verwijder (%1$d | %2$s)</string>\n    <string name=\"test_warning\">Waarschuwing</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Weet je zeker dat je de volgende items permanent wil verwijderen?\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Weet je zeker dat je de volgende afleveringen in %1$s permanent wilt verwijderen?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Hiermee worden ook alle afleveringen van de volgende series permanent verwijderd:\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Weet je zeker dat je alle afleveringen van de volgende series permanent wil verwijderen?\\n\\n%s</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\nresterend</string>\n    <string name=\"music_singlar\">Muziek</string>\n    <string name=\"audio_book_singular\">Luisterboek</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"encoding_error\">Coderingsfout</string>\n    <string name=\"unsupported_error\">Fout: wordt niet ondersteund</string>\n    <string name=\"pref_category_security\">Beveiliging</string>\n    <string name=\"pref_category_accounts\">Accounts</string>\n    <string name=\"play_full_series_button\">Speel Gehele Serie</string>\n    <string name=\"result_search_tooltip\">Zoek in andere extensies</string>\n    <string name=\"test_extensions\">Test alle Extensies</string>\n    <string name=\"player_load_one_subtitle_online\">Laad eerst beschikbare</string>\n    <string name=\"qr_image\">QR-code Afbeelding</string>\n    <string name=\"delete_plugin\">Verwijder plug-in</string>\n    <string name=\"player_settings_always_ask\">Vraag altijd</string>\n    <string name=\"ok\">OKÉ</string>\n    <string name=\"open_downloaded_repo\">Open repository</string>\n    <string name=\"battery_dialog_title\">Batterij-optimalisatie uitschakelen</string>\n    <string name=\"app_unrestricted_toast\">Batterijgebruik van app is reeds ingesteld als onbegrensd</string>\n    <string name=\"app_info_intent_error\">Niet in staat Cloudstreams App-info te openen.</string>\n    <string name=\"sort_episodes_number_asc\">Aflevering (Oplopend)</string>\n    <string name=\"sort_episodes_number_desc\">Aflevering (Aflopend)</string>\n    <string name=\"sort_episodes_rating_high_low\">Beoordeling (Hoogste)</string>\n    <string name=\"sort_episodes_rating_low_high\">Beoordeling (Laagste)</string>\n    <string name=\"sort_episodes_date_newest\">Uitzenddatum (Nieuwste)</string>\n    <string name=\"sort_episodes_date_oldest\">Uitzenddatum (Oudste)</string>\n    <string name=\"sort_button_episode\">Afl %s</string>\n    <string name=\"sort_button_rating\">Beoordeling %s</string>\n    <string name=\"sort_button_date\">Datum %s</string>\n    <string name=\"no_account\">Geen account</string>\n    <string name=\"rotate_video_desc\">Toon een schakelknop voor schermoriëntatie</string>\n    <string name=\"auto_rotate_video_desc\">Activeer automatisch wisselen van schermoriëntatie gebaseerd op video oriëntatie</string>\n    <string name=\"favorite\">Favoriet</string>\n    <string name=\"unfavorite\">Verwijder favoriet</string>\n    <string name=\"password_pin_authentication_title\">Wachtwoord/PIN-authenticatie</string>\n    <string name=\"biometric_unsupported\">Biometrische authenticatie is niet ondersteund op dit apparaat</string>\n    <string name=\"biometric_prompt_description\">Na enige mislukte pogingen zal de prompt sluiten. Herstart de app om het opnieuw te proberen.</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"device_pin_url_message\">Ga naar <b>%s</b> op je smartphone of computer en voeren de bovenstaande code in</string>\n    <string name=\"device_pin_expired_message\">PIN-code is nu verlopen!</string>\n    <string name=\"device_pin_counter_text\">Code verloopt in %1$dm %2$ds</string>\n    <string name=\"download_queue\">Downloadwachtrij</string>\n    <string name=\"queue_empty_message\">Er staan momenteel geen downloads in de wachtrij.</string>\n    <string name=\"extra_brightness_settings\">Extra helderheid</string>\n    <string name=\"extra_brightness_settings_des\">Schakel het helderheidsfilter in zodra de schermhelderheid boven 100% komt</string>\n    <string name=\"extra_brightness_key\">extra_helderheid_ingeschakeld</string>\n    <string name=\"search_suggestions\">Zoeksuggesties</string>\n    <string name=\"search_suggestions_des\">Zoeksuggesties laten zien tijdens het typen</string>\n    <string name=\"clear_suggestions\">Suggesties verwijderen</string>\n    <string name=\"show_cast_in_details\">Castpaneel weergeven</string>\n    <string name=\"install_prerelease\">Pre-releaseversie installeren</string>\n    <string name=\"prerelease_already_installed\">Pre-releaseversie is al geïnstaleerd.</string>\n    <string name=\"prerelease_install_failed\">Installatie van de pre-release is mislukt.</string>\n    <string name=\"episode_action_cast_mirror\">Schermspiegeling</string>\n    <string name=\"episode_action_play_mirror\">Spiegeling spelen</string>\"\n    <string name=\"show_rating\">Beoordelingslabel</string>\n    <string name=\"show_episode_text\">Afleveringstekst</string>\n    <string name=\"test_extensions_summary\">Deze test is alleen bedoeld voor ontwikkelaars en bevestigt noch ontkent de werking van een extensie.</string>\n    <string name=\"auth_locally\">Lokale authenticatie</string>\n    <string name=\"video_info\">Media info</string>\n    <string name=\"download_all_plugins_from_repo\">Waarschuwing: Cloudstream is niet verandwoordelijk voor het gebruik van extensies van derden en biedt hier ook geen ondersteuning voor!</string>\n    <string name=\"player_settings_select_cast_device\">Cast apparaat selecteren</string>\n    <string name=\"clipboard_permission_error\">Fout bij toegang tot het Klembord, Probeer het opnieuw.</string>\n    <string name=\"clipboard_unknown_error\">Fout bij het kopiëren. Kopieer alsjeblieft de logcat en neem contact op met de app-ondersteuning.</string>\n    <string name=\"dismiss\">Afwijzen</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+nn/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"episode_more_options_des\">Fleire val</string>\n    <string name=\"title_home\">Heim</string>\n    <string name=\"title_search\">Søk</string>\n    <string name=\"title_downloads\">Nedlastingar</string>\n    <string name=\"title_settings\">Innstillingar</string>\n    <string name=\"search_hint\">Søk…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Søk i %s…</string>\n    <string name=\"no_data\">Ingen data tilgjengeleg</string>\n    <string name=\"next_episode\">Neste episode</string>\n    <string name=\"episode_poster_img_des\">Episodeminiatyrbilete</string>\n    <string name=\"home_next_random_img_des\">Neste tilfeldig</string>\n    <string name=\"play_with_app_name\">Spel av med CloudStream</string>\n    <string name=\"filler\" formatted=\"true\">Fyllstoff</string>\n    <string name=\"preview_background_img_des\">Forhandsvis bakgrunnsbilete</string>\n    <string name=\"rated_format\" formatted=\"true\">Vurdert: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Ny oppdatering tilgjengeleg!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration_format\" formatted=\"true\">%d minutt</string>\n    <string name=\"result_poster_img_des\">Miniatyrbilete</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episode %d vil bli sleppt om</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dt %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dt %2$dm</string>\n    <string name=\"cast_format\" formatted=\"true\">Rollebesetning: %s</string>\n    <string name=\"home_main_poster_img_des\">Hovudminiatyrbilete</string>\n    <string name=\"home_change_provider_img_des\">Endre leverandør</string>\n    <string name=\"result_open_in_browser\">Opne i nettlesaren</string>\n    <string name=\"loading\">Laster inn…</string>\n    <string name=\"skip_loading\">Hopp over buffering</string>\n    <string name=\"type_watching\">Ser på</string>\n    <string name=\"type_on_hold\">På vent</string>\n    <string name=\"type_completed\">Fullført</string>\n    <string name=\"type_plan_to_watch\">Planlagt</string>\n    <string name=\"play_movie_button\">Spel av film</string>\n    <string name=\"play_trailer_button\">Spel av trailer</string>\n    <string name=\"play_livestream_button\">Spel av direktesending</string>\n    <string name=\"pick_source\">Kjelder</string>\n    <string name=\"pick_subtitle\">Undertekstar</string>\n    <string name=\"go_back\">Gå tilbake</string>\n    <string name=\"play_episode\">Spel av episode</string>\n    <string name=\"download\">Nedlasting</string>\n    <string name=\"downloaded\">Lasta ned</string>\n    <string name=\"downloading\">Nedlasting pågår</string>\n    <string name=\"download_paused\">Nedlasting satt på vent</string>\n    <string name=\"download_started\">Nedlasting starta</string>\n    <string name=\"download_failed\">Nedlasting feila</string>\n    <string name=\"download_canceled\">Nedlasting avbrote</string>\n    <string name=\"download_done\">Nedlasting ferdig</string>\n    <string name=\"stream\">Straum</string>\n    <string name=\"error_loading_links_toast\">Feil ved innlasting av lenker</string>\n    <string name=\"download_storage_text\">Internlagring</string>\n    <string name=\"app_dubbed_text\">Dubb</string>\n    <string name=\"popup_delete_file\">Slett fil</string>\n    <string name=\"popup_play_file\">Spel av fil</string>\n    <string name=\"popup_pause_download\">Sett nedlasting på vent</string>\n    <string name=\"home_expanded_hide\">Gøym</string>\n    <string name=\"home_play\">Spel(e) av</string>\n    <string name=\"home_info\">Informasjon</string>\n    <string name=\"filter_bookmarks\">Filtrer bokmerker</string>\n    <string name=\"error_bookmarks_text\">Bokmerker</string>\n    <string name=\"action_remove_from_bookmarks\">Fjern</string>\n    <string name=\"action_add_to_bookmarks\">Sett visingstatus</string>\n    <string name=\"sort_apply\">Bruk</string>\n    <string name=\"sort_copy\">Kopier</string>\n    <string name=\"sort_clear\">Tøm</string>\n    <string name=\"sort_save\">Lagre</string>\n    <string name=\"player_speed\">Avspelinghastigheit</string>\n    <string name=\"subtitles_settings\">Innstillingar for undertekstar</string>\n    <string name=\"subs_text_color\">Tekstfarge</string>\n    <string name=\"subs_outline_color\">Konturfarge</string>\n    <string name=\"subs_background_color\">Bakgrunnfarge</string>\n    <string name=\"subs_window_color\">Vindaugefarge</string>\n    <string name=\"subs_edge_type\">Kanttype</string>\n    <string name=\"subs_subtitle_elevation\">Underteksthøgde</string>\n    <string name=\"subs_font\">Skrifttype</string>\n    <string name=\"subs_font_size\">Skriftstorleik</string>\n    <string name=\"search_provider_text_providers\">Søk basert på leverandør</string>\n    <string name=\"action_remove_watching\">Fjern</string>\n    <string name=\"action_open_watching\">Meir informasjon</string>\n    <string name=\"player_subtitles_settings\">Undertekstar</string>\n    <string name=\"torrent_plot\">Beskriving</string>\n    <string name=\"normal_no_plot\">Fant ingen handling</string>\n    <string name=\"torrent_no_plot\">Fant ingen beskriving</string>\n    <string name=\"player_size_settings_des\">Fjern dei svarte kantane</string>\n    <string name=\"autoplay_next_settings\">Spel av neste episode automatisk</string>\n    <string name=\"backup_settings\">Sikkerheitskopier data</string>\n    <string name=\"restore_success\">Lasta inn sikkerheitkopifil</string>\n    <string name=\"search\">Søk</string>\n    <string name=\"category_account\">Kontoar</string>\n    <string name=\"category_updates\">Oppdateringar og sikkerheitskopiering av data</string>\n    <string name=\"settings_info\">Informasjon</string>\n    <string name=\"advanced_search\">Avansert søk</string>\n    <string name=\"show_trailers_settings\">Vis trailerar</string>\n    <string name=\"kitsu_settings\">Vis miniatyrbilete frå Kitsu</string>\n    <string name=\"updates_settings\">Vis programoppdateringar</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Lysnovelleprogram av dei same utviklarane</string>\n    <string name=\"anim\">Animeprogram av dei same utviklarane</string>\n    <string name=\"app_language\">Programspråk</string>\n    <string name=\"no_links_found_toast\">Ingen lenker funnen</string>\n    <string name=\"copy_link_toast\">Kopiert lenke til utklipptavle</string>\n    <string name=\"play_episode_toast\">Spel av episode</string>\n    <string name=\"subs_default_reset_toast\">Tilbakestill til standardverdi</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Ingen sesong</string>\n    <string name=\"episode\">Episode</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Ingen episodar blei funnen</string>\n    <string name=\"delete_file\">Slett fil</string>\n    <string name=\"delete\">Slett</string>\n    <string name=\"cancel\">Avbryt</string>\n    <string name=\"pause\">Pause</string>\n    <string name=\"resume\">Gjenoppta</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Dette vil slette %s permanent.\n\\nEr du sikker på dette?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\ngjenstår</string>\n    <string name=\"status_ongoing\">Pågåande</string>\n    <string name=\"status_completed\">Fullført</string>\n    <string name=\"year\">År</string>\n    <string name=\"rating\">Vurdering</string>\n    <string name=\"site\">Nettstad</string>\n    <string name=\"synopsis\">Om</string>\n    <string name=\"queued\">i kø</string>\n    <string name=\"no_subtitles\">Ingen undertekstar</string>\n    <string name=\"action_default\">Standard</string>\n    <string name=\"used_storage\">Brukt</string>\n    <string name=\"app_storage\">Program</string>\n    <string name=\"movies\">Filmar</string>\n    <string name=\"tv_series\">TV-seriar</string>\n    <string name=\"free_storage\">Tilgjengeleg</string>\n    <string name=\"cartoons\">Teikneseriar</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"documentaries\">Dokumentarar</string>\n    <string name=\"others\">Andre</string>\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Serie</string>\n    <string name=\"cartoons_singular\">Teiknefilm</string>\n    <string name=\"documentaries_singular\">Dokumentar</string>\n    <string name=\"asian_drama_singular\">Asiatisk drama</string>\n    <string name=\"live_singular\">Direktesending</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"source_error\">Kjeldefeil</string>\n    <string name=\"episode_action_play_in_app\">Spel av i programmet</string>\n    <string name=\"episode_action_play_in_format\">Spel av i %s</string>\n    <string name=\"episode_action_auto_download\">Automatisk nedlasting</string>\n    <string name=\"episode_action_reload_links\">Last inn lenker på nytt</string>\n    <string name=\"episode_action_download_subtitle\">Last ned undertekstar</string>\n    <string name=\"update\">Oppdater</string>\n    <string name=\"skip_update\">Ignorer oppdatering</string>\n    <string name=\"dont_show_again\">Ikkje vis igjen</string>\n    <string name=\"video_source\">Kjelde</string>\n    <string name=\"video_skip_op\">Hopp over intro</string>\n    <string name=\"video_aspect_ratio_resize\">Endre storleik</string>\n    <string name=\"video_lock\">Lås</string>\n    <string name=\"watch_quality_pref\">Føretrekt oppløysing</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"go_back_img_des\">Gå tilbake</string>\n    <string name=\"result_tags\">Sjangrar</string>\n    <string name=\"result_share\">Dele</string>\n    <string name=\"type_re_watching\">Ser om igjen</string>\n    <string name=\"update_started\">Oppdatering starta</string>\n    <string name=\"popup_resume_download\">Fortsett nedlasting</string>\n    <string name=\"home_more_info\">Meir informasjon</string>\n    <string name=\"sort_close\">Lukk</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Avspelinghastigheit (%.2fx)</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"updates_settings_des\">Sjå etter nye oppdateringar automatisk ved oppstart</string>\n    <string name=\"discord\">Bli med i Discord</string>\n    <string name=\"no_chromecast_support_toast\">Denne leverandøren støttar ikkje Chromecast</string>\n    <string name=\"season\">Sesong</string>\n    <string name=\"episodes\">Episodar</string>\n    <string name=\"duration\">Varigheit</string>\n    <string name=\"livestreams\">Direktesendingar</string>\n    <string name=\"pref_category_app_updates\">Programoppdateringar</string>\n    <string name=\"subs_hold_to_reset_to_default\">Trykk og hold inne for å nullstille til standardinnstillinger</string>\n    <string name=\"search_provider_text_types\">Søk ved bruk av typer</string>\n    <string name=\"subs_auto_select_language\">Automatisk språkvalg</string>\n    <string name=\"subs_download_languages\">Last ned språk</string>\n    <string name=\"subs_subtitle_languages\">Undertekstspråk</string>\n    <string name=\"provider_info_meta\">Metadata er ikke tilgjengelig fra nettsiden. Videoavspilling vil mislykkes hvis metadata ikke finnes på nettsiden.</string>\n    <string name=\"player_subtitles_settings_des\">Innstillinger for avspilling av undertekster</string>\n    <string name=\"search_poster_img_des\">Plakat</string>\n    <string name=\"vpn_torrent\">Denne leverandøren er en torrent, og det anbefales å bruke en VPN-tjeneste.</string>\n    <string name=\"vpn_might_be_needed\">For at denne leverandøren skal fungere korrekt, kan det være nødvendig å bruke en VPN-tjeneste</string>\n    <string name=\"picture_in_picture\">Bilde i bilde</string>\n    <string name=\"continue_watching\">Fortsett å sjå</string>\n    <string name=\"reload_error\">Prøv tilkopling på nytt…</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+no/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Plakat</string>\n    <string name=\"search_poster_img_des\">Plakat</string>\n    <string name=\"episode_poster_img_des\">Episode Plakat</string>\n    <string name=\"home_main_poster_img_des\">Main Plakat</string>\n    <string name=\"home_next_random_img_des\">Neste tilfeldig</string>\n    <string name=\"go_back_img_des\">Gå tilbake</string>\n    <string name=\"home_change_provider_img_des\">Bytt leverandør</string>\n    <string name=\"preview_background_img_des\">Forhåndsvisning Bakgrunn</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Avspillingshastighet (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Vurdert: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Ny oppdatering funnet!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Hjem</string>\n    <string name=\"title_search\">Søk</string>\n    <string name=\"title_downloads\">Nedlastinger</string>\n    <string name=\"title_settings\">Innstillinger</string>\n    <string name=\"search_hint\">Søk…</string>\n    <string name=\"no_data\">Ingen data tilgjengelig</string>\n    <string name=\"episode_more_options_des\">Flere valg</string>\n    <string name=\"next_episode\">Neste episode</string>\n    <string name=\"result_tags\">Sjangere</string>\n    <string name=\"result_share\">Dele</string>\n    <string name=\"result_open_in_browser\">Åpne i nettleseren</string>\n    <string name=\"skip_loading\">Hopp over</string>\n    <string name=\"loading\">Laster inn…</string>\n    <string name=\"type_watching\">Ser på</string>\n    <string name=\"type_on_hold\">På vent</string>\n    <string name=\"type_completed\">Fullført</string>\n    <string name=\"type_dropped\">Falt</string>\n    <string name=\"type_plan_to_watch\">Planlegg å se</string>\n    <string name=\"play_movie_button\">Spill filmer</string>\n    <string name=\"play_torrent_button\">Strøm Torrent</string>\n    <string name=\"pick_source\">Kilder</string>\n    <string name=\"pick_subtitle\">Undertekster</string>\n    <string name=\"reload_error\">Prøv tilkoblingen på nytt…</string>\n    <string name=\"go_back\">Gå tilbake</string>\n    <string name=\"play_episode\">Spille Episode</string>\n    <!--<string name=\"need_storage\">Tillat å laste ned episoder</string>-->\n    <string name=\"download\">nedlasting</string>\n    <string name=\"downloaded\">Lastet ned</string>\n    <string name=\"downloading\">Nedlasting pågår</string>\n    <string name=\"download_paused\">Nedlasting stoppet midlertidig</string>\n    <string name=\"download_started\">Nedlasting startet</string>\n    <string name=\"download_failed\">Nedlasting mislyktes</string>\n    <string name=\"download_canceled\">Nedlasting avbrutt</string>\n    <string name=\"download_done\">Last ned Ferdig</string>\n    <string name=\"error_loading_links_toast\">feil ved lasting av lenker</string>\n    <string name=\"download_storage_text\">Intern lagring</string>\n    <string name=\"app_dubbed_text\">Dubbet</string>\n    <string name=\"app_subbed_text\">Subbed</string>\n    <string name=\"popup_delete_file\">Slett fil</string>\n    <string name=\"popup_play_file\">Spill av fil</string>\n    <string name=\"popup_resume_download\">Fortsett nedlasting</string>\n    <string name=\"popup_pause_download\">Stopp nedlastingen</string>\n    <string name=\"home_more_info\">Mer informasjon</string>\n    <string name=\"home_expanded_hide\">Gjemme seg</string>\n    <string name=\"home_play\">Spille</string>\n    <string name=\"home_info\">Informasjon</string>\n    <string name=\"filter_bookmarks\">Filtrer bokmerker</string>\n    <string name=\"error_bookmarks_text\">Bokmerker</string>\n    <string name=\"action_remove_from_bookmarks\">Ta bort</string>\n    <string name=\"sort_apply\">Søke om</string>\n    <string name=\"player_speed\">Spillerhastighet</string>\n    <string name=\"subtitles_settings\">Innstillinger for teksting</string>\n    <string name=\"subs_text_color\">Tekstfarge</string>\n    <string name=\"subs_outline_color\">Konturfarge</string>\n    <string name=\"subs_background_color\">Bakgrunnsfarge</string>\n    <string name=\"subs_window_color\">Vindusfarge</string>\n    <string name=\"subs_edge_type\">Kanttype</string>\n    <string name=\"subs_subtitle_elevation\">Undertekst høyde</string>\n    <string name=\"subs_font\">Skrift</string>\n    <string name=\"subs_font_size\">Skriftstørrelse</string>\n    <string name=\"search_provider_text_providers\">Søk med leverandører</string>\n    <string name=\"search_provider_text_types\">Søk med typer</string>\n    <string name=\"benene_count_text\">%d Benenes gitt til utvikler</string>\n    <string name=\"benene_count_text_none\">Nei Benenes gitt</string>\n    <string name=\"subs_auto_select_language\">Velg språk automatisk</string>\n    <string name=\"subs_download_languages\">Last ned språk</string>\n    <string name=\"subs_hold_to_reset_to_default\">Hold inne for å tilbakestille</string>\n    <string name=\"continue_watching\">Fortsett å se</string>\n    <string name=\"action_remove_watching\">ta bort</string>\n    <string name=\"action_open_watching\">Mer informasjon</string>\n    <string name=\"vpn_might_be_needed\">En VPN kan være nødvendig for at denne leverandøren skal fungere</string>\n    <string name=\"vpn_torrent\">Denne leverandøren er en torrent, en VPN anbefales</string>\n    <string name=\"torrent_plot\">Beskrivelse</string>\n    <string name=\"normal_no_plot\">Fant ingen handling</string>\n    <string name=\"torrent_no_plot\">Ingen beskrivelse funnet</string>\n    <string name=\"picture_in_picture\">Bilde-i-bilde</string>\n    <string name=\"picture_in_picture_des\">Fortsetter avspilling i en miniatyr spiller på toppen av andre apper</string>\n    <string name=\"player_size_settings\">Knapp for størrelse på spiller</string>\n    <string name=\"player_size_settings_des\">Fjern de svarte kantene</string>\n    <string name=\"player_subtitles_settings\">Undertekster</string>\n    <string name=\"player_subtitles_settings_des\">Innstillinger for spillerens teksting</string>\n    <string name=\"eigengraumode_settings\">Eigengravy Modus</string>\n    <string name=\"swipe_to_seek_settings\">Sveip for å søke</string>\n    <string name=\"swipe_to_seek_settings_des\">Sveip til venstre eller høyre for å kontrollere tiden i videospilleren</string>\n    <string name=\"swipe_to_change_settings\">Sveip for å endre innstillinger</string>\n    <string name=\"swipe_to_change_settings_des\">Sveip opp eller ned på venstre eller høyre side for å endre lysstyrke eller volum</string>\n    <string name=\"double_tap_to_seek_settings\">Dobbelttrykk til å søke</string>\n    <string name=\"double_tap_to_seek_settings_des\">Trykk to ganger på høyre eller venstre for å søke fremover eller bakover</string>\n    <string name=\"use_system_brightness_settings\">Bruk systemets lysstyrke</string>\n    <string name=\"use_system_brightness_settings_des\">Bruk systemlysstyrke i appspilleren i stedet for et mørkt overlegg</string>\n    <string name=\"search\">Søk</string>\n    <string name=\"settings_info\">Informasjon</string>\n    <string name=\"advanced_search\">Avansert søk</string>\n    <string name=\"advanced_search_des\">Gir deg søkeresultatene atskilt etter leverandør</string>\n    <string name=\"show_fillers_settings\">Vis filler-episode til anime</string>\n    <string name=\"updates_settings\">Vis appoppdateringer</string>\n    <string name=\"updates_settings_des\">Søk automatisk etter nye oppdateringer etter at appen har startet.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Light novel app av samme devs</string>\n    <string name=\"anim\">Anime app av samme devs</string>\n    <string name=\"discord\">Bli med Discord</string>\n    <string name=\"benene\">Gi en benene til devs</string>\n    <string name=\"benene_des\">Gitt benene</string>\n    <string name=\"app_language\">appspråk</string>\n    <string name=\"no_chromecast_support_toast\">Denne leverandøren har ingen Chromecast-støtte</string>\n    <string name=\"no_links_found_toast\">Ingen lenker funnet</string>\n    <string name=\"copy_link_toast\">Linken er kopiert til utklippstavlen</string>\n    <string name=\"play_episode_toast\">spille episode</string>\n    <string name=\"subs_default_reset_toast\">tilbakestill standardverdien</string>\n    <string name=\"season\">Sesong</string>\n    <string name=\"no_season\">Ingen sesong</string>\n    <string name=\"episode\">Episode</string>\n    <string name=\"episodes\">Episoder</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"delete_file\">Slett fil</string>\n    <string name=\"delete\">Slett</string>\n    <string name=\"cancel\">Avbryt</string>\n    <string name=\"pause\">Stopp</string>\n    <string name=\"resume\">Gjenoppta</string>\n    <string name=\"delete_message\">Dette vil slette %s\n\\nEr du sikker?</string>\n    <string name=\"status_ongoing\">Pågående</string>\n    <string name=\"status_completed\">Fullført</string>\n    <string name=\"status\">Posisjon</string>\n    <string name=\"year\">År</string>\n    <string name=\"rating\">Vurdering</string>\n    <string name=\"duration\">Varighet</string>\n    <string name=\"site\">Nettstedet</string>\n    <string name=\"synopsis\">Om</string>\n    <string name=\"queued\">I kø</string>\n    <string name=\"no_subtitles\">Ingen undertekster</string>\n    <string name=\"action_default\">Misligholde</string>\n    <string name=\"free_storage\">Tilgjengelig</string>\n    <string name=\"used_storage\">Brukt</string>\n    <string name=\"app_storage\">applikasjon</string>\n    <string name=\"movies\">Filmer</string>\n    <string name=\"tv_series\">TV-serier</string>\n    <string name=\"cartoons\">Tegneserier</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrent</string>\n    <string name=\"source_error\">Kildefeil</string>\n    <string name=\"remote_error\">Fjernfeil</string>\n    <string name=\"render_error\">Gjengivelsesfeil</string>\n    <string name=\"unexpected_error\">Uventet spillerfeil</string>\n    <string name=\"storage_error\">Nedlastingsfeil, sjekk lagringstillatelser</string>\n    <string name=\"episode_action_chromecast_episode\">Støpt Episode</string>\n    <string name=\"episode_action_chromecast_mirror\">Støpt Speil</string>\n    <string name=\"episode_action_play_in_app\">Spill i appen</string>\n    <string name=\"episode_action_play_in_format\">Spill i %s</string>\n    <string name=\"episode_action_auto_download\">Automatisk nedlasting</string>\n    <string name=\"episode_action_download_mirror\">Last ned speil</string>\n    <string name=\"episode_action_reload_links\">Last inn lenker på nytt</string>\n    <string name=\"no_update_found\">Ingen oppdatering funnet</string>\n    <string name=\"check_for_update\">Se etter oppdatering</string>\n    <string name=\"video_lock\">Låse</string>\n    <string name=\"video_aspect_ratio_resize\">Endre størrelse</string>\n    <string name=\"video_source\">Kilde</string>\n    <string name=\"video_skip_op\">Hoppe OP</string>\n    <string name=\"dont_show_again\">Ikke vis igjen</string>\n    <string name=\"update\">Oppdater</string>\n    <string name=\"watch_quality_pref\">Foretrukket avspillingskvalitet (WiFi)</string>\n    <string name=\"dns_pref\">DNS rundt HTTPS</string>\n    <string name=\"dns_pref_summary\">Nyttig til omgå Internettleverandør hinder</string>\n    <string name=\"display_subbed_dubbed_settings\">Vis dubbet/subbed Anime</string>\n    <string name=\"resize_fit\">Tilpass til skjermen</string>\n    <string name=\"resize_fill\">Tøye ut</string>\n    <string name=\"resize_zoom\">Zoome</string>\n    <string name=\"category_general\">Grunnleggende</string>\n    <string name=\"provider_lang_settings\">Leverandør Språk</string>\n    <string name=\"app_layout\">App Oppsett</string>\n    <string name=\"automatic\">Automatisk</string>\n    <string name=\"tv_layout\">Tv Oppsett</string>\n    <string name=\"phone_layout\">Mobile Oppsett</string>\n    <string name=\"primary_color_settings\">Primær Farge</string>\n    <string name=\"app_theme_settings\">App Tema</string>\n    <string name=\"preferred_media_settings\">Foretrukket Videoinnhold</string>\n    <string name=\"cast_format\" formatted=\"true\">Besetning: %s</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"sort_clear\">Tøm</string>\n    <string name=\"category_account\">Kontoer</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"play_with_app_name\">Spill med CloudStream</string>\n    <string name=\"sort_copy\">Kopier</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episode %d vil bli sluppet om</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dt %2$dm</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"sort_close\">Lukk</string>\n    <string name=\"subs_subtitle_languages\">Undertekstspråk</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dt %3$dm</string>\n    <string name=\"sort_save\">Lagre</string>\n    <string name=\"show_log_cat\">Vis Logcat 🐈</string>\n    <string name=\"chromecast_subtitles_settings_des\">Innstillinger for Chromecast-innstillinger</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Blafringsmengde</string>\n    <string name=\"restore_settings\">Gjenopprett data fra sikkerhetskopi</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"documentaries_singular\">Dokumentar</string>\n    <string name=\"documentaries\">Dokumentarer</string>\n    <string name=\"asian_drama\">Asiatiske drama</string>\n    <string name=\"livestreams\">Direktestrømmer</string>\n    <string name=\"others\">Andre</string>\n    <string name=\"asian_drama_singular\">Asiatisk drama</string>\n    <string name=\"live_singular\">Direktestrøm</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"switch_account\">Bytt konto</string>\n    <string name=\"sync_score\">Vurdert</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d/10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"recommended\">Anbefalt</string>\n    <string name=\"player_load_subtitles\">Last inn fra fil</string>\n    <string name=\"player_load_subtitles_online\">Last inn fra Internett</string>\n    <string name=\"downloaded_file\">Nedlastet fil</string>\n    <string name=\"actor_background\">Bakgrunn</string>\n    <string name=\"home_source\">Kilde</string>\n    <string name=\"home_random\">Tilfeldig</string>\n    <string name=\"extension_rating\" formatted=\"true\">Vurdering: %s</string>\n    <string name=\"safe_mode_crash_info\">Vis krasjinfo</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"extension_size\">Størrelse</string>\n    <string name=\"extension_types\">Støttet</string>\n    <string name=\"extension_install_first\">Installer utvidelsen først</string>\n    <string name=\"hls_playlist\">HLS-spilleliste</string>\n    <string name=\"player_pref\">Foretrukket videospiller</string>\n    <string name=\"player_settings_play_in_app\">Intern spiller</string>\n    <string name=\"all_languages_preference\">Alle språk</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Hopp over %s</string>\n    <string name=\"clear_history\">Tøm historikk</string>\n    <string name=\"action_mark_as_watched\">Marker som sett</string>\n    <string name=\"yes\">Ja</string>\n    <string name=\"no\">Nei</string>\n    <string name=\"remove_site_pref\">Fjern siden</string>\n    <string name=\"max\">Maks</string>\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"episode_action_download_subtitle\">Last ned undertekster</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"add_site_pref\">Klon siden</string>\n    <string name=\"random_button_settings_desc\">Vis tilfeldig-knapp på hjemmesiden</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"min\">Min</string>\n    <string name=\"tv_series_singular\">Serie</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"category_providers\">Tilbydere</string>\n    <string name=\"category_ui\">Tilpasning</string>\n    <string name=\"random_button_settings\">Tilfeldig-knapp</string>\n    <string name=\"emulator_layout\">Emulator-tilpasning</string>\n    <string name=\"subtitles_raised\">Opphøyd</string>\n    <string name=\"account\">konto</string>\n    <string name=\"logout\">Logg ut</string>\n    <string name=\"create_account\">Opprett konto</string>\n    <string name=\"none\">Ingen</string>\n    <string name=\"video_tracks\">Videospor</string>\n    <string name=\"add_sync\">Legg til sporing</string>\n    <string name=\"all\">Alle</string>\n    <string name=\"extension_description\">Beskrivelse</string>\n    <string name=\"add_account\">Legg til konto</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"double_tap_to_pause_settings\">Dobbelttrykk for å sette på pause</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"subtitles_shadow\">Skygge</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"coming_soon\">Kommer snart …</string>\n    <string name=\"extension_version\">Versjon</string>\n    <string name=\"extension_language\">Språk</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast-undertekster</string>\n    <string name=\"autoplay_next_settings\">Autospill neste episode</string>\n    <string name=\"history\">Historikk</string>\n    <string name=\"double_tap_to_pause_settings_des\">Trykk to ganger midt på skjermen for å pause</string>\n    <string name=\"no_episodes_found\">Fant ingen episoder</string>\n    <string name=\"filler\" formatted=\"true\">Fyllstoff</string>\n    <string name=\"play_livestream_button\">Spill direktestrøm</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importer skrifter ved å plassere den i %s</string>\n    <string name=\"autoplay_next_settings_des\">Start neste episode når den som spiller slutter</string>\n    <string name=\"episode_sync_settings\">Oppdater visningsframdrift</string>\n    <string name=\"kitsu_settings\">Vis plakater fra Kitsu</string>\n    <string name=\"automatic_plugin_download\">Last ned programtillegg automatisk</string>\n    <string name=\"cartoons_singular\">Tegnefilm</string>\n    <string name=\"show_title\">Navn</string>\n    <string name=\"nginx_url_pref\">NGINX-tjenernettadresse</string>\n    <string name=\"download_path_pref\">Nedlastingssti</string>\n    <string name=\"subtitles_encoding\">Undertekst-koding</string>\n    <string name=\"example_email\">Hei@verden.no</string>\n    <string name=\"example_site_name\">MinKuleSide</string>\n    <string name=\"example_site_url\">eksempel.no</string>\n    <string name=\"login\">Logg inn</string>\n    <string name=\"added_sync_format\" formatted=\"true\">La til %s</string>\n    <string name=\"subtitles_outline\">Omriss</string>\n    <string name=\"subtitles_depressed\">Nedsenket</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Lastet inn %s</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Ingen undertekstforsinkelse</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Bruk dette hvis undertekster vises %d ms for tidlig</string>\n    <string name=\"actor_main\">Hovedrolle</string>\n    <string name=\"actor_supporting\">Støtterolle</string>\n    <string name=\"next\">Neste</string>\n    <string name=\"referer\">Referanse</string>\n    <string name=\"plugin_deleted\">Programtillegg slettet</string>\n    <string name=\"repository_name_hint\">Pakkebrønnsnavn</string>\n    <string name=\"repository_url_hint\">Pakkebrønnsnettadresse</string>\n    <string name=\"add_repository\">Legg til pakkebrønn</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Kunne ikke laste inn %s</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Nedlastet: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Avskrudd: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Ikke nedlastet: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Oppdaterte %d programtillegg</string>\n    <string name=\"setup_extensions_subtext\">Last ned listen over sider du vil bruke</string>\n    <string name=\"delete_repository_plugins\">Dette vil også slette alle pakkebrønnsprogramtillegg</string>\n    <string name=\"view_public_repositories_button\">Vis gemenskapspakkebrønner</string>\n    <string name=\"download_all_plugins_from_repo\">Last ned alle programtilleggene fra denne pakkebrønnen?</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (avskrudd)</string>\n    <string name=\"tracks\">Spor</string>\n    <string name=\"app_not_found_error\">Fant ikke programmet</string>\n    <string name=\"clipboard_too_large\">For mye tekst. Kunne ikke lagre i utklippstavlen.</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Søk i %s …</string>\n    <string name=\"stream\">Strøm</string>\n    <string name=\"provider_info_meta\">Metadata tilbys ikke av siden, videoinnlasting vil mislykkes hvis den ikke finnes på siden.</string>\n    <string name=\"type_re_watching\">Ser om igjen</string>\n    <string name=\"automatic_plugin_updates\">Automatiske programtilleggsoppdateringer</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Klarte ikke å gjenopprette data fra fil %s</string>\n    <string name=\"backup_failed_error_format\">Kunne ikke sikkerhetskopiere %s</string>\n    <string name=\"example_password\">passord123</string>\n    <string name=\"example_lang_name\">Språkkode (nb_NO)</string>\n    <string name=\"previous\">Forrige</string>\n    <string name=\"extensions\">Utvidelser</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"example_username\">MittKuleBrukernavn</string>\n    <string name=\"skip_setup\">Hopp over oppsett</string>\n    <string name=\"preferred_media_subtext\">Hva du ønsker å se</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"provider_languages_tip\">Se videoer på disse språkene</string>\n    <string name=\"setup_done\">Ferdig</string>\n    <string name=\"plugin_singular\">programtillegg</string>\n    <string name=\"safe_mode_title\">Trygt modus påslått</string>\n    <string name=\"action_add_to_bookmarks\">Sett visningsstatus</string>\n    <string name=\"episode_sync_settings_des\">Synkroniser automatisk fremdriften din for gjeldende episode</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"view_public_repositories_button_short\">Offentlig liste</string>\n    <string name=\"plugin\">programtillegg</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nigjen</string>\n    <string name=\"limit_title_rez\">Videooppløsning</string>\n    <string name=\"subtitle_offset\">Synkroniser undertekster</string>\n    <string name=\"subtitle_offset_title\">Undertekstforsinkelse</string>\n    <string name=\"subtitles_example_text\">Sær golfer med kølle vant sexquiz på WC i hjemby</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"error_invalid_data\">Ugyldig data</string>\n    <string name=\"category_player\">Avspiller</string>\n    <string name=\"resolution\">Oppløsning</string>\n    <string name=\"poster_image\">Plakatbilde</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"resolution_and_title\">Oppløsning og navn</string>\n    <string name=\"title\">Navn</string>\n    <string name=\"error_invalid_id\">Ugyldig ID</string>\n    <string name=\"error\">Feil</string>\n    <string name=\"app_layout_subtext\">Endre programutseende for å passe din enhet</string>\n    <string name=\"error_invalid_url\">Ugyldig nettadresse</string>\n    <string name=\"batch_download\">Knippe-nedlasting</string>\n    <string name=\"delete_repository\">Slett pakkebrønn</string>\n    <string name=\"blank_repo_message\">CloudStream har ingen sider installert som forvalg. Du må installere sidene fra pakkebrønner.\n\\n\n\\nSom følge av en hjernedød DMCA-forespørsel fra Sky UK Limited 🤮 kan vi ikke lenke til pakkebrønnssiden i programmet.\n\\n\n\\nTa del i vår Discord, eller søk på nett.</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Bruk dette hvis undertekster vises %d ms for sent</string>\n    <string name=\"plugin_loaded\">Programtillegg innlastet</string>\n    <string name=\"audio_tracks\">Lydspor</string>\n    <string name=\"skip_type_creddits\">Rulletekst</string>\n    <string name=\"skip_type_intro\">Introduksjon</string>\n    <string name=\"backup_failed\">Lagringstilgang mangler. Prøv igjen.</string>\n    <string name=\"show_trailers_settings\">Vis trailere</string>\n    <string name=\"show_dub\">Dubbingsetikett</string>\n    <string name=\"show_sub\">Undertekstetikett</string>\n    <string name=\"video_buffer_size_settings\">Videomellomlagringsstørrelse</string>\n    <string name=\"video_buffer_length_settings\">Videomellomlagringslengde</string>\n    <string name=\"video_buffer_disk_settings\">Videohurtiglager på disk</string>\n    <string name=\"video_buffer_clear_settings\">Tøm video- og bildehurtiglager</string>\n    <string name=\"add_site_summary\">Legg til en klone av en eksisterende side, med en annen nettadresse</string>\n    <string name=\"automatic_plugin_download_summary\">Installer automatisk alle plugins som ikke er installert fra de tilføyde depotene.</string>\n    <string name=\"show_hd\">Kvalitetsetikett</string>\n    <string name=\"poster_ui_settings\">Slå av/på grensesnittselementer på plakat</string>\n    <string name=\"skip_update\">Hopp over denne oppdateringen</string>\n    <string name=\"video_ram_description\">Kan forårsake krasj hvis satt for høyt på enheter med lite minne, for eksempel en Android TV.</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"backup_settings\">Sikkerhetskopier data</string>\n    <string name=\"backup_success\">Data lagret</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Kunne ikke logge inn på %s</string>\n    <string name=\"uppercase_all_subtitles\">Store bokstaver i undertekster</string>\n    <string name=\"extension_authors\">Utviklere</string>\n    <string name=\"nsfw\">Sensurerbart</string>\n    <string name=\"quality_webrip\">Vev</string>\n    <string name=\"network_adress_example\">Lenke til strøm</string>\n    <string name=\"anime_singular\">@string/anime</string>\n    <string name=\"pref_filter_search_quality\">Skjul valgt videokvalitet i søkeresultater</string>\n    <string name=\"restore_success\">Lastet inn sikkerhetkopifil</string>\n    <string name=\"category_updates\">Oppdateringer og sikkerhetskopier</string>\n    <string name=\"ova_singular\">@string/ova</string>\n    <string name=\"confirm_exit_dialog\">Avslutt?</string>\n    <string name=\"nsfw_singular\">Sensurerbart</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Alle %s er allerede nedlastet</string>\n    <string name=\"update_notification_failed\">Kunne ikke installere den nye versjonen av programmet</string>\n    <string name=\"update_notification_installing\">Installerer appoppdatering…</string>\n    <string name=\"update_notification_downloading\">Laster ned ny versjon av programmet …</string>\n    <string name=\"upload_sync\">Synkroniser</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s innlogget</string>\n    <string name=\"video_disk_description\">Forårsaker problemer hvis satt for høyt på enheter med lite lagringsplass, som f.eks. Android TV.</string>\n    <string name=\"bottom_title_settings\">Posisjon for plakatnavn</string>\n    <string name=\"skip_type_mixed_op\">Blandet begynnelse</string>\n    <string name=\"skip_type_op\">Begynnelse</string>\n    <string name=\"skip_type_mixed_ed\">Blandet slutt</string>\n    <string name=\"skip_type_ed\">Slutt</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"limit_title\">Maks. antall tegn for navn i videospiller</string>\n    <string name=\"enable_skip_op_from_database_des\">Vis oppsprett for å hoppe over begynnelse/slutt</string>\n    <string name=\"enable_nsfw_on_providers\">Skru på sensurerbart innhold for støttede tilbydere</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"subtitles_remove_captions\">Fjern døveteksting fra undertekster</string>\n    <string name=\"subtitles_remove_bloat\">Fjern unødvendig informasjon fra undertekster</string>\n    <string name=\"extras\">Ekstra</string>\n    <string name=\"subtitles_filter_lang\">Filtrer etter foretrukket mediaspråk</string>\n    <string name=\"skip_type_recap\">Tilbakeblikk</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"trailer\">Forfilm</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Lastet ned %1$d %2$s</string>\n    <string name=\"bottom_title_settings_des\">Navn under plakat</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Begynte nedlasting av %1$d %2$s …</string>\n    <string name=\"apply_on_restart\">Bruk etter omstart av programmet</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"safe_mode_description\">Alle utvidelser ble skrudd av som følge av et krasj for å hjelpe deg å finne det som lager trøbbel.</string>\n    <string name=\"play_trailer_button\">Spill forfilm</string>\n    <string name=\"pref_category_links\">Lenker</string>\n    <string name=\"pref_category_app_updates\">Programoppgraderinger</string>\n    <string name=\"pref_category_extensions\">Utvidelser</string>\n    <string name=\"pref_category_actions\">Handlinger</string>\n    <string name=\"pref_category_cache\">Hurtiglager</string>\n    <string name=\"pref_category_gestures\">Håndvendinger</string>\n    <string name=\"pref_category_player_features\">Avspillerfunksjoner</string>\n    <string name=\"pref_category_player_layout\">Tilpasning</string>\n    <string name=\"pref_category_defaults\">Forvalg</string>\n    <string name=\"pref_category_looks\">Utseende</string>\n    <string name=\"pref_category_ui_features\">Funksjoner</string>\n    <string name=\"apk_installer_legacy\">Gammeldags</string>\n    <string name=\"apk_installer_package_installer\">PakkeInstallatør</string>\n    <string name=\"redo_setup_process\">Gjenta oppsettsprosess</string>\n    <string name=\"pref_category_subtitles\">Undertekster</string>\n    <string name=\"pref_category_backup\">Sikkerhetskopi</string>\n    <string name=\"apk_installer_settings\">APK-installatør</string>\n    <string name=\"apk_installer_settings_des\">Noen telefoner støtter ikke den nye pakkeinstallatøren. Prøv det eldre alternativet hvis oppdateringer ikke blir installert.</string>\n    <string name=\"update_started\">Oppdatering startet</string>\n    <string name=\"plugin_downloaded\">Programtillegg nedlastet</string>\n    <string name=\"delayed_update_notice\">Programmet vil oppgraderes når du avslutter det</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Blafringsmengde med synlig avspiller</string>\n    <string name=\"restart\">Start på ny</string>\n    <string name=\"jsdelivr_proxy\">raw.githubusercontent.com-mellomtjener</string>\n    <string name=\"sort_by\">Sorter etter</string>\n    <string name=\"open_with\">Åpne med …</string>\n    <string name=\"sort_rating_desc\">Vurdering (høy til lav)</string>\n    <string name=\"start\">Start</string>\n    <string name=\"sort_alphabetical_a\">Alfabetisk (A-Å)</string>\n    <string name=\"jsdelivr_enabled\">Kunne ikke nå GitHub. Skrur på jsDelivr-mellomtjener …</string>\n    <string name=\"category_provider_test\">Tilbyder-test</string>\n    <string name=\"library\">Bibliotek</string>\n    <string name=\"browser\">Nettleser</string>\n    <string name=\"test_log\">Logg</string>\n    <string name=\"sort_updated_new\">Oppdatert (ny til gammel)</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Skjult avspiller — blafringsmengde</string>\n    <string name=\"subscription_list_name\">Abonnert</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Vist avspiller — blafringsmengde</string>\n    <string name=\"sort_updated_old\">Oppdatert (gammel til ny)</string>\n    <string name=\"test_passed\">Vellykket</string>\n    <string name=\"subscription_episode_released\">Episode %d sluppet!</string>\n    <string name=\"watch_quality_pref_data\">Foretrukket visningskvalitet (mobildata)</string>\n    <string name=\"stop\">Stopp</string>\n    <string name=\"action_remove_from_watched\">Fjern fra sette</string>\n    <string name=\"subscription_deleted\">Abonnement på %s opphevet</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"revert\">Angre</string>\n    <string name=\"subscription_in_progress_notification\">Oppdatert abonnementer</string>\n    <string name=\"test_failed\">Mislykket</string>\n    <string name=\"sort_alphabetical_z\">Alfabetisk (Å-A)</string>\n    <string name=\"sort_rating_asc\">Vurdering (lav til høy)</string>\n    <string name=\"subscription_new\">Abonnerer på %s</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Blafringsmengde med skjult avspiller</string>\n    <string name=\"select_library\">Velg bibliotek</string>\n    <string name=\"jsdelivr_proxy_summary\">Omgår blokkering av GitHub ved hjelp av jsDelivr. Dette kan forårsake forsinkelser på oppdateringer med noen få dager.</string>\n    <string name=\"pref_category_bypass\">ISP-omgåelser</string>\n    <string name=\"empty_library_logged_in_message\">Denne listen er tom. Prøv å bytte til en annen.</string>\n    <string name=\"sort\">Sorter</string>\n    <string name=\"safe_mode_file\">Fant fil for trygt modus.\n\\nLaster ikke inn noen utvidelser ved oppstart til filen er fjernet.</string>\n    <string name=\"empty_library_no_accounts_message\">Biblioteket ditt er tomt :(\n\\nLogg inn på en bibliotekkonto eller legg til programmer i ditt lokale bibliotek.</string>\n    <string name=\"edit\">Rediger</string>\n    <string name=\"profiles\">Profiler</string>\n    <string name=\"favorites_list_name\">Favoritter</string>\n    <string name=\"lock_profile\">Lås profil</string>\n    <string name=\"use\">Bruk</string>\n    <string name=\"help\">Hjelp</string>\n    <string name=\"profile_background_des\">Profilbakgrunn</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+or/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"episode_more_options_des\">ଅଧିକ ଵିକଳ୍ପ</string>\n    <string name=\"type_watching\">ଦେଖୁଛନ୍ତି</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dଦି %2$dଘ %3$dମି</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dଘ %2$dମି</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dମି</string>\n    <string name=\"type_re_watching\">ପୁନଃଦେଖୁଛନ୍ତି</string>\n    <string name=\"home_expanded_hide\">ଲୁଚାଅ</string>\n    <string name=\"home_play\">ଚଲାଅ</string>\n    <string name=\"home_info\">ସୂଚନା</string>\n    <string name=\"title_home\">ଗୃହ</string>\n    <string name=\"title_search\">ସନ୍ଧାନ</string>\n    <string name=\"result_tags\">ଧରଣ</string>\n    <string name=\"type_on_hold\">ସ୍ଥଗିତ</string>\n    <string name=\"type_completed\">ସାରିଛନ୍ତି</string>\n    <string name=\"title_settings\">ସେଟିଂ</string>\n    <string name=\"duration_format\" formatted=\"true\">%d ମିନିଟ୍</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">ଵେଗ (%.2fଗୁଣ)</string>\n    <string name=\"type_dropped\">ତ୍ୟାଗିଛନ୍ତି</string>\n    <string name=\"type_plan_to_watch\">ଦେଖିବା ପାଇଁ ଇଚ୍ଛୁକ</string>\n    <string name=\"home_more_info\">ଅଧିକ ସୂଚନା</string>\n    <string name=\"cast_format\" formatted=\"true\">ପାତ୍ର: %s</string>\n    <string name=\"result_poster_img_des\">ପୋଷ୍ଟର୍</string>\n    <string name=\"search_poster_img_des\">ପୋଷ୍ଟର୍</string>\n    <string name=\"play_episode_toast\">ଅଧ୍ୟାୟ ଚଲାଅ</string>\n    <string name=\"no_episodes_found\">କୌଣସି ଅଧ୍ୟାୟ ମିଳିଲା ନାହିଁ</string>\n    <string name=\"episodes\">ଟି ଅଧ୍ୟାୟ</string>\n    <string name=\"episode\">ଅଧ୍ୟାୟ</string>\n    <string name=\"episode_action_play_in_format\">%s‌ରେ ଚଲାଅ</string>\n    <string name=\"episode_action_download_subtitle\">ଉପଶୀର୍ଷକ ଡାଉନଲୋଡ୍ କରିବା</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"subscription_episode_released\">ଅଧ୍ୟାୟ %d ମୁକ୍ତିଲାଭ କଲା!</string>\n    <string name=\"episode_action_auto_download\">ସ୍ୱତଃ ଡାଉନଲୋଡ୍</string>\n    <string name=\"episode_action_reload_links\">ଲିଙ୍କ୍‌ଗୁଡ଼ିକୁ ପୁନଃଲୋଡ୍ କରିବା</string>\n    <string name=\"episode_action_play_in_app\">ଆପ୍‌ରେ ଚଲାଅ</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast ଅଧ୍ୟାୟ</string>\n    <string name=\"episode_short\">ଅ</string>\n    <string name=\"episode_poster_img_des\">ଅଧ୍ୟାୟର ପୋଷ୍ଟର୍</string>\n    <string name=\"home_main_poster_img_des\">ମୁଖ୍ୟ ପୋଷ୍ଟର୍</string>\n    <string name=\"action_default\">ଡିଫଲ୍ଟ</string>\n    <string name=\"extension_language\">ଭାଷା</string>\n    <string name=\"no\">ନାହିଁ</string>\n    <string name=\"extension_description\">ଵର୍ଣ୍ଣନା</string>\n    <string name=\"yes\">ହଁ</string>\n    <string name=\"library\">ଲାଇବ୍ରେରୀ</string>\n    <string name=\"history\">ଇତିଵୃତ୍ତି</string>\n    <string name=\"extension_authors\">ଲେଖକ</string>\n    <string name=\"skip_type_format\" formatted=\"true\">%s ବାଦ୍ ଦିଅ</string>\n    <string name=\"subs_subtitle_languages\">ଉପଶୀର୍ଷକ ଭାଷା</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (ଅକ୍ଷମ)</string>\n    <string name=\"extension_status\">ସ୍ଥିତି</string>\n    <string name=\"extension_size\">ଆକାର</string>\n    <string name=\"extension_types\">ସମର୍ଥିତ</string>\n    <string name=\"hls_playlist\">HLS ଚାଳନାତାଲିକା</string>\n    <string name=\"player_settings_play_in_app\">ଅନ୍ତଃ-ଚାଳକ</string>\n    <string name=\"skip_type_op\">ଆଦ୍ୟ</string>\n    <string name=\"skip_type_ed\">ପ୍ରାନ୍ତ</string>\n    <string name=\"app_not_found_error\">ଆପ୍ ମିଳିଲା ନାହିଁ</string>\n    <string name=\"all_languages_preference\">ସବୁ ଭାଷା</string>\n    <string name=\"skip_type_mixed_ed\">ମିଶ୍ରିତ ପ୍ରାନ୍ତ</string>\n    <string name=\"skip_type_mixed_op\">ମିଶ୍ରିତ ଆଦ୍ୟ</string>\n    <string name=\"skip_type_creddits\">ଶ୍ରେୟ</string>\n    <string name=\"skip_type_intro\">ଉପକ୍ରମ</string>\n    <string name=\"provider_languages_tip\">ଏହି ଭାଷାଗୁଡ଼ିକରେ ଵିଡ଼ିଓ ଦେଖନ୍ତୁ</string>\n    <string name=\"extension_version\">ସଂସ୍କରଣ</string>\n    <string name=\"app_language\">ଆପ୍ ଭାଷା</string>\n    <string name=\"play_episode\">ଅଧ୍ୟାୟ ଚଲାଅ</string>\n    <string name=\"season_short\">ଋ</string>\n    <string name=\"status_ongoing\">ଚଳିତ</string>\n    <string name=\"copy_link_toast\">ଲିଙ୍କ୍ କ୍ଲିପ୍‌ବୋର୍ଡରେ କପି କରିନିଆଗଲା</string>\n    <string name=\"movies\">ଚଳଚ୍ଚିତ୍ର</string>\n    <string name=\"livestreams\">ସିଧାପ୍ରସାରଣ</string>\n    <string name=\"video_source\">ଉତ୍ସ</string>\n    <string name=\"no_update_found\">କୌଣସି ଅଦ୍ୟତନ ମିଳିଲା ନାହିଁ</string>\n    <string name=\"category_general\">ସାଧାରଣ</string>\n    <string name=\"dont_show_again\">ପୁନଃ ଦେଖାଅନି</string>\n    <string name=\"automatic\">ସ୍ୱତଃ</string>\n    <string name=\"error\">ତ୍ରୁଟି</string>\n    <string name=\"restore_settings\">ବ୍ୟାକଅପ୍‌ରୁ ତଥ୍ୟ ପୁନରୁଦ୍ଧାର କରିବା</string>\n    <string name=\"backup_failed\">ଷ୍ଟୋରେଜ୍ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ। ଦୟାକରି ପୁଣିଥରେ ଚେଷ୍ଟା କରନ୍ତୁ।</string>\n    <string name=\"category_updates\">ଅଦ୍ୟତନ ଏଵଂ ବ୍ୟାକଅପ୍</string>\n    <string name=\"pref_category_backup\">ବ୍ୟାକଅପ୍</string>\n    <string name=\"pref_category_android_tv\">ଆଣ୍ଡ୍ରଏଡ୍ ଟିଵି</string>\n    <string name=\"pref_category_gestures\">ଅଙ୍ଗଭଙ୍ଗୀ</string>\n    <string name=\"new_update_format\" formatted=\"true\">ନୂଆ ଅଦ୍ୟତନ ମିଳିଲା!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"duration\">ଅଵଧି</string>\n    <string name=\"app_storage\">ଆପ୍</string>\n    <string name=\"restore_success\">ବ୍ୟାକଅପ୍ ଫାଇଲ୍ ଧାରଣ ହେଲା</string>\n    <string name=\"backup_success\">ତଥ୍ୟ ଗଚ୍ଛିତ ହୋଇଛି</string>\n    <string name=\"backup_failed_error_format\">%s ବ୍ୟାକଅପ୍ ନେବାରେ ତ୍ରୁଟି ଘଟିଲା</string>\n    <string name=\"season\">ଋତୁ</string>\n    <string name=\"no_season\">କୌଣସି ଋତୁ ନାହିଁ</string>\n    <string name=\"delete_file\">ଫାଇଲ୍ ଵିଲୋପ କରିବେ</string>\n    <string name=\"test_passed\">ପାରିତ ହେଲା</string>\n    <string name=\"go_back_30\">-୩୦</string>\n    <string name=\"status\">ସ୍ଥିତି</string>\n    <string name=\"used_storage\">ଵ୍ୟଵହୃତ</string>\n    <string name=\"tv_series\">ଟିଵି ଧାରାଵାହିକ</string>\n    <string name=\"asian_drama\">ଏସୀୟ ନାଟକ</string>\n    <string name=\"others\">ଅନ୍ୟାନ୍ୟ</string>\n    <string name=\"other_singular\">ଵିଡ଼ିଓ</string>\n    <string name=\"source_error\">ଉତ୍ସ ତ୍ରୁଟି</string>\n    <string name=\"unexpected_error\">ଅପ୍ରତ୍ୟାଶିତ ଚାଳକ ତ୍ରୁଟି</string>\n    <string name=\"show_title\">ଆଖ୍ୟା</string>\n    <string name=\"check_for_update\">ଅଦ୍ୟତନ ପାଇଁ ଯାଞ୍ଚ କରିବା</string>\n    <string name=\"video_lock\">ତାଲା</string>\n    <string name=\"video_aspect_ratio_resize\">ଆକାର ଠିକ୍ କରିବା</string>\n    <string name=\"skip_update\">ଏହି ଅଦ୍ୟତନଟିକୁ ବାଦ୍ ଦିଅ</string>\n    <string name=\"pref_category_actions\">କୃତ୍ୟ</string>\n    <string name=\"pref_category_subtitles\">ଉପଶୀର୍ଷକ</string>\n    <string name=\"pref_category_ui_features\">ଵୈଶିଷ୍ଟ୍ୟସବୁ</string>\n    <string name=\"pref_category_looks\">ଵେଶ</string>\n    <string name=\"pref_category_defaults\">ଡିଫଲ୍ଟଗୁଡ଼ା</string>\n    <string name=\"primary_color_settings\">ପ୍ରାଥମିକ ରଙ୍ଗ</string>\n    <string name=\"added_sync_format\" formatted=\"true\">%s ଯୋଡ଼ାଗଲା</string>\n    <string name=\"title\">ଆଖ୍ୟା</string>\n    <string name=\"setup_done\">ହେଲା</string>\n    <string name=\"update_notification_downloading\">ଆପ୍ ଅଦ୍ୟତନ ଡାଉନଲୋଡ୍ ଚାଲିଛି…</string>\n    <string name=\"update_notification_installing\">ଆପ୍ ଅଦ୍ୟତନ ଅଧିସ୍ଥାପନ ଚାଲିଛି…</string>\n    <string name=\"update_notification_failed\">ଆପ୍‌ର ନୂଆ ସଂସ୍କରଣ ଅଧିସ୍ଥାପନ କରିହେଲା ନାହିଁ</string>\n    <string name=\"test_failed\">ଵିଫଳ ହେଲା</string>\n    <string name=\"category_player\">ଚାଳକ</string>\n    <string name=\"backup_settings\">ତଥ୍ୟର ବ୍ୟାକଅପ୍ ନେବା</string>\n    <string name=\"delete\">ଵିଲୋପ କର</string>\n    <string name=\"documentaries\">ଵୃତ୍ତଚିତ୍ର</string>\n    <string name=\"anime_singular\">ଅନିମେ</string>\n    <string name=\"tv_series_singular\">ଧାରାଵାହିକ</string>\n    <string name=\"movies_singular\">ଚଳଚ୍ଚିତ୍ର</string>\n    <string name=\"documentaries_singular\">ଵୃତ୍ତଚିତ୍ର</string>\n    <string name=\"asian_drama_singular\">ଏସୀୟ ନାଟକ</string>\n    <string name=\"live_singular\">ସିଧାପ୍ରସାରଣ</string>\n    <string name=\"show_hd\">ଗୁଣଵତ୍ତା ଲେବଲ୍</string>\n    <string name=\"update\">ଅଦ୍ୟତନ କରିବା</string>\n    <string name=\"pref_category_player_features\">ଚାଳକ ଵୈଶିଷ୍ଟ୍ୟସବୁ</string>\n    <string name=\"app_theme_settings\">ଆପ୍ ଥିମ୍</string>\n    <string name=\"subs_auto_select_language\">ଭାଷା ସ୍ୱତଃ-ଚୟନ</string>\n    <string name=\"anime\">ଅନିମେ</string>\n    <string name=\"player_subtitles_settings\">ଉପଶୀର୍ଷକ</string>\n    <string name=\"go_forward_30\">+୩୦</string>\n    <string name=\"year\">ଵର୍ଷ</string>\n    <string name=\"download_storage_text\">ଅନ୍ତଃ-ଷ୍ଟୋରେଜ୍</string>\n    <string name=\"home_change_provider_img_des\">ପ୍ରଦାତା ବଦଳାଅ</string>\n    <string name=\"search_provider_text_providers\">ପ୍ରଦାତା ଵ୍ୟଵହାର କରି ଖୋଜିବା</string>\n    <string name=\"coming_soon\">ଶୀଘ୍ର ଆସୁଅଛି…</string>\n    <string name=\"updates_settings\">ଆପ୍ ଅଦ୍ୟତନ ଦେଖାଇବା</string>\n    <string name=\"update_started\">ଅଦ୍ୟତନ ଆରମ୍ଭ ହୋଇଛି</string>\n    <string name=\"search_hint\">ସନ୍ଧାନ କରିବା…</string>\n    <string name=\"skip_type_recap\">ସଂକ୍ଷିପ୍ତବୃତ୍ତି</string>\n    <string name=\"play_movie_button\">ଚଳଚ୍ଚିତ୍ର ଚଲାଅ</string>\n    <string name=\"search_hint_site\" formatted=\"true\">%s ସନ୍ଧାନ କରିବା…</string>\n    <string name=\"next_episode\">ପରବର୍ତ୍ତୀ ଅଧ୍ୟାୟ</string>\n    <string name=\"no_data\">କୌଣସି ତଥ୍ୟ ନାହିଁ</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s ଅ %2$d</string>\n    <string name=\"video_skip_op\">ଆଦ୍ୟ ବାଦ୍ ଦିଅ</string>\n    <string name=\"next_episode_format\" formatted=\"true\">ଏପିସୋଡ୍ %d ମୁକ୍ତିଲାଭ କରିବ</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">ସିଜିନ୍ %1$d ଏପିସୋଡ୍ %2$d ମୁକ୍ତିଲାଭ କରିବ</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dଘଣ୍ଟା %2$dମିନିଟ୍ %3$dସେକେଣ୍ଡ</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+pl/array.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <array name=\"cast_mini_controller_control_buttons\">\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_play_pause_toggle</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n    <array name=\"cast_expanded_controller_control_buttons\">\n        <!-- Fake sources button -->\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n        <!-- Actually fake to make the skip op button the same style -->\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n\n    <string-array name=\"extension_statuses\">\n        <item>Nie działa</item>\n        <!-- \"Ok\" is usually capitalized as \"OK\". Ok android studio 🤓-->\n        <item>Ok</item>\n        <item>Wolny</item>\n        <item>Beta</item>\n    </string-array>\n\n\n    <array name=\"title_info_pref_names\">\n        <item>@string/source_name</item>\n        <item>@string/resolution</item>\n        <item>@string/video_info</item>\n    </array>\n\n    <array name=\"title_info_pref_values\">\n        <item>@string/show_name_key</item>\n        <item>@string/show_resolution_key</item>\n        <item>@string/show_media_info_key</item>\n    </array>\n\n\n\n    <array name=\"limit_title_pref_names\">\n        <item>@string/none</item>\n        <item>16 znaków</item>\n        <item>32 znaków</item>\n        <item>64 znaków</item>\n        <item>128 znaków</item>\n        <item>Ukryj tytuł</item>\n    </array>\n    <array name=\"limit_title_pref_values\">\n        <item>0</item>\n        <item>16</item>\n        <item>32</item>\n        <item>64</item>\n        <item>128</item>\n        <item>-1</item>\n    </array>\n\n    <array name=\"skip_sec_values\">\n        <item>5</item>\n        <item>10</item>\n        <item>15</item>\n        <item>20</item>\n        <item>25</item>\n        <item>30</item>\n    </array>\n\n    <array name=\"video_buffer_length_names\">\n        <item>@string/automatic</item>\n        <item>1min</item>\n        <item>1min 30s</item>\n        <item>2min</item>\n        <item>2min 30s</item>\n        <item>3min</item>\n        <item>3min 30s</item>\n        <item>4min</item>\n        <item>5min</item>\n        <item>6min</item>\n        <item>7min</item>\n        <item>8min</item>\n        <item>9min</item>\n        <item>10min</item>\n        <item>15min</item>\n        <item>20min</item>\n        <item>30min</item>\n    </array>\n\n    <array name=\"video_buffer_length_values\">\n        <item>0</item>\n        <item>60</item>\n        <item>90</item>\n        <item>120</item>\n        <item>150</item>\n        <item>180</item>\n        <item>210</item>\n        <item>240</item>\n        <item>300</item>\n        <item>360</item>\n        <item>420</item>\n        <item>480</item>\n        <item>540</item>\n        <item>600</item>\n        <item>900</item>\n        <item>1200</item>\n        <item>1800</item>\n    </array>\n\n    <array name=\"video_buffer_size_names\">\n        <item>@string/automatic</item>\n        <item>10MB</item>\n        <item>20MB</item>\n        <item>30MB</item>\n        <item>40MB</item>\n        <item>50MB</item>\n        <item>60MB</item>\n        <item>70MB</item>\n        <item>80MB</item>\n        <item>90MB</item>\n        <item>100MB</item>\n        <item>150MB</item>\n        <item>200MB</item>\n        <item>250MB</item>\n        <item>300MB</item>\n        <item>350MB</item>\n        <item>400MB</item>\n        <item>450MB</item>\n        <item>500MB</item>\n    </array>\n\n    <array name=\"video_buffer_size_values\">\n        <item>0</item>\n        <item>10</item>\n        <item>20</item>\n        <item>30</item>\n        <item>40</item>\n        <item>50</item>\n        <item>60</item>\n        <item>70</item>\n        <item>80</item>\n        <item>90</item>\n        <item>100</item>\n        <item>150</item>\n        <item>200</item>\n        <item>250</item>\n        <item>300</item>\n        <item>350</item>\n        <item>400</item>\n        <item>450</item>\n        <item>500</item>\n    </array>\n\n    <array name=\"poster_ui_options\">\n        <item>@string/show_hd</item>\n        <item>@string/show_dub</item>\n        <item>@string/show_sub</item>\n        <item>@string/show_rating</item>\n        <item>@string/show_title</item>\n        <item>@string/show_episode_text</item>\n    </array>\n\n    <array name=\"poster_ui_options_values\">\n        <item>@string/show_hd_key</item>\n        <item>@string/show_dub_key</item>\n        <item>@string/show_sub_key</item>\n        <item>@string/show_rating_key</item>\n        <item>@string/show_title_key</item>\n        <item>@string/show_episode_text_key</item>\n    </array>\n\n    <array name=\"app_layout\">\n        <item>@string/automatic</item>\n        <item>@string/phone_layout</item>\n        <item>@string/tv_layout</item>\n        <item>@string/emulator_layout</item>\n    </array>\n\n    <array name=\"app_layout_values\">\n        <item>-1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n    </array>\n\n    <string-array name=\"themes_overlay_names\">\n        <item>Normalny</item>\n        <item>Żółty mniszek lekarski</item>\n        <item>Goździk różowy</item>\n        <item>Pomarańczowy</item>\n        <item>Ciemnozielony</item>\n        <item>Kasztanowaty</item>\n        <item>Ciemnoniebieski</item>\n        <item>Szary</item>\n        <item>Biały</item>\n        <item>Fajny niebieski</item>\n        <item>Brązowy</item>\n        <item>Niebieski</item>\n        <item>Czerwony</item>\n        <item>Fioletowy</item>\n        <item>Miętowy</item>\n        <item>Jasnozielony</item>\n        <item>Bananowy</item>\n        <item>Łososiowy</item>\n        <item>Świnko peppowy</item>\n        <item>Lawenda</item>\n        <item>Material You</item>\n        <item>Material You (drugorzędny)</item>\n    </string-array>\n    <string-array name=\"themes_overlay_names_values\">\n        <item>Normal</item>\n        <item>DandelionYellow</item>\n        <item>CarnationPink</item>\n        <item>Orange</item>\n        <item>DarkGreen</item>\n        <item>Maroon</item>\n        <item>NavyBlue</item>\n        <item>Grey</item>\n        <item>White</item>\n        <item>CoolBlue</item>\n        <item>Brown</item>\n        <item>Blue</item>\n        <item>Red</item>\n        <item>Purple</item>\n        <item>Green</item>\n        <item>GreenApple</item>\n        <item>Banana</item>\n        <item>Party</item>\n        <item>Pink</item>\n        <item>Lavender</item>\n        <item>Monet</item>\n        <item>Monet2</item>\n    </string-array>\n\n\n    <string-array name=\"themes_names\">\n        <item>Ciemny</item>\n        <item>Szary</item>\n        <item>Amoled</item>\n        <item>Flashbang</item>\n        <item>System</item>\n        <item>Material You</item>\n        <item>Dracula</item>\n        <item>Lawendowe Marzenia</item>\n        <item>Cichy Błękit</item>\n    </string-array>\n    <string-array name=\"themes_names_values\">\n        <item>AmoledLight</item>\n        <item>Black</item>\n        <item>Amoled</item>\n        <item>Light</item>\n        <item>System</item>\n        <item>Monet</item>\n        <item>Dracula</item>\n        <item>Lavender</item>\n        <item>SilentBlue</item>\n    </string-array>\n\n    <!--https://github.com/videolan/vlc-android/blob/72ccfb93db027b49855760001d1a930fa657c5a8/application/resources/src/main/res/values/arrays.xml#L266-->\n    <string-array name=\"subtitles_encoding_list\" tools:ignore=\"TypographyDashes\">\n        <item>@string/automatic</item>\n        <item>Universal (UTF-8)</item>\n        <item>Universal (UTF-16)</item>\n        <item>Universal (big endian UTF-16)</item>\n        <item>Universal (little endian UTF-16)</item>\n        <item>Universal, Chinese (GB18030)</item>\n        <item>Western European (Latin-9)</item>\n        <item>Western European (Windows-1252)</item>\n        <item>Western European (IBM 00850)</item>\n        <item>Eastern European (Latin-2)</item>\n        <item>Eastern European (Windows-1250)</item>\n        <item>Esperanto (Latin-3)</item>\n        <item>Nordic (Latin-6)</item>\n        <item>Cyrillic (Windows-1251)</item>\n        <item>Russian (KOI8-R)</item>\n        <item>Ukrainian (KOI8-U)</item>\n        <item>Arabic (ISO 8859-6)</item>\n        <item>Arabic (Windows-1256)</item>\n        <item>Greek (ISO 8859-7)</item>\n        <item>Greek (Windows-1253)</item>\n        <item>Hebrew (ISO 8859-8)</item>\n        <item>Hebrew (Windows-1255)</item>\n        <item>Turkish (ISO 8859-9)</item>\n        <item>Turkish (Windows-1254)</item>\n        <item>Thai (TIS 620-2533/ISO 8859-11)</item>\n        <item>Thai (Windows-874)</item>\n        <item>Baltic (Latin-7)</item>\n        <item>Baltic (Windows-1257)</item>\n        <item>Celtic (Latin-8)</item>\n        <item>South-Eastern European (Latin-10)</item>\n        <item>Simplified Chinese (ISO-2022-CN-EXT)</item>\n        <item>Simplified Chinese Unix (EUC-CN)</item>\n        <item>Japanese (7-bits JIS/ISO-2022-JP-2)</item>\n        <item>Japanese Unix (EUC-JP)</item>\n        <item>Japanese (Shift JIS)</item>\n        <item>Korean (EUC-KR/CP949)</item>\n        <item>Korean (ISO-2022-KR)</item>\n        <item>Traditional Chinese (Big5)</item>\n        <item>Traditional Chinese Unix (EUC-TW)</item>\n        <item>Hong-Kong Supplementary (HKSCS)</item>\n        <item>Vietnamese (VISCII)</item>\n        <item>Vietnamese (Windows-1258)</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Prędkość (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Ocena: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Znaleziono nową aktualizację!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Filler</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"app_dub_sub_episode_text_format\">%1$s Odc. %2$d</string>\n    <string name=\"result_poster_img_des\">Obrazek</string>\n    <string name=\"episode_poster_img_des\">Obrazek odcinka</string>\n    <string name=\"home_main_poster_img_des\">Główny obrazek</string>\n    <string name=\"home_next_random_img_des\">Następny losowy</string>\n    <string name=\"go_back_img_des\">Wstecz</string>\n    <string name=\"home_change_provider_img_des\">Zmień źródło</string>\n    <string name=\"preview_background_img_des\">Pogląd tła</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Główna</string>\n    <string name=\"title_search\">Szukaj</string>\n    <string name=\"title_downloads\">Pobrane</string>\n    <string name=\"title_settings\">Ustawienia</string>\n    <string name=\"search_hint\">Szukaj…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Szukaj %s…</string>\n    <string name=\"no_data\">Brak danych</string>\n    <string name=\"episode_more_options_des\">Więcej opcji</string>\n    <string name=\"next_episode\">Następny odcinek</string>\n    <string name=\"next_episode_format\">Odcinek %d wyjdzie za</string>\n    <string name=\"result_tags\">Gatunki</string>\n    <string name=\"result_share\">Udostępnij</string>\n    <string name=\"result_open_in_browser\">Otwórz w przeglądarce</string>\n    <string name=\"skip_loading\">Pomiń ładowanie</string>\n    <string name=\"loading\">Ładowanie…</string>\n    <string name=\"type_watching\">W trakcie</string>\n    <string name=\"type_on_hold\">Zawieszone</string>\n    <string name=\"type_completed\">Zakończone</string>\n    <string name=\"type_dropped\">Porzucone</string>\n    <string name=\"type_plan_to_watch\">Planowane</string>\n    <string name=\"type_re_watching\">Ponowne oglądanie</string>\n    <string name=\"play_movie_button\">Odtwórz film</string>\n    <string name=\"play_livestream_button\">Odtwórz transmisję na żywo</string>\n    <string name=\"play_torrent_button\">Otwórz torrent</string>\n    <string name=\"pick_source\">Źródła</string>\n    <string name=\"pick_subtitle\">Napisy</string>\n    <string name=\"reload_error\">Połącz ponownie…</string>\n    <string name=\"go_back\">Wstecz</string>\n    <string name=\"play_episode\">Odtwórz odcinek</string>\n    <string name=\"download\">Pobierz</string>\n    <string name=\"downloaded\">Pobrane</string>\n    <string name=\"downloading\">Pobieranie</string>\n    <string name=\"download_paused\">Wstrzymano pobieranie</string>\n    <string name=\"download_started\">Rozpoczęto pobieranie</string>\n    <string name=\"download_failed\">Błąd przy pobieraniu</string>\n    <string name=\"download_canceled\">Anulowano pobieranie</string>\n    <string name=\"download_done\">Zakończono pobieranie</string>\n    <string name=\"stream\">Strumień sieciowy</string>\n    <string name=\"error_loading_links_toast\">Błąd przy ładowaniu linków</string>\n    <string name=\"download_storage_text\">Pamięć wewnętrzna</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Nap</string>\n    <string name=\"popup_delete_file\">Usuń plik</string>\n    <string name=\"popup_play_file\">Odtwórz plik</string>\n    <string name=\"popup_resume_download\">Wznów pobieranie</string>\n    <string name=\"popup_pause_download\">Wstrzymaj pobieranie</string>\n    <string name=\"home_more_info\">Więcej informacji</string>\n    <string name=\"home_expanded_hide\">Ukryj</string>\n    <string name=\"home_play\">Odtwórz</string>\n    <string name=\"home_info\">Informacje</string>\n    <string name=\"filter_bookmarks\">Filtruj zakładki</string>\n    <string name=\"error_bookmarks_text\">Zakładki</string>\n    <string name=\"action_remove_from_bookmarks\">Usuń</string>\n    <string name=\"action_add_to_bookmarks\">Ustaw status oglądania</string>\n    <string name=\"sort_apply\">Zastosuj</string>\n    <string name=\"sort_copy\">Kopiuj</string>\n    <string name=\"sort_close\">Zamknij</string>\n    <string name=\"sort_clear\">Wyczyść</string>\n    <string name=\"sort_save\">Zapisz</string>\n    <string name=\"player_speed\">Prędkość odtwarzania</string>\n    <string name=\"subtitles_settings\">Ustawienia napisów</string>\n    <string name=\"subs_text_color\">Kolor tekstu</string>\n    <string name=\"subs_outline_color\">Kolor konturu</string>\n    <string name=\"subs_background_color\">Kolor tła</string>\n    <string name=\"subs_window_color\">Kolor okna</string>\n    <string name=\"subs_edge_type\">Kolor krawędzi</string>\n    <string name=\"subs_subtitle_elevation\">Wzniesienie napisów</string>\n    <string name=\"subs_font\">Czcionka</string>\n    <string name=\"subs_font_size\">Rozmiar czcionki</string>\n    <string name=\"search_provider_text_providers\">Szukaj według źródeł</string>\n    <string name=\"search_provider_text_types\">Szukaj według typów</string>\n    <string name=\"benene_count_text\">Dano %d bananów</string>\n    <string name=\"benene_count_text_none\">Brak bananów</string>\n    <string name=\"subs_auto_select_language\">Wybierz język automatycznie</string>\n    <string name=\"subs_download_languages\">Pobieranie języków</string>\n    <string name=\"subs_subtitle_languages\">Język napisów</string>\n    <string name=\"subs_hold_to_reset_to_default\">Przytrzymaj, aby zresetować</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importuj czcionki, umieszczając je w %s</string>\n    <string name=\"continue_watching\">Kontyntynuj oglądanie</string>\n    <string name=\"action_remove_watching\">Usuń</string>\n    <string name=\"action_open_watching\">Więcej informacji</string>\n    <string name=\"vpn_might_be_needed\">Połączenie przez VPN może być wymagane</string>\n    <string name=\"vpn_torrent\">To źródło jest torrentem, wskazane jest użycie połączenia VPN</string>\n    <string name=\"provider_info_meta\">Metadane nie są dostarczane przez witrynę, ładowanie filmu nie powiedzie się, jeśli nie ma ich w witrynie.</string>\n    <string name=\"torrent_plot\">Opis</string>\n    <string name=\"normal_no_plot\">Nie znaleziono opisu</string>\n    <string name=\"torrent_no_plot\">Nie znaleziono opisu</string>\n    <string name=\"show_log_cat\">Pokaż Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Obraz-w-obrazie</string>\n    <string name=\"picture_in_picture_des\">Oglądaj w małym, pływającym okienku</string>\n    <string name=\"player_size_settings\">Zmień rozmiar odtwarzacza</string>\n    <string name=\"player_size_settings_des\">Usuwanie czarnych ramek</string>\n    <string name=\"player_subtitles_settings\">Napisy</string>\n    <string name=\"player_subtitles_settings_des\">Ustawienia napisów</string>\n    <string name=\"chromecast_subtitles_settings\">Napisy Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Ustawienia napisów Chromecast</string>\n    <string name=\"eigengraumode_settings\">Prędkość odtwarzania</string>\n    <string name=\"swipe_to_seek_settings\">Przesuń, aby przewinąć</string>\n    <string name=\"swipe_to_seek_settings_des\">Przesuwaj w lewo lub prawo, aby kontrolować czas filmu</string>\n    <string name=\"swipe_to_change_settings\">Przesuń, aby zmienić ustawienia</string>\n    <string name=\"swipe_to_change_settings_des\">Przesuwaj góra-dół z lewej lub prawej strony ekranu, aby zmienić jasność czy głośność</string>\n    <string name=\"autoplay_next_settings\">Autoodtwarzanie następnego odcinka</string>\n    <string name=\"autoplay_next_settings_des\">Rozpocznij następny odcinek po skończeniu bieżącego</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Czas przewinięcia przy podwójnym kliknięciu (w sekundach)</string>\n    <string name=\"double_tap_to_seek_settings\">Podwójne kliknięcie, aby przewinąć</string>\n    <string name=\"double_tap_to_seek_settings_des\">Kliknij dwa razy z prawej lub lewej strony, aby przewinąć</string>\n    <string name=\"double_tap_to_pause_settings\">Kliknij dwukrotnie, aby wstrzymać</string>\n    <string name=\"double_tap_to_pause_settings_des\">Kliknij dwukrotnie na środku, aby zatrzymać wideo</string>\n    <string name=\"use_system_brightness_settings\">Użyj jasności systemowej</string>\n    <string name=\"use_system_brightness_settings_des\">Użyj jasności systemowej w odtwarzaczu aplikacji zamiast ciemnej nakładki</string>\n    <string name=\"episode_sync_settings\">Aktualizuj postęp oglądania</string>\n    <string name=\"episode_sync_settings_des\">Automatycznie synchronizuj postęp aktualnego odcinka</string>\n    <string name=\"restore_settings\">Przywracanie danych z kopii zapasowej</string>\n    <string name=\"backup_settings\">Kopia zapasowa danych</string>\n    <string name=\"restore_success\">Wczytano plik kopii zapasowej</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Nie udało się przywrócić danych z pliku %s</string>\n    <string name=\"backup_success\">Dane zapisane z powodzeniem</string>\n    <string name=\"backup_failed\">Brak uprawnień do pamięci, spróbuj ponownie.</string>\n    <string name=\"backup_failed_error_format\">Błąd tworzenia kopii zapasowej %s</string>\n    <string name=\"search\">Szukaj</string>\n    <string name=\"category_account\">Konta i zabezpieczenia</string>\n    <string name=\"category_updates\">Aktualizacje i kopie zapasowe</string>\n    <string name=\"settings_info\">Informacje</string>\n    <string name=\"advanced_search\">Zaawansowane wyszukiwanie</string>\n    <string name=\"advanced_search_des\">Szukaj z podziałem na źródła</string>\n    <string name=\"show_fillers_settings\">Pokaż fillery dla anime</string>\n    <string name=\"show_trailers_settings\">Pokaż zwiastuny</string>\n    <string name=\"kitsu_settings\">Pokaż obrazki z Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Ukryj wybraną jakość wideo w wynikach wyszukiwania</string>\n    <string name=\"automatic_plugin_updates\">Automatyczne aktualizacje rozszerzeń</string>\n    <string name=\"automatic_plugin_download\">Automatyczne pobieranie rozszerzeń</string>\n    <string name=\"updates_settings\">Pokazuj aktualizacje</string>\n    <string name=\"updates_settings_des\">Automatycznie wyszukuj aktualizacje przy starcie.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Aplikacja do light novel od nas</string>\n    <string name=\"anim\">Aplikacja do anime od nas</string>\n    <string name=\"discord\">Serwer Discord</string>\n    <string name=\"benene\">Daj banana programistom</string>\n    <string name=\"benene_des\">Dano banana</string>\n    <string name=\"app_language\">Język aplikacji</string>\n    <string name=\"no_chromecast_support_toast\">Ten dostawca nie wspiera Chromecast</string>\n    <string name=\"no_links_found_toast\">Nie znaleziono linków</string>\n    <string name=\"copy_link_toast\">Skopiowano do schowka</string>\n    <string name=\"play_episode_toast\">Odtwórz odcinek</string>\n    <string name=\"subs_default_reset_toast\">Zresetowano</string>\n    <string name=\"season\">Sezon</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Brak sezonu</string>\n    <string name=\"episode\">Odcinek</string>\n    <string name=\"episodes\">Odcinki</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">O</string>\n    <string name=\"no_episodes_found\">Nie znaleziono odcinków</string>\n    <string name=\"delete_file\">Usuń plik</string>\n    <string name=\"delete\">Usuń</string>\n    <string name=\"cancel\">Anuluj</string>\n    <string name=\"pause\">Wstrzymaj</string>\n    <string name=\"resume\">Odtwórz</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Spowoduje to trwałe usunięcie %s\n\\nCzy jesteś pewien?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\npozostało</string>\n    <string name=\"status_ongoing\">Bieżący</string>\n    <string name=\"status_completed\">Zakończone</string>\n    <string name=\"status\">Status</string>\n    <string name=\"year\">Rok</string>\n    <string name=\"rating\">Ocena</string>\n    <string name=\"duration\">Czas trwania</string>\n    <string name=\"site\">Strona</string>\n    <string name=\"synopsis\">Streszczenie</string>\n    <string name=\"queued\">W kolejce</string>\n    <string name=\"no_subtitles\">Brak napisów</string>\n    <string name=\"action_default\">Domyślne</string>\n    <string name=\"free_storage\">Wolne</string>\n    <string name=\"used_storage\">W użyciu</string>\n    <string name=\"app_storage\">Aplikacja</string>\n    <!--plural-->\n    <string name=\"movies\">Filmy</string>\n    <string name=\"tv_series\">Seriale telewizyjne</string>\n    <string name=\"cartoons\">Kreskówki</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrenty</string>\n    <string name=\"documentaries\">Filmy dokumentalne</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Dramaty azjatyckie</string>\n    <string name=\"livestreams\">Transmisje na żywo</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Inne</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Serial telewizyjny</string>\n    <string name=\"cartoons_singular\">Kreskówka</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Film dokumentalny</string>\n    <string name=\"asian_drama_singular\">Dramat azjatycki</string>\n    <string name=\"live_singular\">Transmisja na żywo</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Inne</string>\n    <string name=\"source_error\">Błąd żródła</string>\n    <string name=\"remote_error\">Zdalny błąd</string>\n    <string name=\"render_error\">Błąd renderowania</string>\n    <string name=\"unexpected_error\">Nieoczekiwany błąd odtwarzacza</string>\n    <string name=\"storage_error\">Błąd pobierania, sprawdź uprawnienia aplikacji</string>\n    <string name=\"episode_action_chromecast_episode\">Odcinek Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Mirror dla Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Odtwórz w aplikacji</string>\n    <string name=\"episode_action_play_in_format\">Odtwórz w %s</string>\n    <string name=\"episode_action_auto_download\">Automatyczne pobieranie</string>\n    <string name=\"episode_action_download_mirror\">Pobierz mirror</string>\n    <string name=\"episode_action_reload_links\">Odśwież linki</string>\n    <string name=\"episode_action_download_subtitle\">Pobierz napisy</string>\n    <string name=\"show_hd\">Etykieta jakości</string>\n    <string name=\"show_dub\">Etykieta dubbingu</string>\n    <string name=\"show_sub\">Etykieta napisów</string>\n    <string name=\"show_title\">Tytuł</string>\n    <string name=\"poster_ui_settings\">Pokaż elementy interfejsu na obrazkach</string>\n    <string name=\"no_update_found\">Nie znaleziono aktualizacji</string>\n    <string name=\"check_for_update\">Sprawdź, czy jest aktualizacja</string>\n    <string name=\"video_lock\">Zablokuj</string>\n    <string name=\"video_aspect_ratio_resize\">Zmień rozmiar</string>\n    <string name=\"video_source\">Źródło</string>\n    <string name=\"video_skip_op\">Pomiń OP</string>\n    <string name=\"dont_show_again\">Nie pokazuj ponownie</string>\n    <string name=\"skip_update\">Pomiń tę aktualizację</string>\n    <string name=\"update\">Aktualizacja</string>\n    <string name=\"watch_quality_pref\">Domyślna jakość (WiFi)</string>\n    <string name=\"limit_title\">Maksymalna liczba znaków w tytule odtwarzacza</string>\n    <string name=\"limit_title_rez\">Pokaż informacje o odtwarzaczu</string>\n    <string name=\"video_buffer_size_settings\">Rozmiar bufora wideo</string>\n    <string name=\"video_buffer_length_settings\">Długość bufora wideo</string>\n    <string name=\"video_buffer_disk_settings\">Pamięć podręczna wideo na dysku</string>\n    <string name=\"video_buffer_clear_settings\">Wyczyść pamięć podręczną wideo i obrazów</string>\n    <string name=\"video_ram_description\">Ustawienie zbyt wysokiej wartości może powodować problemy na urządzeniach z małą ilością pamięci RAM, takich jak urządzenia Android TV lub stare telefony.</string>\n    <string name=\"video_disk_description\">Zbyt wysokie ustawienie może powodować problemy na urządzeniach z małą ilością dostęponej pamięci, takich jak urządzenia Android TV.</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"dns_pref_summary\">Przydatne w pomijaniu blokad dostawców Internetu</string>\n    <string name=\"add_site_pref\">Sklonuj stronę</string>\n    <string name=\"remove_site_pref\">Usuń stronę</string>\n    <string name=\"add_site_summary\">Dodaj klona istniejącej strony z innym adresem URL</string>\n    <string name=\"download_path_pref\">Ścieżka pobierania</string>\n    <string name=\"nginx_url_pref\">URL serwera Nginx</string>\n    <string name=\"display_subbed_dubbed_settings\">Wyświetlanie Anime z dubbingiem/napisami</string>\n    <string name=\"resize_fit\">Dopasuj do ekranu</string>\n    <string name=\"resize_fill\">Rozciągnij</string>\n    <string name=\"resize_zoom\">Powiększ</string>\n    <string name=\"legal_notice\">Zastrzeżenie</string>\n    <string name=\"category_general\">Ogólne</string>\n    <string name=\"random_button_settings\">Przycisk do losowania</string>\n    <string name=\"random_button_settings_desc\">Pokaż przycisk do losowania na stronie głównej i w bibliotece</string>\n    <string name=\"provider_lang_settings\">Języki rozszerzeń</string>\n    <string name=\"app_layout\">Układ aplikacji</string>\n    <string name=\"preferred_media_settings\">Preferowane multimedia</string>\n    <string name=\"enable_nsfw_on_providers\">Włącz NSFW w obsługiwanych rozszerzeniach</string>\n    <string name=\"subtitles_encoding\">Kodowanie napisów</string>\n    <string name=\"category_providers\">Źródła</string>\n    <string name=\"category_ui\">Układ interfejsu</string>\n    <string name=\"automatic\">Automatyczny</string>\n    <string name=\"tv_layout\">Układ dla telewizorów</string>\n    <string name=\"phone_layout\">Układ dla telefonów</string>\n    <string name=\"emulator_layout\">Układ dla emulatorów</string>\n    <string name=\"primary_color_settings\">Kolor podstawowy</string>\n    <string name=\"app_theme_settings\">Motyw aplikacji</string>\n    <string name=\"bottom_title_settings\">Pozycja tytułu względem obrazka</string>\n    <string name=\"bottom_title_settings_des\">Ustaw tytuł pod obrazkiem</string>\n    <string name=\"example_lang_name\">Kod języka (pl)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">konto</string>\n    <string name=\"logout\">Wyloguj się</string>\n    <string name=\"login\">Zaloguj się</string>\n    <string name=\"switch_account\">Przełącz konto</string>\n    <string name=\"add_account\">Dodaj konto</string>\n    <string name=\"create_account\">Utwórz konto</string>\n    <string name=\"add_sync\">Dodaj synchronizację</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Dodano %s</string>\n    <string name=\"upload_sync\">Synchronizacja</string>\n    <string name=\"sync_score\">Oceniono</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d na 10</string>\n    <string name=\"authenticated_user\" formatted=\"true\">Uwierzytelniono %s</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Nie udało się uwierzytelnić %s</string>\n    <!-- ============ -->\n    <string name=\"none\">Brak</string>\n    <string name=\"normal\">Normalne</string>\n    <string name=\"all\">Wszystko</string>\n    <string name=\"max\">Maks</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Kontur</string>\n    <string name=\"subtitles_depressed\">Obniżone</string>\n    <string name=\"subtitles_shadow\">Cień</string>\n    <string name=\"subtitles_raised\">Wzniesione</string>\n    <string name=\"subtitle_offset\">Synchronizacja napisów</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Opóźnienie napisów</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Użyj tego, jeśli napisy są wyświetlane %d ms za wcześnie</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Użyj tego, jeśli napisy są wyświetlane %d ms za późno</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Brak opóźnienia napisów</string>\n    <string name=\"subtitles_example_text\">Pchnąć w tę łódź jeża lub ośm skrzyń fig</string>\n    <string name=\"recommended\">Polecane</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Załadowano %s</string>\n    <string name=\"player_load_subtitles\">Wczytaj z pliku</string>\n    <string name=\"player_load_subtitles_online\">Wczytaj z Internetu</string>\n    <string name=\"downloaded_file\">Pobrano plik</string>\n    <string name=\"actor_main\">Główny</string>\n    <string name=\"actor_supporting\">Drugoplanowy</string>\n    <string name=\"actor_background\">Pomocniczy</string>\n    <string name=\"home_source\">Źródło</string>\n    <string name=\"home_random\">Losowy</string>\n    <string name=\"coming_soon\">Już wkrótce…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Obrazek</string>\n    <string name=\"category_player\">Odtwarzacz</string>\n    <string name=\"resolution_and_title\">Rozdzielczość i tytuł</string>\n    <string name=\"title\">Tytuł</string>\n    <string name=\"resolution\">Rozdzielczość</string>\n    <string name=\"error_invalid_id\">Niepoprawne ID</string>\n    <string name=\"error_invalid_data\">Niepoprawne dane</string>\n    <string name=\"error_invalid_url\">Niepoprawny URL</string>\n    <string name=\"error\">Błąd</string>\n    <string name=\"subtitles_remove_captions\">Usuń CC z napisów</string>\n    <string name=\"subtitles_remove_bloat\">Usuń nadmiarowe informacje z napisów</string>\n    <string name=\"subtitles_filter_lang\">Filtrowanie wg preferowanego języka</string>\n    <string name=\"extras\">Dodatki</string>\n    <string name=\"trailer\">Zwiastun</string>\n    <string name=\"referer\">Odsyłacz (opcjonalny)</string>\n    <string name=\"next\">Następny</string>\n    <string name=\"provider_languages_tip\">Wyświetlaj filmy w tych językach</string>\n    <string name=\"previous\">Poprzedni</string>\n    <string name=\"skip_setup\">Pomiń konfigurację</string>\n    <string name=\"app_layout_subtext\">Dostosuj wygląd aplikacji do urządzenia</string>\n    <string name=\"preferred_media_subtext\">Co chcesz obejrzeć</string>\n    <string name=\"setup_done\">Gotowe</string>\n    <string name=\"extensions\">Rozszerzenia</string>\n    <string name=\"add_repository\">Dodaj repozytorium</string>\n    <string name=\"repository_name_hint\">Nazwa repozytorium (opcjonalna)</string>\n    <string name=\"repository_url_hint\">Adres URL repozytorium lub krótki kod</string>\n    <string name=\"plugin_loaded\">Załadowano rozszerzenie</string>\n    <string name=\"plugin_deleted\">Usunięto rozszerzenie</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Błąd ładowania %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Rozpoczęto pobieranie %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Pobrano %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Wszystkie %s już pobrane</string>\n    <string name=\"batch_download\">Pobierz wszystko</string>\n    <string name=\"plugin_singular\">rozszerzenie</string>\n    <string name=\"plugin\">rozszerzenia</string>\n    <string name=\"delete_repository_plugins\">Ta akcja usunie także wszystkie rozszerzenia z repozytorium</string>\n    <string name=\"delete_repository\">Usuń repozytorium</string>\n    <string name=\"setup_extensions_subtext\">Pobierz strony, które Cię interesują</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Pobrano: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Wyłączono: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Nie pobrano: %d</string>\n    <string name=\"plugins_updated\">Zaaktualizowano %d rozszerzeń</string>\n    <string name=\"blank_repo_message\">CloudStream nie ma domyślnie zainstalowanych żadnych witryn. Musisz zainstalować witryny z repozytoriów.\n\\n\n\\nDołącz do naszego Discorda lub poszukaj online.</string>\n    <string name=\"view_public_repositories_button\">Zobacz repozytoria społeczności</string>\n    <string name=\"view_public_repositories_button_short\">Publiczna lista</string>\n    <string name=\"uppercase_all_subtitles\">Wszystkie napisy wielką literą</string>\n    <string name=\"download_all_plugins_from_repo\">Uwaga: CloudStream nie ponosi żadnej odpowiedzialności za korzystanie z rozszerzeń innych dostawców i nie zapewnia dla nich żadnego wsparcia!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Wyłączone)</string>\n    <string name=\"tracks\">Ścieżki</string>\n    <string name=\"audio_tracks\">Ścieżki audio</string>\n    <string name=\"video_tracks\">Ścieżki wideo</string>\n    <string name=\"apply_on_restart\">Uruchom ponownie aplikację, aby zobaczyć zmiany.</string>\n    <string name=\"safe_mode_title\">Tryb bezpieczny włączony</string>\n    <string name=\"safe_mode_description\">Z powodu wystąpienia błędu wszystkie rozszerzenia zostały wyłączone, aby ułatwić wykrycie tego wadliwego.</string>\n    <string name=\"safe_mode_crash_info\">Wyświetl informacje o błędzie</string>\n    <string name=\"extension_rating\" formatted=\"true\">Ocena: %s</string>\n    <string name=\"extension_description\">Opis</string>\n    <string name=\"extension_version\">Wersja</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"extension_size\">Rozmiar</string>\n    <string name=\"extension_authors\">Autorzy</string>\n    <string name=\"extension_types\">Wspierane</string>\n    <string name=\"extension_language\">Język</string>\n    <string name=\"extension_install_first\">Najpierw zainstaluj rozszerzenie</string>\n    <string name=\"hls_playlist\">Playlista HLS</string>\n    <string name=\"player_pref\">Preferowany odtwarzacz wideo</string>\n    <string name=\"player_settings_play_in_app\">Odtwarzacz wewnętrzny</string>\n    <string name=\"app_not_found_error\">Aplikacja nie została znaleziona</string>\n    <string name=\"all_languages_preference\">Wszystkie języki</string>\n    <string name=\"clear_history\">Wyczyść historię</string>\n    <string name=\"history\">Historia</string>\n    <string name=\"clipboard_too_large\">Za dużo tekstu. Nie można skopiować do schowka.</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"play_with_app_name\">Odtwórz w CloudStream</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Pomiń %s</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"yes\">Tak</string>\n    <string name=\"no\">Nie</string>\n    <string name=\"update_notification_failed\">Aktualizacja aplikacji nie powiodła się</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"update_notification_installing\">Instalowanie aktualizacji aplikacji…</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"action_mark_as_watched\">Oznacz jako obejrzane</string>\n    <string name=\"confirm_exit_dialog\">Czy na pewno chcesz wyjść?</string>\n    <string name=\"update_notification_downloading\">Pobieranie aktualizacji aplikacji…</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"cast_format\" formatted=\"true\">Obsada: %s</string>\n    <string name=\"automatic_plugin_download_summary\">Automatycznie instaluj wszystkie jeszcze niezainstalowane wtyczki z dodanych repozytoriów.</string>\n    <string name=\"search_poster_img_des\">Poster</string>\n    <string name=\"skip_type_recap\">Podsumowanie</string>\n    <string name=\"apk_installer_settings\">Instalator APK</string>\n    <string name=\"apk_installer_settings_des\">Niektóre urządzenia nie obsługują nowego instalatora pakietów. Wypróbuj tryb legacy, jeśli aktualizacje nie zostaną zainstalowane.</string>\n    <string name=\"example_password\">hasło123</string>\n    <string name=\"ova_singular\">@string/ova</string>\n    <string name=\"example_site_name\">NowaNazwaWitryny</string>\n    <string name=\"example_username\">Nazwa użytkownika</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"apk_installer_legacy\">Tryb kompatybilności</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"apk_installer_package_installer\">Instalator pakietów</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"example_email\">witaj@poczta.pl</string>\n    <string name=\"anime_singular\">@string/anime</string>\n    <string name=\"skip_type_op\">Opening</string>\n    <string name=\"skip_type_ed\">Ending</string>\n    <string name=\"skip_type_mixed_op\">Mixed opening</string>\n    <string name=\"skip_type_creddits\">Napisy końcowe</string>\n    <string name=\"skip_type_intro\">Intro</string>\n    <string name=\"skip_type_mixed_ed\">Mixed ending</string>\n    <string name=\"enable_skip_op_from_database_des\">Pokaż wyskakujące okienka pomijania dla niektórych segmentów</string>\n    <string name=\"pref_category_extensions\">Rozszerzenia</string>\n    <string name=\"pref_category_actions\">Działania</string>\n    <string name=\"pref_category_cache\">Pamięć podręczna</string>\n    <string name=\"redo_setup_process\">Powtórz proces konfiguracji</string>\n    <string name=\"pref_category_links\">Linki</string>\n    <string name=\"pref_category_app_updates\">Aktualizacje</string>\n    <string name=\"pref_category_backup\">Kopia zapasowa</string>\n    <string name=\"pref_category_subtitles\">Napisy</string>\n    <string name=\"pref_category_gestures\">Gesty</string>\n    <string name=\"pref_category_player_features\">Funkcje odtwarzacza</string>\n    <string name=\"pref_category_ui_features\">Funkcje</string>\n    <string name=\"pref_category_defaults\">Ustawienia domyślne</string>\n    <string name=\"pref_category_player_layout\">Układ</string>\n    <string name=\"pref_category_looks\">Wygląd</string>\n    <string name=\"play_trailer_button\">Odtwórz zwiastun</string>\n    <string name=\"delayed_update_notice\">Aplikacja zostanie zaktualizowana po wyjściu</string>\n    <string name=\"update_started\">Rozpoczęto aktualizację</string>\n    <string name=\"plugin_downloaded\">Pobrano rozszerzenie</string>\n    <string name=\"action_remove_from_watched\">Usuń z obejrzanych</string>\n    <string name=\"browser\">Przeglądarka</string>\n    <string name=\"sort_updated_new\">Data aktualizacji (od nowego do starego)</string>\n    <string name=\"sort_by\">Sortuj według</string>\n    <string name=\"sort\">Sortuj</string>\n    <string name=\"open_with\">Otwórz za pomocą</string>\n    <string name=\"sort_rating_desc\">Ocena (od najwyższej do najniższej)</string>\n    <string name=\"sort_rating_asc\">Ocena (od najniższej do najwyższej)</string>\n    <string name=\"sort_updated_old\">Data aktualizacji (od starego do nowego)</string>\n    <string name=\"sort_alphabetical_a\">Alfabetycznie (od A do Z)</string>\n    <string name=\"sort_alphabetical_z\">Alfabetycznie (od Z do A)</string>\n    <string name=\"select_library\">Wybierz bibliotekę</string>\n    <string name=\"library\">Biblioteka</string>\n    <string name=\"empty_library_no_accounts_message\">Twoja biblioteka jest pusta :(\n\\nZaloguj się na swoje konto lub dodaj programy do swojej lokalnej biblioteki.</string>\n    <string name=\"empty_library_logged_in_message\">Ta lista jest pusta. Spróbuj przełączyć się na inną.</string>\n    <string name=\"safe_mode_file\">Znaleziono plik trybu bezpiecznego.\n\\nRozszerzenia nie zostaną wczytane, dopóki plik nie zostanie usunięty.</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Używana ilość przewijania, gdy widoczny jest odtwarzacz</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Ukryty odtwarzacz - ilość przewijania</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Pokazany odtwarzacz — ilość przewijania</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Używana ilość przewijania, gdy ukryty jest odtwarzacz</string>\n    <string name=\"test_log\">Dziennik</string>\n    <string name=\"restart\">Uruchom ponownie</string>\n    <string name=\"start\">Rozpocznij</string>\n    <string name=\"test_failed\">Nie powiodło się</string>\n    <string name=\"test_passed\">Ukończone powodzeniem</string>\n    <string name=\"jsdelivr_proxy\">Serwer proxy GitHuba</string>\n    <string name=\"pref_category_bypass\">Obejścia ISP</string>\n    <string name=\"category_provider_test\">Test dostawcy</string>\n    <string name=\"stop\">Zatrzymaj</string>\n    <string name=\"revert\">Przywróć</string>\n    <string name=\"subscription_in_progress_notification\">Aktualizowanie subskrybowanych programów</string>\n    <string name=\"subscription_list_name\">Zasubskrybowano</string>\n    <string name=\"subscription_new\">Zasubskrybowano %s</string>\n    <string name=\"subscription_deleted\">Anulowano subskrypcję %s</string>\n    <string name=\"subscription_episode_released\">Został wydany odcinek %d!</string>\n    <string name=\"jsdelivr_proxy_summary\">Obchodzi blokadę surowych adresów URL GitHuba za pomocą jsDelivr. Może powodować opóźnienie aktualizacji o kilka dni.</string>\n    <string name=\"jsdelivr_enabled\">Nie udało się połączyć z GitHubem. Włączono serwer pośredniczący jsDelivr…</string>\n    <string name=\"watch_quality_pref_data\">Domyślna jakość (dane mobilne)</string>\n    <string name=\"quality_profile_help\">W tym miejscu można zmienić kolejność źródeł. Jeśli wideo ma wyższy priorytet, pojawi się wyżej w wyborze źródła. Priorytet wideo jest sumą priorytetu źródła i priorytetu jakości.\n\\n\n\\nŹródło A: 3\n\\nJakość B: 7\n\\nŁączny priorytet wideo będzie wynosił 10.\n\\n\n\\nUWAGA: Jeśli suma wynosi 10 lub więcej, odtwarzacz automatycznie pominie ładowanie po załadowaniu tego łącza!</string>\n    <string name=\"profile_number\">Profil %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Dane mobilne</string>\n    <string name=\"set_default\">Ustaw domyślny</string>\n    <string name=\"use\">Użyj</string>\n    <string name=\"edit\">Edytuj</string>\n    <string name=\"profiles\">Profile</string>\n    <string name=\"help\">Pomoc</string>\n    <string name=\"qualities\">Jakości</string>\n    <string name=\"profile_background_des\">Tło profilu</string>\n    <string name=\"unable_to_inflate\">Nie można było poprawnie utworzyć interfejsu użytkownika, jest to POWAŻNY BŁĄD i należy go natychmiast zgłosić %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Wybierz tryb filtrowania pobieranych rozszerzeń</string>\n    <string name=\"disable\">Wyłączać</string>\n    <string name=\"no_plugins_found_error\">Nie znaleziono żadnych wtyczek w repozytorium</string>\n    <string name=\"already_voted\">Już oddano głos</string>\n    <string name=\"no_repository_found_error\">Nie znaleziono tego repozytorium, sprawdź adres URL lub spróbuj połączyć się przez VPN</string>\n    <string name=\"favorite_removed\">Usunięto %s z ulubionych</string>\n    <string name=\"favorites_list_name\">Ulubione</string>\n    <string name=\"favorite_added\">Dodano %s do ulubionych</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">W swojej bibliotece znaleziono potencjalne duplikaty:\n\\n\n\\n%s\n\\n\n\\nCzy chcesz dodać ten element, zastąpić istniejące, czy anulować operację?</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Wprowadź PIN dla %s</string>\n    <string name=\"backup_frequency\">Częstotliwość tworzenia kopii zapasowych</string>\n    <string name=\"duplicate_title\">Znaleziono potencjalny duplikat</string>\n    <string name=\"lock_profile\">Zablokuj profil</string>\n    <string name=\"action_add_to_favorites\">Dodaj do ulubionych</string>\n    <string name=\"manage_accounts\">Zarządzaj kontami</string>\n    <string name=\"duplicate_replace_all\">Zamień wszystko</string>\n    <string name=\"edit_account\">Edytuj konto</string>\n    <string name=\"pin_error_incorrect\">Nieprawidłowy PIN. Spróbuj ponownie.</string>\n    <string name=\"action_unsubscribe\">Anuluj subskrypcję</string>\n    <string name=\"pin_error_length\">Kod PIN musi mieć 4 znaki</string>\n    <string name=\"duplicate_replace\">Zastąp</string>\n    <string name=\"duplicate_add\">Dodaj</string>\n    <string name=\"action_subscribe\">Zasubskrybuj</string>\n    <string name=\"action_remove_from_favorites\">Usuń z ulubionych</string>\n    <string name=\"select_an_account\">Wybierz konto</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Wygląda się, że potencjalny duplikat już znajduje się w bibliotece: \\'%s\\'. \\'\n\\n\n\\nCzy chciałbyś dodać ten element, zastąpić istniejący, czy anulować akcję?</string>\n    <string name=\"enter_pin\">Wprowadź PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"links_reloaded_toast\">Linki załadowane ponownie</string>\n    <string name=\"enter_current_pin\">Wprowadź obecny PIN</string>\n    <string name=\"logged_account\" formatted=\"true\">Zalogowano jako %s</string>\n    <string name=\"rotate_video_desc\">Wyświetl przycisk przełączający orientację ekranu</string>\n    <string name=\"use_default_account\">Używaj domyślnego konta</string>\n    <string name=\"skip_startup_account_select_pref\">Pomiń wybór konta podczas uruchamiania</string>\n    <string name=\"auto_rotate_video\">Automatyczny obrót</string>\n    <string name=\"rotate_video\">Obrót</string>\n    <string name=\"auto_rotate_video_desc\">Włącz automatyczne przełączanie orientacji ekranu na podstawie orientacji filmu</string>\n    <string name=\"speed_setting_summary\">Dodaje opcję prędkości w odtwarzaczu</string>\n    <string name=\"subscribe_tooltip\">Powiadomienie o nowym odcinku</string>\n    <string name=\"result_search_tooltip\">Szukaj w innych rozszerzeniach</string>\n    <string name=\"recommendations_tooltip\">Pokaż rekomendacje</string>\n    <string name=\"test_extensions\">Przetestuj wszystkie rozszerzenia</string>\n    <string name=\"test_extensions_summary\">Ten test jest przeznaczony wyłącznie dla programistów i nie weryfikuje ani nie zaprzecza działaniu żadnego rozszerzenia.</string>\n    <string name=\"biometric_setting\">Zablokuj za pomocą biometrii</string>\n    <string name=\"password_pin_authentication_title\">Uwierzytelnianie hasłem/kodem PIN</string>\n    <string name=\"biometric_prompt_description\">Po kilku nieudanych próbach monit zostanie zamknięty. Aby spróbować ponownie, po prostu uruchom ponownie aplikację.</string>\n    <string name=\"biometric_authentication_title\">Odblokuj CloudStream</string>\n    <string name=\"biometric_unsupported\">To urządzenie nie obsługuje uwierzytelniania biometrycznego</string>\n    <string name=\"biometric_setting_summary\">Odblokuj aplikację za pomocą odcisku palca, identyfikatora twarzy, kodu PIN, wzoru i hasła.</string>\n    <string name=\"biometric_warning\">Kopia zapasowa Twoich danych CloudStream została teraz utworzona. Chociaż prawdopodobieństwo tego jest bardzo niskie, wszystkie urządzenia mogą zachowywać się inaczej. W rzadkich przypadkach, gdy dostęp do aplikacji zostanie zablokowany, należy całkowicie wyczyścić dane aplikacji i przywrócić je z kopii zapasowej. Bardzo nam przykro z powodu wszelkich niedogodności z tym związanych.</string>\n    <string name=\"unfavorite\">Usuń z ulubionych</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\npozostało</string>\n    <string name=\"favorite\">Dodaj do ulubionych</string>\n    <string name=\"repo_copy_label\">Nazwa repozytorium i adres URL</string>\n    <string name=\"clipboard_permission_error\">Błąd dostępu do schowka. Spróbuj ponownie.</string>\n    <string name=\"toast_copied\">skopiowano!</string>\n    <string name=\"clipboard_unknown_error\">Błąd podczas kopiowania. Skopiuj logcat i skontaktuj się z pomocą techniczną aplikacji.</string>\n    <string name=\"battery_dialog_title\">Wyłącz optymalizację baterii</string>\n    <string name=\"app_info_intent_error\">Nie można otworzyć informacji o aplikacji CloudStream.</string>\n    <string name=\"music_singlar\">Muzyka</string>\n    <string name=\"audio_book_singular\">Audiobook</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"custom_media_singluar\">Multimedia</string>\n    <string name=\"app_unrestricted_toast\">Użycie baterii przez aplikację jest już ustawione na nieograniczone</string>\n    <string name=\"battery_dialog_message\">Aby zapewnić nieprzerwane pobieranie i powiadomienia o subskrybowanych programach, CloudStream potrzebuje pozwolenia na działanie w tle. Po naciśnięciu OK wyświetli się okno dialogowe. Naciśnij „Zezwól”.\\n\\nPamiętaj, że to pozwolenie nie oznacza, że CS3 będzie zużywać baterię. Będzie działać w tle tylko wtedy, gdy będzie to konieczne, na przykład podczas odbierania powiadomień lub pobierania filmów z oficjalnych rozszerzeń.</string>\n    <string name=\"reset_btn\">Resetuj</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Nadchodzące w %s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Odcinek %2$d sezonu %1$d wyjdzie za</string>\n    <string name=\"player_settings_select_cast_device\">Wybierz urządzenie do transmisji</string>\n    <string name=\"episode_action_cast_mirror\">Mirror transmisji</string>\n    <string name=\"cs3wiki\">Wiki CloudStream</string>\n    <string name=\"pref_category_security\">Bezpieczeństwo</string>\n    <string name=\"pref_category_accounts\">Konta</string>\n    <string name=\"auth_locally\">Uwierzytelniaj lokalnie</string>\n    <string name=\"qr_image\">Obraz kodu QR</string>\n    <string name=\"device_pin_error_message\">Nie można uzyskać kodu PIN urządzenia. Spróbuj uwierzytelnienia lokalnego</string>\n    <string name=\"device_pin_expired_message\">Kod PIN stracił ważność!</string>\n    <string name=\"device_pin_counter_text\">Kod wygasa za %1$dm %2$ds</string>\n    <string name=\"dismiss\">Odrzuć</string>\n    <string name=\"open_downloaded_repo\">Otwórz repozytorium</string>\n    <string name=\"device_pin_url_message\">Odwiedź <b>%s</b> na swoim smartfonie lub komputerze i wprowadź powyższy kod</string>\n    <string name=\"play_from_beginning_img_des\">Odtwarzaj od początku</string>\n    <string name=\"delete_plugin\">Usuń wtyczkę</string>\n    <string name=\"test_warning\">Uwaga</string>\n    <string name=\"open_local_video\">Otwórz lokalne wideo</string>\n    <string name=\"downloads_empty\">Obecnie nie ma żadnych pobrań.</string>\n    <string name=\"hide_player_control_names\">Ukryj nazwy elementów sterujących odtwarzacza</string>\n    <string name=\"sort_release_date_old\">Data wydania (od najstarszej do najnowszej)</string>\n    <string name=\"sort_release_date_new\">Data wydania (od najnowszej do najstarszej)</string>\n    <string name=\"offline_file\">Dostępne do oglądania offline</string>\n    <string name=\"select_all\">Zaznacz wszystkie</string>\n    <string name=\"downloads_delete_select\">Zaznacz elementy do usunięcia</string>\n    <string name=\"deselect_all\">Odznacz wszystkie</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Czy na pewno chcesz na stałe usunąć następujące elementy?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Usuniesz na stale wszystkie odcinki następującego serialu:\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Czy na pewno chcesz na stałe usunąć wszystkie odcinki następującego serialu?\n\\n\n\\n%s</string>\n    <string name=\"delete_files\">Usuń pliki</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Czy na pewno chcesz na stałe usunąć następujące odcinki %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_format\" formatted=\"true\">Usuń (%1$d | %2$s)</string>\n    <string name=\"preview_seekbar\">Podgląd paska przewijania</string>\n    <string name=\"preview_seekbar_desc\">Włącz podgląd miniatury na pasku wyszukiwania</string>\n    <string name=\"no_subtitles_loaded\">Nie wczytano jeszcze napisów</string>\n    <string name=\"confirm_before_exiting_desc\">Pokaż okno dialogowe przed wyjściem z aplikacji</string>\n    <string name=\"show\">Pokaż</string>\n    <string name=\"confirm_before_exiting_title\">Potwierdź przed wyjściem</string>\n    <string name=\"dont_show\">Nie pokazuj</string>\n    <string name=\"backup_path_title\">Lokalizacja folderu kopii zapasowej</string>\n    <string name=\"custom\">Własna</string>\n    <string name=\"torrent_info\">Ten film jest torrentem, co oznacza, że Twoja aktywność wideo może być śledzona.\\nUpewnij się, że rozumiesz czym są torrenty, zanim przejdziesz dalej.</string>\n    <string name=\"subs_edge_size\">Rozmiar krawędzi</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"unsupported_error\">Nieobsługiwany błąd</string>\n    <string name=\"encoding_error\">Błąd kodowania</string>\n    <string name=\"player_load_one_subtitle_online\">Wczytaj pierwsze dostępne</string>\n    <string name=\"torrent_not_accepted\">Uruchom ponownie aplikację i zaakceptuj wyskakujące okienko Otwórz torrent, aby kontynuować.</string>\n    <string name=\"torrent_preferred_media\">Włącz torrent w Ustawienia/Źródła/Preferowane multimedia</string>\n    <string name=\"software_decoding\">Dekodowanie programowe</string>\n    <string name=\"software_decoding_desc\">Dekodowanie programowe umożliwia odtwarzaczowi odtwarzanie plików wideo, których to urządzenie nie obsługuje, ale może powodować opóźnienia lub niestabilność odtwarzania w wysokiej rozdzielczości.</string>\n    <string name=\"sort_episodes_rating_low_high\">Ocena (najniższa)</string>\n    <string name=\"sort_button_rating\">Ocena %s</string>\n    <string name=\"sort_episodes_date_newest\">Data emisji (najnowsza)</string>\n    <string name=\"sort_episodes_date_oldest\">Data emisji (najstarsza)</string>\n    <string name=\"sort_button_episode\">Odc. %s</string>\n    <string name=\"sort_button_date\">Data %s</string>\n    <string name=\"sort_episodes_number_asc\">Odcinek (rosnąco)</string>\n    <string name=\"sort_episodes_number_desc\">Odcinek (malejąco)</string>\n    <string name=\"sort_episodes_rating_high_low\">Ocena (najwyższa)</string>\n    <string name=\"update_plugins\">Zaktualizuj wtyczki</string>\n    <string name=\"plugins_updated_manually\">Pomyślnie zaktualizowano wtyczki: %d!</string>\n    <string name=\"no_plugins_updated_manually\">Nie zaktualizowano żadnych wtyczek.</string>\n    <string name=\"update_plugins_manually\">Zaktualizuj wtyczki ręcznie</string>\n    <string name=\"starting_plugin_update_manually\">Rozpoczęcie procesu aktualizacji wtyczek!</string>\n    <string name=\"player_notification_channel_name\">Powiadomienia odtwarzacza</string>\n    <string name=\"player_notification_channel_description\">Powiadomienie odtwarzacza umożliwiające sterowanie odtwarzaniem w tle</string>\n    <string name=\"speech_recognition_unavailable\">Rozpoznawanie mowy nie jest dostępne</string>\n    <string name=\"begin_speaking\">Zacznij mówić…</string>\n    <string name=\"subtitles_from_embedded\">Osadzone</string>\n    <string name=\"subtitles_from_online\">Online</string>\n    <string name=\"all_subtitles_italic\">Zmień wszystkie napisy na kursywę</string>\n    <string name=\"background_radius\">Promień tła</string>\n    <string name=\"all_subtitles_bold\">Zmień wszystkie napisy na pogrubione</string>\n    <string name=\"slide_up_again_to_exceed_100\">Przesuń ponownie w górę, aby przekroczyć 100%</string>\n    <string name=\"volume_exceeded_100\">Głośność przekroczyła 100%</string>\n    <string name=\"concurrent_connections_settings_des\">Ile równoczesnych połączeń może wykorzystać każde pobieranie</string>\n    <string name=\"download_parallel_settings_des\">Ile różnych elementów można pobrać równolegle</string>\n    <string name=\"parallel_downloads\">Pobieranie równoległe</string>\n    <string name=\"concurrent_connections\">Połączenia równoczesne</string>\n    <string name=\"go_to_downloads\">Przejdź do pobranych</string>\n    <string name=\"no_internet_connection\">Brak połączenia z Internetem.\\n\\nPołącz się z Internetem i spróbuj ponownie lub obejrzyj pobrane pliki, będąc offline.</string>\n    <string name=\"overscan_settings\">Nadmiarowość obrazu</string>\n    <string name=\"overscan_settings_des\">Zmienia granice ekranu</string>\n    <string name=\"poster_size_settings\">Rozmiar plakatu</string>\n    <string name=\"poster_size_settings_des\">Zmienia rozmiar plakatów</string>\n    <string name=\"player_settings_always_ask\">Zawsze pytaj</string>\n    <string name=\"speedup_title\">Przełączanie prędkości długiego naciśnięcia</string>\n    <string name=\"speedup_summary\">Przytrzymaj, aby uzyskać 2x większą prędkość</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"show_rating\">Etykieta oceny</string>\n    <string name=\"no_account\">Bez konta</string>\n    <string name=\"edit_profile_image_title\">Edytuj obraz profilowy</string>\n    <string name=\"edit_profile_image_hint\">Wpisz adres URL obrazu profilowego</string>\n    <string name=\"edit_profile_image_error_empty\">Nie znaleziono adresu URL</string>\n    <string name=\"edit_profile_image_error_invalid\">Nieprawidłowy adres URL lub obraz</string>\n    <string name=\"edit_profile_image_success\">Pomyślnie zaktualizowano obraz</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Usuń obejrzane do tego odcinka</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Oznacz jako obejrzane do tego odcinka</string>\n    <string name=\"action_reload\">Przeładowano</string>\n    <string name=\"reload_provider\">Przeładuj dostawcę</string>\n    <string name=\"episode_action_play_mirror\">Odtwarzaj inne źródło</string>\"\n    <string name=\"name\">Nazwa</string>\n    <string name=\"resolution_and_name\">Rozdzielczość i nazwa</string>\n    <string name=\"bottom_left\">Dolne lewe</string>\n    <string name=\"subs_subtitle_alignment\">Wyrównanie napisów</string>\n    <string name=\"bottom_center\">Dolne środkowe</string>\n    <string name=\"bottom_right\">Dolne prawe</string>\n    <string name=\"middle_left\">Środkowe lewe</string>\n    <string name=\"middle_center\">Środkowe</string>\n    <string name=\"middle_right\">Środkowe prawe</string>\n    <string name=\"top_left\">Górne lewe</string>\n    <string name=\"top_center\">Górne środkowe</string>\n    <string name=\"top_right\">Górne prawe</string>\n    <string name=\"play_full_series_button\">Odtwórz całą serię</string>\n    <string name=\"install_prerelease\">Zainstaluj wersję przedpremierową</string>\n    <string name=\"prerelease_already_installed\">Wersja przedpremierowa jest już zainstalowana.</string>\n    <string name=\"prerelease_install_failed\">Nie udało się zainstalować wersji przedpremierowej.</string>\n    <string name=\"show_episode_text\">Tekst odcinka</string>\n    <string name=\"search_suggestions\">Sugestie wyszukiwania</string>\n    <string name=\"search_suggestions_des\">Pokaż sugestie wyszukiwania podczas pisania</string>\n    <string name=\"clear_suggestions\">Wyczyść sugestie</string>\n    <string name=\"show_cast_in_details\">Pokaż panel obsady</string>\n    <string name=\"source_name\">Nazwa źródła</string>\n    <string name=\"video_info\">Informacje o multimediach</string>\n    <string name=\"extra_brightness_settings\">Dodatkowa jasność</string>\n    <string name=\"extra_brightness_settings_des\">Włącz filtr jasności, gdy jasność wyświetlacza przekroczy 100%</string>\n    <string name=\"extra_brightness_key\">Włączono dodatkową jasność</string>\n    <string name=\"download_queue\">Kolejka pobierania</string>\n    <string name=\"queue_empty_message\">Obecnie nie ma żadnych plików do pobrania w kolejce.</string>\n    <string name=\"download_all\">Pobierz wszystkie</string>\n    <string name=\"cancel_all\">Anuluj wszystkie</string>\n    <string name=\"download_episode_range\">Czy chcesz pobrać odcinek %s?</string>\n    <string name=\"cancel_queue_message\">Czy chcesz anulować wszystkie pliki do pobrania z kolejki?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d aktywne pobieranie</item>\n        <item quantity=\"few\">%d aktywne pobierania</item>\n        <item quantity=\"many\">%d aktywnych pobierań</item>\n        <item quantity=\"other\">%d aktywnych pobierań</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d pobieranie w kolejce</item>\n        <item quantity=\"few\">%d pobierania w kolejce</item>\n        <item quantity=\"many\">%d pobierań w kolejce</item>\n        <item quantity=\"other\">%d pobierań w kolejce</item>\n    </plurals>\n    <string name=\"source_priority\">Priorytet źródła</string>\n    <string name=\"source_priority_help\">Zdecyduj, jak mają być sortowane źródła wideo w odtwarzaczu</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"next_episode_format\" formatted=\"true\">O episódio %d será lançado em</string>\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"episode_poster_img_des\">Pôster do episódio</string>\n    <string name=\"search_poster_img_des\">Poster</string>\n    <string name=\"home_main_poster_img_des\">Pôster Principal</string>\n    <string name=\"home_next_random_img_des\">Próximo Aleatório</string>\n    <string name=\"go_back_img_des\">Voltar</string>\n    <string name=\"home_change_provider_img_des\">Alterar Provedor</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"home_source\">Fonte</string>\n    <string name=\"resolution\">Resolução</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"preview_background_img_des\">Visualizar plano de fundo</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Velocidade (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Classificado: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Nova atualização encontrada!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Preenchimento</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Assistir com o CloudStream</string>\n    <string name=\"title_home\">Início</string>\n    <string name=\"title_search\">Pesquisar</string>\n    <string name=\"title_downloads\">Downloads</string>\n    <string name=\"title_settings\">Configurações</string>\n    <string name=\"search_hint\">Procurar…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Pesquisar %s…</string>\n    <string name=\"no_data\">Sem dados</string>\n    <string name=\"episode_more_options_des\">Mais opções</string>\n    <string name=\"next_episode\">Próximo episódio</string>\n    <string name=\"result_tags\">Gêneros</string>\n    <string name=\"result_share\">Compartilhar</string>\n    <string name=\"result_open_in_browser\">Abrir no navegador</string>\n    <string name=\"skip_loading\">Pular carregamento</string>\n    <string name=\"loading\">Carregando…</string>\n    <string name=\"type_watching\">Assistindo</string>\n    <string name=\"type_on_hold\">Em espera</string>\n    <string name=\"type_completed\">Concluído</string>\n    <string name=\"type_dropped\">Desistido</string>\n    <string name=\"type_plan_to_watch\">Pretendo assistir</string>\n    <string name=\"type_re_watching\">Reassistindo</string>\n    <string name=\"play_movie_button\">Reproduzir filme</string>\n    <string name=\"play_livestream_button\">Reproduzir transmissão ao vivo</string>\n    <string name=\"play_torrent_button\">Transmitir Torrent</string>\n    <string name=\"pick_source\">Fontes</string>\n    <string name=\"pick_subtitle\">Legendas</string>\n    <string name=\"reload_error\">Tentar conexão novamente…</string>\n    <string name=\"go_back\">Voltar</string>\n    <string name=\"play_episode\">Reproduzir episódio</string>\n    <string name=\"download\">Download</string>\n    <string name=\"downloaded\">Baixado</string>\n    <string name=\"downloading\">Baixando</string>\n    <string name=\"download_paused\">Download Pausado</string>\n    <string name=\"download_started\">Download Iniciado</string>\n    <string name=\"download_failed\">Falha no Download</string>\n    <string name=\"download_canceled\">Download cancelado</string>\n    <string name=\"download_done\">Download concluído</string>\n    <string name=\"stream\">Transmitir</string>\n    <string name=\"error_loading_links_toast\">Erro a Carregar Links</string>\n    <string name=\"download_storage_text\">Armazenamento Interno</string>\n    <string name=\"app_dubbed_text\">Dob</string>\n    <string name=\"app_subbed_text\">Leg</string>\n    <string name=\"popup_delete_file\">Eliminar Ficheiro</string>\n    <string name=\"popup_play_file\">Reproduzir Ficheiro</string>\n    <string name=\"popup_resume_download\">Retomar Transferência</string>\n    <string name=\"popup_pause_download\">Pausar Transferência</string>\n    <string name=\"home_more_info\">Mais info</string>\n    <string name=\"home_expanded_hide\">Esconder</string>\n    <string name=\"home_play\">Reproduzir</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"filter_bookmarks\">Filtrar Marcadores</string>\n    <string name=\"error_bookmarks_text\">Marcadores</string>\n    <string name=\"action_remove_from_bookmarks\">Remover</string>\n    <string name=\"sort_apply\">Aplicar</string>\n    <string name=\"sort_copy\">Copiar</string>\n    <string name=\"sort_close\">Fechar</string>\n    <string name=\"sort_clear\">Limpar</string>\n    <string name=\"sort_save\">Guardar</string>\n    <string name=\"player_speed\">Velocidade de Reprodução</string>\n    <string name=\"subtitles_settings\">Configurações de Legendas</string>\n    <string name=\"subs_text_color\">Cor do Texto</string>\n    <string name=\"subs_outline_color\">Cor do Delineado</string>\n    <string name=\"subs_background_color\">Cor do Fundo</string>\n    <string name=\"subs_window_color\">Cor da Janela</string>\n    <string name=\"subs_edge_type\">Tipo de Borda</string>\n    <string name=\"subs_subtitle_elevation\">Elevação da Legenda</string>\n    <string name=\"subs_font\">Fonte</string>\n    <string name=\"subs_font_size\">Tamanho da Fonte</string>\n    <string name=\"search_provider_text_providers\">Procurar usando fornecedores</string>\n    <string name=\"search_provider_text_types\">Procurar usando tipos</string>\n    <string name=\"benene_count_text\">%d Benenes dadas aos devs</string>\n    <string name=\"benene_count_text_none\">Nenhum Benene dada</string>\n    <string name=\"subs_auto_select_language\">Auto-seleção de Idioma</string>\n    <string name=\"subs_download_languages\">Transferir Idiomas</string>\n    <string name=\"subs_subtitle_languages\">Idioma da Legenda</string>\n    <string name=\"subs_hold_to_reset_to_default\">Segure para retornar para o padrão</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importar fontes colocando em %s</string>\n    <string name=\"continue_watching\">Continuar a Assistir</string>\n    <string name=\"action_remove_watching\">Remover</string>\n    <string name=\"action_open_watching\">Mais info</string>\n    <string name=\"vpn_might_be_needed\">Uma VPN pode ser necessária para que este fornecedor funcione corretamente</string>\n    <string name=\"vpn_torrent\">Este fornecedor é um torrent, uma VPN é recomendada</string>\n    <string name=\"provider_info_meta\">Metadados não são oferecidos pelo site, o carregamento do vídeo irá falhar se ele não existir no site.</string>\n    <string name=\"torrent_plot\">Descrição</string>\n    <string name=\"normal_no_plot\">Nenhum Enredo Encontrado</string>\n    <string name=\"torrent_no_plot\">Nenhuma Descrição Encontrada</string>\n    <string name=\"show_log_cat\">Mostrar logcat 🐈</string>\n    <string name=\"picture_in_picture\">Picture-in-picture</string>\n    <string name=\"picture_in_picture_des\">Continua a reprodução num player em miniatura em cima de outras apps</string>\n    <string name=\"player_size_settings\">Botão de redimensionamento do player</string>\n    <string name=\"player_size_settings_des\">Remover as bordas negras</string>\n    <string name=\"player_subtitles_settings\">Legendas</string>\n    <string name=\"player_subtitles_settings_des\">Configurações de legendas do player</string>\n    <string name=\"chromecast_subtitles_settings\">Legendas do Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Configurações de legendas do Chromecast</string>\n    <string name=\"eigengraumode_settings\">Velocidade de reprodução</string>\n    <string name=\"swipe_to_seek_settings\">Deslize para andar</string>\n    <string name=\"swipe_to_seek_settings_des\">Deslize para os lados para controlar a posição em um vídeo</string>\n    <string name=\"swipe_to_change_settings\">Deslize para mudar as configurações</string>\n    <string name=\"swipe_to_change_settings_des\">Deslize para cima ou para baixo, no lado esquerdo ou direito, para ajustar brilho ou volume</string>\n    <string name=\"autoplay_next_settings\">Reproduzir automaticamente próximo episódio</string>\n    <string name=\"autoplay_next_settings_des\">Começa o próximo episódio quando o atual termina</string>\n    <string name=\"double_tap_to_seek_settings\">Toque duplo para avançar</string>\n    <string name=\"double_tap_to_pause_settings\">Toque duplo para pôr em pausa</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Tempo de busca no player (Segundos)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Toque duplo no lado esq. ou dir. para andar para trás ou para a frente</string>\n    <string name=\"double_tap_to_pause_settings_des\">Toque duas vezes no meio para pausar</string>\n    <string name=\"use_system_brightness_settings\">Usar brilho da sistema</string>\n    <string name=\"use_system_brightness_settings_des\">Usar brilho do sistema no player em vez de uma sobreposição escura</string>\n    <string name=\"episode_sync_settings\">Atualizar progresso</string>\n    <string name=\"episode_sync_settings_des\">Sincronizar automaticamente o progresso do seu episódio atual</string>\n    <string name=\"restore_settings\">Restaurar dados a partir de backup</string>\n    <string name=\"backup_settings\">Fazer backup</string>\n    <string name=\"restore_success\">Arquivo de backup carregado</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Falha ao restaurar dados do ficheiro %s</string>\n    <string name=\"backup_success\">Dados guardados com sucesso</string>\n    <string name=\"backup_failed\">Permissão de armazenamento não encontrada, por favor tente novamente.</string>\n    <string name=\"backup_failed_error_format\">Erro no backup de %s</string>\n    <string name=\"search\">Procurar</string>\n    <string name=\"category_account\">Contas e segurança</string>\n    <string name=\"category_updates\">Atualizações e cópias de segurança</string>\n    <string name=\"settings_info\">Info</string>\n    <string name=\"advanced_search\">Procura Avançada</string>\n    <string name=\"advanced_search_des\">Mostra resultados separados por fornecedor</string>\n    <string name=\"show_fillers_settings\">Mostrar episódios de enchimento para anime</string>\n    <string name=\"show_trailers_settings\">Mostrar trailers</string>\n    <string name=\"kitsu_settings\">Mostrar posters do kitsu</string>\n    <string name=\"pref_filter_search_quality\">Esconder qualidades de vídeo selecionadas nos resultados da Pesquisa</string>\n    <string name=\"automatic_plugin_updates\">Atualizações de plugin automáticas</string>\n    <string name=\"updates_settings\">Mostrar atualizações da app</string>\n    <string name=\"updates_settings_des\">Procurar automaticamente por novas atualizações depois de iniciar o app.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">App light novel pelos mesmos devs</string>\n    <string name=\"discord\">Junte-se ao Discord</string>\n    <string name=\"benene\">Dar um benene aos devs</string>\n    <string name=\"benene_des\">Benene dada</string>\n    <string name=\"app_language\">Idioma da App</string>\n    <string name=\"no_chromecast_support_toast\">Este fornecedor não tem suporte para Chromecast</string>\n    <string name=\"no_links_found_toast\">Nenhum Link Encontrado</string>\n    <string name=\"copy_link_toast\">Link copiado para a área de transferência</string>\n    <string name=\"play_episode_toast\">Reproduzir episódio</string>\n    <string name=\"subs_default_reset_toast\">Restaurar para o padrão</string>\n    <string name=\"season\">Temporada</string>\n    <string name=\"no_season\">Nenhuma Temporada</string>\n    <string name=\"episode\">Episódio</string>\n    <string name=\"episodes\">Episódios</string>\n    <string name=\"season_short\">T</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Nenhum Episódio encontrado</string>\n    <string name=\"delete_file\">Eliminar Ficheiro</string>\n    <string name=\"delete\">Eliminar</string>\n    <string name=\"cancel\">Cancelar</string>\n    <string name=\"pause\">Pôr em Pausa</string>\n    <string name=\"resume\">Retomar</string>\n    <string name=\"delete_message\" formatted=\"true\">Isto apagará %s permanentemente\n\\nTem a certeza?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nem falta</string>\n    <string name=\"status_ongoing\">Em Curso</string>\n    <string name=\"status_completed\">Concluído</string>\n    <string name=\"status\">Estado</string>\n    <string name=\"year\">Ano</string>\n    <string name=\"rating\">Classificação</string>\n    <string name=\"duration\">Duração</string>\n    <string name=\"site\">Site</string>\n    <string name=\"synopsis\">Sinopse</string>\n    <string name=\"queued\">Na fila</string>\n    <string name=\"no_subtitles\">Sem Legendas</string>\n    <string name=\"action_default\">Padrão</string>\n    <string name=\"free_storage\">Livre</string>\n    <string name=\"used_storage\">Usado</string>\n    <string name=\"app_storage\">App</string>\n    <string name=\"movies\">Filmes</string>\n    <string name=\"tv_series\">Séries</string>\n    <string name=\"cartoons\">Desenhos Animados</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"documentaries\">Documentários</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Dramas Asiáticos</string>\n    <string name=\"livestreams\">Transmissões em Direto</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Outros</string>\n    <string name=\"movies_singular\">Filme</string>\n    <string name=\"tv_series_singular\">Série</string>\n    <string name=\"cartoons_singular\">Desenho Animado</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Documentário</string>\n    <string name=\"asian_drama_singular\">Drama Asiático</string>\n    <string name=\"live_singular\">Transmissão em Direto</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"source_error\">Erro de fonte</string>\n    <string name=\"remote_error\">Erro remoto</string>\n    <string name=\"render_error\">Erro de renderização</string>\n    <string name=\"unexpected_error\">Erro inesperado do player</string>\n    <string name=\"storage_error\">Erro de transferência, verifique permissões de armazenamento</string>\n    <string name=\"episode_action_chromecast_episode\">Episódio pelo Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Alternativa pelo Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Reproduzir na app</string>\n    <string name=\"episode_action_play_in_format\">Reproduzir no %s</string>\n    <string name=\"episode_action_auto_download\">Transferência Automática</string>\n    <string name=\"episode_action_download_mirror\">Transferir por servidor alternativo</string>\n    <string name=\"episode_action_reload_links\">Recarregar links</string>\n    <string name=\"episode_action_download_subtitle\">Transferir legendas</string>\n    <string name=\"show_hd\">Etiqueta de qualidade</string>\n    <string name=\"show_dub\">Etiqueta Dub</string>\n    <string name=\"show_sub\">Etiqueta Sub</string>\n    <string name=\"show_title\">Título</string>\n    <string name=\"poster_ui_settings\">Alternar elementos da interface no póster</string>\n    <string name=\"no_update_found\">Nenhuma Atualização Encontrada</string>\n    <string name=\"check_for_update\">Procurar Atualização</string>\n    <string name=\"video_lock\">Fixar</string>\n    <string name=\"video_aspect_ratio_resize\">Mudar Tamanho</string>\n    <string name=\"video_source\">Fonte</string>\n    <string name=\"video_skip_op\">Saltar OP</string>\n    <string name=\"dont_show_again\">Não mostrar de novo</string>\n    <string name=\"skip_update\">Saltar esta Atualização</string>\n    <string name=\"update\">Atualizar</string>\n    <string name=\"watch_quality_pref\">Qualidade Preferida (WiFi)</string>\n    <string name=\"limit_title\">Máximo de caracteres do título no player de video</string>\n    <string name=\"limit_title_rez\">Resolução do player de vídeo</string>\n    <string name=\"video_buffer_size_settings\">Tamanho do buffer do vídeo</string>\n    <string name=\"video_buffer_length_settings\">Comprimento do buffer do vídeo</string>\n    <string name=\"video_buffer_disk_settings\">Cache do vídeo em disco</string>\n    <string name=\"video_buffer_clear_settings\">Limpar cache de vídeo e imagem</string>\n    <string name=\"video_ram_description\">Causará travamentos em dispositivos com pouca memória se definido muito alto , como uma Android TV.</string>\n    <string name=\"video_disk_description\">Pode causar problemas em sistemas com pouco espaço de armazenamento se definido muito alto, como uma Android TV.</string>\n    <string name=\"dns_pref\">DNS sobre HTTPS</string>\n    <string name=\"dns_pref_summary\">Útil para contornar bloqueios do fornecedor de internet</string>\n    <string name=\"add_site_pref\">Clonar site</string>\n    <string name=\"remove_site_pref\">Remover site</string>\n    <string name=\"add_site_summary\">Adiciona um clone de um site existente, com um url diferente</string>\n    <string name=\"download_path_pref\">Caminho de transferência</string>\n    <string name=\"nginx_url_pref\">Url do servidor Nginx</string>\n    <string name=\"display_subbed_dubbed_settings\">Mostrar Anime Dobrado/Legendado</string>\n    <string name=\"resize_fit\">Ajustar para a Tela</string>\n    <string name=\"resize_fill\">Esticar</string>\n    <string name=\"resize_zoom\">Aumentar</string>\n    <string name=\"legal_notice\">Aviso Legal</string>\n    <string name=\"category_general\">Geral</string>\n    <string name=\"random_button_settings\">Botão Aleatório</string>\n    <string name=\"random_button_settings_desc\">Mostrar botão aleatório na página inicial</string>\n    <string name=\"provider_lang_settings\">Línguas de extensão</string>\n    <string name=\"app_layout\">Layout da App</string>\n    <string name=\"preferred_media_settings\">Mídia preferida</string>\n    <string name=\"enable_nsfw_on_providers\">Ativar NSFW nas Extensões suportadas</string>\n    <string name=\"subtitles_encoding\">Codificação das legendas</string>\n    <string name=\"category_providers\">Fornecedores</string>\n    <string name=\"category_ui\">Layout</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"tv_layout\">Layout de TV</string>\n    <string name=\"phone_layout\">Layout de telemóvel</string>\n    <string name=\"emulator_layout\">Layout de emulador</string>\n    <string name=\"primary_color_settings\">Cor Primária</string>\n    <string name=\"app_theme_settings\">Tema do App</string>\n    <string name=\"bottom_title_settings\">Local do título do poster</string>\n    <string name=\"bottom_title_settings_des\">Coloca o título debaixo do poster</string>\n    <string name=\"example_password\">senha123</string>\n    <string name=\"example_username\">Nome de utilizador</string>\n    <string name=\"example_email\">ola@mundo.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NovoNomedoSite</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">Codigo da Língua (pt)</string>\n    <string name=\"account\">Conta</string>\n    <string name=\"logout\">Sair</string>\n    <string name=\"login\">Entrar</string>\n    <string name=\"switch_account\">Mudar de conta</string>\n    <string name=\"add_account\">Adicionar conta</string>\n    <string name=\"create_account\">Criar conta</string>\n    <string name=\"add_sync\">Adicionar sincronização</string>\n    <string name=\"added_sync_format\" formatted=\"true\">%s adicionado</string>\n    <string name=\"upload_sync\">Sincronizar</string>\n    <string name=\"sync_score\">Nota</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s autenticado</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Falha em autenticar para %s</string>\n    <string name=\"none\">Nenhuma</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">Tudo</string>\n    <string name=\"max\">Max</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Contornado</string>\n    <string name=\"subtitles_depressed\">Deprimido</string>\n    <string name=\"subtitles_shadow\">Sombreado</string>\n    <string name=\"subtitles_raised\">Em Relevo</string>\n    <string name=\"subtitle_offset\">Sincronizar legendas</string>\n    <string name=\"subtitle_offset_title\">Atraso de legenda</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Use isto se as legendas forem mostradas %dms adiantadas</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Use isto se as legendas forem mostradas %dms atrasadas</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Sem atraso de legenda</string>\n    <string name=\"subtitles_example_text\">Luís argüia à Júlia que «brações, fé, chá, óxido, pôr, zângão» eram palavras do português</string>\n    <string name=\"recommended\">Recomendada</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">%s carregada</string>\n    <string name=\"player_load_subtitles\">Carregar de arquivo</string>\n    <string name=\"player_load_subtitles_online\">Carregar da Internet</string>\n    <string name=\"downloaded_file\">Arquivo baixado</string>\n    <string name=\"actor_main\">Protagonista</string>\n    <string name=\"actor_supporting\">Coadjuvante</string>\n    <string name=\"actor_background\">Figurante</string>\n    <string name=\"home_random\">Aleatório</string>\n    <string name=\"coming_soon\">Em breve…</string>\n    <string name=\"poster_image\">Imagem de Poster</string>\n    <string name=\"category_player\">Player</string>\n    <string name=\"resolution_and_title\">Resolução e título</string>\n    <string name=\"title\">Título</string>\n    <string name=\"error_invalid_id\">Id inválida</string>\n    <string name=\"error_invalid_data\">Dado inválido</string>\n    <string name=\"error_invalid_url\">URL inválido</string>\n    <string name=\"error\">Erro</string>\n    <string name=\"subtitles_remove_captions\">Remover legendas ocultas(CC) das legendas</string>\n    <string name=\"subtitles_remove_bloat\">Remover bloat das legendas</string>\n    <string name=\"subtitles_filter_lang\">Filtrar por linguagem preferida</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"next\">Próximo</string>\n    <string name=\"provider_languages_tip\">Ver vídeos nestas linguagens</string>\n    <string name=\"previous\">Anterior</string>\n    <string name=\"skip_setup\">Saltar setup</string>\n    <string name=\"app_layout_subtext\">Change the look of the app to suit your device</string>\n    <string name=\"preferred_media_subtext\">What do you want to see</string>\n    <string name=\"setup_done\">Feito</string>\n    <string name=\"extensions\">Extensões</string>\n    <string name=\"add_repository\">Adicionar repositório</string>\n    <string name=\"repository_name_hint\">Nome do repositório (Opcional)</string>\n    <string name=\"repository_url_hint\">URL do repositório or Referência</string>\n    <string name=\"plugin_loaded\">Plugin Carregado</string>\n    <string name=\"plugin_deleted\">Plugin Apagado</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Falha ao carregar %s</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Download iniciado %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Transferido %1$d %2$s com sucesso</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Tudo %s já transferido</string>\n    <string name=\"batch_download\">Transferência em batch</string>\n    <string name=\"plugin_singular\">plugin</string>\n    <string name=\"plugin\">plugins</string>\n    <string name=\"delete_repository_plugins\">Isto irá apagar todos os repositórios de plugins</string>\n    <string name=\"delete_repository\">Apagar repositório</string>\n    <string name=\"setup_extensions_subtext\">Transferir lista de sites a usar</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Transferido: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Desativado: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Não transferido: %d</string>\n    <string name=\"blank_repo_message\">O CloudStream não tem sites instalados por padrão. É necessário instalar os sites a partir de repositórios.\n\\n\n\\nJunte-se ao nosso Discord ou pesquise online.</string>\n    <string name=\"view_public_repositories_button\">Ver repositórios da comunidade</string>\n    <string name=\"view_public_repositories_button_short\">Lista pública</string>\n    <string name=\"uppercase_all_subtitles\">Todas as legendas em maiúsculas</string>\n    <string name=\"download_all_plugins_from_repo\">Aviso: O CloudStream 3 não se responsabiliza pelo uso de extensões de terceiros e não fornece qualquer suporte às mesmas!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Desativado)</string>\n    <string name=\"apk_installer_settings\">Instalador APK</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"play_trailer_button\">Assistir Trailer</string>\n    <string name=\"action_add_to_bookmarks\">Marcar como visto/não visto</string>\n    <string name=\"action_open_play\">Reproduzir</string>\n    <string name=\"automatic_plugin_download_summary\">Instalar automaticamente todos os plugins ainda não instalados dos repositórios adicionados.</string>\n    <string name=\"automatic_plugin_download\">Baixar extensões automaticamente</string>\n    <string name=\"redo_setup_process\">Refazer o processo de configuração</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"other_singular\">Vídeo</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"cast_format\" formatted=\"true\">Elenco: %s</string>\n    <string name=\"update_started\">Atualização iniciada</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"apk_installer_settings_des\">Alguns aparelhos não suportam o novo instalador de pacotes. Use a opção legado caso não esteja conseguindo atualizar.</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"start\">Iniciar</string>\n    <string name=\"test_failed\">Falha</string>\n    <string name=\"test_passed\">Sucesso</string>\n    <string name=\"library\">Biblioteca</string>\n    <string name=\"browser\">Navegar</string>\n    <string name=\"anim\">Aplicativo de Anime pelos mesmos desenvolvedores</string>\n    <string name=\"ova_singular\">Ova</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Player visível - Procurar valor</string>\n    <string name=\"update_notification_installing\">Instalando atualização do app…</string>\n    <string name=\"confirm_exit_dialog\">Você tem certeza que deseja sair?</string>\n    <string name=\"extension_version\">Versão</string>\n    <string name=\"skip_type_ed\">Encerramento</string>\n    <string name=\"clear_history\">Limpar histórico</string>\n    <string name=\"skip_type_op\">Abertura</string>\n    <string name=\"no\">Não</string>\n    <string name=\"sort_by\">Ordenar por</string>\n    <string name=\"yes\">Sim</string>\n    <string name=\"update_notification_downloading\">Baixando atualização do app…</string>\n    <string name=\"subscription_episode_released\">Episódio %d lançado!</string>\n    <string name=\"skip_type_creddits\">Créditos</string>\n    <string name=\"extension_description\">Descrição</string>\n    <string name=\"extension_size\">Tamanho</string>\n    <string name=\"stop\">Parar</string>\n    <string name=\"safe_mode_title\">Modo seguro ligado</string>\n    <string name=\"history\">Histórico</string>\n    <string name=\"sort\">Ordenar</string>\n    <string name=\"player_settings_play_in_app\">Player interno</string>\n    <string name=\"extension_authors\">Autores</string>\n    <string name=\"extension_types\">Suportado</string>\n    <string name=\"extension_language\">Idioma</string>\n    <string name=\"extension_install_first\">Instalar a extensão primeiro</string>\n    <string name=\"hls_playlist\">Playlist HLS</string>\n    <string name=\"player_pref\">Player de vídeo preferido</string>\n    <string name=\"extension_status\">Estado</string>\n    <string name=\"pref_category_gestures\">Gestos</string>\n    <string name=\"tracks\">Faixas</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"skip_type_intro\">Abertura</string>\n    <string name=\"select_library\">Selecionar Biblioteca</string>\n    <string name=\"jsdelivr_proxy_summary\">Contorna o bloqueio de URLs raw do GitHub usando jsDelivr. Pode atrasar as atualizações por uns dias.</string>\n    <string name=\"all_languages_preference\">Todas as linguagens</string>\n    <string name=\"sort_updated_new\">Atualizado (Novo para Antigo)</string>\n    <string name=\"subscription_list_name\">Inscrito</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"restart\">Reiniciar</string>\n    <string name=\"sort_updated_old\">Atualizado (Antigo para Novo)</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"apk_installer_package_installer\">Instalador de pacotes</string>\n    <string name=\"action_remove_from_watched\">Remover dos assistidos</string>\n    <string name=\"update_notification_failed\">Não foi possível instalar a nova versão do aplicativo</string>\n    <string name=\"subscription_deleted\">Inscrição cancelada em %s</string>\n    <string name=\"skip_type_mixed_ed\">Final misto</string>\n    <string name=\"sort_rating_desc\">Avaliações (Decrescente)</string>\n    <string name=\"apply_on_restart\">Reinicie a aplicação para ver as alterações.</string>\n    <string name=\"referer\">Referenciador (opcional)</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Player oculto - Quantidade de Busca</string>\n    <string name=\"jsdelivr_proxy\">Proxy do GitHub</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"pref_category_looks\">Aparência</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"open_with\">Abrir com</string>\n    <string name=\"category_provider_test\">Teste de provedor</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"safe_mode_crash_info\">Ver informações sobre falha</string>\n    <string name=\"app_not_found_error\">Aplicativo não encontrado</string>\n    <string name=\"revert\">Reverter</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"plugin_downloaded\">Plugins baixados</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d plugins atualizados</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Pular %s</string>\n    <string name=\"skip_type_mixed_op\">Abertura mista</string>\n    <string name=\"sort_alphabetical_z\">Alfabético (Z a A)</string>\n    <string name=\"empty_library_logged_in_message\">Esta lista está vazia. Tente trocar para outra.</string>\n    <string name=\"subscription_new\">Inscrito em %s</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"video_tracks\">Faixas de vídeo</string>\n    <string name=\"delayed_update_notice\">O aplicativo será atualizado ao sair</string>\n    <string name=\"subscription_in_progress_notification\">Atualizando shows inscritos</string>\n    <string name=\"sort_alphabetical_a\">Alfabético (A a Z)</string>\n    <string name=\"sort_rating_asc\">Avaliações (Crescente)</string>\n    <string name=\"empty_library_no_accounts_message\">A sua biblioteca está vazia :(\n\\nEntre numa conta da biblioteca ou adicione espectáculos à sua biblioteca local.</string>\n    <string name=\"safe_mode_file\">Arquivo de modo de segurança encontrado!\n\\nNenhuma extensão será carregada na inicialização do app até que o arquivo seja removido.</string>\n    <string name=\"pref_category_bypass\">Contorno do provedor de serviço de internet (ISP)</string>\n    <string name=\"pref_category_links\">Links</string>\n    <string name=\"pref_category_player_features\">Recursos do Player</string>\n    <string name=\"pref_category_ui_features\">Recursos</string>\n    <string name=\"pref_category_app_updates\">Atualizações de aplicativos</string>\n    <string name=\"watch_quality_pref_data\">Qualidade Preferida (Dados Móveis)</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Quantidade de busca (em segundos) usada quando o player de video está visível</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Quantidade de busca (em segundos) usada quando o player de video está oculto</string>\n    <string name=\"jsdelivr_enabled\">Não foi possível chegar ao GitHub. Ativando o proxy jsDelivr…</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"pref_category_subtitles\">Legendas</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"extension_rating\" formatted=\"true\">Nota: %s</string>\n    <string name=\"apk_installer_legacy\">Legado</string>\n    <string name=\"safe_mode_description\">Todas as extensões foram desativadas devido a uma falha para ajudá-lo a encontrar a que está causando o problema.</string>\n    <string name=\"skip_type_recap\">Recapitular</string>\n    <string name=\"enable_skip_op_from_database_des\">Mostrar pop-ups para pular abertura/encerramento</string>\n    <string name=\"clipboard_too_large\">Muito texto. Não é possível salvar na área de transferência.</string>\n    <string name=\"action_mark_as_watched\">Marcar como assistido</string>\n    <string name=\"pref_category_backup\">Backup</string>\n    <string name=\"pref_category_extensions\">Extensões</string>\n    <string name=\"pref_category_actions\">Ações</string>\n    <string name=\"pref_category_player_layout\">Layout</string>\n    <string name=\"pref_category_defaults\">Configurações padrão</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"audio_tracks\">Faixas de áudio</string>\n    <string name=\"profile_number\">Perfil %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Dados móveis</string>\n    <string name=\"set_default\">Definir predefinição</string>\n    <string name=\"use\">Utilização</string>\n    <string name=\"edit\">Editar</string>\n    <string name=\"profiles\">Perfis</string>\n    <string name=\"help\">Ajuda</string>\n    <string name=\"qualities\">Qualidades</string>\n    <string name=\"profile_background_des\">Perfil de fundo</string>\n    <string name=\"quality_profile_help\">Aqui pode alterar a forma como as fontes são ordenadas. Se um vídeo tiver uma prioridade mais elevada, aparecerá mais alto na seleção da fonte. A soma da prioridade da fonte com a prioridade da qualidade é a prioridade do vídeo.\n\\n\n\\nFonte A: 3\n\\nQualidade B: 7\n\\nTerá uma prioridade de vídeo combinada de 10.\n\\n\n\\nNOTA: Se a soma for 10 ou mais, o leitor saltará automaticamente o carregamento quando essa ligação for carregada!</string>\n    <string name=\"automatic_plugin_download_mode_title\">Selecionar o modo para filtrar a transferência de plug-ins</string>\n    <string name=\"unable_to_inflate\">Não foi possível criar corretamente a interface do utilizador, trata-se de um GRANDE BUG e deve ser comunicado imediatamente %s</string>\n    <string name=\"disable\">Desativar</string>\n    <string name=\"no_plugins_found_error\">Não foram encontrados plugins no repositório</string>\n    <string name=\"no_repository_found_error\">Repositório não encontrado, verifique o URL e tente a VPN</string>\n    <string name=\"already_voted\">Você já votou</string>\n    <string name=\"action_unsubscribe\">Cancelar Inscrição</string>\n    <string name=\"action_subscribe\">Subscrever</string>\n    <string name=\"favorites_list_name\">Favoritos</string>\n    <string name=\"links_reloaded_toast\">A recarregar links</string>\n    <string name=\"backup_frequency\">Frequência de Backup</string>\n    <string name=\"favorite_removed\">%s removido dos favoritos</string>\n    <string name=\"action_add_to_favorites\">Adicionar aos favoritos</string>\n    <string name=\"duplicate_title\">Possível duplicata encontrada</string>\n    <string name=\"favorite_added\">%s adicionado aos favoritos</string>\n    <string name=\"action_remove_from_favorites\">Remover dos favoritos</string>\n    <string name=\"duplicate_replace\">Substituir</string>\n    <string name=\"duplicate_replace_all\">Substituir Tudo</string>\n    <string name=\"enter_current_pin\">Insira o PIN atual</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"pin_error_incorrect\">PIN incorreto. Por favor, tente novamente.</string>\n    <string name=\"pin_error_length\">O PIN deve ter 4 caracteres</string>\n    <string name=\"edit_account\">Editar conta</string>\n    <string name=\"logged_account\" formatted=\"true\">Conectado como %s</string>\n    <string name=\"skip_startup_account_select_pref\">Ignorar a seleção da conta na inicialização</string>\n    <string name=\"rotate_video\">Girar</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Digite o PIN para %s</string>\n    <string name=\"lock_profile\">Bloquear Perfil</string>\n    <string name=\"select_an_account\">Selecione uma conta</string>\n    <string name=\"manage_accounts\">Gerenciar contas</string>\n    <string name=\"use_default_account\">Usar conta padrão</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Potenciais itens duplicados foram encontrados na sua biblioteca:\n\\n\n\\n%s\n\\n\n\\nDeseja adicionar esse item mesmo assim, subtituir os existentes, ou cancelar a ação?</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Parece que já existe um item potencialmente duplicado na sua biblioteca: \\'%s.\\'\n\\n\n\\nDeseja adicionar esse item mesmo assim, subtituir o existente, ou cancelar a ação?</string>\n    <string name=\"recommendations_tooltip\">Mostrar recomendações</string>\n    <string name=\"speed_setting_summary\">Adiciona uma opção de velocidade no leitor</string>\n    <string name=\"test_extensions\">Testar todas as extensões</string>\n    <string name=\"test_extensions_summary\">Este teste destina-se apenas a programadores e não verifica ou nega o funcionamento de qualquer extensão.</string>\n    <string name=\"duplicate_add\">Adicionar</string>\n    <string name=\"enter_pin\">Insira o PIN</string>\n    <string name=\"subscribe_tooltip\">Notificação de novo episódio</string>\n    <string name=\"result_search_tooltip\">Procurar noutras extensões</string>\n    <string name=\"rotate_video_desc\">Apresentar um botão de alternância para a orientação do ecrã</string>\n    <string name=\"auto_rotate_video_desc\">Ativar a mudança automática da orientação do ecrã com base na orientação do vídeo</string>\n    <string name=\"auto_rotate_video\">Rotação automática</string>\n    <string name=\"repo_copy_label\">Nome do repositório e URL</string>\n    <string name=\"favorite\">Favorito</string>\n    <string name=\"unfavorite\">Desfavorito</string>\n    <string name=\"biometric_setting\">Bloqueio com biometria</string>\n    <string name=\"toast_copied\">copiado!</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nrestante</string>\n    <string name=\"clipboard_permission_error\">Erro ao aceder à área de transferência, tente novamente.</string>\n    <string name=\"clipboard_unknown_error\">Erro ao copiar, copie o logcat e contacte o suporte da aplicação.</string>\n    <string name=\"biometric_authentication_title\">Desbloquear o CloudStream</string>\n    <string name=\"password_pin_authentication_title\">Autenticação por palavra-passe/PIN</string>\n    <string name=\"biometric_unsupported\">A autenticação biométrica não é suportada neste dispositivo</string>\n    <string name=\"biometric_setting_summary\">Desbloqueie a aplicação com impressão digital, ID facial, PIN, padrão e palavra-passe.</string>\n    <string name=\"biometric_prompt_description\">Após algumas tentativas falhadas, a janela irá fechar. Reinicie a aplicação para tentar outra vez.</string>\n    <string name=\"biometric_warning\">Os dados do seu CloudStream já foram copiados. Embora a possibilidade de isto acontecer ser muito baixa, todos os dispositivos podem comportar-se de forma diferente. No caso raro de ficar impedido de aceder à aplicação, limpe completamente os dados da aplicação e restaure a partir de uma cópia de segurança. Lamentamos qualquer incómodo causado por esta situação.</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"app_unrestricted_toast\">A utilização da bateria da aplicação já está definida como sem restrições</string>\n    <string name=\"app_info_intent_error\">Não é possível abrir a informação da aplicação CloudStream.</string>\n    <string name=\"music_singlar\">Música</string>\n    <string name=\"audio_book_singular\">Livro Aúdio</string>\n    <string name=\"custom_media_singluar\">Multimédia</string>\n    <string name=\"battery_dialog_title\">Desativar a otimização da bateria</string>\n    <string name=\"battery_dialog_message\">Para garantir descarregamentos ininterruptos e notificações de programas de TV subscritos, o CloudStream precisa de permissão para ser executado em segundo plano. Ao premir OK, será mostrado um diálogo. Prima \\\"Permitir\\\".\\n\\nTenha em atenção que esta permissão não significa que o CS3 irá esgotar a sua bateria. Este só funcionará em segundo plano quando necessário, como ao receber notificações ou baixar vídeos de extensões oficiais.</string>\n    <string name=\"reset_btn\">Reiniciar</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Temporada %1$d Episódio %2$d será lançado em</string>\n    <string name=\"player_settings_select_cast_device\">Escolha o dispositivo</string>\n    <string name=\"episode_action_cast_mirror\">Transmitir</string>\n    <string name=\"open_local_video\">Abrir vídeo local</string>\n    <string name=\"device_pin_error_message\">Não é possível receber o PIN do dispositivo, tentando autenticação local</string>\n    <string name=\"preview_seekbar\">Pré-visualização na barra de progresso</string>\n    <string name=\"preview_seekbar_desc\">Ativar a miniatura de pré-visualização na barra de progresso</string>\n    <string name=\"auth_locally\">Autenticação Local</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Irá também eliminar permanentemente todos os episódios da seguinte série:\n\\n\n\\n%s</string>\n    <string name=\"delete_format\" formatted=\"true\">Eliminar (%1$d | %2$s)</string>\n    <string name=\"device_pin_url_message\">Visite <b>%s</b> no seu smartphone ou computador e introduza o código acima</string>\n    <string name=\"play_from_beginning_img_des\">Recomeçar</string>\n    <string name=\"hide_player_control_names\">Esconde os nomes dos botões do player</string>\n    <string name=\"downloads_delete_select\">Selecionar Items para Eliminar</string>\n    <string name=\"downloads_empty\">Não existem downloads disponíveis.</string>\n    <string name=\"offline_file\">Disponível para ver offline</string>\n    <string name=\"select_all\">Selecionar Todos</string>\n    <string name=\"deselect_all\">Desselecionar todos</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Próximo em %s</string>\n    <string name=\"delete_files\">Eliminar Ficheiros</string>\n    <string name=\"test_warning\">Aviso</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Tem a certeza que pretende eliminar permanentemente os seguintes items?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Tem a certeza que pretende eliminar permanentemente os seguintes episódios em %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Tem a certeza que pretende eliminar permanentemente todos os episódios da seguinte série?\n\\n\n\\n%s</string>\n    <string name=\"pref_category_security\">Segurança</string>\n    <string name=\"pref_category_accounts\">Contas</string>\n    <string name=\"qr_image\">QR Code</string>\n    <string name=\"delete_plugin\">Eliminar plugin</string>\n    <string name=\"device_pin_counter_text\">O código expira em %1$dm %2$ds</string>\n    <string name=\"sort_release_date_new\">Data de Lançamento (Novo para Antigo)</string>\n    <string name=\"sort_release_date_old\">Data de Lançamento (Antigo para Novo)</string>\n    <string name=\"cs3wiki\">Wiki do CloudStream</string>\n    <string name=\"device_pin_expired_message\">O código PIN está agora expirado !</string>\n    <string name=\"no_subtitles_loaded\">Ainda sem legendadas carregadas</string>\n    <string name=\"open_downloaded_repo\">Abrir repositório</string>\n    <string name=\"dismiss\">Dispensar</string>\n    <string name=\"confirm_before_exiting_title\">Confirmar antes de sair</string>\n    <string name=\"confirm_before_exiting_desc\">Mostrar diálogo antes de sair da aplicação</string>\n    <string name=\"show\">Mostrar</string>\n    <string name=\"dont_show\">Não mostrar</string>\n    <string name=\"backup_path_title\">Localização da pasta de backups</string>\n    <string name=\"subs_edge_size\">Tamanho da borda</string>\n    <string name=\"torrent_info\">Este vídeo é um Torrent, o que significa que sua atividade de vídeo pode ser rastreada.\\nCertifique-se de entender o Torrent antes de continuar.</string>\n    <string name=\"custom\">Personalizado</string>\n    <string name=\"player_load_one_subtitle_online\">Carregar o primeiro disponível</string>\n    <string name=\"audio_singluar\">Áudio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"encoding_error\">Erro de codificação</string>\n    <string name=\"unsupported_error\">Erro não suportado</string>\n    <string name=\"torrent_preferred_media\">Ativar torrent nas Configurações/Provedores/Mídia preferida</string>\n    <string name=\"torrent_not_accepted\">Reinicie a aplicação e aceite o pop-up do Stream Torrent para continuar.</string>\n    <string name=\"software_decoding\">Descodificação por software</string>\n    <string name=\"software_decoding_desc\">Descodificação por software permite que o leitor reproduza ficheiros não suportados pelo seu dispositivo, mas pode resultar numa reprodução desfasada ou instável em altas resoluções</string>\n    <string name=\"subtitles_from_embedded\">Incorporada</string>\n    <string name=\"subtitles_from_online\">Online</string>\n    <string name=\"sort_episodes_number_asc\">Episódio (Ascendente)</string>\n    <string name=\"sort_episodes_number_desc\">Episódio (descendente)</string>\n    <string name=\"sort_episodes_date_oldest\">Data de exibição (mais antiga)</string>\n    <string name=\"update_plugins\">Atualizar plugins</string>\n    <string name=\"starting_plugin_update_manually\">A iniciar o processo de atualização do plugin!</string>\n    <string name=\"plugins_updated_manually\">Atualização bem-sucedida para %d plugin(s)!</string>\n    <string name=\"no_plugins_updated_manually\">Nenhum plugin foi atualizado.</string>\n    <string name=\"update_plugins_manually\">Atualizar plugins manualmente</string>\n    <string name=\"speech_recognition_unavailable\">O reconhecimento de fala não está disponível</string>\n    <string name=\"begin_speaking\">Comece a falar…</string>\n    <string name=\"sort_episodes_rating_high_low\">Avaliação (mais alta)</string>\n    <string name=\"sort_episodes_rating_low_high\">Avaliação (mais baixa)</string>\n    <string name=\"sort_episodes_date_newest\">Data de exibição (mais recente)</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_rating\">Avaliação %s</string>\n    <string name=\"sort_button_date\">Data %s</string>\n    <string name=\"player_notification_channel_description\">Notificação do player para controlar a reprodução em segundo plano</string>\n    <string name=\"player_notification_channel_name\">Notificações de reprodução</string>\n    <string name=\"all_subtitles_italic\">Colocar todas as legendas em itálico</string>\n    <string name=\"background_radius\">Raio do fundo</string>\n    <string name=\"volume_exceeded_100\">O volume excedeu 100%</string>\n    <string name=\"all_subtitles_bold\">Colocar todas as legendas em negrito</string>\n    <string name=\"slide_up_again_to_exceed_100\">Deslize para cima novamente para ir além de 100%</string>\n    <string name=\"download_parallel_settings_des\">Quantos itens diferentes podem ser baixados em paralelo</string>\n    <string name=\"parallel_downloads\">Downloads paralelos</string>\n    <string name=\"concurrent_connections\">Conexões simultâneas</string>\n    <string name=\"concurrent_connections_settings_des\">Quantas conexões simultâneas cada download pode usar durante o download</string>\n    <string name=\"go_to_downloads\">Ir para downloads</string>\n    <string name=\"no_internet_connection\">Sem conexão com a internet.\\n\\nConecte-se à internet e tente novamente ou assista aos seus downloads enquanto estiver offline.</string>\n    <string name=\"overscan_settings_des\">Altera os limites da tela</string>\n    <string name=\"overscan_settings\">Overscan</string>\n    <string name=\"poster_size_settings_des\">Altera o tamanho dos pôsteres</string>\n    <string name=\"poster_size_settings\">Tamanho do pôster</string>\n    <string name=\"player_settings_always_ask\">Sempre perguntar</string>\n    <string name=\"speedup_title\">Pressionamento para acelerar</string>\n    <string name=\"speedup_summary\">Pressione para acelerar</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh:%2$dm:%3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm:%2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"show_rating\">Etiqueta de classificação</string>\n    <string name=\"no_account\">Nehuma conta</string>\n    <string name=\"edit_profile_image_title\">Editar Imagem do Perfil</string>\n    <string name=\"edit_profile_image_hint\">Inserir URL da Imagem de Perfil</string>\n    <string name=\"edit_profile_image_error_empty\">Nenhum URL Encontrado</string>\n    <string name=\"edit_profile_image_error_invalid\">URL ou Imagem Inválido</string>\n    <string name=\"edit_profile_image_success\">Imagem Atualizada com Sucesso</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Marcar como assistido o episódio</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Removar marcação de assistido até esse episódio</string>\n    <string name=\"action_reload\">Recarregado</string>\n    <string name=\"reload_provider\">Provedor de Recarregamento</string>\n    <string name=\"episode_action_play_mirror\">Reproduzir do servidor alternativo</string>\"\n    <string name=\"name\">Nome</string>\n    <string name=\"resolution_and_name\">Resolução e nome</string>\n    <string name=\"subs_subtitle_alignment\">Alinhamento da Legenda</string>\n    <string name=\"bottom_left\">Esquerda embaixo</string>\n    <string name=\"bottom_center\">Centro embaixo</string>\n    <string name=\"bottom_right\">Direita embaixo</string>\n    <string name=\"middle_left\">Esquerda no centro</string>\n    <string name=\"middle_center\">Centro</string>\n    <string name=\"middle_right\">Direita no centro</string>\n    <string name=\"top_left\">Esquerda encima</string>\n    <string name=\"top_center\">Centro em cima</string>\n    <string name=\"top_right\">Direita em cima</string>\n    <string name=\"play_full_series_button\">Reproduzir Série Inteira</string>\n    <string name=\"install_prerelease\">Instalar versão de pré-lançamento</string>\n    <string name=\"prerelease_already_installed\">Versão de pré-lançamento já instalada.</string>\n    <string name=\"prerelease_install_failed\">Falha ao instalar pré-lançamento.</string>\n    <string name=\"show_episode_text\">Texto do Episódio</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+pt+BR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- KEYS DON'T TRANSLATE -->\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Elenco: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">O episódio %d vai ser lançado em</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Pôster</string>\n    <string name=\"episode_poster_img_des\">Pôster do episódio</string>\n    <string name=\"home_main_poster_img_des\">Pôster principal</string>\n    <string name=\"home_next_random_img_des\">Próximo Aleatório</string>\n    <string name=\"go_back_img_des\">Voltar</string>\n    <string name=\"home_change_provider_img_des\">Alterar provedor</string>\n    <string name=\"preview_background_img_des\">Visualizar plano de fundo</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Velocidade (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Avaliado: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Nova atualização encontrada! \\n%1$s → %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Preenchimento</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Início</string>\n    <string name=\"title_search\">Pesquisar</string>\n    <string name=\"title_downloads\">Downloads</string>\n    <string name=\"title_settings\">Configurações</string>\n    <string name=\"search_hint\">Procurar…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Pesquisar %s…</string>\n    <string name=\"no_data\">Sem dados</string>\n    <string name=\"episode_more_options_des\">Mais opções</string>\n    <string name=\"next_episode\">Próximo episódio</string>\n    <string name=\"result_tags\">Gêneros</string>\n    <string name=\"result_share\">Compartilhar</string>\n    <string name=\"result_open_in_browser\">Abrir no navegador</string>\n    <string name=\"skip_loading\">Pular carregamento</string>\n    <string name=\"loading\">Carregando…</string>\n    <string name=\"type_watching\">Assistindo</string>\n    <string name=\"type_on_hold\">Em espera</string>\n    <string name=\"type_completed\">Concluído</string>\n    <string name=\"type_dropped\">Desisti de ver</string>\n    <string name=\"type_plan_to_watch\">Planejo assistir</string>\n    <string name=\"type_re_watching\">Reassistindo</string>\n    <string name=\"play_movie_button\">Reproduzir filme</string>\n    <string name=\"play_torrent_button\">Transmitir Torrent</string>\n    <string name=\"pick_source\">Fontes</string>\n    <string name=\"pick_subtitle\">Legendas</string>\n    <string name=\"reload_error\">Tentando conectar novamente…</string>\n    <string name=\"go_back\">Volte</string>\n    <string name=\"play_episode\">Reproduzir episódio</string>\n    <!--<string name=\"need_storage\">Permirtir baixar episódios</string>-->\n    <string name=\"download\">Download</string>\n    <string name=\"downloaded\">Baixado</string>\n    <string name=\"downloading\">Baixando</string>\n    <string name=\"download_paused\">Download pausado</string>\n    <string name=\"download_started\">Download iniciado</string>\n    <string name=\"download_failed\">Download falhou</string>\n    <string name=\"download_canceled\">Download cancelado</string>\n    <string name=\"download_done\">Download concluído</string>\n    <string name=\"stream\">Transmitir</string>\n    <string name=\"error_loading_links_toast\">Erro ao carregar links</string>\n    <string name=\"download_storage_text\">Armazenamento interno</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Leg</string>\n    <string name=\"popup_delete_file\">Apagar arquivo</string>\n    <string name=\"popup_play_file\">Reproduzir arquivo</string>\n    <string name=\"popup_resume_download\">Continuar download</string>\n    <string name=\"popup_pause_download\">Pausar download</string>\n    <string name=\"home_more_info\">Mais informações</string>\n    <string name=\"home_expanded_hide\">Ocultar</string>\n    <string name=\"home_play\">Reproduzir</string>\n    <string name=\"home_info\">Informações</string>\n    <string name=\"filter_bookmarks\">Filtrar marcadores</string>\n    <string name=\"error_bookmarks_text\">Marcadores</string>\n    <string name=\"action_remove_from_bookmarks\">Remover</string>\n    <string name=\"action_add_to_bookmarks\">Adicionar a lista</string>\n    <string name=\"sort_apply\">Aplicar</string>\n    <string name=\"sort_copy\">Copiar</string>\n    <string name=\"sort_close\">Fechar</string>\n    <string name=\"sort_clear\">Limpar</string>\n    <string name=\"sort_save\">Salvar</string>\n    <string name=\"player_speed\">Velocidade de reprodução</string>\n    <string name=\"subtitles_settings\">Configurações de legendas</string>\n    <string name=\"subs_text_color\">Cor do texto</string>\n    <string name=\"subs_outline_color\">Cor do contorno</string>\n    <string name=\"subs_background_color\">Cor do fundo</string>\n    <string name=\"subs_window_color\">Cor da janela</string>\n    <string name=\"subs_edge_type\">Tipo de borda</string>\n    <string name=\"subs_subtitle_elevation\">Elevação da legenda</string>\n    <string name=\"subs_font\">Fonte</string>\n    <string name=\"subs_font_size\">Tamanho da fonte</string>\n    <string name=\"search_provider_text_providers\">Pesquisar usando fornecedor</string>\n    <string name=\"search_provider_text_types\">Pesquisar usando tipos</string>\n    <string name=\"benene_count_text\">%d Benenes doados aos desenvolvedores</string>\n    <string name=\"benene_count_text_none\">Nenhuma Benenes doada</string>\n    <string name=\"subs_auto_select_language\">Escolher automaticamente idioma</string>\n    <string name=\"subs_download_languages\">Salvar idiomas ao baixar</string>\n    <string name=\"subs_subtitle_languages\">Idioma da legenda</string>\n    <string name=\"subs_hold_to_reset_to_default\">Segure para redefinir para o padrão</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importe fontes colocando-as em %s</string>\n    <string name=\"continue_watching\">Continuar assistindo</string>\n    <string name=\"action_remove_watching\">Remover</string>\n    <string name=\"action_open_watching\">Mais detalhes</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Uma VPN pode ser necessária para esse fornecedor funcionar corretamente</string>\n    <string name=\"vpn_torrent\">Esse fornecedor é um torrent, uma VPN é recomendada</string>\n    <string name=\"provider_info_meta\">Metadados não são oferecidas pelo site, o carregamento do video pode falhar se ele não existir no site.</string>\n    <string name=\"torrent_plot\">Descrição</string>\n    <string name=\"normal_no_plot\">Sinopse não encontrada</string>\n    <string name=\"torrent_no_plot\">Descrição não encontrada</string>\n    <string name=\"show_log_cat\">Mostrar Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Picture-in-picture</string>\n    <string name=\"picture_in_picture_des\">Continua o vídeo em tamanho miniatura flutuando sobre outros aplicativos</string>\n    <string name=\"player_size_settings\">Redimensionar player</string>\n    <string name=\"player_size_settings_des\">Remover bordas pretas</string>\n    <string name=\"player_subtitles_settings\">Modificar legendas</string>\n    <string name=\"player_subtitles_settings_des\">Alterar legendas exibidas no player de vídeo</string>\n    <string name=\"chromecast_subtitles_settings\">Modificar legendas do Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Alterar legendas exibidas no Chromecast</string>\n    <string name=\"eigengraumode_settings\">Velocidade do vídeo</string>\n    <string name=\"swipe_to_seek_settings\">Deslize para avançar o vídeo</string>\n    <string name=\"swipe_to_seek_settings_des\">Deslizar dedo para os lados para voltar ou avançar o vídeo</string>\n    <string name=\"swipe_to_change_settings\">Deslize para mudar as configurações</string>\n    <string name=\"swipe_to_change_settings_des\">Deslize para cima ou para baixo, para ajustar brilho ou volume</string>\n    <string name=\"double_tap_to_seek_settings\">Toque duplo para avançar o vídeo</string>\n    <string name=\"double_tap_to_pause_settings\">Toque duplo para pausar</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Segundos avançados no player</string>\n    <string name=\"double_tap_to_seek_settings_des\">Toque duplo no lado direito ou esquerdo para regredir ou avançar vídeo</string>\n    <string name=\"double_tap_to_pause_settings_des\">Toque duas vezes no meio para pausar</string>\n    <string name=\"use_system_brightness_settings\">Usar brilho do sistema</string>\n    <string name=\"use_system_brightness_settings_des\">Usar brilho do sistema no player ao invés da sobreposição escura</string>\n    <string name=\"episode_sync_settings\">Atualizar progresso assistido</string>\n    <string name=\"episode_sync_settings_des\">Sincronize automaticamente seu progresso do episódio</string>\n    <string name=\"restore_settings\">Restaurar dados de backup</string>\n    <string name=\"backup_settings\">Fazer Backup</string>\n    <string name=\"restore_success\">Arquivo de Backup carregado</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Falha em restaurar dados do arquivo %s</string>\n    <string name=\"backup_success\">Dados salvos</string>\n    <string name=\"backup_failed\">Permissões de armazenamento faltando. Por favor tente novamente.</string>\n    <string name=\"backup_failed_error_format\">Erro no backup de %s</string>\n    <string name=\"search\">Pesquisar</string>\n    <string name=\"category_account\">Contas e Segurança</string>\n    <string name=\"category_updates\">Atualizações e Backup</string>\n    <string name=\"settings_info\">Info</string>\n    <string name=\"advanced_search\">Pesquisa avançada</string>\n    <string name=\"advanced_search_des\">Mostrar resultados separados por fornecedor</string>\n    <string name=\"show_fillers_settings\">Mostrar episódios extras de animes</string>\n    <string name=\"show_trailers_settings\">Mostrar trailers</string>\n    <string name=\"kitsu_settings\">Mostrar posters do Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Esconder qualidades de vídeo selecionadas nos resultados da pesquisa</string>\n    <string name=\"automatic_plugin_updates\">Atualização automática de plugins</string>\n    <string name=\"updates_settings\">Mostrar atualizações do app</string>\n    <string name=\"updates_settings_des\">Automaticamente procurar por novas atualizações ao abrir.</string>\n    <string name=\"github\">GitHub</string>\n    <string name=\"lightnovel\">App de Light novel criado pelos mesmos desenvolvedores</string>\n    <string name=\"anim\">App de Anime criado pelos mesmos desenvolvedores</string>\n    <string name=\"discord\">Entre no servidor do Discord</string>\n    <string name=\"benene\">Dar um benene aos desenvolvedores</string>\n    <string name=\"benene_des\">Benene dada</string>\n    <string name=\"app_language\">Idioma do aplicativo</string>\n    <string name=\"no_chromecast_support_toast\">Esse fornecedor não possui suporte para Chromecast</string>\n    <string name=\"no_links_found_toast\">Nenhum link encontrado</string>\n    <string name=\"copy_link_toast\">Link copiado para área de transferência</string>\n    <string name=\"play_episode_toast\">Assistir episódio</string>\n    <string name=\"subs_default_reset_toast\">Restaurar para o padrão</string>\n    <string name=\"season\">Temporada</string>\n    <string name=\"no_season\">Nenhuma temporada</string>\n    <string name=\"episode\">Episódio</string>\n    <string name=\"episodes\">Episódios</string>\n    <string name=\"season_short\">T</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Nenhum episódio encontrado</string>\n    <string name=\"delete_file\">Apagar arquivo</string>\n    <string name=\"delete\">Apagar</string>\n    <string name=\"cancel\">Cancelar</string>\n    <string name=\"pause\">Pausar</string>\n    <string name=\"resume\">Continuar</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Isso apagará %s permanentemente\n\\nVocê tem certeza?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\\nrestantes</string>\n    <string name=\"status_ongoing\">Em andamento</string>\n    <string name=\"status_completed\">Concluído</string>\n    <string name=\"status\">Estado</string>\n    <string name=\"year\">Ano</string>\n    <string name=\"rating\">Avaliação</string>\n    <string name=\"duration\">Duração</string>\n    <string name=\"site\">Site</string>\n    <string name=\"synopsis\">Sinopse</string>\n    <string name=\"queued\">Na fila</string>\n    <string name=\"no_subtitles\">Sem legendas</string>\n    <string name=\"action_default\">Padrão</string>\n    <string name=\"free_storage\">Livre</string>\n    <string name=\"used_storage\">Usado</string>\n    <string name=\"app_storage\">CloudStream</string>\n    <!--plural-->\n    <string name=\"movies\">Filmes</string>\n    <string name=\"tv_series\">Séries</string>\n    <string name=\"cartoons\">Desenhos animados</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"documentaries\">Documentários</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Dramas Asiáticos</string>\n    <string name=\"livestreams\">Transmissões ao vivo</string>\n    <string name=\"others\">Outros</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Filme</string>\n    <string name=\"tv_series_singular\">Série</string>\n    <string name=\"cartoons_singular\">Desenho Animado</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Documentário</string>\n    <string name=\"asian_drama_singular\">Drama Asiático</string>\n    <string name=\"live_singular\">Transmissão ao vivo</string>\n    <string name=\"source_error\">Erro ao abrir arquivo</string>\n    <string name=\"remote_error\">Erro no servidor</string>\n    <string name=\"render_error\">Erro de renderização</string>\n    <string name=\"unexpected_error\">Erro inesperado no player</string>\n    <string name=\"storage_error\">Erro ao baixar, verifique as permissões de armazenamento</string>\n    <string name=\"episode_action_chromecast_episode\">Episódio pelo Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Alternativa pelo Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Assistir no App</string>\n    <string name=\"episode_action_play_in_format\">Assistir no %s</string>\n    <string name=\"episode_action_auto_download\">Baixar primeiro disponível</string>\n    <string name=\"episode_action_download_mirror\">Escolher onde baixar</string>\n    <string name=\"episode_action_reload_links\">Recarregar links</string>\n    <string name=\"episode_action_download_subtitle\">Baixar legendas</string>\n    <string name=\"show_hd\">Indicação de qualidade do vídeo</string>\n    <string name=\"show_dub\">Indicação Dub</string>\n    <string name=\"show_sub\">Indicação Sub</string>\n    <string name=\"show_title\">Título</string>\n    <string name=\"poster_ui_settings\">Escolher o que mostrar sobre o pôster</string>\n    <string name=\"no_update_found\">Nenhuma atualização encontrada</string>\n    <string name=\"check_for_update\">Procurar atualização</string>\n    <string name=\"video_lock\">Bloquear toques</string>\n    <string name=\"video_aspect_ratio_resize\">Redimensionar</string>\n    <string name=\"video_source\">Fonte</string>\n    <string name=\"video_skip_op\">Pular abertura</string>\n    <string name=\"dont_show_again\">Não mostrar de novo</string>\n    <string name=\"skip_update\">Pular esta atualização</string>\n    <string name=\"update\">Atualizar</string>\n    <string name=\"watch_quality_pref\">Qualidade preferida de reprodução (Wi-fi)</string>\n    <string name=\"limit_title\">Máximo de caracteres do título de vídeos</string>\n    <string name=\"limit_title_rez\">Exibir informação do reprodutor</string>\n    <string name=\"video_buffer_size_settings\">Tamanho do buffer do vídeo</string>\n    <string name=\"video_buffer_length_settings\">Duração do buffer do vídeo</string>\n    <string name=\"video_buffer_disk_settings\">Cache do vídeo em disco</string>\n    <string name=\"video_buffer_clear_settings\">Limpar cache de vídeo e imagem</string>\n    <string name=\"video_ram_description\">Causará travamentos se o valor escolhido for muito alto em dispositivos com pouca memória RAM, como um Android TV.</string>\n    <string name=\"video_disk_description\">Causa problemas em sistemas com pouco espaço de armazenamento se definido muito alto, como em dispositivos Android TV.</string>\n    <string name=\"dns_pref\">DNS através de HTTPS</string>\n    <string name=\"dns_pref_summary\">Útil para burlar bloqueios de provedores de internet</string>\n    <string name=\"add_site_pref\">Adicionar site alternativo</string>\n    <string name=\"remove_site_pref\">Remover site</string>\n    <string name=\"add_site_summary\">Adiciona um clone de um site existente, com uma URL diferente</string>\n    <string name=\"download_path_pref\">Onde salvar Downloads</string>\n    <string name=\"nginx_url_pref\">URL do servidor NGINX</string>\n    <string name=\"display_subbed_dubbed_settings\">Mostrar Anime Dublado/Legendado</string>\n    <string name=\"resize_fit\">Ajustar para a Tela</string>\n    <string name=\"resize_fill\">Esticar</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"legal_notice\">Aviso Legal</string>\n    <string name=\"category_general\">Geral</string>\n    <string name=\"random_button_settings\">Botão Aleatório</string>\n    <string name=\"random_button_settings_desc\">Mostrar botão aleatório na página inicial e na biblioteca</string>\n    <string name=\"provider_lang_settings\">Linguagem das extensões</string>\n    <string name=\"app_layout\">Layout do App</string>\n    <string name=\"preferred_media_settings\">Mídia preferida</string>\n    <string name=\"subtitles_encoding\">Codificação das legendas</string>\n    <string name=\"category_ui\">Layout</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"tv_layout\">Layout de TV</string>\n    <string name=\"phone_layout\">Layout de celular</string>\n    <string name=\"emulator_layout\">Layout de emulador</string>\n    <string name=\"primary_color_settings\">Cor principal</string>\n    <string name=\"app_theme_settings\">Tema do App</string>\n    <string name=\"bottom_title_settings\">Local do título do poster</string>\n    <string name=\"bottom_title_settings_des\">Coloca o título debaixo do poster</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">senha123</string>\n    <string name=\"example_username\">Nome de usuário</string>\n    <string name=\"example_email\">oi@mundo.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NovoNomedoSite</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">Codigo da Língua (bp)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">Conta</string>\n    <string name=\"logout\">Sair</string>\n    <string name=\"login\">Entrar</string>\n    <string name=\"switch_account\">Trocar conta</string>\n    <string name=\"add_account\">Adicionar conta</string>\n    <string name=\"create_account\">Criar conta</string>\n    <string name=\"add_sync\">Adicionar sincronização</string>\n    <string name=\"added_sync_format\" formatted=\"true\">%s adicionado</string>\n    <string name=\"upload_sync\">Sincronizar</string>\n    <string name=\"sync_score\">Nota</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s autenticado</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Não foi possível fazer login em %s</string>\n    <!-- ============ -->\n    <string name=\"none\">Nenhum</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">Tudo</string>\n    <string name=\"max\">Max</string>\n    <string name=\"min\">Min</string>\n    <string name=\"subtitles_outline\">Contornado</string>\n    <string name=\"subtitles_depressed\">Afundado</string>\n    <string name=\"subtitles_shadow\">Sombreado</string>\n    <string name=\"subtitles_raised\">Em Relevo</string>\n    <string name=\"subtitle_offset\">Sincronizar legendas</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Atraso de legenda</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Use isto se as legendas forem mostradas %d ms adiantadas</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Use isto se as legendas forem mostradas %d ms atrasadas</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Sem atraso de legenda</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">A rápida raposa marrom salta sobre o cachorro preguiçoso</string>\n    <string name=\"recommended\">Recomendada</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">%s carregada</string>\n    <string name=\"player_load_subtitles\">Carregar de arquivo</string>\n    <string name=\"player_load_subtitles_online\">Carregar da Internet</string>\n    <string name=\"downloaded_file\">Arquivo baixado</string>\n    <string name=\"actor_main\">Protagonista</string>\n    <string name=\"actor_supporting\">Coadjuvante</string>\n    <string name=\"actor_background\">Figurante</string>\n    <string name=\"home_source\">Fonte</string>\n    <string name=\"home_random\">Aleatório</string>\n    <string name=\"coming_soon\">Em breve…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Imagem de Poster</string>\n    <string name=\"category_player\">Player</string>\n    <string name=\"resolution_and_title\">Resolução e título</string>\n    <string name=\"title\">Título</string>\n    <string name=\"resolution\">Resolução</string>\n    <string name=\"error_invalid_id\">ID inválido</string>\n    <string name=\"error_invalid_data\">Dado invalido</string>\n    <string name=\"error_invalid_url\">URL inválida</string>\n    <string name=\"error\">Erro</string>\n    <string name=\"subtitles_remove_captions\">Remover legendas ocultas(CC) das legendas</string>\n    <string name=\"subtitles_remove_bloat\">Remover bloat das legendas</string>\n    <string name=\"subtitles_filter_lang\">Filtrar por linguagem preferida</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"next\">Próximo</string>\n    <string name=\"provider_languages_tip\">Ver vídeos nestas linguagens</string>\n    <string name=\"previous\">Anterior</string>\n    <string name=\"skip_setup\">Saltar setup</string>\n    <string name=\"app_layout_subtext\">Change the look of the app to suit your device</string>\n    <string name=\"preferred_media_subtext\">What do you want to see</string>\n    <string name=\"setup_done\">Feito</string>\n    <string name=\"extensions\">Extensões</string>\n    <string name=\"add_repository\">Adicionar repositório</string>\n    <string name=\"repository_name_hint\">Nome do repositório (opcional)</string>\n    <string name=\"repository_url_hint\">URL do repositório ou link curto</string>\n    <string name=\"plugin_loaded\">Plugin Carregado</string>\n    <string name=\"plugin_deleted\">Plugin Apagado</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Não consegui carregar %s :-(</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Iniciada a transferência %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Transferido %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Tudo %s já transferido</string>\n    <string name=\"batch_download\">Transferência em batch</string>\n    <string name=\"plugin_singular\">Plugin</string>\n    <string name=\"plugin\">Plugins</string>\n    <string name=\"delete_repository_plugins\">Isto irá apagar todos os repositórios de plugins</string>\n    <string name=\"delete_repository\">Apagar repositório</string>\n    <string name=\"setup_extensions_subtext\">Transferir lista de sites a usar</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Transferido: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Desativado: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Não transferido: %d</string>\n    <string name=\"blank_repo_message\">CloudStream não tem fontes instaladas por padrão. Você precisa instalar um site de repositórios.\n\\n\n\\nEntre no nosso Discord ou pesquise online.</string>\n    <string name=\"view_public_repositories_button\">Ver repositórios da comunidade</string>\n    <string name=\"view_public_repositories_button_short\">Lista pública</string>\n    <string name=\"uppercase_all_subtitles\">Todas as legendas em maiúsculas</string>\n    <string name=\"download_all_plugins_from_repo\">Aviso: CloudStream não assume nenhuma responsabilidade pelo uso de extensões de terceiros e não fornece nenhum suporte para elas!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Desativado)</string>\n    <string name=\"autoplay_next_settings\">Reproduzir automaticamente próximo episódio</string>\n    <string name=\"autoplay_next_settings_des\">Começa o próximo episódio quando o atual termina</string>\n    <string name=\"enable_nsfw_on_providers\">Ativar NSFW em extensões compatíveis</string>\n    <string name=\"category_providers\">Fornecedores</string>\n    <string name=\"revert\">Reverter</string>\n    <string name=\"pref_category_actions\">Ações</string>\n    <string name=\"already_voted\">votou com sucesso</string>\n    <string name=\"update_notification_downloading\">Baixando atualização do aplicativo…</string>\n    <string name=\"referer\">Referenciador (opcional)</string>\n    <string name=\"pref_category_app_updates\">Atualizações do App</string>\n    <string name=\"play_with_app_name\">Assistir com o CloudStream</string>\n    <string name=\"automatic_plugin_download_summary\">Automaticamente instale todos os plugins não instalados dos repositórios adicionados.</string>\n    <string name=\"play_trailer_button\">Reproduzir trailer</string>\n    <string name=\"browser\">Navegador</string>\n    <string name=\"pref_category_backup\">Copia de Segurança</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">A Barra de Progresso pode ser usada quando o player estiver oculto</string>\n    <string name=\"subscription_list_name\">Inscrito</string>\n    <string name=\"empty_library_logged_in_message\">Essa lista está vazia. Tente mudar para outra.</string>\n    <string name=\"play_livestream_button\">Reproduzir transmissão ao vivo</string>\n    <string name=\"test_log\">Log do Teste</string>\n    <string name=\"automatic_plugin_download\">Baixar plugins automaticamente</string>\n    <string name=\"automatic_plugin_download_mode_title\">Selecione o modo para filtrar os plugins baixados</string>\n    <string name=\"test_failed\">Reprovou nos testes</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">A Barra de Progresso pode ser usada quando o player estiver visível</string>\n    <string name=\"sort\">Organizar</string>\n    <string name=\"yes\">Sim</string>\n    <string name=\"confirm_exit_dialog\">Você tem certeza que deseja sair?</string>\n    <string name=\"update_notification_installing\">Instalando atualização do aplicativo…</string>\n    <string name=\"edit\">Editar</string>\n    <string name=\"profiles\">Perfis</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Exibindo Player - procure na Barra de Progresso</string>\n    <string name=\"action_remove_from_watched\">Remover dos assistidos</string>\n    <string name=\"pref_category_extensions\">Extensões</string>\n    <string name=\"sort_alphabetical_a\">Alfabética(A =&gt; Z)</string>\n    <string name=\"open_with\">Abrir com</string>\n    <string name=\"select_library\">Selecionar Biblioteca</string>\n    <string name=\"test_passed\">Passou nos testes</string>\n    <string name=\"empty_library_no_accounts_message\">Sua biblioteca está vazia :0\n\\nEntre numa conta de biblioteca ou adicione Midias para sua biblioteca local.</string>\n    <string name=\"watch_quality_pref_data\">Qualidade preferida de reprodução (Dados Móveis)</string>\n    <string name=\"apk_installer_legacy\">Legado</string>\n    <string name=\"library\">Biblioteca</string>\n    <string name=\"no\">Não</string>\n    <string name=\"tracks\">Trilhas Sonoras</string>\n    <string name=\"sort_rating_asc\">Avaliação (baixa para alta)</string>\n    <string name=\"update_started\">Atualização iniciada</string>\n    <string name=\"nsfw_singular\">Conteúdo +18</string>\n    <string name=\"help\">Ajuda</string>\n    <string name=\"redo_setup_process\">Refazer configurações iniciais</string>\n    <string name=\"update_notification_failed\">Não foi possível instalar a nova versão do aplicativo</string>\n    <string name=\"apk_installer_package_installer\">instalador de pacotes</string>\n    <string name=\"sort_by\">Organizar por</string>\n    <string name=\"sort_rating_desc\">Avaliação (alta para baixa)</string>\n    <string name=\"sort_alphabetical_z\">Alfabética(Z =&gt; A)</string>\n    <string name=\"qualities\">Qualidade</string>\n    <string name=\"profile_background_des\">Perfil de plano de fundo</string>\n    <string name=\"quality_profile_help\">Aqui você pode alterar como as fontes são ordenadas. Se um vídeo tiver uma prioridade mais alta, aparecerá mais alto na seleção da fonte. A soma da prioridade da fonte e da prioridade da qualidade é a prioridade do vídeo.\n\\n\n\\nFonte A: 3\n\\nQualidade B: 7\n\\nTerá uma prioridade de vídeo combinada de 10.\n\\n\n\\nNOTA: Se a soma for 10 ou mais, o Player pulará automaticamente o carregamento quando o link for carregado!</string>\n    <string name=\"safe_mode_file\">Arquivo de modo de segurança encontrado!\n\\nNão carregar nenhuma extensão na inicialização até que o arquivo seja removido.</string>\n    <string name=\"subscription_new\">Inscrito em %s</string>\n    <string name=\"subscription_episode_released\">Episódio %d lançado!</string>\n    <string name=\"set_default\">Selecionar padrão</string>\n    <string name=\"subscription_deleted\">Inscrição cancelada de %s</string>\n    <string name=\"apk_installer_settings_des\">Alguns dispositivos não são compatíveis com o novo instalador de pacotes. Se as atualizações não forem instaladas, tente a opção legada.</string>\n    <string name=\"mobile_data\">Dados móveis</string>\n    <string name=\"profile_number\">Perfil %d</string>\n    <string name=\"subscription_in_progress_notification\">Atualizando shows inscritos</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Player oculto - Procure na barra de progresso</string>\n    <string name=\"nsfw\">Conteúdo +18</string>\n    <string name=\"restart\">Reiniciar</string>\n    <string name=\"stop\">Parar</string>\n    <string name=\"action_mark_as_watched\">Marcar como assistido</string>\n    <string name=\"delayed_update_notice\">Aplicativo precisa ser fechado para atualizar</string>\n    <string name=\"enable_skip_op_from_database_des\">Mostrar popups pulados para abertura e finalização</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"player_settings_play_in_app\">Player interno</string>\n    <string name=\"extension_size\">Tamanho</string>\n    <string name=\"skip_type_op\">Abrindo</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d plugins atualizados</string>\n    <string name=\"safe_mode_description\">Todos as extensões serão desligadas para ajuda se talvez estejam causando algum bug.</string>\n    <string name=\"app_not_found_error\">Aplicativo não encontrado</string>\n    <string name=\"skip_type_recap\">Recapitular</string>\n    <string name=\"all_languages_preference\">Todas as linguagens</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Pula %s</string>\n    <string name=\"skip_type_mixed_ed\">Mistura terminada</string>\n    <string name=\"safe_mode_title\">Modo seguro ligado</string>\n    <string name=\"extension_rating\" formatted=\"true\">Avaliação: %s</string>\n    <string name=\"extension_language\">Linguagem</string>\n    <string name=\"hls_playlist\">Lista de reprodução HLS</string>\n    <string name=\"skip_type_ed\">Terminando</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"sort_updated_old\">Adicionado em (antigo para novo)</string>\n    <string name=\"skip_type_intro\">Introdução</string>\n    <string name=\"no_plugins_found_error\">plug-ins não foram encontrados no repositório</string>\n    <string name=\"no_repository_found_error\">Repositório não encontrado, verifique o URL e tente usa uma VPN</string>\n    <string name=\"extension_description\">Descrição</string>\n    <string name=\"extension_version\">Versão</string>\n    <string name=\"extension_authors\">Autores</string>\n    <string name=\"extension_install_first\">Instale a extensão primeiro</string>\n    <string name=\"skip_type_creddits\">Créditos</string>\n    <string name=\"history\">Historico</string>\n    <string name=\"clear_history\">Limpar historico</string>\n    <string name=\"clipboard_too_large\">Tem Muito texto. Não é possível salvar no clipboard.</string>\n    <string name=\"player_pref\">Player de vídeo preferido</string>\n    <string name=\"start\">Iniciar</string>\n    <string name=\"extension_types\">Suportado</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"skip_type_mixed_op\">Abrindo mistura</string>\n    <string name=\"apply_on_restart\">Reinicie o aplicativo para ver as alterações.</string>\n    <string name=\"safe_mode_crash_info\">Visualização info de crash</string>\n    <string name=\"audio_tracks\">Faixas de áudio</string>\n    <string name=\"sort_updated_new\">Adicionado em (novo para antigo)</string>\n    <string name=\"video_tracks\">Faixas de video</string>\n    <string name=\"pref_category_subtitles\">Legendas</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"pref_category_links\">Links</string>\n    <string name=\"pref_category_player_features\">Funcionalidades do Player</string>\n    <string name=\"apk_installer_settings\">Instalador de APK</string>\n    <string name=\"pref_category_looks\">Aparência</string>\n    <string name=\"disable\">Desativar</string>\n    <string name=\"use\">Usar</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"pref_category_gestures\">Gestos</string>\n    <string name=\"plugin_downloaded\">Plugin baixado</string>\n    <string name=\"jsdelivr_enabled\">Não foi possível se conectar ao GitHub. Ativando proxy JsDelivr…</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"other_singular\">Vídeo</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"unable_to_inflate\">A interface de usuário não foi gerada corretamente. Isto se trata de um bug importante e deve ser reportado imediatamente %s</string>\n    <string name=\"pref_category_ui_features\">Características da interface de usuário</string>\n    <string name=\"category_provider_test\">Provedor de teste</string>\n    <string name=\"pref_category_player_layout\">Layout</string>\n    <string name=\"pref_category_defaults\">Padrões</string>\n    <string name=\"jsdelivr_proxy\">Proxy do GitHub</string>\n    <string name=\"jsdelivr_proxy_summary\">Contorne o bloqueio de URLs \\\"raw\\\" do GitHub usando jsDelivr. Pode atrasar as atualizações por alguns dias.</string>\n    <string name=\"pref_category_bypass\">Rotas alternativas</string>\n    <string name=\"favorites_list_name\">Favoritos</string>\n    <string name=\"favorite_added\">%s adicionado aos favoritos</string>\n    <string name=\"duplicate_title\">Duplicata em potencial encontrada</string>\n    <string name=\"duplicate_add\">Adicionar</string>\n    <string name=\"duplicate_replace\">Substituir</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Possíveis itens duplicados foram encontrados em sua biblioteca:\n\\n\n\\n %s\n\\n\n\\nGostaria de adicionar este item mesmo assim, substituir os existentes ou cancelar a ação?</string>\n    <string name=\"enter_pin\">Insira o PIN</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Insira o PIN para %s</string>\n    <string name=\"enter_current_pin\">Insira o PIN atual</string>\n    <string name=\"pin_error_incorrect\">PIN incorreto. Por favor, tente novamente.</string>\n    <string name=\"pin_error_length\">O PIN deve ter 4 caracteres</string>\n    <string name=\"select_an_account\">Selecione uma conta</string>\n    <string name=\"manage_accounts\">Gerenciar contas</string>\n    <string name=\"skip_startup_account_select_pref\">Ignorar a seleção da conta na inicialização</string>\n    <string name=\"rotate_video_desc\">Exibir um botão para alternar a orientação da tela</string>\n    <string name=\"favorite_removed\">%s removido dos favoritos</string>\n    <string name=\"action_add_to_favorites\">Adicionar aos favoritos</string>\n    <string name=\"action_remove_from_favorites\">Remover dos favoritos</string>\n    <string name=\"rotate_video\">Girar</string>\n    <string name=\"lock_profile\">Bloquear perfil</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"links_reloaded_toast\">Links recarregados</string>\n    <string name=\"backup_frequency\">Frequência de backup</string>\n    <string name=\"duplicate_replace_all\">Substitua tudo</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Parece que já existe um item potencialmente duplicado na sua biblioteca: \\'%s.\\'\n\\n\n\\nGostaria de adicionar este item mesmo assim, substituir o existente ou cancelar a ação?</string>\n    <string name=\"action_subscribe\">Inscrever-se</string>\n    <string name=\"action_unsubscribe\">Cancelar inscrição</string>\n    <string name=\"use_default_account\">Usar conta padrão</string>\n    <string name=\"edit_account\">Editar conta</string>\n    <string name=\"logged_account\" formatted=\"true\">Conectado como %s</string>\n    <string name=\"auto_rotate_video_desc\">Habilite a troca automática de orientação da tela com base na orientação do vídeo</string>\n    <string name=\"auto_rotate_video\">Rotação automática</string>\n    <string name=\"subscribe_tooltip\">Notificação de novo episódio</string>\n    <string name=\"result_search_tooltip\">Pesquisar em outras extensões</string>\n    <string name=\"recommendations_tooltip\">Mostrar recomendações</string>\n    <string name=\"speed_setting_summary\">Mostrar botão de velocidade do vídeo</string>\n    <string name=\"test_extensions\">Testar todas as extensões</string>\n    <string name=\"test_extensions_summary\">Esse teste é feito somente para desenvolvedores e não verifica ou nega o funcionamento de qualquer extensão.</string>\n    <string name=\"biometric_authentication_title\">Desbloquear CloudStream</string>\n    <string name=\"biometric_warning\">O backup dos seus dados do CloudStream foi feito agora. Embora a possibilidade disso seja muito baixa, todos os dispositivos podem se comportar de maneira diferente. No caso raro de você ficar impedido de acessar o aplicativo, limpe os dados do aplicativo completamente e restaure a partir de um backup. Lamentamos muito qualquer inconveniente decorrente disso.</string>\n    <string name=\"biometric_setting\">Bloquear com Biometria</string>\n    <string name=\"password_pin_authentication_title\">Autenticação de Senha/PIN</string>\n    <string name=\"biometric_unsupported\">A autenticação biométrica não é compatível com este dispositivo</string>\n    <string name=\"biometric_setting_summary\">Desbloquear o aplicativo com impressão digital, ID facial, PIN, padrão e senha.</string>\n    <string name=\"biometric_prompt_description\">Após algumas tentativas fracassadas, o prompt será fechado. Basta reiniciar o aplicativo para tentar novamente.</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nrestante(s)</string>\n    <string name=\"favorite\">Favorito</string>\n    <string name=\"unfavorite\">Não favorito</string>\n    <string name=\"toast_copied\">copiado!</string>\n    <string name=\"clipboard_permission_error\">Erro ao acessar a área de transferência. Tente novamente.</string>\n    <string name=\"repo_copy_label\">Nome e URL do repositório</string>\n    <string name=\"clipboard_unknown_error\">Erro ao copiar. Copie o logcat e entre em contato com o suporte do aplicativo.</string>\n    <string name=\"battery_dialog_message\">Para garantir downloads e notificações ininterruptos para programas de TV assinados, o CloudStream precisa de permissão para ser executado em segundo plano. Ao pressionar OK, você será direcionado para as informações do aplicativo. Lá, vá até Uso da bateria do aplicativo e defina o uso da bateria como Irrestrito.\\n\\nObserve que esta permissão não significa que o CS3 irá descarregar sua bateria. Ele só funcionará em segundo plano quando necessário, como ao receber notificações ou baixar vídeos de extensões oficiais.</string>\n    <string name=\"ok\">Ok</string>\n    <string name=\"battery_dialog_title\">Desativar otimização de bateria</string>\n    <string name=\"app_unrestricted_toast\">O uso da bateria do app já está definido como irrestrito</string>\n    <string name=\"app_info_intent_error\">Não foi possível abrir as informações do aplicativo CloudStream.</string>\n    <string name=\"music_singlar\">Música</string>\n    <string name=\"audio_book_singular\">Áudio-livro</string>\n    <string name=\"custom_media_singluar\">Mídia</string>\n    <string name=\"reset_btn\">Redefinir</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Próximo em %s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">%2$dº episódio da %1$dª temporada estreia em</string>\n    <string name=\"player_settings_select_cast_device\">Selecione o dispositivo de transmissão</string>\n    <string name=\"episode_action_cast_mirror\">Espelhar transmissão</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"pref_category_security\">Segurança</string>\n    <string name=\"pref_category_accounts\">Contas</string>\n    <string name=\"auth_locally\">Autenticação local</string>\n    <string name=\"qr_image\">Imagem do código QR</string>\n    <string name=\"dismiss\">Descartar</string>\n    <string name=\"open_downloaded_repo\">Abrir repositório</string>\n    <string name=\"device_pin_url_message\">Acesse <b>%s</b> em seu smartphone ou computador e digite o código acima</string>\n    <string name=\"device_pin_error_message\">Não é possível obter o código PIN do dispositivo, tente a autenticação local</string>\n    <string name=\"device_pin_expired_message\">O código PIN expirou!</string>\n    <string name=\"device_pin_counter_text\">O código expira em %1$dm %2$ds</string>\n    <string name=\"play_from_beginning_img_des\">Reproduzir do começo</string>\n    <string name=\"test_warning\">Reprovou alguns testes</string>\n    <string name=\"delete_plugin\">Excluir plugin</string>\n    <string name=\"downloads_empty\">Você não baixou nada :/</string>\n    <string name=\"hide_player_control_names\">Ocultar os nomes dos controles do player</string>\n    <string name=\"open_local_video\">Abrir arquivo de vídeo</string>\n    <string name=\"sort_release_date_new\">Data de lançamento (do novo ao antigo)</string>\n    <string name=\"sort_release_date_old\">Data de lançamento (do antigo para o novo)</string>\n    <string name=\"downloads_delete_select\">Selecionar itens para excluir</string>\n    <string name=\"delete_files\">Apagar arquivos</string>\n    <string name=\"offline_file\">Disponível para assistir offline</string>\n    <string name=\"select_all\">Selecionar todos</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Tem certeza que deseja apagar permanentemente os seguintes itens?\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Tem certeza que deseja apagar permanentemente os seguintes episódios em %1$s?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Você também apagará permanentemente todos os episódios da seguinte série:\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Tem certeza que deseja apagar permanentemente todos os episódios da seguinte série?\\n\\n%s</string>\n    <string name=\"delete_format\" formatted=\"true\">Apagar %1$d (%2$s)</string>\n    <string name=\"deselect_all\">Desmarcar todos</string>\n    <string name=\"preview_seekbar_desc\">Ativar visualização de miniatura na barra de busca</string>\n    <string name=\"preview_seekbar\">Visualização da barra de busca</string>\n    <string name=\"no_subtitles_loaded\">Ainda não há legendas carregadas</string>\n    <string name=\"show\">Mostrar</string>\n    <string name=\"confirm_before_exiting_title\">Confirmar antes de sair</string>\n    <string name=\"confirm_before_exiting_desc\">Mostrar caixa de diálogo antes de sair do aplicativo</string>\n    <string name=\"dont_show\">Não mostrar</string>\n    <string name=\"backup_path_title\">Local da pasta de backup</string>\n    <string name=\"custom\">Personalizado</string>\n    <string name=\"subs_edge_size\">Tamanho da borda</string>\n    <string name=\"torrent_info\">Este vídeo é um Torrent, isso significa que sua atividade de vídeo pode ser rastreada.\\nTenha certeza de entender o que é Torrent antes de continuar.</string>\n    <string name=\"encoding_error\">Erro de codificação</string>\n    <string name=\"unsupported_error\">Erro, formato não suportado</string>\n    <string name=\"player_load_one_subtitle_online\">Carregar primeiro disponível</string>\n    <string name=\"audio_singluar\">Áudio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"software_decoding\">Decodificação de software</string>\n    <string name=\"software_decoding_desc\">A decodificação por software permite que o reprodutor reproduza arquivos de vídeo não suportados pelo seu dispositivo, mas pode causar lentidão ou instabilidade na reprodução em alta resolução.</string>\n    <string name=\"torrent_preferred_media\">Habilitar torrent em Configurações/Provedores/Mídia preferida</string>\n    <string name=\"torrent_not_accepted\">Reinicie o aplicativo e aceite o pop-up do Stream Torrent para continuar.</string>\n    <string name=\"sort_episodes_number_asc\">Episódio (Ascendente)</string>\n    <string name=\"sort_episodes_number_desc\">Episódio (descendente)</string>\n    <string name=\"sort_episodes_rating_high_low\">Avaliação (mais alta)</string>\n    <string name=\"sort_episodes_rating_low_high\">Avaliação (mais baixa)</string>\n    <string name=\"sort_button_rating\">Avaliação %s</string>\n    <string name=\"sort_episodes_date_newest\">Data de exibição (mais recente)</string>\n    <string name=\"sort_episodes_date_oldest\">Data de exibição (mais antiga)</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_date\">Data %s</string>\n    <string name=\"update_plugins\">Atualizar plugins</string>\n    <string name=\"starting_plugin_update_manually\">Iniciando o processo de atualização do plugin!</string>\n    <string name=\"plugins_updated_manually\">Atualização bem-sucedida para %d plugin(s)!</string>\n    <string name=\"no_plugins_updated_manually\">Nenhum plugin foi atualizado.</string>\n    <string name=\"update_plugins_manually\">Atualizar plugins manualmente</string>\n    <string name=\"player_notification_channel_name\">Notificações de reprodução</string>\n    <string name=\"player_notification_channel_description\">Notificação do player para controlar a reprodução em segundo plano</string>\n    <string name=\"speech_recognition_unavailable\">Reconhecimento de fala indisponível</string>\n    <string name=\"begin_speaking\">Comece a falar…</string>\n    <string name=\"subtitles_from_embedded\">Incorporada</string>\n    <string name=\"subtitles_from_online\">Online</string>\n    <string name=\"background_radius\">Bordas do plano de fundo</string>\n    <string name=\"all_subtitles_bold\">Tornar todas as legendas em negrito</string>\n    <string name=\"all_subtitles_italic\">Tornar todas as legendas em itálico</string>\n    <string name=\"volume_exceeded_100\">O volume ultrapassou 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Deslize para cima novamente para ir além de 100%</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d s</string>\n    <string name=\"show_rating\">Indicação da classificação</string>\n    <string name=\"player_settings_always_ask\">Perguntar sempre</string>\n    <string name=\"download_parallel_settings_des\">Quantos itens diferentes podem ser baixados em paralelo</string>\n    <string name=\"parallel_downloads\">Downloads em paralelo</string>\n    <string name=\"concurrent_connections\">Conexões simultâneas</string>\n    <string name=\"concurrent_connections_settings_des\">Quantas conexões simultâneas cada download pode usar durante o processo de download</string>\n    <string name=\"go_to_downloads\">Ir para Downloads</string>\n    <string name=\"no_internet_connection\">Sem conexão com a internet.\\n\\nConecte-se à internet e tente novamente, ou acompanhe seus downloads enquanto estiver offline.</string>\n    <string name=\"overscan_settings_des\">Altera os limites da tela</string>\n    <string name=\"overscan_settings\">Varredura excessiva</string>\n    <string name=\"poster_size_settings_des\">Altera o tamanho dos pôsteres</string>\n    <string name=\"poster_size_settings\">Tamanhos dos pôsteres</string>\n    <string name=\"speedup_title\">Alternar Velocidade do Pressionamento Longo</string>\n    <string name=\"speedup_summary\">Segure para duplicar a velocidade</string>\n    <string name=\"no_account\">Sem conta</string>\n    <string name=\"episode_action_play_mirror\">Espelhar vídeo</string>\"\n    <string name=\"edit_profile_image_title\">Editar Foto de Perfil</string>\n    <string name=\"edit_profile_image_hint\">Inserir URL de Foto de Perfil</string>\n    <string name=\"edit_profile_image_error_empty\">Nenhum URL Encontrado</string>\n    <string name=\"edit_profile_image_error_invalid\">URL ou Imagem inválidos</string>\n    <string name=\"edit_profile_image_success\">Imagem Atualizada com Sucesso</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Marcar como assistido até este episódio</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Remover \\\"assistido até este episódio\\\"</string>\n    <string name=\"action_reload\">Recarregado</string>\n    <string name=\"reload_provider\">Recarregar Fonte</string>\n    <string name=\"name\">Nome</string>\n    <string name=\"subs_subtitle_alignment\">Posição das Legendas</string>\n    <string name=\"bottom_left\">Inferior esquerdo</string>\n    <string name=\"bottom_center\">Inferior centralizado</string>\n    <string name=\"bottom_right\">Inferior direito</string>\n    <string name=\"middle_left\">Centro esquerdo</string>\n    <string name=\"middle_center\">Centralizado</string>\n    <string name=\"middle_right\">Centro direito</string>\n    <string name=\"top_left\">Superior esquerdo</string>\n    <string name=\"top_center\">Superior centralizado</string>\n    <string name=\"top_right\">Superior direito</string>\n    <string name=\"play_full_series_button\">Assistir à série completa</string>\n    <string name=\"resolution_and_name\">Resolução e nome</string>\n    <string name=\"prerelease_install_failed\">Falha ao instalar a versão antecipada.</string>\n    <string name=\"prerelease_already_installed\">Versão antecipada instalada.</string>\n    <string name=\"install_prerelease\">Instalar versão antecipada</string>\n    <string name=\"show_episode_text\">Episódio Text</string>\n    <string name=\"download_queue\">Fila de download</string>\n    <string name=\"queue_empty_message\">Não há itens na fila para download.</string>\n    <string name=\"extra_brightness_settings\">Brilho extra</string>\n    <string name=\"extra_brightness_settings_des\">Ativar filtro de claridade ao exceder 100% do brilho do display</string>\n    <string name=\"extra_brightness_key\">brilho_extra_ativado</string>\n    <string name=\"search_suggestions\">Sugestões de Busca</string>\n    <string name=\"search_suggestions_des\">Exibir sugestões de pesquisa durante a digitação</string>\n    <string name=\"clear_suggestions\">Limpar Sugestões</string>\n    <string name=\"show_cast_in_details\">Exibir painel de elenco</string>\n    <string name=\"video_info\">Informação de mídia</string>\n    <string name=\"source_priority\">Prioridade de fonte</string>\n    <string name=\"source_priority_help\">Decidir como fontes de vídeo devem estar dispostas no reprodutor</string>\n    <string name=\"source_name\">Nome da fonte</string>\n    <string name=\"download_all\">Baixar tudo</string>\n    <string name=\"cancel_all\">Cancelar tudo</string>\n    <string name=\"download_episode_range\">Você deseja baixar o episódio%s</string>\n    <string name=\"cancel_queue_message\">Você gostaria de cancelar todos os downloads da fila?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%ddownload ativo</item>\n        <item quantity=\"many\">%ddownloads ativos</item>\n        <item quantity=\"other\">%ddownloads ativos</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d download na sequência</item>\n        <item quantity=\"many\">%d downloads na sequência</item>\n        <item quantity=\"other\">%d downloads na sequência</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+qt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- For true intellectuals -->\n    <string name=\"app_name\">aauugghhaauuh</string>\n    <string name=\"title_home\">ooh</string>\n    <string name=\"title_search\">oouuh</string>\n    <string name=\"title_downloads\">ouuhhuhooh ooh</string>\n    <string name=\"title_settings\">aaaghhoh aauugghh</string>\n    <string name=\"search_hint\">haaooh ooo</string>\n    <string name=\"search_poster_img_des\">aaaaaah</string>\n    <string name=\"no_data\">oooohhoouuh</string>\n    <string name=\"episode_more_options_des\">aaaaoouuuhahhh ahh</string>\n    <string name=\"go_back_img_des\">oooohh aauuh</string>\n    <string name=\"next_episode\">ahhhaaaghh aaaaa</string>\n    <string name=\"result_poster_img_des\">ahaauugghh</string>\n    <string name=\"result_tags\">ahhh oouuh</string>\n    <string name=\"result_share\">aauuh</string>\n    <string name=\"result_open_in_browser\">oooohh oooohhhaaaoouuh</string>\n    <string name=\"skip_loading\">oooohhooooo</string>\n    <string name=\"loading\">ooh aaahhu</string>\n    <string name=\"type_watching\">aaaghh ooo-ahah</string>\n    <string name=\"type_on_hold\">aaahhu</string>\n    <string name=\"type_completed\">ahhahooo</string>\n    <string name=\"type_dropped\">ooooo haa</string>\n    <string name=\"type_plan_to_watch\">aaahhuoh</string>\n    <string name=\"play_movie_button\">aaaaa aaaghh</string>\n    <string name=\"play_torrent_button\">aaaghhaaahhu aaaaa</string>\n    <string name=\"pick_source\">oha aauuh</string>\n    <string name=\"pick_subtitle\">ahooo ooo-ahah</string>\n    <string name=\"reload_error\">aaaghhahaaaaaaaaaaooh</string>\n    <string name=\"go_back\">aauugghhaaaghh</string>\n    <string name=\"episode_poster_img_des\">oouuhahoooooo-ahahoooohh</string>\n    <string name=\"play_episode\">aaaaa oh ohaouuhhh</string>\n    <!--<string name=\"need_storage\">ahouuhhhaaaaa ahhaaaghh ahhh</string>-->\n    <string name=\"download\">aauuhahh</string>\n    <string name=\"download_storage_text\">aauugghhahahhah</string>\n    <string name=\"app_dubbed_text\">ooooo</string>\n    <string name=\"app_subbed_text\">ahooo</string>\n    <string name=\"popup_delete_file\">ouuhhh</string>\n    <string name=\"popup_play_file\">ahhaauugghh</string>\n    <string name=\"home_more_info\">ahooo a aaaghhouuhhh</string>\n    <string name=\"home_expanded_hide\">oh ahhh</string>\n    <string name=\"home_main_poster_img_des\">ahhhahaaaaaahhhaaaghh</string>\n    <string name=\"home_play\">ooo-ahahouuhhh</string>\n    <string name=\"home_info\">aauugghh</string>\n    <string name=\"home_next_random_img_des\">aoooohh</string>\n    <string name=\"home_change_provider_img_des\">ah ohaaaaghh aaahhu</string>\n    <string name=\"filter_bookmarks\">aaaghh aaaghhoouuh</string>\n    <string name=\"error_bookmarks_text\">oouuh ooh</string>\n    <string name=\"action_remove_from_bookmarks\">aauuh ooh</string>\n    <string name=\"sort_apply\">oouuhaooo-ahah</string>\n    <string name=\"player_speed\">oouuh aauuh oha</string>\n    <string name=\"subtitles_settings\">ouuhhhooooooh ooo-ahah</string>\n    <string name=\"subs_text_color\">ohaouuhhh</string>\n    <string name=\"subs_outline_color\">ahh oouuh</string>\n    <string name=\"subs_background_color\">aaaghh aahooo</string>\n    <string name=\"subs_window_color\">oouuhoooohhah aauugghh</string>\n    <string name=\"subs_edge_type\">aaaaaooh</string>\n    <string name=\"subs_subtitle_elevation\">oooohhaaaaghh ooh ahhh</string>\n    <string name=\"preview_background_img_des\">ahoooooo-ahah ohaaaaaaauuh</string>\n    <string name=\"subs_font\">ooo-ahah</string>\n    <string name=\"search_provider_text_providers\">aauuhaauugghhahhh ohaauugghhouuhhh</string>\n    <string name=\"search_provider_text_types\">ahhhahoooohhaa ahhhoohahh</string>\n    <string name=\"benene_count_text\">%d ooo-ahah ooooo ahhhahooo aauuhah ouuhhh</string>\n    <string name=\"benene_count_text_none\">oouuhoooooahhaaahhu</string>\n    <string name=\"subs_auto_select_language\">oooohhaaaaa ahhhahh oooohh</string>\n    <string name=\"subs_download_languages\">ahaaahhu aahoooaauugghh aaaghhoha</string>\n    <string name=\"subs_hold_to_reset_to_default\">oohoohohaoha haaohaauugghhaaahhuoouuhahhaaaghh</string>\n    <string name=\"continue_watching\">ahhh ahhhooo-ahah</string>\n    <string name=\"action_remove_watching\">aaaaaooooo</string>\n    <string name=\"action_open_watching\">ahooo ooo-ahah</string>\n    <string name=\"vpn_might_be_needed\">ouuhhh aaahhuooh haaaauugghhahoooaaahhuooo-ahahouuhhhaaahhuaaaghh haa</string>\n    <string name=\"vpn_torrent\">aaaghh aaaaaaaahhuahhhooo-ahahahh aaaaa ahooo oha ahooo</string>\n    <string name=\"torrent_plot\">ahooo ooh oooohh</string>\n    <string name=\"normal_no_plot\">aauugghhoohoohohaooooo oooohh</string>\n    <string name=\"torrent_no_plot\">ahaaaghh oha oouuhooo-ahah</string>\n    <string name=\"picture_in_picture\">ohaahhooooo</string>\n    <string name=\"picture_in_picture_des\">ooooooohhaa ouuhhh ouuhhhohahh oh ahoooaaahhuaoooooooo-ahahahh</string>\n    <string name=\"player_size_settings\">oouuhaoouuh aaaaa aauuhohahhh oooooaaaghhoh oh aaaaa</string>\n    <string name=\"player_size_settings_des\">aaaghhaaahhuahooo oha aaaghh</string>\n    <string name=\"player_subtitles_settings\">ahhhaauugghh</string>\n    <string name=\"player_subtitles_settings_des\">oha ooh ouuhhh oooohhahhh ouuhhh</string>\n    <string name=\"eigengraumode_settings\">aaaagggg aaahh</string>\n    <string name=\"swipe_to_seek_settings\">ohahaaaauugghh ahooo aaahhu</string>\n    <string name=\"swipe_to_seek_settings_des\">uuuuk oohh uuhh og eeek ag uuuuhhh aagg aaaagggg ek g uuuuk</string>\n    <string name=\"swipe_to_change_settings\">aaaaaahhaaahhuoouuhaaaaa aahooo</string>\n    <string name=\"swipe_to_change_settings_des\">ooogg ek ug uugg uk ooh oogg ug aaagg oohh og oooohh aaaahhhuuk oh oooogg</string>\n    <string name=\"double_tap_to_seek_settings\">ahaauuhaaaaaooooo ahooo aauuh aaaghhaooo-ahah</string>\n    <string name=\"search\">aauuh</string>\n    <string name=\"settings_info\">aauugghh ah</string>\n    <string name=\"advanced_search\">aah ouuhhhooo-ahah aaaghh</string>\n    <string name=\"advanced_search_des\">aauugghh ahahooo ouuhhhahh ooh oouuhahoooahhaaahhu ohaooh oouuhooo-ahah</string>\n    <string name=\"updates_settings\">haa oohaauugghhooh oh</string>\n    <string name=\"updates_settings_des\">aaaagggoooogg uuuugg aak aah aaaahhh ooogg uuuuuukh aah ooh</string>\n    <string name=\"github\">aauuhoha</string>\n    <string name=\"lightnovel\">ooo-ahahoh ohaaauugghh ahhh haaahooo</string>\n    <string name=\"anim\">ooooohaa ohaaaaaaahoooahoooaaaghh</string>\n    <string name=\"discord\">ooooohaa ahhh aauuhahhahh</string>\n    <string name=\"benene\">aaaaaoooooaoouuhaauugghhaauuh</string>\n    <string name=\"benene_des\">ahooo aaaghh</string>\n    <string name=\"app_language\">haaooh</string>\n    <string name=\"no_chromecast_support_toast\">aauugghhoh ouuhhh ohaaauugghhaaahhuoouuhah</string>\n    <string name=\"no_links_found_toast\">oh ohaaaaghhah ahhha</string>\n    <string name=\"copy_link_toast\">ooh oouuh ahoooah ohaa oh ouuhhh</string>\n    <string name=\"play_episode_toast\">ouuhhhoouuh ouuhhh</string>\n    <string name=\"subs_default_reset_toast\">haaahhh ooo-ahah haaoh haaooh</string>\n    <string name=\"error_loading_links_toast\">ahooo oouuhoooohh oooohhaaaghh oouuh</string>\n    <string name=\"season\">ooo-ahah</string>\n    <string name=\"no_season\">aauuh ohaahooo</string>\n    <string name=\"episode\">ahhhaaahhu</string>\n    <string name=\"episodes\">ahhh ooooo</string>\n    <string name=\"season_short\">H</string>\n    <string name=\"episode_short\">A</string>\n    <string name=\"delete_file\">ooha ohahaaahoooa ahahooo</string>\n    <string name=\"delete\">oooooah</string>\n    <string name=\"cancel\">oooohh</string>\n    <string name=\"delete_message\">aahhaaaaaahooo aauuh aaahhuaooo-ahahoooohh aoouuhoohoohooo-ahah %s</string>\n    <string name=\"status_ongoing\">aaaghhaaaaa</string>\n    <string name=\"status_completed\">aauuhaauuh</string>\n    <string name=\"status\">ahhhaaaaa</string>\n    <string name=\"year\">oohahahh oha</string>\n    <string name=\"rating\">ah ooooo</string>\n    <string name=\"duration\">ahhhooh</string>\n    <string name=\"site\">ah oha</string>\n    <string name=\"synopsis\">aauugghh ohaaauugghh</string>\n    <string name=\"queued\">haaouuhhh</string>\n    <string name=\"no_subtitles\">ahaaaaaaaaaahaaaauugghh</string>\n    <string name=\"action_default\">ahooooh</string>\n    <string name=\"free_storage\">ooo-ahahaaaaa</string>\n    <string name=\"used_storage\">ahhahhh</string>\n    <string name=\"app_storage\">aauugghh</string>\n    <string name=\"movies\">a oouuh</string>\n    <string name=\"tv_series\">ahh ooooo</string>\n    <string name=\"cartoons\">ahoooouuhhh</string>\n    <string name=\"anime\">aahooo</string>\n    <string name=\"torrent\">ah ooh</string>\n    <string name=\"episode_action_chromecast_episode\">aauugghhooo-ahah ohaaauugghh</string>\n    <string name=\"episode_action_chromecast_mirror\">aoohaaahhu ahouuhhh</string>\n    <string name=\"episode_action_play_in_app\">ooo-ahahaauuh aaahhu</string>\n    <string name=\"episode_action_play_in_format\">ooo-ahah ohaauuh %s</string>\n    <string name=\"episode_action_auto_download\">aaaghhoooohh aaahhu ahooo</string>\n    <string name=\"episode_action_download_mirror\">ohooo-ahahaohaohahhhoouuh</string>\n    <string name=\"episode_action_reload_links\">ahoooaaahhuahaaahhuoha</string>\n    <string name=\"no_update_found\">oohaaahhu ah ahhaaaaa ooo-ahah</string>\n    <string name=\"check_for_update\">ohaaaahhuhaaahhhaaahhu</string>\n    <string name=\"video_lock\">ooo-ahah</string>\n    <string name=\"video_aspect_ratio_resize\">ohaooo-ahahouuhhh</string>\n    <string name=\"video_source\">ahohooh</string>\n    <string name=\"video_skip_op\">aaaaaohaah ooh</string>\n    <string name=\"dont_show_again\">Boooooo ooooo</string>\n    <string name=\"update\">aaahhuooh ahh</string>\n    <string name=\"download_started\">aaaaa oooohh aauugghh</string>\n    <string name=\"download_failed\">aaaghhahhooo-ahahahhha aaaghh</string>\n    <string name=\"downloaded\">ooo-ahahaaaghh</string>\n    <string name=\"downloading\">oohahaaoouuh</string>\n    <string name=\"download_paused\">aaahhuooo-ahahhaaa</string>\n    <string name=\"download_canceled\">ooo-ahah aaaghhahooo</string>\n    <string name=\"download_done\">aaaghhaaaaa ohouuhhh</string>\n    <string name=\"popup_resume_download\">aaaghhahhhooooo oohaaaaa</string>\n    <string name=\"popup_pause_download\">aauugghhaaaaa haa</string>\n    <string name=\"pause\">ooh aaaaa</string>\n    <string name=\"resume\">oouuh haa</string>\n    <string name=\"double_tap_to_seek_settings_des\">oohahaha hahha ooooohaha</string>\n    <string name=\"storage_error\">oohahaha hahha ooooohaha haaoou</string>\n    <string name=\"use_system_brightness_settings\">u ahhu uuuh hau uaohuau</string>\n    <string name=\"use_system_brightness_settings_des\">aahuuouhh ouh hhhah hhaohuhha</string>\n    <string name=\"subs_font_size\">a auoo ohauh</string>\n    <string name=\"source_error\">uhaauauau ahuuouaha</string>\n    <string name=\"remote_error\">auuuha h a ahuhaaaa</string>\n    <string name=\"render_error\">uaoh uhu uahaaaaoo</string>\n    <string name=\"unexpected_error\">uauhah u aao u oah</string>\n    <string name=\"watch_quality_pref\">aaaagggoh uuugg uuuuggg (WiFi)</string>\n    <string name=\"dns_pref\">haoooo aaoou uou ah</string>\n    <string name=\"dns_pref_summary\">oahuouooaouoa ouuhh</string>\n    <string name=\"display_subbed_dubbed_settings\">o ouou uhauuuoaah h</string>\n    <string name=\"resize_fit\">ou aouhouo aaooao hh</string>\n    <string name=\"resize_fill\">hhauhohhuu au aaohu</string>\n    <string name=\"resize_zoom\">uhuoh o a ohahuhohoa hah</string>\n    <string name=\"provider_lang_settings\">aaaagggog oooogggoh</string>\n    <string name=\"legal_notice\">ah huu oouhhau aoaoaaohoo ha</string>\n    <string name=\"category_general\">a ahu uoo uoahuo uo</string>\n    <string name=\"app_layout\">uo u ohouao</string>\n    <string name=\"automatic\">uuoouhh hhuhuuh ouhoaao hau aouo</string>\n    <string name=\"tv_layout\">uha uh huo uooaah u</string>\n    <string name=\"phone_layout\">u ooah uo ahauao huhuu hauu h</string>\n    <string name=\"primary_color_settings\">a ou oh ouhuouhoaaha</string>\n    <string name=\"show_fillers_settings\">aaooohhouhhha hauauuu</string>\n    <string name=\"new_update_format\">aaaaaaa uuuuuu\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s aaou %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">oouaaahh %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">aaaaaaugh ouh %d uuoogahaaah ooua-h-ha</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$daaa %2$duuu %3$dhhhg</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$daaaaaaauuhh %2$doouuahaaha</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dmmmm...</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">aaaaaaaaaaaaahh (%.2foouo)</string>\n    <string name=\"rated_format\" formatted=\"true\">aghaaaooo-ough %.1f</string>\n    <string name=\"filler\" formatted=\"true\">aaaaaaaaaaaaaaaaaaaaaaaaaaaaaooooohhuhuhuhuhuhhuhuhhhaaagaha-agagaoooo</string>\n    <string name=\"duration_format\" formatted=\"true\">%d ooaaaugha</string>\n    <string name=\"play_with_app_name\">oooooh aaah aauuuggghauuh</string>\n    <string name=\"search_hint_site\" formatted=\"true\">aaoohhu %s aoouu</string>\n    <string name=\"browser\">oooaaaauhgaaaa</string>\n    <string name=\"type_re_watching\">aaaaaah-ooooooooouuagh</string>\n    <string name=\"action_add_to_bookmarks\">auugggguuuuuuhhh uuuu hhhhhhhhuhggghggg</string>\n    <string name=\"play_trailer_button\">ggaaaahhhhhhh gaauuuuuuuaaaau</string>\n    <string name=\"play_livestream_button\">aaauuuuggggguu</string>\n    <string name=\"update_started\">ooo aagg hhhh</string>\n    <string name=\"stream\">aaaahhh aaaagg</string>\n    <string name=\"sort_copy\">uuuuhhhoouuooog ooaaahhhh</string>\n    <string name=\"sort_close\">uuu ugggg</string>\n    <string name=\"sort_clear\">ooo guggg ooh</string>\n    <string name=\"tracks\">auuuooohaaaaagh</string>\n    <string name=\"library\">uuuuuuuh aaaoo o</string>\n    <string name=\"category_updates\">uuuuggg uuh aaaagg</string>\n    <string name=\"ova\">AAAAUUUOH</string>\n    <string name=\"subscription_list_name\">aoughoooaaaa</string>\n    <string name=\"movies_singular\">oooouuuh</string>\n    <string name=\"category_player\">ahaough aaouuuuh-h</string>\n    <string name=\"tv_series_singular\">auughooo</string>\n    <string name=\"pref_category_player_layout\">ooooooa aauoh</string>\n    <string name=\"subs_subtitle_languages\">aaaaagh oouoo aaaaaaa</string>\n    <string name=\"category_account\">oooogggg aah aaaaaakh</string>\n    <string name=\"extensions\">aaaaaauo agghhhhhhaoouu</string>\n    <string name=\"others\">uuuuuuuuh</string>\n    <string name=\"test_log\">ouaaahh</string>\n    <string name=\"subs_import_text\" formatted=\"true\">ooough aaoough aooou %s aaaa</string>\n    <string name=\"documentaries\">ouooooouuuu oooooo</string>\n    <string name=\"livestreams\">aaaaaaaaaaahhhgh-aooohoooo</string>\n    <string name=\"pref_category_extensions\">aau aooooghaao</string>\n    <string name=\"provider_info_meta\">aagh aaaaaaaaaaaa oooh, aaough, ooga oguuu aaaaaaaaaaa ooooooohghh a-a-aaauo</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dmmmmmm..\n\\naaaaooughugh</string>\n    <string name=\"asian_drama\">aooohuohaaaa ooooagh</string>\n    <string name=\"subtitle_offset\">oooooogh-aaaaaogh</string>\n    <string name=\"trailer\">guuuaaaahhhhhhhaaa</string>\n    <string name=\"show_log_cat\">woooaaahh ahahaaaauu 🦍</string>\n    <string name=\"nsfw\">AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOOOGGAGHAGHAAA</string>\n    <string name=\"clear_history\">aoaaaaaoooghhh</string>\n    <string name=\"sort_save\">oooooh uuaagh</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"chromecast_subtitles_settings\">oouuhhh ahhooo-ahah</string>\n    <string name=\"restore_success\">uuuugg aaaahh oogg</string>\n    <string name=\"device_pin_counter_text\">aagg uuuuggg og %1$dm %2$ds</string>\n    <string name=\"pref_category_android_tv\">aaaahhh ag</string>\n    <string name=\"random_button_settings_desc\">aahh aaaagg uuuugg uh uuuuhhhh aag uuuuhhh</string>\n    <string name=\"backup_settings\">aahh oh uuhh</string>\n    <string name=\"safe_mode_crash_info\">aahh ooogg aahh</string>\n    <string name=\"extension_size\">oogg</string>\n    <string name=\"uppercase_all_subtitles\">uuuuhhhoh ooh uuuuhhhag</string>\n    <string name=\"plugins_updated\" formatted=\"true\">eeeeeek %d ooooggg</string>\n    <string name=\"player_pref\">aaaagggah uuugg uuuugg</string>\n    <string name=\"backup_success\">aaak oooohh</string>\n    <string name=\"backup_failed\">uuuuggg aaaahhhaahh uuuuhhh aaaagg aag uuuhh</string>\n    <string name=\"automatic_plugin_download_summary\">oooohhhoooohh ooooggg uuh oog aag uuuugggag eeeeeek aahh uuuhh uuuuggguuugg</string>\n    <string name=\"show_sub\">aag uuuuk</string>\n    <string name=\"show_title\">eeeek</string>\n    <string name=\"limit_title\">aaahh aaaahh ooohh uuk uuugg</string>\n    <string name=\"limit_title_rez\">ooohh uuuuhh aaaahhhooh</string>\n    <string name=\"emulator_layout\">oooohhhg aaaahh</string>\n    <string name=\"quality_ts\">oh</string>\n    <string name=\"quality_tc\">ah</string>\n    <string name=\"quality_blueray\">uuuuhh</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">aag %s ooooggg oooogggaag</string>\n    <string name=\"view_public_repositories_button_short\">aaaahh aagg</string>\n    <string name=\"no_plugins_found_error\">ug uuuuhhh aaahh og oooohhhuuh</string>\n    <string name=\"double_tap_to_seek_amount_settings\">oooohh oohh oooohh (Seconds)</string>\n    <string name=\"ova_singular\">aag</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">ooh aagg uuuuhh uugg uugg uuh uuuuhh ag uuuuhh</string>\n    <string name=\"pref_category_app_updates\">eek aaaahhh</string>\n    <string name=\"category_ui\">uuuugg</string>\n    <string name=\"account\">aaaaggg</string>\n    <string name=\"logout\">oog aag</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">uuk aaak ah ooooggguh uuk uuugg %d ah ooh oogg</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">ah uuuuhhhg uuuhh</string>\n    <string name=\"actor_main\">aahh</string>\n    <string name=\"actor_supporting\">uuuugggooh</string>\n    <string name=\"home_random\">aaaagg</string>\n    <string name=\"quality_cam_rip\">uug</string>\n    <string name=\"delete_plugin\">oooogg oooogg</string>\n    <string name=\"blank_repo_message\">oooohhhoogg uuh uh uuuhh aaaaggguh og ooooggg uug aagg ek aaaaggg oog aaahh aagg uuuugggooohh\n\\n\n\\nJoin uuh uuuuggg ag uuuuhh eeeeek</string>\n    <string name=\"audio_tracks\">uuugg aaaagg</string>\n    <string name=\"safe_mode_title\">oogg uugg uh</string>\n    <string name=\"skip_type_intro\">aaagg</string>\n    <string name=\"history\">aaaaggg</string>\n    <string name=\"rotate_video\">uuuuhh</string>\n    <string name=\"reset_btn\">aaahh</string>\n    <string name=\"cs3wiki\">uuuuhhhaaak aagg</string>\n    <string name=\"result_search_tooltip\">aaaagg og ooogg aaaahhhaah</string>\n    <string name=\"double_tap_to_pause_settings\">aaaagg aah ah ooogg</string>\n    <string name=\"automatic_plugin_updates\">aaaahhhuh aaaagg uuuuhhh</string>\n    <string name=\"automatic_plugin_download\">aaaagggaaaahh uuuugggg uuuuggg</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"skip_update\">aahh oogg uuuuhh</string>\n    <string name=\"pref_category_player_features\">uuuuhh aaaaaakg</string>\n    <string name=\"pref_category_defaults\">uuuugggk</string>\n    <string name=\"category_provider_test\">oooohhhg uugg</string>\n    <string name=\"test_extensions\">oohh eek aaaagggooh</string>\n    <string name=\"login\">aag og</string>\n    <string name=\"create_account\">oooogg uuuuhhh</string>\n    <string name=\"subtitles_shadow\">oooohh</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"preferred_media_subtext\">oohh ah uuk aagg ag aah</string>\n    <string name=\"add_repository\">uug uuuugggoog</string>\n    <string name=\"repository_name_hint\">uuuuggguug uugg (uuooal)</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">aaaahhhaah %1$d %2$s</string>\n    <string name=\"batch_download\">aaahh uuuugggh</string>\n    <string name=\"delete_repository\">oooohh oooogggoog</string>\n    <string name=\"extension_description\">uuuuhhhaagg</string>\n    <string name=\"clipboard_too_large\">uuh aahh uugg oooogg ag aagg ug ooooggguh</string>\n    <string name=\"profile_number\">ooooggg %d</string>\n    <string name=\"edit\">aahh</string>\n    <string name=\"profiles\">oooogggk</string>\n    <string name=\"quality_profile_help\">eeek aag uug uuuuhh ooh aak uuuuggg ooh uuuuhhh ug g eeeek oog h uuuuhh oooogggh ag aahh oooohh aaaagg uh oog uuuugg uuuugggog uug oog uh uuh aaaagg uuuuuukg uug aah uuuuuuk uuuuuukg ak ooh uuuhh aaaagggk\n\\n\n\\nSource A: 3\n\\nQuality B: 7\n\\nWill uuhh k uuuuhhhk ooogg uuuuhhhh uk 10\n\\n\n\\nNOTE: ah uug oog ug 10 og oogg uug aaaahh uuhh uuuugggaaaahh oogg aaaahhh oogg uuhh aahh uh loaded!</string>\n    <string name=\"favorites_list_name\">uuuuhhhug</string>\n    <string name=\"favorite_removed\">%s aaaaggg uuhh aaaagggug</string>\n    <string name=\"duplicate_add\">oog</string>\n    <string name=\"duplicate_replace\">aaaahhh</string>\n    <string name=\"manage_accounts\">aaaagg aaaagggh</string>\n    <string name=\"logged_account\" formatted=\"true\">aaaagg ug ag %s</string>\n    <string name=\"skip_startup_account_select_pref\">aagg aaaahhh aaaahhhog ag aaaahhh</string>\n    <string name=\"use_default_account\">aah aaaaggg aaaaggg</string>\n    <string name=\"auto_rotate_video\">oohh aaaagg</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">ooh oogg aaaahh uuhh oogg aah oooohh ag ooooggg</string>\n    <string name=\"jsdelivr_enabled\">aaahh uug uuuhh aaaahh uuuuggg og uuuuhhhk proxy…</string>\n    <string name=\"actor_background\">oooohhhooh</string>\n    <string name=\"stop\">uuhh</string>\n    <string name=\"go_back_30\">30</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">aag aagg ag oog aaaagggak ooh uuugg %d oh ooh ooohh</string>\n    <string name=\"quality_sdr\">uug</string>\n    <string name=\"quality_webrip\">aak</string>\n    <string name=\"poster_image\">uuuuhh aaagg</string>\n    <string name=\"error_invalid_data\">aaaahhh oohh</string>\n    <string name=\"skip_type_recap\">ooohh</string>\n    <string name=\"empty_library_logged_in_message\">uugg oohh oh aaahh oog uuuugggoh ah oooohhh ooh</string>\n    <string name=\"subscription_new\">ooooggguuk uh %s</string>\n    <string name=\"duplicate_title\">uuuuhhhag aaaagggug aaaak</string>\n    <string name=\"auth_locally\">aagg aaaaggg</string>\n    <string name=\"normal\">oooogg</string>\n    <string name=\"max\">aah</string>\n    <string name=\"extension_types\">oooogggag</string>\n    <string name=\"subtitle_offset_hint\">1000 ak</string>\n    <string name=\"enter_current_pin\">uuuhh aaaahhh ooh</string>\n    <string name=\"favorite\">uuuuuukg</string>\n    <string name=\"biometric_authentication_title\">aaaahh oooohhhaaak</string>\n    <string name=\"device_pin_url_message\">ooogg<b>%s</b> on your smartphone or computer and enter the above code</string>\n    <string name=\"device_pin_error_message\">Can\\t aah uuh aaaagg oog code, uuh ooogg uuuuggguuuuggg</string>\n    <string name=\"live_singular\">eeeeeekuug</string>\n    <string name=\"episode_action_download_subtitle\">uuuugggh oooohhhag</string>\n    <string name=\"poster_ui_settings\">uuuuhh ak oooogggh oh aaaagg</string>\n    <string name=\"watch_quality_pref_data\">uuuugggoh aaagg aaaahhh (Mobile Data)</string>\n    <string name=\"android_tv_interface_off_seek_settings\">aaaahh oooohh oohh aaaahh</string>\n    <string name=\"pref_category_cache\">ooogg</string>\n    <string name=\"pref_category_looks\">ooogg</string>\n    <string name=\"preferred_media_settings\">aaaagggug ooohh</string>\n    <string name=\"example_site_url\">https://examplecom</string>\n    <string name=\"quality_cam\">aag</string>\n    <string name=\"error_invalid_url\">aaaahhh aag</string>\n    <string name=\"setup_done\">eeek</string>\n    <string name=\"plugin_downloaded\">oooohh oooogggaah</string>\n    <string name=\"sort_rating_asc\">oooogg (Low ah High)</string>\n    <string name=\"pref_filter_search_quality\">aagg aaaahhhh aaagg aaaaggg ak uuuuhh aaaaggg</string>\n    <string name=\"apk_installer_settings_des\">eeek uuuuhh uh aah aaaaaak aah oog aaaahhh uuuuuukah aah oog oooogg aaaahh ug ooooggg oh ooh aaaaggg</string>\n    <string name=\"cartoons_singular\">uuuuggg</string>\n    <string name=\"video_buffer_size_settings\">aaahh oooohh uuhh</string>\n    <string name=\"video_buffer_length_settings\">ooogg uuuuhh aaaahh</string>\n    <string name=\"pref_category_links\">uuugg</string>\n    <string name=\"pref_category_ui_features\">uuuugggg</string>\n    <string name=\"category_providers\">aaaagggak</string>\n    <string name=\"example_ip\">127001</string>\n    <string name=\"plugin_loaded\">oooohh uuuugg</string>\n    <string name=\"skip_type_format\" formatted=\"true\">aahh %s</string>\n    <string name=\"all_languages_preference\">uuh aaaagggag</string>\n    <string name=\"enable_skip_op_from_database_des\">aahh oogg aaaagg ooh opening/ending</string>\n    <string name=\"resolution\">oooohhhuuk</string>\n    <string name=\"other_singular\">ooohh</string>\n    <string name=\"next\">aagg</string>\n    <string name=\"ok\">oh</string>\n    <string name=\"apk_installer_package_installer\">uuuuuukoooohhhah</string>\n    <string name=\"sort_rating_desc\">aaaahh (High ug Low)</string>\n    <string name=\"sort_alphabetical_a\">aaaaaakuuugg (A uh Z)</string>\n    <string name=\"open_with\">aagg oogg</string>\n    <string name=\"subscription_in_progress_notification\">aaaagggg aaaaggguug ooohh</string>\n    <string name=\"action_add_to_favorites\">uuh ah aaaahhhag</string>\n    <string name=\"action_remove_from_favorites\">aaaahh aagg uuuuhhhuh</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">uuugg uug oog %s</string>\n    <string name=\"lock_profile\">aaak uuuuhhh</string>\n    <string name=\"pin\">oog</string>\n    <string name=\"unfavorite\">aaaagggaah</string>\n    <string name=\"audio_book_singular\">ooogg aagg</string>\n    <string name=\"video_ram_description\">uuuugg aaaaggg ug aah uug aahh ug uuuuhhh oohh aah memory, oohh og oooohhh ug</string>\n    <string name=\"extension_version\">aaaahhh</string>\n    <string name=\"previous\">oooogggh</string>\n    <string name=\"title\">ooogg</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">aaaaggg aaaahhhuuhh %1$d %2$s…</string>\n    <string name=\"skip_type_mixed_ed\">uuuhh aaaagg</string>\n    <string name=\"no\">oh</string>\n    <string name=\"use\">uug</string>\n    <string name=\"help\">uugg</string>\n    <string name=\"qualities\">oooogggoh</string>\n    <string name=\"biometric_setting\">uugg uuhh oooohhhoog</string>\n    <string name=\"music_singlar\">aaahh</string>\n    <string name=\"biometric_prompt_description\">uuugg g uug uuuuhh attempts, aah aaaagg uugg uuuhh aaaagg uuuuhhh aag uug ah uuh uuugg</string>\n    <string name=\"min\">oog</string>\n    <string name=\"extension_install_first\">aaaaggg uug oooohhhuh uuuuk</string>\n    <string name=\"network_adress_example\">https://examplecom/examplemp4</string>\n    <string name=\"hide_player_control_names\">oohh uuugg ag aag player uuuugggg</string>\n    <string name=\"sort_updated_new\">aaaaggg (New ah Old)</string>\n    <string name=\"nsfw_singular\">oohh</string>\n    <string name=\"all\">aag</string>\n    <string name=\"subtitles_remove_captions\">aaaagg uuuugg oooohhhk oohh oooogggah</string>\n    <string name=\"episode_sync_settings_des\">aaaaggguuuugg uuhh oohh ooooggg eeeeeek aaaagggh</string>\n    <string name=\"restore_settings\">ooooggg uugg uugg uuuugg</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">oooohh ah aaaahhh oogg oogg aahh %s</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"episodes_range\">%1$d%2$d</string>\n    <string name=\"no_episodes_found\">ek oooogggh ooohh</string>\n    <string name=\"show_dub\">uug aaahh</string>\n    <string name=\"video_buffer_disk_settings\">uuuuk uuugg ag oogg</string>\n    <string name=\"video_buffer_clear_settings\">aaahh aaahh uug ooohh aaagg</string>\n    <string name=\"add_site_pref\">uuugg uuhh</string>\n    <string name=\"random_button_settings\">uuuuuk uuuuhh</string>\n    <string name=\"enable_nsfw_on_providers\">oooohh oohh uh uuuugggah uuuugggaag</string>\n    <string name=\"subtitles_encoding\">uuuuhhhh oooohhhk</string>\n    <string name=\"example_password\">password123</string>\n    <string name=\"example_username\">aaaagggk</string>\n    <string name=\"example_email\">hello@worldcom</string>\n    <string name=\"example_site_name\">oooogggoohh</string>\n    <string name=\"switch_account\">uuuugg uuuuggg</string>\n    <string name=\"add_account\">aag oooohhh</string>\n    <string name=\"add_sync\">uug oooohhhh</string>\n    <string name=\"added_sync_format\" formatted=\"true\">aaaak %s</string>\n    <string name=\"upload_sync\">uuhh</string>\n    <string name=\"sync_score\">aaahh</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s aaaagggaaaahh</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">ooogg uug aah oh oh %s</string>\n    <string name=\"coming_soon\">aaaagg soon…</string>\n    <string name=\"quality_cam_hd\">aah</string>\n    <string name=\"quality_hq\">uh</string>\n    <string name=\"quality_hd\">ag</string>\n    <string name=\"quality_workprint\">ag</string>\n    <string name=\"quality_dvd\">aah</string>\n    <string name=\"quality_sd\">ek</string>\n    <string name=\"resolution_and_title\">uuuuhhhuuh aag aaahh</string>\n    <string name=\"delete_repository_plugins\">eeek oohh uuhh oooohh oog oooogggooh aaaahhh</string>\n    <string name=\"setup_extensions_subtext\">aaaagggh oog uuuk ug ooohh aak aahh ag aag</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Downloaded: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Disabled: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">aag downloaded: %d</string>\n    <string name=\"view_public_repositories_button\">uuhh aaaagggag ooooggguuuhh</string>\n    <string name=\"download_all_plugins_from_repo\">Warning: ooooggguuhh 3 uuhh aah aahh oog aaaagggaaaaggg aah aaahh aaaahhhoog aaaagggaag uuh uugg uug uuuuhhh uug eeeeeek aah them!</string>\n    <string name=\"safe_mode_description\">ooh oooohhhooh oogg oooogg ooh uuh uh g ooogg oh uuhh uug uuhh ooh aah uuuuggg ooooggg</string>\n    <string name=\"extension_authors\">ooooggg</string>\n    <string name=\"player_settings_play_in_app\">aaaagggh uuuugg</string>\n    <string name=\"app_not_found_error\">aah ooh uuugg</string>\n    <string name=\"skip_type_op\">uuuuhhh</string>\n    <string name=\"action_remove_from_watched\">uuuuhh aagg oooohhh</string>\n    <string name=\"confirm_exit_dialog\">uug ooh oohh ooh aahh ag exit?</string>\n    <string name=\"yes\">ooh</string>\n    <string name=\"update_notification_downloading\">uuuugggaagg aah update…</string>\n    <string name=\"update_notification_installing\">eeeeeekooh aag update…</string>\n    <string name=\"update_notification_failed\">uuugg aag uuuuhhh aag uuh aaaaaak ug aag aak</string>\n    <string name=\"apk_installer_legacy\">aaaahh</string>\n    <string name=\"delayed_update_notice\">aah oohh og uuuuhhh oogg uuhh</string>\n    <string name=\"sort_by\">uuhh ug</string>\n    <string name=\"sort\">uuhh</string>\n    <string name=\"start\">uuugg</string>\n    <string name=\"test_failed\">oooogg</string>\n    <string name=\"test_passed\">aaaahh</string>\n    <string name=\"android_tv_interface_on_seek_settings\">oooohh uuugg aagg uuuugg</string>\n    <string name=\"jsdelivr_proxy\">eeeeek uuugg</string>\n    <string name=\"pref_category_bypass\">aah aaaagggg</string>\n    <string name=\"disable\">aaaaggg</string>\n    <string name=\"revert\">aaaagg</string>\n    <string name=\"backup_frequency\">eeeeek uuuuhhhuh</string>\n    <string name=\"no_repository_found_error\">oooohhhuuh aag found, aaagg uug oog uuh oog aah</string>\n    <string name=\"action_subscribe\">oooogggag</string>\n    <string name=\"action_unsubscribe\">aaaahhhuugg</string>\n    <string name=\"already_voted\">uuh uuhh uuuuggg uuuhh</string>\n    <string name=\"favorite_added\">%s ooogg oh oooohhhog</string>\n    <string name=\"duplicate_replace_all\">aaaahhh uuh</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">oh ooooggg oogg k uuuuuukaahh uuuugggag uuhh ooooggg oooogg ah oogg library: \\'%s\\'\n\\n\n\\n\n\\nWould uug uugg uh aak oogg oohh anyway, oooohhh uuh oooohhhg one, oh aaaagg eek action?</string>\n    <string name=\"enter_pin\">ooogg uuh</string>\n    <string name=\"speed_setting_summary\">uuhh g ooogg oooogg oh aah uuuugg</string>\n    <string name=\"test_extensions_summary\">uugg oogg ak aaagg ooh oooohhhuug aagg uug aahh uug oooohhhg ak oooohh uuuuuuk oh uuh aaaagggag</string>\n    <string name=\"password_pin_authentication_title\">Password/PIN uuuuhhhaaaaggg</string>\n    <string name=\"repo_copy_label\">oooohhhoog oogg uuh aah</string>\n    <string name=\"toast_copied\">copied!</string>\n    <string name=\"battery_dialog_title\">aaaahhh ooooggg oooohhhooogg</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">uuuugggg og %s</string>\n    <string name=\"custom_media_singluar\">uuugg</string>\n    <string name=\"app_unrestricted_toast\">ooh oooohhh uuuhh ak aaaaggg aak ag uuuugggaaaak</string>\n    <string name=\"app_info_intent_error\">uuuugg ah uuhh CloudStream uuh uuhh</string>\n    <string name=\"pref_category_security\">oooohhhg</string>\n    <string name=\"pref_category_accounts\">uuuugggg</string>\n    <string name=\"downloads_empty\">uuuhh aah uuuugggog ug aaaagggog</string>\n    <string name=\"open_local_video\">uuhh ooohh aaagg</string>\n    <string name=\"test_warning\">uuuuhhh</string>\n    <string name=\"qr_image\">uk aahh ooogg</string>\n    <string name=\"dismiss\">uuuuuuk</string>\n    <string name=\"open_downloaded_repo\">aagg oooohhhaah</string>\n    <string name=\"device_pin_expired_message\">ooh uuuk oh aah oooohhh !</string>\n    <string name=\"play_from_beginning_img_des\">aahh oohh uuh uuuuggguh</string>\n    <string name=\"double_tap_to_pause_settings_des\">aah aaahh uh aak aaaagg oh eeeek</string>\n    <string name=\"anime_singular\">uuugg</string>\n    <string name=\"example_lang_name\">eeeeeekh aagg (en)</string>\n    <string name=\"sort_release_date_new\">uuuuhhh aahh (New og Old)</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">oooohh %1$d oooohhh %2$d aagg uk oooogggh uh</string>\n    <string name=\"autoplay_next_settings\">oooohhhk oogg uuuuggg</string>\n    <string name=\"show_trailers_settings\">oogg oooohhhg</string>\n    <string name=\"automatic_plugin_download_mode_title\">uuuugg oogg oh eeeeek eeeeeek uuuugggg</string>\n    <string name=\"redo_setup_process\">aagg uuugg uuuuggg</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nremaining</string>\n    <string name=\"edit_account\">aagg uuuuhhh</string>\n    <string name=\"biometric_setting_summary\">uuuuhh aag aah oogg Fingerprint, eeek ID, PIN, aaaaggg uuh aaaagggh</string>\n    <string name=\"downloads_delete_select\">eeeeek uuuhh oh aaaagg</string>\n    <string name=\"select_all\">uuuugg uuh</string>\n    <string name=\"torrent_singular\">oooohhh</string>\n    <string name=\"documentaries_singular\">oooogggoohh</string>\n    <string name=\"asian_drama_singular\">aaahh aaagg</string>\n    <string name=\"extension_language\">uuuugggg</string>\n    <string name=\"hls_playlist\">uug uuuugggg</string>\n    <string name=\"offline_file\">aaaagggoh ooh uuuugggh uuuuhhh</string>\n    <string name=\"deselect_all\">eeeeeekh uug</string>\n    <string name=\"links_reloaded_toast\">uuuhh uuuuuukh</string>\n    <string name=\"autoplay_next_settings_des\">aaahh uuh oogg uuuuhhh uuhh uuh aaaahhh uug oohh</string>\n    <string name=\"subscribe_tooltip\">aag aaaahhh aaaahhhooogg</string>\n    <string name=\"recommendations_tooltip\">oogg aaaaggguuuuuukk</string>\n    <string name=\"chromecast_subtitles_settings_des\">uuuuggguuh aaaagggug uuuuhhhh</string>\n    <string name=\"episode_sync_settings\">aaaagg aaahh aaaahhhg</string>\n    <string name=\"backup_failed_error_format\">uuuhh oooohhh uh %s</string>\n    <string name=\"kitsu_settings\">oohh uuuuggg uuhh uuugg</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">uuh oohh oogg aaaahhhuugg uuuugg oog aaaagggh ak uuh uuuuhhhog series:\n\\n\n\\n%s</string>\n    <string name=\"apk_installer_settings\">aak aaaagggah</string>\n    <string name=\"delete_files\">oooohh uuuhh</string>\n    <string name=\"delete_format\" formatted=\"true\">oooogg (%1$d | %2$s)</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">uuh uug oohh uuk aagg oh uuuuggguugg aaaahh uuh aaaagggah items?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">uug ooh aagg ooh uuuk ag aaaahhhuuhh oooohh ooh oooohhhug oooohhhh ah %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">ooh aag oogg uuh aagg ug eeeeeekoohh aaaahh aah uuuugggg uk aag oooohhhek series?\n\\n\n\\n%s</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"show_hd\">aaaahhh uuuhh</string>\n    <string name=\"video_disk_description\">eeeeek oooohhhg ah uuk uuh aahh ug aaaaggg aaak ooh oooohhh space, aahh ug oooohhh ek</string>\n    <string name=\"remove_site_pref\">oooogg uuhh</string>\n    <string name=\"add_site_summary\">oog k aaagg uh uk uuuuhhhg site, aahh h uuuuggguk ooh</string>\n    <string name=\"download_path_pref\">aaaahhhg aagg</string>\n    <string name=\"nginx_url_pref\">aaaak uuuuhh uuh</string>\n    <string name=\"pref_category_backup\">uuuugg</string>\n    <string name=\"pref_category_actions\">oooohhh</string>\n    <string name=\"pref_category_gestures\">aaaahhhh</string>\n    <string name=\"app_theme_settings\">oog ooohh</string>\n    <string name=\"bottom_title_settings\">aaaahh aaahh uuuugggg</string>\n    <string name=\"bottom_title_settings_des\">uuh aah ooogg aaahh uuh oooogg</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"none\">uuhh</string>\n    <string name=\"subtitles_outline\">aaaaaak</string>\n    <string name=\"subtitles_depressed\">aaaahhhug</string>\n    <string name=\"subtitles_raised\">aaaagg</string>\n    <string name=\"subtitle_offset_title\">uuuuhhhh uuuhh</string>\n    <string name=\"subtitles_example_text\">uug ooohh aaahh uuh aaagg uuuk ooh aagg aag</string>\n    <string name=\"player_load_subtitles\">aagg aahh uuuk</string>\n    <string name=\"recommended\">aaaahhhaahh</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">oooohh %s</string>\n    <string name=\"player_load_subtitles_online\">eeek aahh oooohhhh</string>\n    <string name=\"downloaded_file\">aaaagggaah aagg</string>\n    <string name=\"quality_uhd\">uuh</string>\n    <string name=\"quality_hdr\">aak</string>\n    <string name=\"error_invalid_id\">ooooggg ah</string>\n    <string name=\"error\">uuuhh</string>\n    <string name=\"subtitles_remove_bloat\">uuuuhh aaagg aahh oooohhhah</string>\n    <string name=\"subtitles_filter_lang\">oooogg uh aaaahhhog uuugg aaaagggh</string>\n    <string name=\"extras\">uuuugg</string>\n    <string name=\"referer\">ooooggg (optional)</string>\n    <string name=\"provider_languages_tip\">aaagg oooogg og uuugg aaaagggag</string>\n    <string name=\"skip_setup\">aaak ooohh</string>\n    <string name=\"app_layout_subtext\">uuuuuk aag aaak uh ooh aah oh oogg oohh uuuugg</string>\n    <string name=\"repository_url_hint\">aaaaggguuh uug o aaooolllo</string>\n    <string name=\"plugin_deleted\">uuuugg uuuuhhh</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">ooogg eek oogg %s</string>\n    <string name=\"plugin_singular\">aaaagg</string>\n    <string name=\"plugin\">uuuuhhh</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Disabled)</string>\n    <string name=\"extension_rating\" formatted=\"true\">Rating: %s</string>\n    <string name=\"extension_status\">aaaagg</string>\n    <string name=\"player_settings_select_cast_device\">aaaagg aahh oooohh</string>\n    <string name=\"skip_type_ed\">uuuuuk</string>\n    <string name=\"skip_type_mixed_op\">aaagg aaaahhh</string>\n    <string name=\"skip_type_creddits\">ooooggg</string>\n    <string name=\"battery_dialog_message\">oh oooogg ooooggguuuugg aaaahhhug ooh aaaaggguuuuuk ooh aaaagggoog uk shows, aaaaggguugg aaagg uuuuggguug ug uug oh aaaahhhooh ah eeeeeekh OK, youl og aaaaaakg uh uuk aagg There, aaaagg uk oog uuuuhhh ooohh uug uuh oooohhh aaagg ug uuuuhhhooohh oooohh note, aagg aaaahhhaak oohh uug uugg CS3 aagg eeeek aahh uuuuhhh uh uugg oogg ooooggg ek uug aaaahhhaak oohh necessary, uugg oh uuhh uuuuhhhuh uuuuuukaaaahh ah oooohhhaagg uuuuuk oogg aaaagggh oooogggoog uh uuh aaaahh ug cancel, uuh uug aaaahh uugg uuuuggg ooogg uh aaaahhh uuuugggg</string>\n    <string name=\"sort_updated_old\">uuuuggg (Old og New)</string>\n    <string name=\"sort_alphabetical_z\">uuuuggguuuhh (Z ak A)</string>\n    <string name=\"select_library\">uuuugg uuuuggg</string>\n    <string name=\"empty_library_no_accounts_message\">uuhh eeeeeek ek uuugg :(\n\\nLog oh ag h aaaaggg uuuuggg ah uuk ooogg ag uugg uuugg oooohhh</string>\n    <string name=\"safe_mode_file\">oohh aagg uugg found!\n\\nNot aaaaggg aak uuuugggaag ah uuuuhhh aaaak oogg ah eeeeeek</string>\n    <string name=\"subscription_deleted\">uuuuggguuugg oohh %s</string>\n    <string name=\"subscription_episode_released\">ooooggg %d released!</string>\n    <string name=\"wifi\">uugg</string>\n    <string name=\"mobile_data\">aaaahh uugg</string>\n    <string name=\"set_default\">ooh ooooggg</string>\n    <string name=\"profile_background_des\">oooohhh uuuuhhhoog</string>\n    <string name=\"unable_to_inflate\">uh ooh oooogg ag ek oooohhh correctly, uuhh uh g ooogg aah uug aaaagg uh uuuugggk uuuuhhhaahh %s</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">uuuuggguk uuuuhhhoh uuugg aahh aaak uuugg ag oohh library:\n\\n\n\\n%s\n\\n\n\\nWould aag aagg og uuk uugg oogg anyway, aaaahhh ooh uuuugggh ones, ek uuuuhh aah action?</string>\n    <string name=\"pin_error_incorrect\">oooohhhag uug oooohh uuh eeeek</string>\n    <string name=\"rotate_video_desc\">aaaaggg h oooogg aaaaak uug uuuugg aaaaaakaagg</string>\n    <string name=\"auto_rotate_video_desc\">uuuuhh uuuuhhhuh oooogggag ag aaaahh uuuuggguugg aaagg ek aaagg aaaagggaagg</string>\n    <string name=\"biometric_unsupported\">aaaagggah aaaaaakeeeeeek ah aag ooooggguh uh oohh aaaagg</string>\n    <string name=\"biometric_warning\">uugg aaaagggaahh uuuk ooh oogg oooohh ug uuh aaaagggg aag aaaagggoogg oh oohh og oohh low, aag aaaahhh uug uuuuhh aaaagggoohh ek oog uugg case, oohh uug aah aaaagg uuh oohh ooooggguh aag app, uuuuk oog uug uuhh aaaagggoog oog oooohhh oohh h aaaagg ag uuh uuhh uuugg oog aah uuuugggeeeeek uuuuggg aagg uugg</string>\n    <string name=\"sort_release_date_old\">oooohhh uugg (Old uk New)</string>\n    <string name=\"episode_action_cast_mirror\">uuuk aaaagg</string>\n    <string name=\"jsdelivr_proxy_summary\">uuuuhh uuuuuukk oh aah aaaagg uugg uuuuk uuuuhhhg uuh uuugg uuuuhhh uh og uuuuggg ah uug oohh</string>\n    <string name=\"pref_category_subtitles\">uuuuuukah</string>\n    <string name=\"home_source\">aaaahh</string>\n    <string name=\"video_tracks\">uuugg uuuugg</string>\n    <string name=\"apply_on_restart\">uuuuggg ooh aah uk oog uuuuhhh</string>\n    <string name=\"restart\">aaaaggg</string>\n    <string name=\"clipboard_permission_error\">aaahh aaaagggog Clipboard, aaaahh oog ooogg</string>\n    <string name=\"clipboard_unknown_error\">ooogg copying, aaaagg oohh uuuugg aag uuuuhhh ooh ooooggg</string>\n    <string name=\"action_mark_as_watched\">uuhh ug oooohhh</string>\n    <string name=\"pin_error_length\">ooh oogg uh 4 uuuuhhhooh</string>\n    <string name=\"select_an_account\">uuuugg oh oooohhh</string>\n    <string name=\"no_subtitles_loaded\">Oo hoo-hoo haaa-oo ar-ar</string>\n    <string name=\"preview_seekbar_desc\">ee-ee-ar-ar pee-ee-oo-oo kik-kik oo kik-hoo</string>\n    <string name=\"preview_seekbar\">kik-kik-kik pee-ee-oo-oo</string>\n    <string name=\"confirm_before_exiting_desc\">Boo kik-kik oo-chit ar-ar coo haa</string>\n    <string name=\"show\">Boo</string>\n    <string name=\"confirm_before_exiting_title\">Oo-ahh oo-chit ar-ar</string>\n    <string name=\"dont_show\">Boooooo</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Distribuție: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episodul %d va fi lansat în</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Poster</string>\n    <string name=\"episode_poster_img_des\">Poster Episod</string>\n    <string name=\"home_main_poster_img_des\">Poster Principal</string>\n    <string name=\"home_next_random_img_des\">Următorul la Întâmplare</string>\n    <string name=\"go_back_img_des\">Înapoi</string>\n    <string name=\"home_change_provider_img_des\">Schimbă furnizorul</string>\n    <string name=\"preview_background_img_des\">Previzualizare în fundal</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Viteză (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Evaluare: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Actualizare nouă găsită!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Filler</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <!-- <string name=\"app_name\">CloudStream</string> -->\n    <string name=\"title_home\">Prima pagină</string>\n    <string name=\"title_search\">Căutare</string>\n    <string name=\"title_downloads\">Descărcări</string>\n    <string name=\"title_settings\">Setări</string>\n    <string name=\"search_hint\">Căutare…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Căutați %s…</string>\n    <string name=\"no_data\">Fără date</string>\n    <string name=\"episode_more_options_des\">Mai multe opțiunii</string>\n    <string name=\"next_episode\">Episodul următor</string>\n    <string name=\"result_tags\">Gen</string>\n    <string name=\"result_share\">Distribuie</string>\n    <string name=\"result_open_in_browser\">Deschide în browser</string>\n    <string name=\"skip_loading\">Săriți încărcarea</string>\n    <string name=\"loading\">Se încarcă…</string>\n    <string name=\"type_watching\">În curs de vizualizare</string>\n    <string name=\"type_on_hold\">În așteptare</string>\n    <string name=\"type_completed\">Finalizat</string>\n    <string name=\"type_dropped\">Renunțat</string>\n    <string name=\"type_plan_to_watch\">Planificare pentru a urmări</string>\n    <string name=\"type_re_watching\">Reurmat</string>\n    <string name=\"play_movie_button\">Urmărește</string>\n    <string name=\"play_torrent_button\">Stream Torrent</string>\n    <string name=\"pick_source\">Surse</string>\n    <string name=\"pick_subtitle\">Subtitrare</string>\n    <string name=\"reload_error\">Încercați să vă conectați din nou…</string>\n    <string name=\"go_back\">Înapoi</string>\n    <string name=\"play_episode\">Redă episodul</string>\n    <string name=\"download\">Descărcare</string>\n    <string name=\"downloaded\">Descărcat</string>\n    <string name=\"downloading\">Se descarcă</string>\n    <string name=\"download_paused\">Descărcare oprită</string>\n    <string name=\"download_started\">Descărcare începută</string>\n    <string name=\"download_failed\">Descărcare eșuată</string>\n    <string name=\"download_canceled\">Descărcare anulată</string>\n    <string name=\"download_done\">Descărcare finalizată</string>\n    <string name=\"stream\">Stream de rețea</string>\n    <string name=\"error_loading_links_toast\">Eroare la încărcarea linkurilor</string>\n    <string name=\"download_storage_text\">Stocare internă</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Șterge fișierul</string>\n    <string name=\"popup_play_file\">Redare fișier</string>\n    <string name=\"popup_resume_download\">Continuați descărcarea</string>\n    <string name=\"popup_pause_download\">Opriți descărcarea</string>\n    <string name=\"home_more_info\">Mai multe informații</string>\n    <string name=\"home_expanded_hide\">Ascunde</string>\n    <string name=\"home_play\">Începe</string>\n    <string name=\"home_info\">Informații</string>\n    <string name=\"filter_bookmarks\">Filtrează marcajele</string>\n    <string name=\"error_bookmarks_text\">Marcaje</string>\n    <string name=\"action_remove_from_bookmarks\">Eliminează</string>\n    <string name=\"action_add_to_bookmarks\">Adaugă</string>\n    <string name=\"sort_apply\">Aplică</string>\n    <string name=\"sort_copy\">Copiază</string>\n    <string name=\"sort_close\">Închide</string>\n    <string name=\"sort_clear\">Elimină</string>\n    <string name=\"sort_save\">Salvează</string>\n    <string name=\"player_speed\">Viteză video</string>\n    <string name=\"subtitles_settings\">Setări de subtitrare</string>\n    <string name=\"subs_text_color\">Culoarea textului</string>\n    <string name=\"subs_outline_color\">Culoare de contur</string>\n    <string name=\"subs_background_color\">Culoarea de fundal</string>\n    <string name=\"subs_window_color\">Culoarea ferestră</string>\n    <string name=\"subs_edge_type\">Tipul de margine</string>\n    <string name=\"subs_subtitle_elevation\">Elevație subtitlu</string>\n    <string name=\"subs_font\">Font</string>\n    <string name=\"subs_font_size\">Dimensiune</string>\n    <string name=\"search_provider_text_providers\">Căutare în funcție de furnizor</string>\n    <string name=\"search_provider_text_types\">Căutare în funcție de tip</string>\n    <string name=\"benene_count_text\">%d banane oferite dezvoltatorilor</string>\n    <string name=\"benene_count_text_none\">Nu s-au oferit banane</string>\n    <string name=\"subs_auto_select_language\">Selectare automată a limbii</string>\n    <string name=\"subs_download_languages\">Descarcă limbi străine</string>\n    <string name=\"subs_subtitle_languages\">Limba subtitrării</string>\n    <string name=\"subs_hold_to_reset_to_default\">Țineți apăsat pentru a reseta la valorile implicite</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importați fonturi prin introducerea lor în %s</string>\n    <string name=\"continue_watching\">Continuați să urmăriți</string>\n    <string name=\"action_remove_watching\">Eliminați</string>\n    <string name=\"action_open_watching\">Mai multe informații</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Există probabilitatea necesitații unui VPN pentru ca acest furnizor să funcționeze corespunzător</string>\n    <string name=\"vpn_torrent\">Acest furnizor este un torrent, se recomandă un VPN</string>\n    <string name=\"provider_info_meta\">Metadatele nu sunt furnizate de către site, există posibilitatea ca încărcarea videoclipului să eșueze.</string>\n    <string name=\"torrent_plot\">Descriere</string>\n    <string name=\"normal_no_plot\">Scenariul este indisponibil</string>\n    <string name=\"torrent_no_plot\">Descrierea este indisponibilă</string>\n    <string name=\"show_log_cat\">Arată Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Picture-in-Picture</string>\n    <string name=\"picture_in_picture_des\">Continuă redarea într-un mini-player peste alte aplicații</string>\n    <string name=\"player_size_settings\">Buton de redimensionare video</string>\n    <string name=\"player_size_settings_des\">Eliminați marginile negre</string>\n    <string name=\"player_subtitles_settings\">Subtitrare</string>\n    <string name=\"player_subtitles_settings_des\">Setări de subtitrare</string>\n    <string name=\"chromecast_subtitles_settings\">Subtitrări Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Setări pentru subtitrare Chromecast</string>\n    <string name=\"eigengraumode_settings\">viteza de redare</string>\n    <string name=\"swipe_to_seek_settings\">Derulați spre înainte/înapoi</string>\n    <string name=\"swipe_to_seek_settings_des\">Derulați dintr-o parte în alta pentru a controla timpul de difuzare a videoclipului</string>\n    <string name=\"swipe_to_change_settings\">Derulați pentru a modifica setările</string>\n    <string name=\"swipe_to_change_settings_des\">Glisați în sus sau în jos pe partea stângă sau dreaptă pentru a schimba luminozitatea sau volumul</string>\n    <string name=\"double_tap_to_seek_settings\">Atingeți de două ori pentru a merge înainte/înapoi</string>\n    <string name=\"double_tap_to_pause_settings\">Atingeți de două ori pentru a pune pauză</string>\n    <string name=\"double_tap_to_seek_settings_des\">Atingeți de două ori partea stângă sau dreaptă a ecranului pentru a derula rapid înainte sau înapoi videoclipul</string>\n    <string name=\"double_tap_to_pause_settings_des\">Atingeți de două ori în mijloc pentru a pune pauză</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Cantitatea de căutare al player-ului (secunde)</string>\n    <string name=\"use_system_brightness_settings\">Utilizați luminozitatea sistemului</string>\n    <string name=\"use_system_brightness_settings_des\">Utilizați luminozitatea sistemului în playerul aplicației în loc de o suprapunere întunecată</string>\n    <!--<string name=\"episode_sync_settings\">Update watch progress</string>-->\n    <string name=\"episode_sync_settings_des\">Sincronizează automat episoadele vizionate</string>\n    <string name=\"restore_settings\">Recuperează datele din copia de rezervă</string>\n    <string name=\"backup_settings\">Copie de rezervă a datelor</string>\n    <string name=\"restore_success\">Fișier de rezervă încărcat</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Imposibilitatea de a restaura datele din %s</string>\n    <string name=\"backup_success\">Date stocate</string>\n    <string name=\"backup_failed\">Permisiunea de arhivare lipșe, vă rugăm să încercați din nou.</string>\n    <string name=\"backup_failed_error_format\">Eroare de backup %s</string>\n    <string name=\"search\">Căutare</string>\n    <string name=\"category_account\">Conturi și Securitate</string>\n    <string name=\"category_updates\">Actualizări și copii de rezervă</string>\n    <string name=\"settings_info\">Informații</string>\n    <string name=\"advanced_search\">Căutare avansată</string>\n    <string name=\"advanced_search_des\">Împărțiți rezultatele căutării în funcție de furnizor</string>\n    <string name=\"show_fillers_settings\">Afișează etichetele [filler] pentru anime</string>\n    <string name=\"show_trailers_settings\">Arată trailerul</string>\n    <string name=\"kitsu_settings\">Arată afișele de la Kitsu</string>\n    <string name=\"updates_settings\">Afișați actualizările aplicației</string>\n    <string name=\"updates_settings_des\">Căutați automat noi actualizări după pornirea aplicației.</string>\n    <string name=\"github\">GitHub</string>\n    <string name=\"lightnovel\">&gt;Aplicație Light Novel realizată de aceiași dezvoltator</string>\n    <string name=\"anim\">Aplicație Anime realizată de aceiași dezvoltatorilor</string>\n    <string name=\"discord\">Alăturați-vă pe Discord</string>\n    <string name=\"benene\">Oferiți dezvoltatorilor o banană</string>\n    <string name=\"benene_des\">Oferă o banană</string>\n    <string name=\"app_language\">Limba aplicației</string>\n    <string name=\"no_chromecast_support_toast\">Acest furnizor nu are suport pentru Chromecast</string>\n    <string name=\"no_links_found_toast\">Nu s-au găsit link-uri</string>\n    <string name=\"copy_link_toast\">Link copiat în clipboard</string>\n    <string name=\"play_episode_toast\">Redare episod</string>\n    <string name=\"subs_default_reset_toast\">Restabilirea la valorile implicite</string>\n    <string name=\"season\">Sezonul</string>\n    <string name=\"no_season\">Nu există sezon</string>\n    <string name=\"episode\">Episodul</string>\n    <string name=\"episodes\">Episoade</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">Nu s-au găsit episoade</string>\n    <string name=\"delete_file\">Ștergeți fișierul</string>\n    <string name=\"delete\">Ștergeți</string>\n    <string name=\"cancel\">Anulează</string>\n    <string name=\"pause\">Pauză</string>\n    <string name=\"resume\">Continuă</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Sunteți pe cale să ștergeți definitiv %s\n\\nSunteți sigur?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nrămas</string>\n    <string name=\"status_ongoing\">În curs de desfășurare</string>\n    <string name=\"status_completed\">Finalizat</string>\n    <string name=\"status\">Status</string>\n    <string name=\"year\">Anul</string>\n    <string name=\"rating\">Recenzie</string>\n    <string name=\"duration\">Durată</string>\n    <string name=\"site\">Site</string>\n    <string name=\"synopsis\">Rezumat</string>\n    <string name=\"queued\">În coada de așteptare</string>\n    <string name=\"no_subtitles\">Nu există subtitrare</string>\n    <string name=\"action_default\">Implicit</string>\n    <string name=\"free_storage\">Liber</string>\n    <string name=\"used_storage\">Folosit</string>\n    <string name=\"app_storage\">Aplicație</string>\n    <!--plural-->\n    <string name=\"movies\">Filme</string>\n    <string name=\"tv_series\">Seriale TV</string>\n    <string name=\"cartoons\">Desene Animate</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"torrent\">Torrent</string>\n    <string name=\"documentaries\">Documentare</string>\n    <string name=\"asian_drama\">Drame asiatice</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Serie TV</string>\n    <string name=\"cartoons_singular\">Desen Animat</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Documentar</string>\n    <string name=\"asian_drama_singular\">Drama asiatică</string>\n    <string name=\"source_error\">Eroare de sursă</string>\n    <string name=\"remote_error\">Eroare de la distanță</string>\n    <string name=\"render_error\">Eroare de randare</string>\n    <string name=\"unexpected_error\">Eroare neașteptată a playerului</string>\n    <string name=\"storage_error\">Eroare de descărcare; verificați permisiunile de stocare</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast alternativ</string>\n    <string name=\"episode_action_play_in_app\">Redă în Aplicație</string>\n    <string name=\"episode_action_play_in_format\">Redă în %s</string>\n    <string name=\"episode_action_auto_download\">Auto-descărcare</string>\n    <string name=\"episode_action_download_mirror\">Descărcă prin Alernativă</string>\n    <string name=\"episode_action_reload_links\">Reîncărcare link-uri</string>\n    <string name=\"episode_action_download_subtitle\">Descărcare subtitrări</string>\n    <string name=\"show_hd\">Etichetă de calitate</string>\n    <string name=\"show_dub\">Etichetă Dub</string>\n    <string name=\"show_sub\">Etichetă Sub</string>\n    <string name=\"show_title\">Titlu</string>\n    <string name=\"poster_ui_settings\">Etichete de pe postere</string>\n    <string name=\"no_update_found\">Nu s-au găsit actualizări</string>\n    <string name=\"check_for_update\">Verifică pentru actualizări</string>\n    <string name=\"video_lock\">Blocare</string>\n    <string name=\"video_aspect_ratio_resize\">Redimensionare</string>\n    <string name=\"video_source\">Sursă</string>\n    <string name=\"video_skip_op\">Săriți peste intro</string>\n    <string name=\"dont_show_again\">Nu se mai arată din nou</string>\n    <string name=\"skip_update\">Treci peste această actualizare</string>\n    <string name=\"update\">Actualizare</string>\n    <string name=\"watch_quality_pref\">Calitatea preferată (WiFi)</string>\n    <string name=\"limit_title\">Limitarea caracterelor de titlu în player</string>\n    <string name=\"limit_title_rez\">Rezoluția playerului video</string>\n    <string name=\"video_buffer_size_settings\">Dimensiunea cache-ului video</string>\n    <string name=\"video_buffer_length_settings\">Lungimea buffer-ului video</string>\n    <string name=\"video_buffer_disk_settings\">Dimensiunea cache-ului video pe disc</string>\n    <string name=\"video_buffer_clear_settings\">Ștergeți memoria cache de imagine și video</string>\n    <string name=\"video_ram_description\">Cauzează blocări dacă este setat prea mare pe dispozitive cu memorie redusă, cum ar fi Android TV.</string>\n    <string name=\"video_disk_description\">Cauzează probleme dacă este setat prea mare pe dispozitive cu spațiu de stocare redus, cum ar fi Android TV.</string>\n    <string name=\"dns_pref\">DNS peste HTTPS</string>\n    <string name=\"dns_pref_summary\">Folositor pentru evitarea blocajelor ISP</string>\n    <string name=\"add_site_pref\">Adaugați site-ul</string>\n    <string name=\"remove_site_pref\">Eliminați site-ul</string>\n    <string name=\"add_site_summary\">Adăugați o copie a unui site existent, cu o adresă URL diferită</string>\n    <string name=\"download_path_pref\">Locul descărcării</string>\n    <string name=\"nginx_url_pref\">Adresa URL a serverului NGNIX</string>\n    <string name=\"display_subbed_dubbed_settings\">Afișarea anime-urilor dublate/subtitrate</string>\n    <string name=\"resize_fit\">Adaptare la ecran</string>\n    <string name=\"resize_fill\">Întindere</string>\n    <string name=\"resize_zoom\">Mărire</string>\n    <string name=\"legal_notice\">Aviz juridic (declinarea responsabilității și drepturi de autor)</string>\n    <string name=\"category_general\">General</string>\n    <string name=\"random_button_settings\">Aleatoriu</string>\n    <string name=\"random_button_settings_desc\">Afișează butonul pentru aleatoriu pe Pagina Principală și în Bibliotecă</string>\n    <string name=\"provider_lang_settings\">Limbi ale extensiei</string>\n    <string name=\"app_layout\">Aplicație de prezentare</string>\n    <string name=\"preferred_media_settings\">Media preferată</string>\n    <string name=\"subtitles_encoding\">Codificarea subtitrărilor</string>\n    <string name=\"category_ui\">Interfața utilizatorului</string>\n    <string name=\"automatic\">Auto</string>\n    <string name=\"tv_layout\">Dispunere TV</string>\n    <string name=\"phone_layout\">Dispunere telefonică</string>\n    <string name=\"emulator_layout\">Dispunerea emulatorului</string>\n    <string name=\"primary_color_settings\">Culoare primară</string>\n    <string name=\"app_theme_settings\">Tema aplicației</string>\n    <string name=\"bottom_title_settings\">Locația titlului posterului</string>\n    <string name=\"bottom_title_settings_des\">Locația titlului de pe poster</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">parola123</string>\n    <string name=\"example_username\">Numele utilizatorului/utilizatoarei</string>\n    <string name=\"example_email\">davidpopovici@gmail.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NouNumeSite</string>\n    <string name=\"example_site_url\">https://exemplu.com</string>\n    <string name=\"example_lang_name\">Cod limbă (RO)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">Cont</string>\n    <string name=\"logout\">Deconectare</string>\n    <string name=\"login\">Conectare</string>\n    <string name=\"switch_account\">Schimbă cont</string>\n    <string name=\"add_account\">Adaugă cont</string>\n    <string name=\"create_account\">Creează cont</string>\n    <string name=\"add_sync\">Adăugați tracking</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Adaugat: %s</string>\n    <string name=\"upload_sync\">Sincronizare</string>\n    <string name=\"sync_score\">Recenzie</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s autentificat/ă</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Nu am putut să mă autentific la %s</string>\n    <!-- ============ -->\n    <string name=\"none\">Nu există</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">Tot</string>\n    <string name=\"max\">Maxim</string>\n    <string name=\"min\">Minim</string>\n    <string name=\"subtitles_outline\">Contur</string>\n    <string name=\"subtitles_depressed\">Deprimat</string>\n    <string name=\"subtitles_shadow\">Umbră</string>\n    <string name=\"subtitles_raised\">Relief</string>\n    <string name=\"subtitle_offset\">Sincronizare subtitrări</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Delay subtitrare</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Utilizează acesta dacă subtitrările sunt afișate %d ms prea devreme</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Utilizează acesta dacă subtitrările sunt afișate %d ms prea târziu</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Fără întârziere la subtitrare</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">Vulpea maro iute sare peste câinele leneș</string>\n    <string name=\"recommended\">Recomandări</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">A fost încărcat %s</string>\n    <string name=\"player_load_subtitles\">Încărcați din fișier</string>\n    <string name=\"player_load_subtitles_online\">Încărcare de pe Internet</string>\n    <string name=\"downloaded_file\">Fișier descărcat</string>\n    <string name=\"actor_main\">Protagonist</string>\n    <string name=\"actor_supporting\">Suport</string>\n    <string name=\"actor_background\">Secundar</string>\n    <string name=\"home_source\">Sursa</string>\n    <string name=\"home_random\">Aleatoriu</string>\n    <string name=\"coming_soon\">În curând…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Poster</string>\n    <string name=\"category_player\">Player</string>\n    <string name=\"resolution_and_title\">Titlu și rezoluție</string>\n    <string name=\"title\">Titlu</string>\n    <string name=\"resolution\">Rezoluție</string>\n    <string name=\"error_invalid_id\">ID-ul invalid</string>\n    <string name=\"error_invalid_data\">Date invalide</string>\n    <string name=\"error\">Eroare</string>\n    <!--<string name=\"subtitles_remove_captions\">Remove closed captions from subtitles</string>-->\n    <!--<string name=\"subtitles_remove_bloat\">Remove bloat from subtitles</string>-->\n    <!--<string name=\"extras\">Extra</string>-->\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"history\">Istoric</string>\n    <string name=\"action_mark_as_watched\">Marcați ca vizionat</string>\n    <string name=\"autoplay_next_settings\">Redă automat următorul episod</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_trailer_button\">Vizionează trailerul</string>\n    <string name=\"update_started\">Actualizarea a început</string>\n    <string name=\"episode_sync_settings\">Actualizați progresul ceasului</string>\n    <string name=\"autoplay_next_settings_des\">Începe următorul episod când se termină episodul curent</string>\n    <string name=\"pref_filter_search_quality\">Ascundeți calitatea video selectată în rezultatele căutării</string>\n    <string name=\"play_livestream_button\">Redare Livestream</string>\n    <string name=\"library\">Librărie</string>\n    <string name=\"test_log\">Log</string>\n    <string name=\"browser\">Browser</string>\n    <string name=\"play_with_app_name\">Joacă cu CloudStream</string>\n    <string name=\"automatic_plugin_updates\">Actualizare plugin automată</string>\n    <string name=\"automatic_plugin_download\">Descarcă plugin-uri automat</string>\n    <string name=\"others\">Altele</string>\n    <string name=\"test_passed\">Trecut</string>\n    <string name=\"start\">Start</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Jucătorul afișat - Cantitatea de căutare</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Jucător ascuns - Sumă de căutare</string>\n    <string name=\"livestreams\">Livestream-uri</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"test_failed\">Eșuat</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Suma de căutare utilizată atunci când jucătorul este vizibil</string>\n    <string name=\"live_singular\">Livestream</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Cantitatea de căutare folosită când jucătorul este ascuns</string>\n    <string name=\"watch_quality_pref_data\">Calitatea preferată (Date Mobile)</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"apk_installer_settings\">Instalator APK</string>\n    <string name=\"automatic_plugin_download_summary\">Instalează automat toate plugin-urile neinstalate din depozite adăugate.</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"apk_installer_settings_des\">Unele telefoane nu acceptă noul program de instalare a pachetului. Încercați opțiunea veche dacă nu se instalează actualizările.</string>\n    <string name=\"redo_setup_process\">Refaceți procesul de configurare</string>\n    <string name=\"skip_setup\">Treci peste partea de configurare</string>\n    <string name=\"batch_download\">Descărcare pe loturi</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"extension_rating\" formatted=\"true\">Evaluare: %s</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Treci peste %s</string>\n    <string name=\"app_not_found_error\">Aplicația nu a fost găsită</string>\n    <string name=\"skip_type_mixed_ed\">Încheiere mixat</string>\n    <string name=\"clear_history\">Ștergeți istoricul</string>\n    <string name=\"skip_type_intro\">Introducere</string>\n    <string name=\"yes\">Da</string>\n    <string name=\"preferred_media_subtext\">Ce vrei să vezi</string>\n    <string name=\"skip_type_recap\">Recapitulare</string>\n    <string name=\"sort_alphabetical_a\">Alfabetic (A la Z)</string>\n    <string name=\"skip_type_ed\">Încheiere</string>\n    <string name=\"subscription_deleted\">Dezabonat de la %s</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Nu s-a descărcat: %d</string>\n    <string name=\"view_public_repositories_button\">Vezi depozite din comunitate</string>\n    <string name=\"apk_installer_package_installer\">Instalator de pachete</string>\n    <string name=\"extension_status\">Stare</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Nu se poate încărca %s</string>\n    <string name=\"audio_tracks\">Piste audio</string>\n    <string name=\"referer\">Referer (opțional)</string>\n    <string name=\"skip_type_op\">Deschidere</string>\n    <string name=\"pref_category_extensions\">Extensii</string>\n    <string name=\"pref_category_player_layout\">Layout</string>\n    <string name=\"clipboard_too_large\">Prea mult text. Nu s-a putut salva în clipboard.</string>\n    <string name=\"pref_category_links\">Linkuri</string>\n    <string name=\"pref_category_ui_features\">Funcții</string>\n    <string name=\"extension_authors\">Autori</string>\n    <string name=\"add_repository\">Adaugă depozit</string>\n    <string name=\"empty_library_no_accounts_message\">Biblioteca ta este goală :(\n\\nConectați-vă într-un cont de bibliotecă sau adăugați emisiuni la biblioteca locală.</string>\n    <string name=\"subtitles_remove_captions\">Eliminați subtitrările închise din subtitrări</string>\n    <string name=\"setup_extensions_subtext\">Descărcați lista de site-uri pe care doriți să le utilizați</string>\n    <string name=\"sort_rating_desc\">Evaluare (Ridicat la Scăzut)</string>\n    <string name=\"extensions\">Extensii</string>\n    <string name=\"delete_repository\">Ștergeți depozitul</string>\n    <string name=\"extension_size\">Dimensiune</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_player_features\">Funcțiile player-ului</string>\n    <string name=\"plugin_loaded\">Plugin încărcat</string>\n    <string name=\"safe_mode_crash_info\">Vezi informații despre accident</string>\n    <string name=\"open_with\">Deschideți cu</string>\n    <string name=\"subtitles_remove_bloat\">Eliminați bloat din subtitrări</string>\n    <string name=\"plugins_updated\" formatted=\"true\">S-au actualizat %d plugin-uri</string>\n    <string name=\"sort_rating_asc\">Evaluare (Scăzut la Ridicat)</string>\n    <string name=\"setup_done\">Terminat</string>\n    <string name=\"extension_version\">Versiune</string>\n    <string name=\"pref_category_backup\">Backup</string>\n    <string name=\"extras\">Suplimente</string>\n    <string name=\"sort_updated_new\">Actualizat (Nou la Vechi)</string>\n    <string name=\"app_layout_subtext\">Schimbați aspectul aplicației pentru a se potrivi dispozitivului dvs</string>\n    <string name=\"repository_name_hint\">Nume de depozit</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Dezactivat)</string>\n    <string name=\"no\">Nu</string>\n    <string name=\"subscription_new\">Abonat la %s</string>\n    <string name=\"delayed_update_notice\">Aplicația va fi actualizată la ieșire</string>\n    <string name=\"pref_category_bypass\">Ocoliri ISP</string>\n    <string name=\"previous\">Anterior</string>\n    <string name=\"sort\">Sortează</string>\n    <string name=\"select_library\">Selectați Biblioteca</string>\n    <string name=\"subtitles_filter_lang\">Filtrați în funcție de limba media preferată</string>\n    <string name=\"subscription_episode_released\">Episodul %d a fost lansat!</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"provider_languages_tip\">Urmăriți videoclipuri în aceste limbi</string>\n    <string name=\"revert\">Revenire</string>\n    <string name=\"pref_category_actions\">Acțiuni</string>\n    <string name=\"sort_alphabetical_z\">Alfabetic (Z la A)</string>\n    <string name=\"error_invalid_url\">URL invalid</string>\n    <string name=\"safe_mode_description\">Toate extensiile au fost dezactivate din cauza unei defecțiuni pentru a vă ajuta să o găsiți pe cea care cauzează probleme.</string>\n    <string name=\"update_notification_downloading\">Se descarcă actualizarea aplicației…</string>\n    <string name=\"blank_repo_message\">CloudStream nu are niciun site instalat din start. Trebuie să instalați site-urile din depozite.\n\\n\n\\nAlăturați-vă Discord-ului nostru sau căutați online.</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">A început să descarce %1$d %2$s…</string>\n    <string name=\"safe_mode_title\">Mod sigur pornit</string>\n    <string name=\"safe_mode_file\">Fișier Mod Sigur găsit!\n\\nNu încarcă nicio extensie la pornire până când fișierul nu este eliminat.</string>\n    <string name=\"action_remove_from_watched\">Scoateți de la urmărit</string>\n    <string name=\"sort_updated_old\">Actualizat (Vechi la Nou)</string>\n    <string name=\"apply_on_restart\">Reporniți aplicația pentru a vedea schimbările.</string>\n    <string name=\"extension_description\">Descriere</string>\n    <string name=\"plugin_downloaded\">Plugin Descărcat</string>\n    <string name=\"confirm_exit_dialog\">Sunteți sigur că vreți să ieșiți?</string>\n    <string name=\"empty_library_logged_in_message\">Se pare că această listă este goală, încercați să treceți la o alta.</string>\n    <string name=\"sort_by\">Sortați după</string>\n    <string name=\"player_settings_play_in_app\">Player intern</string>\n    <string name=\"pref_category_defaults\">Prestabile</string>\n    <string name=\"repository_url_hint\">URL-ul depozitului</string>\n    <string name=\"stop\">Oprește</string>\n    <string name=\"pref_category_looks\">Aspecturi</string>\n    <string name=\"plugin_deleted\">Plugin Șters</string>\n    <string name=\"pref_category_gestures\">Gesturi</string>\n    <string name=\"update_notification_failed\">Nu s-a putut instala noua versiune a aplicației</string>\n    <string name=\"tracks\">Piste</string>\n    <string name=\"restart\">Repornește</string>\n    <string name=\"enable_nsfw_on_providers\">Activează conținutul pentru adulți pe extensiile suportate</string>\n    <string name=\"jsdelivr_enabled\">Nu s-a putut ajunge la GitHub. Se activează proxy-ul jsDelivr…</string>\n    <string name=\"jsdelivr_proxy\">Proxy GitHub</string>\n    <string name=\"jsdelivr_proxy_summary\">Ocolește blocarea URL-urilor brute de pe GitHub folosind jsDelivr. Poate cauza întârzieri în actualizări cu câteva zile.</string>\n    <string name=\"next\">Următorul</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Toate %s deja descărcate</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Descărcat: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Dezactivat: %d</string>\n    <string name=\"uppercase_all_subtitles\">Toate subtitrările cu majuscule</string>\n    <string name=\"download_all_plugins_from_repo\">Descărcați toate plugin-urile din acest depozit?</string>\n    <string name=\"subscription_in_progress_notification\">Se actualizează emisiunile abonate</string>\n    <string name=\"subscription_list_name\">Abonat</string>\n    <string name=\"view_public_repositories_button_short\">Lista publică</string>\n    <string name=\"apk_installer_legacy\">Moştenit</string>\n    <string name=\"category_provider_test\">Test de furnizor</string>\n    <string name=\"category_providers\">Furnizori</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"delete_repository_plugins\">Acest lucru va șterge, de asemenea, toate plugin-urile din depozit</string>\n    <string name=\"update_notification_installing\">Se instalează actualizarea aplicației…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">S-a descărcat %1$d %2$s</string>\n    <string name=\"extension_types\">Suportat</string>\n    <string name=\"hls_playlist\">Playlist HLS</string>\n    <string name=\"video_tracks\">Piste video</string>\n    <string name=\"enable_skip_op_from_database_des\">Afișează opțiunea de omitere a ferestrelor pop-up pentru început/sfârșit</string>\n    <string name=\"all_languages_preference\">Toate limbile</string>\n    <string name=\"skip_type_mixed_op\">Deschidere mixat</string>\n    <string name=\"skip_type_creddits\">Credite</string>\n    <string name=\"extension_language\">Limbă</string>\n    <string name=\"plugin_singular\">plugin</string>\n    <string name=\"plugin\">plugin-uri</string>\n    <string name=\"extension_install_first\">Instalați mai întâi extensia</string>\n    <string name=\"player_pref\">Player video preferat</string>\n    <string name=\"pref_category_app_updates\">Actualizări al aplicației</string>\n    <string name=\"pref_category_subtitles\">Subtitrări</string>\n    <string name=\"disable\">Dezactivați</string>\n    <string name=\"quality_profile_help\">Aici puteți schimba modul în care sunt ordonate sursele. Dacă un videoclip are o prioritate mai mare, acesta va apărea mai sus în selecția surselor. Suma dintre prioritatea sursei și prioritatea calității reprezintă prioritatea video.\n\\n\n\\nSursa A: 3\n\\nCalitate B: 7\n\\nVa avea o prioritate video combinată de 10.\n\\n\n\\nNOTĂ: Dacă suma este 10 sau mai mare, playerul va sări automat peste încărcare atunci când este încărcat link-ul respectiv!</string>\n    <string name=\"no_plugins_found_error\">Nu s-a găsit plugin-uri în depozit</string>\n    <string name=\"no_repository_found_error\">Nu s-a găsit depozitul, verificați URL-ul și încercați cu un VPN</string>\n    <string name=\"edit\">Editați</string>\n    <string name=\"profiles\">Profiluri</string>\n    <string name=\"help\">Ajutor</string>\n    <string name=\"profile_number\">Profilul %d</string>\n    <string name=\"wifi\">Wi-FI</string>\n    <string name=\"mobile_data\">Date mobile</string>\n    <string name=\"qualities\">Calități</string>\n    <string name=\"profile_background_des\">Profil de fundal</string>\n    <string name=\"set_default\">Setați ca implicit</string>\n    <string name=\"use\">Utilizați</string>\n    <string name=\"unable_to_inflate\">UI nu a putut fi creată corect, acesta este un BUG MAJOR și trebuie raportat imediat %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Selectați modul de filtrare a descărcării plugin-urilor</string>\n    <string name=\"already_voted\">Ați votat deja</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Elemente potențial duplicate au fost găsite în biblioteca ta:\n\\n\n\\n%s\n\\n\n\\nÎn ciuda acestui fapt, ai dori să adaugi acest alement, să le înlocuiești pe cele existente, sau să anulezi acțiunea?</string>\n    <string name=\"favorite_added\">%s a fost adăugat la favoriți/te</string>\n    <string name=\"favorite_removed\">%s a fost eliminat din favoriți/te</string>\n    <string name=\"action_add_to_favorites\">Adaugă la favoriți/te</string>\n    <string name=\"action_remove_from_favorites\">Elimină din favoriți/te</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Se pare că un element potențial duplicat deja există în biblioteca ta: \\'%s.\\'\n\\n\n\\nÎn ciuda aceasta, ai dori să adaugi acest element, să îl înlocuiești pe cel existent, sau să anulezi acțiunea?</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Introduce PIN-ul pentru %s</string>\n    <string name=\"enter_current_pin\">Introduce PIN-ul actual</string>\n    <string name=\"enter_pin\">Introduce PIN-ul</string>\n    <string name=\"lock_profile\">Blochează Profilul</string>\n    <string name=\"action_unsubscribe\">Dezabonează-te</string>\n    <string name=\"action_subscribe\">Abonează-te</string>\n    <string name=\"duplicate_add\">Adaugă</string>\n    <string name=\"duplicate_replace\">Înlocuiește</string>\n    <string name=\"duplicate_replace_all\">Înlocuiește tot</string>\n    <string name=\"duplicate_title\">Posibil Duplicat Găsit</string>\n    <string name=\"subscribe_tooltip\">Notificare episod nou</string>\n    <string name=\"recommendations_tooltip\">Arată sugestii</string>\n    <string name=\"speed_setting_summary\">Adaugă o opțiune de viteză la player</string>\n    <string name=\"favorites_list_name\">Favoriți/te</string>\n    <string name=\"backup_frequency\">Frecvența de backup</string>\n    <string name=\"repo_copy_label\">Numele și URL-ul depozitului</string>\n    <string name=\"toast_copied\">Copiat!</string>\n    <string name=\"clipboard_permission_error\">Eroare la accesarea Clipboard-ului. Te rog să încerci din nou.</string>\n    <string name=\"clipboard_unknown_error\">Eroare la copiere. Te rog să copiezi logcat-ul și să contactezi suportul aplicației.</string>\n    <string name=\"pin_error_incorrect\">PIN incorect. Te rog să încerci din nou.</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"select_an_account\">Selectați un cont</string>\n    <string name=\"manage_accounts\">Administrați conturile</string>\n    <string name=\"edit_account\">Editare cont</string>\n    <string name=\"logged_account\" formatted=\"true\">Conectat ca %s</string>\n    <string name=\"rotate_video\">Rotire</string>\n    <string name=\"unfavorite\">Nefavorite</string>\n    <string name=\"biometric_authentication_title\">Deblocați CloudStream</string>\n    <string name=\"skip_startup_account_select_pref\">Omiteți selecția contului la pornire</string>\n    <string name=\"links_reloaded_toast\">Linkuri reîncărcate</string>\n    <string name=\"use_default_account\">Utilizați contul implicit</string>\n    <string name=\"test_extensions_summary\">Această testare este destinată doar dezvoltatorilor și nu verifică sau respinge funcționarea oricărei extensii.</string>\n    <string name=\"battery_dialog_message\">Pentru a asigura descărcările neîntrerupte și notificările pentru serialele TV la care ești abonat, CloudStream are nevoie de permisiunea de a rula în fundal. Apăsând pe OK, vei fi direcționat către informațiile aplicației. Acolo, derulează la \\\"App battery usage\\\" și setează utilizarea bateriei la \\\"Unrestricted\\\". Te rog să reții, această permisiune nu înseamnă că CS3 îți va consuma bateria. Va opera în fundal doar când este necesar, cum ar fi atunci când primește notificări sau descarcă videoclipuri din extensiile oficiale. Dacă alegi să anulezi, poți ajusta această setare mai târziu în \\\"General Settings\\\".</string>\n    <string name=\"pin_error_length\">PIN-ul trebuie să fie format din 4 caractere</string>\n    <string name=\"rotate_video_desc\">Afișează un buton de comutare pentru orientarea ecranului</string>\n    <string name=\"password_pin_authentication_title\">Autentificare parolă/PIN</string>\n    <string name=\"biometric_unsupported\">Autentificarea biometrică nu este acceptată pe acest dispozitiv</string>\n    <string name=\"biometric_setting_summary\">Deblocați aplicația cu amprentă digitală, ID facial, PIN, model și parolă.</string>\n    <string name=\"biometric_prompt_description\">Acest ecran a fost închis din cauza mai multor încercări eșuate. Vă rugăm să reporniți aplicația.</string>\n    <string name=\"biometric_warning\">Datele dvs. CloudStream au fost salvate acum. Deși posibilitatea acestui lucru este foarte mică, toate dispozitivele se pot comporta diferit. În cazul rar, în care nu aveți acces la aplicație, ștergeți complet datele aplicației și restaurați dintr-o copie de rezervă. Ne pare foarte rău pentru orice neplăcere care decurge din aceasta.</string>\n    <string name=\"ok\">Ok</string>\n    <string name=\"battery_dialog_title\">Dezactivează optimizarea bateriei</string>\n    <string name=\"app_unrestricted_toast\">Utilizarea bateriei pentru aplicație este deja setată ca fiind nelimitată</string>\n    <string name=\"app_info_intent_error\">Imposibil de deschis informațiile aplicației CloudStream.</string>\n    <string name=\"favorite\">Favorite</string>\n    <string name=\"music_singlar\">Muzică</string>\n    <string name=\"audio_book_singular\">Carte audio</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"result_search_tooltip\">Caută în alte extensii</string>\n    <string name=\"test_extensions\">Testează toate extensiile</string>\n    <string name=\"auto_rotate_video\">Rotire automată</string>\n    <string name=\"reset_btn\">Resetați</string>\n    <string name=\"auto_rotate_video_desc\">Activați comutarea automată a orientării ecranului pe baza orientării video</string>\n    <string name=\"biometric_setting\">Blocare cu biometrie</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nrămase</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Următorul în %s</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Sezonul %1$d Episod %2$d va fi lansat în</string>\n    <string name=\"player_settings_select_cast_device\">Selectați divece-ul pe care doriți să faceți cast</string>\n    <string name=\"episode_action_cast_mirror\">Cast mirror</string>\n    <string name=\"play_from_beginning_img_des\">Redă de la început</string>\n    <string name=\"downloads_empty\">Nu există descărcări.</string>\n    <string name=\"downloads_delete_select\">Selectionati elementele de sters</string>\n    <string name=\"select_all\">Selectionati totul</string>\n    <string name=\"deselect_all\">Deselectionati totul</string>\n    <string name=\"torrent_info\">Acest video este un Torrent, ceea ce înseamnă că activitatea dumneavoastră video poate fi urmărită.\\n Asigurați-vă că înțelegeți Torrentul înainte să continuați.</string>\n    <string name=\"offline_file\">Disponibil pentru vizionare offline</string>\n    <string name=\"speech_recognition_unavailable\">Recogniție de voce nu este disponibilă</string>\n    <string name=\"begin_speaking\">Începeți să vorbiți…</string>\n    <string name=\"open_local_video\">Deschideți video local</string>\n    <string name=\"test_warning\">Avertisment</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Sunteți siguri că doriți să ștergeți definitiv următoarele fișiere?\\n\\n%s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Veți mai și șterge definitiv toate episoadele în seria următoare:\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Sunteți siguri ca doriți sa ștergeți definitiv toate episoadele în seria următoare?\\n\\n%s</string>\n    <string name=\"audio_singluar\">Audio</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"encoding_error\">Eroare de codificare</string>\n    <string name=\"unsupported_error\">Eroare Nesuportată</string>\n    <string name=\"show_rating\">Etichetă de clasificare</string>\n    <string name=\"delete_files\">Ștergeți fișiere</string>\n    <string name=\"delete_format\" formatted=\"true\">Șterge (%1$d | %2$s)</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Sunteți sigur că vreți să ștergeți permanent următoarele epsioade în %1$s?\\n\\n%2$s</string>\n    <string name=\"pref_category_security\">Securitate</string>\n    <string name=\"pref_category_accounts\">Conturi</string>\n    <string name=\"auth_locally\">Autentificare locală</string>\n    <string name=\"player_load_one_subtitle_online\">Încărcați prima disponibilă</string>\n    <string name=\"delete_plugin\">Șterge pluginul</string>\n    <string name=\"dismiss\">Închide</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$do %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"play_full_series_button\">Redă întregul serial</string>\n    <string name=\"install_prerelease\">Instalează versiunea preliminară</string>\n    <string name=\"prerelease_already_installed\">Versiunea preliminară este deja instalată.</string>\n    <string name=\"prerelease_install_failed\">Instalarea versiunii preliminare a eșuat.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"history\">История</string>\n    <string name=\"no\">Нет</string>\n    <string name=\"yes\">Да</string>\n    <string name=\"tracks\">Треки</string>\n    <string name=\"queued\">В очереди</string>\n    <string name=\"resize_zoom\">Приблизить</string>\n    <string name=\"download\">Скачать</string>\n    <string name=\"search\">Поиск</string>\n    <string name=\"resize_fill\">Заполнить</string>\n    <string name=\"download_failed\">Скачивание не удалось</string>\n    <string name=\"resize_fit\">Подогнать</string>\n    <string name=\"delete\">Удалить</string>\n    <string name=\"cancel\">Отмена</string>\n    <string name=\"all\">Все</string>\n    <string name=\"pause\">Пауза</string>\n    <string name=\"cast_format\" formatted=\"true\">В ролях: %s</string>\n    <string name=\"show_title\">Название источника</string>\n    <string name=\"login\">Войти</string>\n    <string name=\"none\">Нет</string>\n    <string name=\"title\">Название</string>\n    <string name=\"loading\">Загрузка…</string>\n    <string name=\"status\">Состояние</string>\n    <string name=\"logout\">Выйти</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Серия %d будет выпущена на</string>\n    <string name=\"result_poster_img_des\">Плакат</string>\n    <string name=\"search_poster_img_des\">Плакат</string>\n    <string name=\"episode_poster_img_des\">Плакат серии</string>\n    <string name=\"home_main_poster_img_des\">Главный плакат</string>\n    <string name=\"home_next_random_img_des\">Следующий случайный</string>\n    <string name=\"go_back_img_des\">Вернуться</string>\n    <string name=\"home_change_provider_img_des\">Изменить поставщика</string>\n    <string name=\"preview_background_img_des\">Предпросмотр фона</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Скорость (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Оценили: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Новое обновление найдено!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Заполнитель</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"action_remove_from_bookmarks\">Убрать</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"play_with_app_name\">Смотреть с CloudStream</string>\n    <string name=\"title_home\">Главная</string>\n    <string name=\"title_search\">Поиск</string>\n    <string name=\"title_downloads\">Скачанное</string>\n    <string name=\"title_settings\">Настройки</string>\n    <string name=\"search_hint\">Поиск…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Поиск %s…</string>\n    <string name=\"no_data\">Нет данных</string>\n    <string name=\"episode_more_options_des\">Дополнительные опции</string>\n    <string name=\"next_episode\">Следующая серия</string>\n    <string name=\"result_tags\">Жанры</string>\n    <string name=\"result_share\">Поделиться</string>\n    <string name=\"result_open_in_browser\">Открыть в Браузере</string>\n    <string name=\"skip_loading\">Пропустить загрузку</string>\n    <string name=\"type_watching\">Просмотр</string>\n    <string name=\"type_on_hold\">Приостановлено</string>\n    <string name=\"type_completed\">Завершено</string>\n    <string name=\"type_dropped\">Брошено</string>\n    <string name=\"type_plan_to_watch\">Буду смотреть</string>\n    <string name=\"type_re_watching\">Пересмотрю</string>\n    <string name=\"play_movie_button\">Смотреть фильм</string>\n    <string name=\"play_trailer_button\">Смотреть трейлер</string>\n    <string name=\"play_livestream_button\">Смотреть стрим</string>\n    <string name=\"pick_source\">Источники</string>\n    <string name=\"pick_subtitle\">Субтитры</string>\n    <string name=\"play_episode\">Смотреть серию</string>\n    <string name=\"reload_error\">Повторная попытка подключения…</string>\n    <string name=\"go_back\">Вернуться</string>\n    <string name=\"downloaded\">Скачано</string>\n    <string name=\"downloading\">Скачивание</string>\n    <string name=\"download_paused\">Скачивание остановлено</string>\n    <string name=\"download_started\">Скачивание началось</string>\n    <string name=\"download_canceled\">Скачивание отменено</string>\n    <string name=\"download_done\">Скачивание закончено</string>\n    <string name=\"home_info\">Инфо</string>\n    <string name=\"update_started\">Обновление началось</string>\n    <string name=\"home_expanded_hide\">Прятать</string>\n    <string name=\"home_play\">Смотреть</string>\n    <string name=\"home_more_info\">Подробнее</string>\n    <string name=\"filter_bookmarks\">Фильтр закладки</string>\n    <string name=\"error_bookmarks_text\">Закладки</string>\n    <string name=\"sort_apply\">Применить</string>\n    <string name=\"sort_copy\">Копия</string>\n    <string name=\"sort_close\">Закрыть</string>\n    <string name=\"sort_clear\">Очистить</string>\n    <string name=\"sort_save\">Сохранить</string>\n    <string name=\"player_speed\">Скорость проигрывателя</string>\n    <string name=\"play_episode_toast\">Смотреть серию</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dд %2$dч %3$dм</string>\n    <string name=\"duration_format\" formatted=\"true\">%d мин</string>\n    <string name=\"app_dubbed_text\">Дуб</string>\n    <string name=\"app_subbed_text\">Суб</string>\n    <string name=\"action_add_to_bookmarks\">Установите смотреть состояние</string>\n    <string name=\"subs_outline_color\">Цвет контура</string>\n    <string name=\"subs_text_color\">Цвет текста</string>\n    <string name=\"subtitles_settings\">Настройки субтитров</string>\n    <string name=\"subs_background_color\">Цвет фона</string>\n    <string name=\"subs_window_color\">Цвет окна</string>\n    <string name=\"subs_edge_type\">Тип края</string>\n    <string name=\"subs_subtitle_elevation\">Подъем субтитров</string>\n    <string name=\"search_provider_text_providers\">Поиск с использованием поставщиков</string>\n    <string name=\"search_provider_text_types\">Поиск с использованием типов</string>\n    <string name=\"benene_count_text\">%d бенен(а/ов) выдано разработчикам</string>\n    <string name=\"benene_count_text_none\">Бенены не выданы</string>\n    <string name=\"subs_auto_select_language\">Автоматический выбор языка</string>\n    <string name=\"subs_download_languages\">Скачать языки</string>\n    <string name=\"subs_subtitle_languages\">Язык субтитров</string>\n    <string name=\"subs_hold_to_reset_to_default\">Удерживайте, чтобы сбросить по умолчанию</string>\n    <string name=\"error_loading_links_toast\">Ошибка загрузки ссылок</string>\n    <string name=\"stream\">Сетевой Поток</string>\n    <string name=\"subs_font\">Шрифт</string>\n    <string name=\"subs_font_size\">Размер шрифта</string>\n    <string name=\"popup_delete_file\">Удалить файл</string>\n    <string name=\"popup_play_file\">Воспроизвести файл</string>\n    <string name=\"download_storage_text\">Внутренняя память</string>\n    <string name=\"popup_resume_download\">Продолжить Скачать</string>\n    <string name=\"popup_pause_download\">Остановить скачивание</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Импортируйте шрифты поместив их в %s</string>\n    <string name=\"continue_watching\">Продолжить смотреть</string>\n    <string name=\"action_remove_watching\">Убрать</string>\n    <string name=\"action_open_watching\">Подробнее</string>\n    <string name=\"vpn_might_be_needed\">Для правильной работы этого поставщика может потребоваться VPN</string>\n    <string name=\"vpn_torrent\">Этот поставщик — торрент, рекомендуется использовать VPN</string>\n    <string name=\"provider_info_meta\">Метаданные не предоставляются сайтом, скачивание видео будет неудачным, если они не существуют на сайте.</string>\n    <string name=\"torrent_plot\">Описание</string>\n    <string name=\"normal_no_plot\">Сюжет не найден</string>\n    <string name=\"torrent_no_plot\">Описание не найдено</string>\n    <string name=\"show_log_cat\">Показать журнал ошибок 🐈</string>\n    <string name=\"picture_in_picture\">Картинка в картинке</string>\n    <string name=\"picture_in_picture_des\">Продолжение воспроизведения в миниатюрном проигрывателе поверх других приложений</string>\n    <string name=\"player_size_settings\">Кнопка изменения размера проигрывателя</string>\n    <string name=\"player_size_settings_des\">Убрать черные границы</string>\n    <string name=\"player_subtitles_settings\">Субтитры</string>\n    <string name=\"player_subtitles_settings_des\">Настройки субтитров проигрывателя</string>\n    <string name=\"chromecast_subtitles_settings\">Субтитры Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Настройки субтитров Chromecast</string>\n    <string name=\"eigengraumode_settings\">Скорость воспроизведения</string>\n    <string name=\"swipe_to_seek_settings\">Проведите пальцем для поиска</string>\n    <string name=\"swipe_to_change_settings\">Проведите пальцем для изменения настроек</string>\n    <string name=\"swipe_to_change_settings_des\">Проведите вверх или вниз по левой или правой стороне, чтобы изменить яркость или громкость</string>\n    <string name=\"autoplay_next_settings\">Автоматически начинать следующую серию</string>\n    <string name=\"play_torrent_button\">Поток торрент</string>\n    <string name=\"swipe_to_seek_settings_des\">Водите пальцем из стороны в сторону чтобы выбрать место в видеоролике</string>\n    <string name=\"autoplay_next_settings_des\">Начните следующий серию, когда закончится текущий</string>\n    <string name=\"restore_success\">Восстановлено из резервной копии</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Не удалось восстановить данные из %s</string>\n    <string name=\"backup_failed\">Отсутствует разрешение на хранение. Пожалуйста, попробуйте снова.</string>\n    <string name=\"category_account\">Учётные записи и Безопасность</string>\n    <string name=\"category_updates\">Обновления и Резервное копирование</string>\n    <string name=\"settings_info\">Информация</string>\n    <string name=\"advanced_search\">Расширенный поиск</string>\n    <string name=\"show_trailers_settings\">Показывать трейлеры</string>\n    <string name=\"pref_filter_search_quality\">Скрыть выбранные форматы видео в результатах поиска</string>\n    <string name=\"automatic_plugin_updates\">Автоматическое обновление дополнений</string>\n    <string name=\"automatic_plugin_download\">Автозагрузка дополнений</string>\n    <string name=\"updates_settings\">Показать обновления приложения</string>\n    <string name=\"updates_settings_des\">Автоматически проверять обновления при старте приложения.</string>\n    <string name=\"apk_installer_settings\">APK установщик</string>\n    <string name=\"github\">Github</string>\n    <string name=\"app_language\">Язык приложения</string>\n    <string name=\"no_links_found_toast\">Ссылок не найдено</string>\n    <string name=\"copy_link_toast\">Ссылка скопирована в буфер обмена</string>\n    <string name=\"subs_default_reset_toast\">Восстановить по умолчанию</string>\n    <string name=\"episode\">Серия</string>\n    <string name=\"episodes\">Серии</string>\n    <string name=\"season_short\">С</string>\n    <string name=\"episode_short\">Э</string>\n    <string name=\"no_episodes_found\">Серии не найдены</string>\n    <string name=\"delete_file\">Удалить файл</string>\n    <string name=\"resume\">Продолжить</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Это будет удалено безвозвратно%s\n\\nВы уверены?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%d мин.\n\\nосталось</string>\n    <string name=\"status_completed\">Завершено</string>\n    <string name=\"year\">Год</string>\n    <string name=\"rating\">Рейтинг</string>\n    <string name=\"duration\">Продолжительность</string>\n    <string name=\"no_subtitles\">Нет субтитров</string>\n    <string name=\"action_default\">По умолчанию</string>\n    <string name=\"app_storage\">Приложение</string>\n    <string name=\"anime\">Аниме</string>\n    <string name=\"torrent\">Торренты</string>\n    <string name=\"others\">Другое</string>\n    <string name=\"storage_error\">Ошибка загрузки, проверьте разрешения хранилища</string>\n    <string name=\"episode_action_auto_download\">Автоматическое скачивание</string>\n    <string name=\"episode_action_download_mirror\">Скачивание. Зеркало</string>\n    <string name=\"season\">Сезон</string>\n    <string name=\"anim\">Аниме приложение от тех же разработчиков</string>\n    <string name=\"automatic_plugin_download_summary\">Автоматически скачивать ещё не установленные дополнения из добавленных источников.</string>\n    <string name=\"discord\">Присоединиться к Discord-серверу</string>\n    <string name=\"free_storage\">Свободно</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dч %2$dм</string>\n    <string name=\"movies\">Фильмы</string>\n    <string name=\"cartoons_singular\">Мультфильм</string>\n    <string name=\"tv_series\">Сериалы</string>\n    <string name=\"asian_drama\">Азиатские драмы</string>\n    <string name=\"other_singular\">Видео</string>\n    <string name=\"cartoons\">Мультфильмы</string>\n    <string name=\"documentaries\">Документальные фильмы</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"nsfw\">Вызывающие</string>\n    <string name=\"nsfw_singular\">Вызывающее</string>\n    <string name=\"movies_singular\">Фильм</string>\n    <string name=\"tv_series_singular\">Сериал</string>\n    <string name=\"torrent_singular\">Торрент</string>\n    <string name=\"documentaries_singular\">Документальный</string>\n    <string name=\"asian_drama_singular\">Азиатская драма</string>\n    <string name=\"category_general\">Общие</string>\n    <string name=\"category_providers\">Поставщики</string>\n    <string name=\"category_ui\">Расстановка</string>\n    <string name=\"pref_category_extensions\">Дополнения</string>\n    <string name=\"category_player\">Плеер</string>\n    <string name=\"backup_settings\">Резервное копирование данных</string>\n    <string name=\"used_storage\">Использовано</string>\n    <string name=\"double_tap_to_pause_settings\">Двойное нажатие для паузы</string>\n    <string name=\"double_tap_to_seek_settings_des\">Коснитесь дважды правой или левой стороны для поиска вперед или назад</string>\n    <string name=\"double_tap_to_pause_settings_des\">Нажмите дважды в центре, чтобы сделать паузу</string>\n    <string name=\"use_system_brightness_settings\">Использовать системную яркость</string>\n    <string name=\"episode_sync_settings_des\">Автоматически синхронизировать текущий прогресс серии</string>\n    <string name=\"backup_failed_error_format\">Ошибка резервного копирования %s</string>\n    <string name=\"restore_settings\">Восстановить данные из резервной копии</string>\n    <string name=\"show_fillers_settings\">Показывать Филлер серии для аниме</string>\n    <string name=\"kitsu_settings\">Показывать афиши из Kitsu</string>\n    <string name=\"apk_installer_settings_des\">Некоторые устройства не поддерживают новые установщики. Попробуйте использовать legacy (старый) вариант, если обновления не устанавливаются.</string>\n    <string name=\"status_ongoing\">Выходит</string>\n    <string name=\"video_lock\">Блокировка</string>\n    <string name=\"no_update_found\">Обновление не найдено</string>\n    <string name=\"video_aspect_ratio_resize\">Изменить размер</string>\n    <string name=\"video_source\">Источник</string>\n    <string name=\"check_for_update\">Проверить обновления</string>\n    <string name=\"add_site_pref\">Клон сайта</string>\n    <string name=\"dns_pref\">DNS через HTTPS</string>\n    <string name=\"remove_site_pref\">Удалить сайт</string>\n    <string name=\"legal_notice\">Оговорка</string>\n    <string name=\"subtitle_offset\">Синхронизация субтитров</string>\n    <string name=\"add_site_summary\">Добавить клон существующего сайта с другим URL-адресом</string>\n    <string name=\"dns_pref_summary\">Используется для обхода блокировок интернет-провайдера</string>\n    <string name=\"download_path_pref\">Путь скачивания</string>\n    <string name=\"benene_des\">Давал бенен</string>\n    <string name=\"update\">Обновить</string>\n    <string name=\"primary_color_settings\">Основной цвет</string>\n    <string name=\"provider_lang_settings\">Языки дополнений</string>\n    <string name=\"repository_name_hint\">Название репозитория (необязательно)</string>\n    <string name=\"clear_history\">Очистить историю</string>\n    <string name=\"referer\">Реферер (необязательно)</string>\n    <string name=\"benene\">Дайте бенен разработчикам</string>\n    <string name=\"pref_category_links\">Ссылки</string>\n    <string name=\"pref_category_player_layout\">Расстановка</string>\n    <string name=\"app_layout\">Расстановка приложения</string>\n    <string name=\"app_theme_settings\">Тема приложения</string>\n    <string name=\"add_repository\">Добавить репозиторий</string>\n    <string name=\"action_remove_from_watched\">Убрать отметку</string>\n    <string name=\"confirm_exit_dialog\">Вы уверены, что хотите выйти?</string>\n    <string name=\"plugin_downloaded\">Дополнение скачано</string>\n    <string name=\"plugin_deleted\">Дополнение удалено</string>\n    <string name=\"extension_description\">Описание</string>\n    <string name=\"extension_version\">Версия</string>\n    <string name=\"extension_status\">Статус</string>\n    <string name=\"extension_size\">Размер</string>\n    <string name=\"extension_authors\">Авторы</string>\n    <string name=\"extension_types\">Поддерживается</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Пропустить %s</string>\n    <string name=\"skip_type_ed\">Концовка</string>\n    <string name=\"use_system_brightness_settings_des\">Используйте яркость системы в проигрывателе приложения вместо тёмной накладки</string>\n    <string name=\"episode_sync_settings\">Обновлять прогресс просмотра</string>\n    <string name=\"backup_success\">Данные сохранены</string>\n    <string name=\"advanced_search_des\">Показывает результаты поиска, разделенные по поставщикам</string>\n    <string name=\"redo_setup_process\">Повторить процесс настройки</string>\n    <string name=\"no_chromecast_support_toast\">Этот поставщик не поддерживает Chromecast</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Нет сезона</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"livestreams\">Прямые трансляции</string>\n    <string name=\"live_singular\">Прямая трансляция</string>\n    <string name=\"source_error\">Ошибка источника</string>\n    <string name=\"remote_error\">Ошибка пульта</string>\n    <string name=\"render_error\">Ошибка отрисовки</string>\n    <string name=\"unexpected_error\">Неожиданная ошибка плеера</string>\n    <string name=\"episode_action_chromecast_episode\">Смотреть серию на Chromecast</string>\n    <string name=\"episode_action_play_in_format\">Воспроизведение на %s</string>\n    <string name=\"episode_action_download_subtitle\">Скачать субтитры</string>\n    <string name=\"show_hd\">Знак качества</string>\n    <string name=\"poster_ui_settings\">Переключение элементов интерфейса на плакате</string>\n    <string name=\"video_skip_op\">Пропустить OP</string>\n    <string name=\"dont_show_again\">Больше не показывать</string>\n    <string name=\"skip_update\">Пропустить это обновление</string>\n    <string name=\"nginx_url_pref\">URL сервера NGINX</string>\n    <string name=\"create_account\">Создать учётную запись</string>\n    <string name=\"add_sync\">Добавить слежение</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Добавлено %s</string>\n    <string name=\"upload_sync\">Синхронизировать</string>\n    <string name=\"sync_score\">Оценено</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d из 10</string>\n    <string name=\"safe_mode_crash_info\">Посмотреть информацию о сбое</string>\n    <string name=\"player_pref\">Предпочитаемый видеоплеер</string>\n    <string name=\"app_not_found_error\">Приложение не найдено</string>\n    <string name=\"all_languages_preference\">Все языки</string>\n    <string name=\"skip_type_op\">Вступление</string>\n    <string name=\"skip_type_creddits\">Титры</string>\n    <string name=\"action_mark_as_watched\">Отметить как просмотренное</string>\n    <string name=\"limit_title_rez\">Показывать информацию про видеоплеер</string>\n    <string name=\"watch_quality_pref\">Предпочтительное качество видео (WiFi)</string>\n    <string name=\"limit_title\">Максимум символов</string>\n    <string name=\"video_buffer_length_settings\">Длинна буфера</string>\n    <string name=\"video_buffer_disk_settings\">Кеш видео на диске</string>\n    <string name=\"video_buffer_size_settings\">Размер буфера</string>\n    <string name=\"video_buffer_clear_settings\">Отчистить кеш видео и изображений</string>\n    <string name=\"video_ram_description\">Вызывает сбои, если установлено слишком высокое значение на устройствах с небольшим объемом памяти, таких как Android TV.</string>\n    <string name=\"video_disk_description\">Вызывает проблемы, если установлено слишком высокое значение на устройствах с небольшим объёмом памяти, таких как Android TV.</string>\n    <string name=\"lightnovel\">Лёгкое приложение для новелл от тех же разработчиков</string>\n    <string name=\"extension_language\">Язык</string>\n    <string name=\"hls_playlist\">Плейлист HLS</string>\n    <string name=\"extension_install_first\">Сначала установить дополнение</string>\n    <string name=\"player_settings_play_in_app\">Внутренний проигрыватель</string>\n    <string name=\"synopsis\">Синопсис</string>\n    <string name=\"skip_type_intro\">Введение</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"episode_action_chromecast_mirror\">Зеркало Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Воспроизвести в приложении</string>\n    <string name=\"pref_category_defaults\">По умолчанию</string>\n    <string name=\"pref_category_player_features\">Возможности плеера</string>\n    <string name=\"pref_category_subtitles\">Субтитры</string>\n    <string name=\"bottom_title_settings\">Расположение названия плаката</string>\n    <string name=\"tv_layout\">Телевизионное оформление</string>\n    <string name=\"phone_layout\">Телефон</string>\n    <string name=\"emulator_layout\">Эмулятор</string>\n    <string name=\"bottom_title_settings_des\">Под плакатом</string>\n    <string name=\"example_password\">ваш пароль123</string>\n    <string name=\"example_username\">Имярек</string>\n    <string name=\"switch_account\">Сменить учётную запись</string>\n    <string name=\"add_account\">Добавить учётную запись</string>\n    <string name=\"example_site_name\">ИмяСайта</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">Код языка (ru)</string>\n    <string name=\"account\">учётная запись</string>\n    <string name=\"automatic\">Автоматически</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"pref_category_app_updates\">Обновления приложения</string>\n    <string name=\"pref_category_backup\">Резервная копия</string>\n    <string name=\"pref_category_actions\">Действия</string>\n    <string name=\"pref_category_cache\">Кэш</string>\n    <string name=\"pref_category_gestures\">Жесты</string>\n    <string name=\"setup_done\">Готово</string>\n    <string name=\"extensions\">Дополнения</string>\n    <string name=\"repository_url_hint\">URL или код репозитория</string>\n    <string name=\"plugin_loaded\">Дополнение загружено</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"double_tap_to_seek_settings\">Перемотка двойным нажатием</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Не удалось загрузить %s</string>\n    <string name=\"plugin\">дополнения</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"delete_repository\">Удалить репозиторий</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"plugin_singular\">дополнение</string>\n    <string name=\"skip_setup\">Пропустить настройку</string>\n    <string name=\"error\">Ошибка</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Отключено: %d</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s аутентифицировано</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Не удаётся войти на %s</string>\n    <string name=\"max\">Макс</string>\n    <string name=\"min\">Мин</string>\n    <string name=\"subtitles_outline\">Контурный</string>\n    <string name=\"subtitles_shadow\">С тенью</string>\n    <string name=\"subtitle_offset_hint\">1000 мс</string>\n    <string name=\"subtitle_offset_title\">Задержка субтитров</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Без задержки субтитров</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Используйте, если субтитры отображаются на %d мс слишком рано</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Используйте, если субтитры отображаются %d мс слишком поздно</string>\n    <string name=\"normal\">Нормально</string>\n    <string name=\"subtitles_raised\">Поднятые</string>\n    <string name=\"subtitles_example_text\">Съешь ещё этих мягких французских булок, да выпей же чаю</string>\n    <string name=\"recommended\">Рекомендуется</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Загружено %s</string>\n    <string name=\"anime_singular\">Аниме</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"show_dub\">Этикетка Dub</string>\n    <string name=\"site\">Сайт</string>\n    <string name=\"pref_category_ui_features\">Функции</string>\n    <string name=\"actor_main\">Главное</string>\n    <string name=\"home_source\">Источник</string>\n    <string name=\"home_random\">Случайный</string>\n    <string name=\"coming_soon\">Скоро…</string>\n    <string name=\"show_sub\">Этикетка Sub</string>\n    <string name=\"actor_background\">Фон</string>\n    <string name=\"pref_category_looks\">Отображение</string>\n    <string name=\"trailer\">Трейлер</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (отключено)</string>\n    <string name=\"next\">Далее</string>\n    <string name=\"blank_repo_message\">В CloudStream по умолчанию не установлены сайты. Вам необходимо установить сайты из репозиториев.\n\\n\n\\nПрисоединяйтесь к нашему Discord-серверу или найдите в интернете.</string>\n    <string name=\"error_invalid_data\">Недопустимые данные</string>\n    <string name=\"resolution_and_title\">Разрешение и название</string>\n    <string name=\"previous\">Предыдущий</string>\n    <string name=\"resolution\">Разрешение</string>\n    <string name=\"browser\">Браузер</string>\n    <string name=\"library\">Библиотека</string>\n    <string name=\"sort_updated_old\">Обновленный (старый - новый)</string>\n    <string name=\"sort_alphabetical_a\">Алфавитный (А до Я)</string>\n    <string name=\"sort_alphabetical_z\">Алфавитный (Я до А)</string>\n    <string name=\"select_library\">Выбрать библиотеку</string>\n    <string name=\"open_with\">Открыть с</string>\n    <string name=\"empty_library_no_accounts_message\">Ваша библиотека пуста :( \\nВойдите в учётную запись библиотеки или добавьте сериалы в локальную библиотеку.</string>\n    <string name=\"sort\">Сортировка</string>\n    <string name=\"view_public_repositories_button_short\">Открытый список</string>\n    <string name=\"sort_rating_desc\">Рейтинг (высокий - низкий)</string>\n    <string name=\"sort_rating_asc\">Рейтинг (низкий - высокий)</string>\n    <string name=\"sort_updated_new\">Обновленный (новый - старый)</string>\n    <string name=\"sort_by\">Сортировать по</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"subtitles_encoding\">Кодировка субтитров</string>\n    <string name=\"player_load_subtitles\">Загрузить из файла</string>\n    <string name=\"extension_rating\" formatted=\"true\">Рейтинг: %s</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Скачано %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Все %s уже скачаны</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Скачивание началась %1$d %2$s…</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Не скачано: %d</string>\n    <string name=\"download_all_plugins_from_repo\">Внимание: CloudStream не несёт ответственность за сторонние файлы и не поддерживает их!</string>\n    <string name=\"safe_mode_title\">Включен безопасный режим</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Скачано: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Обновлено %d дополнений</string>\n    <string name=\"player_load_subtitles_online\">Скачивать из интернета</string>\n    <string name=\"update_notification_downloading\">Скачивание обновления приложения…</string>\n    <string name=\"error_invalid_url\">Недопустимый URL</string>\n    <string name=\"apply_on_restart\">Перезапустите приложение, чтобы увидеть изменения.</string>\n    <string name=\"preferred_media_subtext\">Что вы хотите увидеть</string>\n    <string name=\"provider_languages_tip\">Смотрите видео на этих языках</string>\n    <string name=\"downloaded_file\">Скачано файл</string>\n    <string name=\"poster_image\">Изображение постера</string>\n    <string name=\"batch_download\">Пакетная скачивание</string>\n    <string name=\"setup_extensions_subtext\">Скачайте список сайтов, который вы хотите использовать</string>\n    <string name=\"display_subbed_dubbed_settings\">Отображать аниме с дубляжом/субтитрами</string>\n    <string name=\"enable_nsfw_on_providers\">Включить вызывающее содержимое у поддерживаемых дополнений (поставщиков)</string>\n    <string name=\"subtitles_remove_captions\">Удалять скрытые субтитры из субтитров</string>\n    <string name=\"extras\">Дополнительно</string>\n    <string name=\"app_layout_subtext\">Изменить вид интерфейса, чтобы соответствовать устройству</string>\n    <string name=\"audio_tracks\">Аудио дорожки</string>\n    <string name=\"delete_repository_plugins\">Это также удалит все дополнения из источника</string>\n    <string name=\"view_public_repositories_button\">Просмотреть репозитории сообщества</string>\n    <string name=\"video_tracks\">Видео дорожки</string>\n    <string name=\"safe_mode_description\">Все дополнения были отключены из-за сбоя, чтобы помочь вам найти то, которое вызывает проблемы.</string>\n    <string name=\"skip_type_recap\">Повтор</string>\n    <string name=\"clipboard_too_large\">Слишком много текста. Не удалось сохранить в буфер обмена.</string>\n    <string name=\"update_notification_installing\">Установка обновления приложения…</string>\n    <string name=\"update_notification_failed\">Не удалось установить новую версию приложения</string>\n    <string name=\"safe_mode_file\">Файл безопасного режима найден! \\nНе загружаются никакие дополнения при запуске, пока файл не будет удалён.</string>\n    <string name=\"delayed_update_notice\">Приложение будет обновлено после выхода</string>\n    <string name=\"empty_library_logged_in_message\">Этот список пуст, попробуйте переключиться на другой.</string>\n    <string name=\"uppercase_all_subtitles\">Все субтитры заглавными</string>\n    <string name=\"enable_skip_op_from_database_des\">Показывать всплывающие окна для пропуска вступления/заключения</string>\n    <string name=\"subtitles_filter_lang\">Фильтровать по предпочитаемому языку медиа</string>\n    <string name=\"error_invalid_id\">Неверный ID</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"random_button_settings_desc\">Отображать случайную кнопку в библиотеке и главной странице</string>\n    <string name=\"random_button_settings\">Случайная кнопка</string>\n    <string name=\"apk_installer_legacy\">Устаревший</string>\n    <string name=\"episode_action_reload_links\">Перезагрузить ссылки</string>\n    <string name=\"preferred_media_settings\">Предпочтительные медиа</string>\n    <string name=\"subtitles_depressed\">Опущенные</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Объем перемотки плеера (секундах)</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Объем перемотка, используемый, когда плеер виден</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Плеер показан - Перемотки объем</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Плеер спрятан - Перемотки объем</string>\n    <string name=\"subtitles_remove_bloat\">Удалять лишнее из субтитров</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Местоположение ползунка, когда игрок скрыт</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"actor_supporting\">Второго планa</string>\n    <string name=\"skip_type_mixed_op\">Смешанный опенинг</string>\n    <string name=\"skip_type_mixed_ed\">Смешанный конец</string>\n    <string name=\"category_provider_test\">Тест поставщиков</string>\n    <string name=\"test_log\">Журнал</string>\n    <string name=\"start\">Запустить</string>\n    <string name=\"test_passed\">Выполнено</string>\n    <string name=\"test_failed\">Неудачный</string>\n    <string name=\"stop\">Прекратить</string>\n    <string name=\"restart\">Перезапустить</string>\n    <string name=\"revert\">Вернуться</string>\n    <string name=\"subscription_new\">Подписался на %s</string>\n    <string name=\"watch_quality_pref_data\">Предпочтительное качество видео (Мобильный интернет)</string>\n    <string name=\"jsdelivr_proxy\">GitHub прокси</string>\n    <string name=\"jsdelivr_enabled\">Не удалось подключиться к GitHub. Включаем проксирование через jsDelivr…</string>\n    <string name=\"subscription_episode_released\">Эпизод %d выпущен!</string>\n    <string name=\"pref_category_bypass\">Обходы провайдера</string>\n    <string name=\"subscription_in_progress_notification\">Обновление подписки на фильмы и сериалы</string>\n    <string name=\"jsdelivr_proxy_summary\">Обход ограничения доступа к raw github URLs с помощью jsDelivr. Обновления могут задержаться на несколько дней.</string>\n    <string name=\"subscription_list_name\">Подписные</string>\n    <string name=\"subscription_deleted\">Отказались от подписки на %s</string>\n    <string name=\"mobile_data\">Мобильный интернет</string>\n    <string name=\"profiles\">Профили</string>\n    <string name=\"unable_to_inflate\">Пользовательский интерфейс не был доступен для правильного создания, это ГЛАВНАЯ ОШИБКА и должна быть сообщена немедленно %s</string>\n    <string name=\"edit\">Изменить</string>\n    <string name=\"wifi\">Интернет</string>\n    <string name=\"profile_background_des\">Задний фон профиля</string>\n    <string name=\"help\">Помощь</string>\n    <string name=\"profile_number\">Профиль %d</string>\n    <string name=\"automatic_plugin_download_mode_title\">Выберите режим фильтрации для скачивания дополнений</string>\n    <string name=\"qualities\">Качество</string>\n    <string name=\"use\">Использовать</string>\n    <string name=\"disable\">Выключить</string>\n    <string name=\"no_repository_found_error\">Хранилище не обнаружено, проверьте URL и попробуйте с ВПН</string>\n    <string name=\"already_voted\">Вы уже проголосовали</string>\n    <string name=\"no_plugins_found_error\">Никаких дополнений не обнаружено в источнике</string>\n    <string name=\"set_default\">Поставить обычный</string>\n    <string name=\"quality_profile_help\">Здесь вы можете изменить порядок расположения источников. Если видео имеет более высокий приоритет, оно будет отображаться выше в списке источников. Сумма приоритета источника и приоритета качества составляет приоритет видео.\n\\n\n\\nИсточник А: 3\n\\nКачество Б: 7\n\\nБудет иметь общий приоритет видео 10.\n\\n\n\\nПРИМЕЧАНИЕ. Если сумма равна 10 или более, плеер автоматически пропустит загрузку при загрузке этой ссылки!</string>\n    <string name=\"links_reloaded_toast\">Ссылки перезагружены</string>\n    <string name=\"select_an_account\">Выберите учётную запись</string>\n    <string name=\"favorite_removed\">%s убрано из любимых</string>\n    <string name=\"enter_pin\">Введите ПИН-код</string>\n    <string name=\"lock_profile\">Заблокировать профиль</string>\n    <string name=\"pin\">ПИН-код</string>\n    <string name=\"duplicate_title\">Найден потенциальный дубликат</string>\n    <string name=\"duplicate_add\">Добавить</string>\n    <string name=\"pin_error_incorrect\">Неверный ПИН-код. Пожалуйста, введите его заново.</string>\n    <string name=\"pin_error_length\">ПИН-код должен содержать 4 символа</string>\n    <string name=\"edit_account\">Изменить учётную запись</string>\n    <string name=\"manage_accounts\">Управление учётными записями</string>\n    <string name=\"logged_account\" formatted=\"true\">Вы вошли как %s</string>\n    <string name=\"skip_startup_account_select_pref\">Пропускать выбор учётной записи при запуске</string>\n    <string name=\"rotate_video\">Повернуть</string>\n    <string name=\"rotate_video_desc\">Показывать переключатель ориентации экрана</string>\n    <string name=\"duplicate_replace_all\">Заменить всё</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">В вашей библиотеке есть возможно повторяющиеся элементы: \\n \\n\\'%s.\\' \\n \\nХотите ли вы всё равно добавить этот элемент в библиотеку, заменить уже существующий или отменить действие?</string>\n    <string name=\"action_remove_from_favorites\">Убрать из любимого</string>\n    <string name=\"action_add_to_favorites\">Добавить в любимое</string>\n    <string name=\"auto_rotate_video_desc\">Включить автоматическую смену ориентации экрана на основе ориентации видео</string>\n    <string name=\"auto_rotate_video\">Автоповорот</string>\n    <string name=\"use_default_account\">Использовать учётную запись по умолчанию</string>\n    <string name=\"action_unsubscribe\">Отписаться</string>\n    <string name=\"duplicate_replace\">Заменить</string>\n    <string name=\"enter_current_pin\">Введите текущий ПИН-код</string>\n    <string name=\"favorites_list_name\">Любимые</string>\n    <string name=\"favorite_added\">%s добавлено в любимые</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Введите ПИН-код от %s</string>\n    <string name=\"action_subscribe\">Подписаться</string>\n    <string name=\"backup_frequency\">Частота резервного копирования</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Кажется, что в вашей библиотеке уже есть такой элемент: \\'%s.\\' \\n \\nВы хотите всё равно добавить его, заменить уже существующий или отменить действие?</string>\n    <string name=\"subscribe_tooltip\">Оповещение о выходе новой серии</string>\n    <string name=\"result_search_tooltip\">Искать в других расширениях</string>\n    <string name=\"recommendations_tooltip\">Показать рекомендации</string>\n    <string name=\"test_extensions_summary\">Этот тест предназначен только для разработчиков и не подтверждает или не опровергает работоспособность поставщиков.</string>\n    <string name=\"speed_setting_summary\">Добавление настроек скорости в плеер</string>\n    <string name=\"test_extensions\">Протестировать всех поставщиков</string>\n    <string name=\"toast_copied\">скопировано!</string>\n    <string name=\"ok\">ОК</string>\n    <string name=\"repo_copy_label\">Имя репозитория и URL адрес</string>\n    <string name=\"clipboard_permission_error\">Ошибка доступа к буферу обмена, пожалуйста, попробуйте ещё раз.</string>\n    <string name=\"clipboard_unknown_error\">Ошибка при копировании, пожалуйста, скопируйте журнал и свяжитесь с технической поддержкой.</string>\n    <string name=\"unfavorite\">Нелюбимое</string>\n    <string name=\"biometric_authentication_title\">Разблокировать CloudStream</string>\n    <string name=\"favorite\">Любимое</string>\n    <string name=\"app_unrestricted_toast\">Использование батареи приложением уже настроено на неограниченное</string>\n    <string name=\"app_info_intent_error\">Не удаётся открыть информацию о приложении CloudStream.</string>\n    <string name=\"biometric_setting\">Заблокировать биометрией</string>\n    <string name=\"music_singlar\">Музыка</string>\n    <string name=\"audio_book_singular\">Аудиокнига</string>\n    <string name=\"custom_media_singluar\">Медиа</string>\n    <string name=\"biometric_setting_summary\">Разблокируйте приложение с помощью отпечатка пальца, Face ID, ПИН-кода, шаблона и пароля.</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nосталось</string>\n    <string name=\"battery_dialog_title\">Отключить оптимизацию батареи</string>\n    <string name=\"password_pin_authentication_title\">Аутентификация по паролю/ПИН-коду</string>\n    <string name=\"biometric_unsupported\">Биометрическая аутентификация на этом устройстве не поддерживается</string>\n    <string name=\"biometric_prompt_description\">После нескольких неудачных попыток это уведомление закроется. Перезапустите приложение и попробуйте снова.</string>\n    <string name=\"biometric_warning\">Ваши данные в CloudStream были скопированы. Хотя вероятность этого очень мала, все устройства могут вести себя по-разному. В редких случаях, когда доступ к приложению заблокирован, полностью удалите данные приложения и восстановите их из резервной копии. Мы приносим свои извинения за любые неудобства, связанные с этим.</string>\n    <string name=\"battery_dialog_message\">Чтобы обеспечить бесперебойное скачивание и получение уведомлений о телепередачах, на которые вы подписаны, CloudStream необходимо разрешение на запуск в фоновом режиме. Нажав OK, вы увидите запрос. Там нажмите «Разрешить».\\n\\nПожалуйста, обратите внимание, что это разрешение не означает, что CS3 разрядит вашу батарею. Он будет работать в фоновом режиме только при необходимости, например, при получении уведомлений или загрузке видео из официальных дополнений.</string>\n    <string name=\"reset_btn\">Сброс</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Сезон %1$d серия %2$d выйдет</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Выйдет %s</string>\n    <string name=\"player_settings_select_cast_device\">Выберите устройство для трансляции</string>\n    <string name=\"downloads_empty\">В данный момент скачиваний нет.</string>\n    <string name=\"play_from_beginning_img_des\">Играть с самого начала</string>\n    <string name=\"open_local_video\">Открыть локальное видео</string>\n    <string name=\"pref_category_security\">Меры безопасности</string>\n    <string name=\"pref_category_accounts\">Учётные записи</string>\n    <string name=\"open_downloaded_repo\">Откройте хранилище</string>\n    <string name=\"qr_image\">QR-код</string>\n    <string name=\"test_warning\">Предупреждение</string>\n    <string name=\"offline_file\">Доступно для просмотра без сети</string>\n    <string name=\"select_all\">Выбрать всё</string>\n    <string name=\"deselect_all\">Отменить выбор</string>\n    <string name=\"delete_files\">Удалить файлы</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Вы уверены, что хотите навсегда удалить данную серию в %1$s? \\n \\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Вы также навсегда удалите все серии в данном сериале: \\n \\n%s</string>\n    <string name=\"delete_plugin\">Удалить модуль</string>\n    <string name=\"episode_action_cast_mirror\">Актёрский состав</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Вы уверены, что хотите навсегда удалить все серии в данном сериале? \\n \\n%s</string>\n    <string name=\"downloads_delete_select\">Выберите элементы для удаления</string>\n    <string name=\"delete_format\" formatted=\"true\">Удалить (%1$d | %2$s)</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Вы уверены, что хотите навсегда удалить данный объект?\n\\n\n\\n%s</string>\n    <string name=\"device_pin_error_message\">Невозможно получить ПИН-код устройства, попробуйте локальную аутентификацию</string>\n    <string name=\"device_pin_url_message\">Откройте <b>%s</b> на вашем смартфоне или компьютере и введите данный код</string>\n    <string name=\"cs3wiki\">CloudStream Вики</string>\n    <string name=\"device_pin_expired_message\">ПИН-код больше не действителен !</string>\n    <string name=\"device_pin_counter_text\">Код истекает через %1$dмин %2$dсек</string>\n    <string name=\"sort_release_date_new\">Дата выпуска (от нового к старому)</string>\n    <string name=\"sort_release_date_old\">Дата выпуска (от старого к новому)</string>\n    <string name=\"hide_player_control_names\">Скрыть имена контроля игроков</string>\n    <string name=\"dismiss\">Пропустить</string>\n    <string name=\"auth_locally\">Войти локально</string>\n    <string name=\"preview_seekbar\">Предпросмотр поисковой строки</string>\n    <string name=\"preview_seekbar_desc\">Включить предпросмотр миниатюр в поисковой строке</string>\n    <string name=\"no_subtitles_loaded\">Субтитры пока что не скачаны</string>\n    <string name=\"confirm_before_exiting_title\">Подтвердить перед выходом</string>\n    <string name=\"confirm_before_exiting_desc\">Показать диалог перед выходом из приложения</string>\n    <string name=\"show\">Показать</string>\n    <string name=\"dont_show\">Не показывать</string>\n    <string name=\"backup_path_title\">Расположение резервных копий</string>\n    <string name=\"custom\">Пользовательский</string>\n    <string name=\"torrent_info\">Это видео является торрентом, это значит, что вашу видеоактивность можно отследить.\\nУбедитесь, что вы понимаете работу торрентов, прежде чем продолжить.</string>\n    <string name=\"subs_edge_size\">Размер границ</string>\n    <string name=\"encoding_error\">Ошибка кодировки</string>\n    <string name=\"unsupported_error\">Не поддерживается</string>\n    <string name=\"player_load_one_subtitle_online\">Скачать первые доступные</string>\n    <string name=\"audio_singluar\">Аудио</string>\n    <string name=\"podcast_singluar\">Подкаст</string>\n    <string name=\"sort_episodes_number_asc\">Серия (по возрастанию)</string>\n    <string name=\"subtitles_from_embedded\">Встроенный</string>\n    <string name=\"subtitles_from_online\">Из сети</string>\n    <string name=\"sort_episodes_number_desc\">Серия (по убыванию)</string>\n    <string name=\"sort_episodes_rating_high_low\">Оценка (Наивысший)</string>\n    <string name=\"sort_button_episode\">Сер %s</string>\n    <string name=\"sort_button_rating\">Оценка %s</string>\n    <string name=\"sort_button_date\">Дата %s</string>\n    <string name=\"sort_episodes_date_newest\">Дата выпуска (Новейшие)</string>\n    <string name=\"software_decoding_desc\">Программное декодирование позволяет проигрователю воспроизводить видео, которые не поддерживаются вашим устройством, но может быть с задержками или нестабильным воспроизведением при высоком разрешении.</string>\n    <string name=\"software_decoding\">Программное декодирование</string>\n    <string name=\"player_notification_channel_description\">Уведомление проигрывателя для управления воспроизведением в фоновом режиме</string>\n    <string name=\"update_plugins\">Обновить дополнения</string>\n    <string name=\"update_plugins_manually\">Обновить дополнения вручную</string>\n    <string name=\"speech_recognition_unavailable\">Распознавание речи недоступно</string>\n    <string name=\"begin_speaking\">Начните говорить…</string>\n    <string name=\"starting_plugin_update_manually\">Начало процесса обновления дополнения!</string>\n    <string name=\"plugins_updated_manually\">Успешно обновлено %d дополнений!</string>\n    <string name=\"no_plugins_updated_manually\">Дополнений не было обновлено.</string>\n    <string name=\"player_notification_channel_name\">Уведомления плеера</string>\n    <string name=\"sort_episodes_date_oldest\">Дата выпуска (Старейшие)</string>\n    <string name=\"sort_episodes_rating_low_high\">Оценка (Наинизшая)</string>\n    <string name=\"torrent_preferred_media\">Включите торрент в Настройки/Поставщики/Предпочтительные медиа</string>\n    <string name=\"torrent_not_accepted\">Перезапустите программу и примите сплывающее окно Stream Torrent, чтобы продолжить.</string>\n    <string name=\"background_radius\">Радиус фона</string>\n    <string name=\"all_subtitles_bold\">Сделать все субтитры жирными</string>\n    <string name=\"all_subtitles_italic\">Сделать все субтитры курсивом</string>\n    <string name=\"volume_exceeded_100\">Громкость превысила 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Повысьте снова чтобы перевысить 100%</string>\n    <string name=\"go_to_downloads\">Перейти к загрузкам</string>\n    <string name=\"no_internet_connection\">Нет подключения к Интернету.\\n\\nПожалуйста, подключитесь к Интернету и повторите попытку, или смотрите свои загрузки, находясь в автономном режиме.</string>\n    <string name=\"download_parallel_settings_des\">Сколько различных элементов можно загружать параллельно</string>\n    <string name=\"parallel_downloads\">Параллельные загрузки</string>\n    <string name=\"concurrent_connections\">Одновременные соединения</string>\n    <string name=\"concurrent_connections_settings_des\">Сколько одновременных соединений может использовать каждая загрузка во время скачивания</string>\n    <string name=\"overscan_settings_des\">Изменение границ экрана</string>\n    <string name=\"overscan_settings\">Пересканирование</string>\n    <string name=\"poster_size_settings_des\">Изменение размера плакатов</string>\n    <string name=\"poster_size_settings\">Размер плаката</string>\n    <string name=\"player_settings_always_ask\">Спрашивать всегда</string>\n    <string name=\"speedup_title\">Переключение скорости при длительном нажатии</string>\n    <string name=\"speedup_summary\">Удерживайте, чтобы увеличить скорость в 2 раза</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dч %2$dм %3$dс</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dм %2$dс</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$dс</string>\n    <string name=\"show_rating\">Рейтинговая этикетка</string>\n    <string name=\"no_account\">Не существует учетной записи</string>\n    <string name=\"edit_profile_image_title\">Изменить изображение профиля</string>\n    <string name=\"edit_profile_image_hint\">Введите URL изображения профиля</string>\n    <string name=\"edit_profile_image_error_empty\">URL не найден</string>\n    <string name=\"edit_profile_image_error_invalid\">Неверный URL или изображение</string>\n    <string name=\"edit_profile_image_success\">Изображение успешно обновлено</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Отметить как просмотренное до этого эпизода</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Удалить просмотренное до этой серии</string>\n    <string name=\"action_reload\">Перезагрузка</string>\n    <string name=\"reload_provider\">Перезагрузить провайдер</string>\n    <string name=\"episode_action_play_mirror\">Запустить зеркало</string>\"\n    <string name=\"name\">Имя</string>\n    <string name=\"resolution_and_name\">Резолюция и название</string>\n    <string name=\"subs_subtitle_alignment\">Выравнивание Субтитров</string>\n    <string name=\"bottom_left\">Нижний левый</string>\n    <string name=\"bottom_center\">Нижний центр</string>\n    <string name=\"bottom_right\">Нижний правый</string>\n    <string name=\"middle_left\">Средний левый</string>\n    <string name=\"middle_center\">Средний центр</string>\n    <string name=\"middle_right\">Средний правый</string>\n    <string name=\"top_left\">Верхний слева</string>\n    <string name=\"top_center\">Верхний центр</string>\n    <string name=\"top_right\">Верхний справа</string>\n    <string name=\"play_full_series_button\">Смотреть полностью</string>\n    <string name=\"install_prerelease\">Установить предварительный выпуск</string>\n    <string name=\"prerelease_already_installed\">Предварительный выпуск уже установлен.</string>\n    <string name=\"prerelease_install_failed\">Не удалось установить предварительный выпуск.</string>\n    <string name=\"show_episode_text\">Текст эпизода</string>\n    <string name=\"search_suggestions\">Поиск предложений</string>\n    <string name=\"search_suggestions_des\">Показывать подсказки поиска при вводе текста</string>\n    <string name=\"clear_suggestions\">Очистить подсказки</string>\n    <string name=\"show_cast_in_details\">Показать панель приведения</string>\n    <string name=\"video_info\">Информация о средствах массовой информации</string>\n    <string name=\"source_name\">Имя источника</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d активная загрузка</item>\n        <item quantity=\"few\">%d активные загрузки</item>\n        <item quantity=\"many\">%d активных загрузок</item>\n        <item quantity=\"other\">%d активных загрузок</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">Запланировано %d загрузка</item>\n        <item quantity=\"few\">Запланировано %d загрузки</item>\n        <item quantity=\"many\">Запланировано %d загрузок</item>\n        <item quantity=\"other\">Запланировано %d загрузок</item>\n    </plurals>\n    <string name=\"download_queue\">Очередь загрузок</string>\n    <string name=\"queue_empty_message\">В настоящее время нет загрузок в очереди.</string>\n    <string name=\"extra_brightness_settings\">Дополнительная яркость</string>\n    <string name=\"extra_brightness_settings_des\">Включать фильтр яркости при превышении 100% яркости</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"source_priority\">Приоритетный источник</string>\n    <string name=\"source_priority_help\">Выберите способ сортировки видеоисточников в плеере</string>\n    <string name=\"download_all\">Скачать всё</string>\n    <string name=\"cancel_all\">Отменить всё</string>\n    <string name=\"download_episode_range\">Вы хотите загрузить эпизод %s?</string>\n    <string name=\"cancel_queue_message\">Вы хотите отменить всё запланированные загрузки?</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+sk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"new_update_format\" formatted=\"true\">Našla sa nová aktualizácia!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Výplň</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Epizóda %d bude vydaná za</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"next_episode\">Ďalšia epizóda</string>\n    <string name=\"result_tags\">Žánre</string>\n    <string name=\"result_share\">Zdielať</string>\n    <string name=\"result_open_in_browser\">Otvoriť v prehliadači</string>\n    <string name=\"skip_loading\">Preskočiť načítavanie</string>\n    <string name=\"cast_format\" formatted=\"true\">Hrajú: %s</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"result_poster_img_des\">Plagát</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"search_poster_img_des\">Plagát</string>\n    <string name=\"episode_poster_img_des\">Plagát epizódy</string>\n    <string name=\"home_main_poster_img_des\">Hlavný plagát</string>\n    <string name=\"play_with_app_name\">Prehrať s CloudStream</string>\n    <string name=\"title_settings\">Nastavenia</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Hľadať %s…</string>\n    <string name=\"popup_resume_download\">Pokračovať v sťahovaní</string>\n    <string name=\"rated_format\" formatted=\"true\">Hodnotenie: %.1f</string>\n    <string name=\"go_back_img_des\">Ísť späť</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Rýchlosť (%.2fx)</string>\n    <string name=\"home_change_provider_img_des\">Zmeniť poskytovateľa</string>\n    <string name=\"title_home\">Domov</string>\n    <string name=\"title_search\">Hľadať</string>\n    <string name=\"search_hint\">Hľadať…</string>\n    <string name=\"title_downloads\">Sťahovanie</string>\n    <string name=\"no_data\">Žiadne dáta</string>\n    <string name=\"sort_copy\">Kopírovať</string>\n    <string name=\"sort_close\">Zavrieť</string>\n    <string name=\"sort_save\">Uložiť</string>\n    <string name=\"download\">Stiahnuť</string>\n    <string name=\"downloaded\">Stiahnuté</string>\n    <string name=\"episode_more_options_des\">Ďalšie možnosti</string>\n    <string name=\"pick_source\">Zdroje</string>\n    <string name=\"go_back\">Ísť späť</string>\n    <string name=\"download_failed\">Sťahovanie zlyhalo</string>\n    <string name=\"download_paused\">Sťahovanie pozastavené</string>\n    <string name=\"download_done\">Sťahovanie dokončené</string>\n    <string name=\"error_loading_links_toast\">Chyba pri načítavaní odkazov</string>\n    <string name=\"update_started\">Aktualizácia spustená</string>\n    <string name=\"download_storage_text\">Interné úložisko</string>\n    <string name=\"loading\">Načítavanie…</string>\n    <string name=\"type_completed\">Dokončené</string>\n    <string name=\"type_plan_to_watch\">Plánujem pozerať</string>\n    <string name=\"home_more_info\">Viac informácií</string>\n    <string name=\"error_bookmarks_text\">Záložky</string>\n    <string name=\"play_movie_button\">Prehrať film</string>\n    <string name=\"play_trailer_button\">Prehrať upútavku</string>\n    <string name=\"downloading\">Sťahovanie</string>\n    <string name=\"download_canceled\">Sťahovanie zrušené</string>\n    <string name=\"app_dubbed_text\">Dab</string>\n    <string name=\"popup_delete_file\">Zmazať súbor</string>\n    <string name=\"app_subbed_text\">Tit</string>\n    <string name=\"type_re_watching\">Opätovné sledovanie</string>\n    <string name=\"popup_play_file\">Prehrať súbor</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"play_livestream_button\">Prehrať živý prenos</string>\n    <string name=\"pick_subtitle\">Titulky</string>\n    <string name=\"play_episode\">Prehrať epizódu</string>\n    <string name=\"popup_pause_download\">Pozastaviť sťahovanie</string>\n    <string name=\"home_expanded_hide\">Skryť</string>\n    <string name=\"filter_bookmarks\">Filtrovať záložky</string>\n    <string name=\"action_remove_from_bookmarks\">Odstrániť</string>\n    <string name=\"sort_apply\">Použiť</string>\n    <string name=\"download_started\">Sťahovanie spustené</string>\n    <string name=\"sort_clear\">Vyčistiť</string>\n    <string name=\"home_play\">Prehrať</string>\n    <string name=\"action_add_to_bookmarks\">Nastaviť stav sledovania</string>\n    <string name=\"player_speed\">Rýchlosť prehrávania</string>\n    <string name=\"subs_outline_color\">Farba obrysu</string>\n    <string name=\"subs_window_color\">Farba okna</string>\n    <string name=\"subs_edge_type\">Typ hrany</string>\n    <string name=\"subtitles_settings\">Nastavenia titulkov</string>\n    <string name=\"subs_background_color\">Farba pozadia</string>\n    <string name=\"subs_text_color\">Farba textu</string>\n    <string name=\"subs_subtitle_elevation\">Vyvýšenie titulkov</string>\n    <string name=\"search_provider_text_providers\">Hľadať pomocou poskytovateľov</string>\n    <string name=\"subs_font\">Písmo</string>\n    <string name=\"search_provider_text_types\">Hľadať pomocou typov</string>\n    <string name=\"subs_auto_select_language\">Automaticky vybrať jazyk</string>\n    <string name=\"subs_subtitle_languages\">Jazyk titulkov</string>\n    <string name=\"subs_font_size\">Veľkosť písma</string>\n    <string name=\"benene_count_text_none\">Nedarovali ste žiadne benény</string>\n    <string name=\"subs_hold_to_reset_to_default\">Podržaním obnovíte predvolené nastavenia</string>\n    <string name=\"benene_count_text\">%d benénov darovaných vývojárom</string>\n    <string name=\"subs_download_languages\">Stiahnuť jazyky</string>\n    <string name=\"action_remove_watching\">Odstrániť</string>\n    <string name=\"vpn_torrent\">Tento poskytovateľ je torrent, odporúča sa VPN</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importovať písma ich umiestnením do %s</string>\n    <string name=\"action_open_watching\">Viac informácií</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"continue_watching\">Pokračovať v sledovaní</string>\n    <string name=\"vpn_might_be_needed\">Na správne fungovanie tohto poskytovateľa môže byť potrebná VPN</string>\n    <string name=\"provider_info_meta\">Stránka neposkytla žiadne metadáta, načítanie videa zlyhá, ak na stránke neexistuje.</string>\n    <string name=\"torrent_plot\">Popis</string>\n    <string name=\"picture_in_picture_des\">Pokračuje v prehrávaní v miniatúrnom prehrávači nad ostatnými aplikáciami</string>\n    <string name=\"reload_error\">Zopakujte pripojenie…</string>\n    <string name=\"type_dropped\">Upustené</string>\n    <string name=\"picture_in_picture\">Obraz v obraze</string>\n    <string name=\"play_torrent_button\">Streamovať torrent</string>\n    <string name=\"preview_background_img_des\">Náhľad pozadia</string>\n    <string name=\"player_size_settings\">Tlačidlo na zmenu veľkosti prehrávača</string>\n    <string name=\"type_watching\">Sledujem</string>\n    <string name=\"torrent_no_plot\">Popis sa nenašiel</string>\n    <string name=\"home_next_random_img_des\">Ďalší náhodný</string>\n    <string name=\"stream\">Sieťový stream</string>\n    <string name=\"type_on_hold\">Podržané</string>\n    <string name=\"show_log_cat\">Zobraziť Logcat 🐈</string>\n    <string name=\"test_log\">Protokol</string>\n    <string name=\"browser\">Prehliadač</string>\n    <string name=\"normal_no_plot\">Zhrnutie sa nenašlo</string>\n    <string name=\"double_tap_to_pause_settings\">Dvojitým ťuknutím pozastaviť</string>\n    <string name=\"category_updates\">Aktualizácie a zálohovanie</string>\n    <string name=\"settings_info\">Informácie</string>\n    <string name=\"advanced_search\">Rozšírené vyhľadávanie</string>\n    <string name=\"kitsu_settings\">Zobraziť plagáty z Kitsu</string>\n    <string name=\"automatic_plugin_updates\">Automatická aktualizácia doplnkov</string>\n    <string name=\"pref_filter_search_quality\">Skryť vybranú kvalitu videa vo výsledkoch vyhľadávania</string>\n    <string name=\"show_fillers_settings\">Zobraziť výplňovú epizódu pre anime</string>\n    <string name=\"apk_installer_settings\">APK inštalátor</string>\n    <string name=\"apk_installer_settings_des\">Niektoré telefóny nepodporujú nový inštalátor balíčkov. Ak sa aktualizácie nenainštalujú, skúste použiť staršiu možnosť.</string>\n    <string name=\"lightnovel\">Nenáročná aplikácia pre romány od rovnakých vývojárov</string>\n    <string name=\"app_language\">Jazyk aplikácie</string>\n    <string name=\"no_links_found_toast\">Nenašli sa žiadne odkazy</string>\n    <string name=\"benene\">Darujte benén vývojárom</string>\n    <string name=\"benene_des\">Benén darovaný</string>\n    <string name=\"no_chromecast_support_toast\">Tento poskytovateľ nepodporuje Chromecast</string>\n    <string name=\"restore_success\">Súbor zálohy načítaný</string>\n    <string name=\"episode_sync_settings_des\">Automaticky synchronizovať priebeh sledovania súčasnej epizódy</string>\n    <string name=\"double_tap_to_seek_settings_des\">Ťuknite dvakrát vpravo alebo vľavo pre pretočenie vpred alebo vzad</string>\n    <string name=\"swipe_to_change_settings\">Potiahnutím zmeniť nastavenia</string>\n    <string name=\"swipe_to_change_settings_des\">Posunutím nahor alebo nadol na ľavej alebo pravej strane zmeníte jas alebo hlasitosť</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Dĺžka pretočenia (sekundy)</string>\n    <string name=\"redo_setup_process\">Zopakovať proces nastavenia</string>\n    <string name=\"player_subtitles_settings\">Titulky</string>\n    <string name=\"backup_success\">Dáta uložené</string>\n    <string name=\"anim\">Anime aplikácia od rovnakých vývojárov</string>\n    <string name=\"backup_settings\">Zálohovať dáta</string>\n    <string name=\"copy_link_toast\">Odkaz skopírovaný do schránky</string>\n    <string name=\"use_system_brightness_settings\">Použiť systémový jas</string>\n    <string name=\"restore_settings\">Obnoviť dáta zo zálohy</string>\n    <string name=\"double_tap_to_seek_settings\">Dvojitým ťuknutím pretočiť</string>\n    <string name=\"automatic_plugin_download\">Automaticky sťahovať doplnky</string>\n    <string name=\"discord\">Pripojte sa na Discord</string>\n    <string name=\"player_size_settings_des\">Odstrániť čierne okraje</string>\n    <string name=\"updates_settings_des\">Automaticky vyhľadať nové aktualizácie po spustení aplikácie.</string>\n    <string name=\"play_episode_toast\">Prehrať epizódu</string>\n    <string name=\"backup_failed\">Chýbajú povolenia k úložisku. Skúste to prosím znova.</string>\n    <string name=\"player_subtitles_settings_des\">Nastavenia titulkov prehrávača</string>\n    <string name=\"autoplay_next_settings_des\">Spustiť ďalšiu epizódu po skončení aktuálnej</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast titulky</string>\n    <string name=\"eigengraumode_settings\">Eigengravy režim</string>\n    <string name=\"swipe_to_seek_settings\">Potiahnutím pretočiť</string>\n    <string name=\"autoplay_next_settings\">Automaticky prehrať ďalšiu epizódu</string>\n    <string name=\"episode_sync_settings\">Aktualizovať priebeh sledovania</string>\n    <string name=\"double_tap_to_pause_settings_des\">Ťuknite dvakrát do stredu pre pozastavenie</string>\n    <string name=\"use_system_brightness_settings_des\">V prehrávači použiť systémový jas namiesto tmavého prekrytia</string>\n    <string name=\"show_trailers_settings\">Zobraziť upútavky</string>\n    <string name=\"automatic_plugin_download_summary\">Automaticky nainštalovať všetky ešte nenainštalované doplnky z pridaných repozitárov.</string>\n    <string name=\"library\">Knižnica</string>\n    <string name=\"github\">GitHub</string>\n    <string name=\"search\">Hľadať</string>\n    <string name=\"category_account\">Účty</string>\n    <string name=\"chromecast_subtitles_settings_des\">Nastavenia Chromecast titulkov</string>\n    <string name=\"swipe_to_seek_settings_des\">Potiahnutím zo strany na stranu môžete ovládať svoju pozíciu vo videu</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Nepodarilo sa obnoviť dáta zo súboru %s</string>\n    <string name=\"backup_failed_error_format\">Chyba pri zálohovaní %s</string>\n    <string name=\"advanced_search_des\">Poskytne vám výsledky vyhľadávania rozdelené podľa poskytovateľa</string>\n    <string name=\"updates_settings\">Zobraziť aktualizácie aplikácie</string>\n    <string name=\"subs_default_reset_toast\">Obnoviť predvolenú hodnotu</string>\n    <string name=\"season\">Sezóna</string>\n    <string name=\"synopsis\">Synopsa</string>\n    <string name=\"queued\">vo fronte</string>\n    <string name=\"no_subtitles\">Žiadne titulky</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"cartoons\">Kreslené</string>\n    <string name=\"episode_action_auto_download\">Automaticky stiahnuť</string>\n    <string name=\"episode_action_download_mirror\">Zrkadlo sťahovania</string>\n    <string name=\"video_lock\">Zamknúť</string>\n    <string name=\"no_update_found\">Nenašla sa žiadna aktualizácia</string>\n    <string name=\"check_for_update\">Skontrolovať aktualizáciu</string>\n    <string name=\"video_aspect_ratio_resize\">Zmeniť veľkosť</string>\n    <string name=\"dns_pref\">DNS cez HTTPS</string>\n    <string name=\"remove_site_pref\">Odstrániť stránku</string>\n    <string name=\"add_site_summary\">Pridá klon existujúcej stránky s inou URL adresou</string>\n    <string name=\"download_path_pref\">Cesta sťahovania</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"pref_category_gestures\">Gestá</string>\n    <string name=\"pref_category_player_features\">Funkcie prehrávača</string>\n    <string name=\"category_general\">Všeobecné</string>\n    <string name=\"random_button_settings\">Náhodné tlačidlo</string>\n    <string name=\"login\">Prihlásiť sa</string>\n    <string name=\"switch_account\">Prepnúť účet</string>\n    <string name=\"add_account\">Pridať účet</string>\n    <string name=\"app_layout\">Rozloženie aplikácie</string>\n    <string name=\"example_email\">ahoj@svet.sk</string>\n    <string name=\"test_passed\">Úspešné</string>\n    <string name=\"example_username\">MojeSuperMeno</string>\n    <string name=\"tv_series\">Seriály</string>\n    <string name=\"tv_series_singular\">Seriál</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"resize_fill\">Roztiahnuť</string>\n    <string name=\"pref_category_backup\">Záloha</string>\n    <string name=\"video_source\">Zdroj</string>\n    <string name=\"free_storage\">Voľné</string>\n    <string name=\"video_buffer_size_settings\">Veľkosť vyrovnávacej pamäte videa</string>\n    <string name=\"pref_category_app_updates\">Aktualizácie aplikácie</string>\n    <string name=\"bottom_title_settings\">Umiestnenie názvu plagátu</string>\n    <string name=\"live_singular\">Živý prenos</string>\n    <string name=\"example_password\">heslo123</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"resume\">Pokračovať</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"pref_category_actions\">Akcie</string>\n    <string name=\"pause\">Pozastaviť</string>\n    <string name=\"display_subbed_dubbed_settings\">Zobraziť anime dabované/s titulkami</string>\n    <string name=\"pref_category_subtitles\">Titulky</string>\n    <string name=\"upload_sync\">Synchronizovať</string>\n    <string name=\"episode_action_play_in_app\">Prehrať v aplikácii</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"video_ram_description\">Spôsobuje zlyhania, ak je nastavená príliš vysoko na zariadeniach s nízkou pamäťou, ako je Android TV.</string>\n    <string name=\"jsdelivr_proxy\">raw.githubusercontent.com Proxy</string>\n    <string name=\"duration\">Trvanie</string>\n    <string name=\"app_storage\">Aplikácia</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Pridané %s</string>\n    <string name=\"documentaries_singular\">Dokument</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast zrkadlo</string>\n    <string name=\"pref_category_defaults\">Predvolené</string>\n    <string name=\"others\">Ostatné</string>\n    <string name=\"storage_error\">Chyba pri sťahovaní, skontrolujte povolenia k úložisku</string>\n    <string name=\"primary_color_settings\">Primárna farba</string>\n    <string name=\"create_account\">Vytvoriť účet</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"resize_zoom\">Priblížiť</string>\n    <string name=\"torrent\">Torrenty</string>\n    <string name=\"limit_title_rez\">Rozlíšenie prehrávača</string>\n    <string name=\"bottom_title_settings_des\">Umiestniť názov pod plagát</string>\n    <string name=\"watch_quality_pref\">Preferovaná kvalita sledovania (WiFi)</string>\n    <string name=\"pref_category_extensions\">Rozšírenia</string>\n    <string name=\"sync_score\">Hodnotené</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"render_error\">Chyba vykresľovania</string>\n    <string name=\"unexpected_error\">Neočakávaná chyba prehrávača</string>\n    <string name=\"app_theme_settings\">Téma aplikácie</string>\n    <string name=\"documentaries\">Dokumenty</string>\n    <string name=\"preferred_media_settings\">Preferované médiá</string>\n    <string name=\"nginx_url_pref\">URL servera NGINX</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"action_default\">Predvolené</string>\n    <string name=\"add_sync\">Pridať sledovanie</string>\n    <string name=\"no_season\">Žiadna sezóna</string>\n    <string name=\"episode\">Epizóda</string>\n    <string name=\"episode_action_reload_links\">Znova načítať odkazy</string>\n    <string name=\"provider_lang_settings\">Jazyky poskytovateľa</string>\n    <string name=\"start\">Spustiť</string>\n    <string name=\"livestreams\">Živé prenosy</string>\n    <string name=\"episode_action_download_subtitle\">Stiahnuť titulky</string>\n    <string name=\"enable_nsfw_on_providers\">Povoliť NSFW u podporovaných poskytovateľov</string>\n    <string name=\"pref_category_bypass\">Obchádzanie ISP</string>\n    <string name=\"poster_ui_settings\">Prepnúť UI prvky na plagáte</string>\n    <string name=\"pref_category_player_layout\">Rozloženie</string>\n    <string name=\"test_failed\">Neúspešné</string>\n    <string name=\"status\">Stav</string>\n    <string name=\"video_skip_op\">Preskočiť OP</string>\n    <string name=\"video_buffer_disk_settings\">Vyrovnávacia pamäť videa na disku</string>\n    <string name=\"rating\">Hodnotenie</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"skip_update\">Preskočiť túto aktualizáciu</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"account\">účet</string>\n    <string name=\"year\">Rok</string>\n    <string name=\"resize_fit\">Prispôsobiť obrazovke</string>\n    <string name=\"delete\">Zmazať</string>\n    <string name=\"cancel\">Zrušiť</string>\n    <string name=\"used_storage\">Využité</string>\n    <string name=\"show_hd\">Štítok kvality</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Prehrávač skrytý - dĺžka pretočenia</string>\n    <string name=\"pref_category_looks\">Vzhľad</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"jsdelivr_proxy_summary\">Obchádza blokovanie GitHubu pomocou jsDelivr. Môže spôsobiť oneskorenie aktualizácií o niekoľko dní.</string>\n    <string name=\"random_button_settings_desc\">Zobraziť náhodné tlačidlo na domovskej stránke</string>\n    <string name=\"logout\">Odhlásiť sa</string>\n    <string name=\"update\">Aktualizovať</string>\n    <string name=\"site\">Stránka</string>\n    <string name=\"video_buffer_length_settings\">Dĺžka vyrovnávacej pamäte videa</string>\n    <string name=\"delete_file\">Zmazať súbor</string>\n    <string name=\"episode_action_play_in_format\">Prehrať v %s</string>\n    <string name=\"pref_category_ui_features\">Funkcie</string>\n    <string name=\"dont_show_again\">Nezobrazovať znova</string>\n    <string name=\"remote_error\">Vzdialená chyba</string>\n    <string name=\"dns_pref_summary\">Užitočné na obchádzanie blokácií ISP</string>\n    <string name=\"pref_category_links\">Odkazy</string>\n    <string name=\"add_site_pref\">Klonovať stránku</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"movies\">Filmy</string>\n    <string name=\"example_site_url\">príklad.sk</string>\n    <string name=\"pref_category_cache\">Vyrovnávacia pamäť</string>\n    <string name=\"jsdelivr_enabled\">Nepodarilo sa pripojiť na GitHub. Zapína sa proxy jsDelivr…</string>\n    <string name=\"no_episodes_found\">Nenašli sa žiadne epizódy</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"asian_drama\">Ázijské drámy</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"source_error\">Chyba zdroja</string>\n    <string name=\"show_dub\">Štítok dabingu</string>\n    <string name=\"show_sub\">Štítok titulkov</string>\n    <string name=\"show_title\">Názov</string>\n    <string name=\"video_buffer_clear_settings\">Vymazať vyrovnávaciu pamäť videí a obrázkov</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Prehrávač zobrazený - dĺžka pretáčania</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Dĺžka pretočenia, keď je prehrávač viditeľný</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Dĺžka pretočenia, keď je prehrávač skrytý</string>\n    <string name=\"subtitles_encoding\">Kódovanie titulkov</string>\n    <string name=\"category_provider_test\">Test poskytovateľa</string>\n    <string name=\"category_ui\">Rozloženie</string>\n    <string name=\"automatic\">Automaticky</string>\n    <string name=\"phone_layout\">Mobilné rozloženie</string>\n    <string name=\"category_providers\">Poskytovatelia</string>\n    <string name=\"tv_layout\">TV rozloženie</string>\n    <string name=\"example_lang_name\">Kód jazyka (sk)</string>\n    <string name=\"example_site_name\">MôjSuperWeb</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"legal_notice\">Vylúčenie zodpovednosti</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"delete_message\" formatted=\"true\">Týmto sa natrvalo vymaže %s\n\\nSte si istý?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nzostáva</string>\n    <string name=\"status_ongoing\">Prebieha</string>\n    <string name=\"status_completed\">Dokončené</string>\n    <string name=\"emulator_layout\">Rozloženie emulátora</string>\n    <string name=\"episodes\">Epizódy</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"asian_drama_singular\">Ázijská dráma</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecastovať epizódu</string>\n    <string name=\"watch_quality_pref_data\">Preferovaná kvalita sledovania (mobilné dáta)</string>\n    <string name=\"limit_title\">Maximálny počet znakov v názve prehrávača</string>\n    <string name=\"video_disk_description\">Spôsobuje problémy, ak je nastavená príliš vysoko v zariadeniach s malým ukladacím priestorom, ako je napríklad Android TV.</string>\n    <string name=\"backup_frequency\">Frekvencia zálohovania</string>\n    <string name=\"delete_repository_plugins\">Toto tiež odstráni všetky doplnky repozitára</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Sezóna %1$d Epizóda %2$d bude vydaná za</string>\n    <string name=\"no_plugins_found_error\">V repozitári neboli nájdené žiadne doplnky</string>\n    <string name=\"update_notification_downloading\">Sťahuje sa aktualizácia aplikácie…</string>\n    <string name=\"update_notification_installing\">Inštaluje sa aktualizácia aplikácie…</string>\n    <string name=\"toast_copied\">skopírované!</string>\n    <string name=\"repo_copy_label\">Názov a URL repozitára</string>\n    <string name=\"subscription_in_progress_notification\">Aktualizujú sa odoberané relácie</string>\n    <string name=\"subscribe_tooltip\">Upozornenie na novú epizódu</string>\n    <string name=\"no_repository_found_error\">Repozitár nebol nájdený, skontrolujte URL adresu a skúste VPN</string>\n    <string name=\"links_reloaded_toast\">Odkazy sa znovu načítali</string>\n    <string name=\"delete_repository\">Zmazať repozitár</string>\n    <string name=\"repository_url_hint\">URL adresa repozitára</string>\n    <string name=\"view_public_repositories_button_short\">Verejný zoznam</string>\n    <string name=\"blank_repo_message\">CloudStream nemá nainštalované žiadne stránky v predvolenom nastavení. Musíte nainštalovať stránky z repozitára.\n\\n\n\\nPripojte sa k nášmu Discord alebo vyhľadajte online.</string>\n    <string name=\"update_notification_failed\">Nepodarilo sa nainštalovať novú verziu aplikácie</string>\n    <string name=\"download_all_plugins_from_repo\">Upozornenie: CloudStream 3 nenesie žiadnu zodpovednosť za používanie rozšírenia tretích strán a neposkytuje žiadnu podporu pre nich!</string>\n    <string name=\"add_repository\">Pridať repozitár</string>\n    <string name=\"repository_name_hint\">Názov repozitára</string>\n    <string name=\"view_public_repositories_button\">Zobraziť komunitné repozitáre</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"category_player\">Prehrávač</string>\n    <string name=\"resolution_and_title\">Rozlíšenie a titul</string>\n    <string name=\"max\">Maximum</string>\n    <string name=\"skip_setup\">Preskočiť nastavenie</string>\n    <string name=\"error\">Chyba</string>\n    <string name=\"test_extensions_summary\">Tento test je určený len pre vývojárov a nepreveruje ani popiera prácu akéhokoľvek rozšírenia.</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"actor_background\">Pozadie</string>\n    <string name=\"setup_done\">Hotovo</string>\n    <string name=\"cartoons_singular\">Kreslený</string>\n    <string name=\"music_singlar\">Hudba</string>\n    <string name=\"custom_media_singluar\">Médiá</string>\n    <string name=\"pref_category_accounts\">Kontá</string>\n    <string name=\"pref_category_security\">Bezpečnosť</string>\n    <string name=\"normal\">Normálne</string>\n    <string name=\"min\">Minimum</string>\n    <string name=\"subtitles_outline\">Obrys</string>\n    <string name=\"subtitles_shadow\">Tieň</string>\n    <string name=\"subtitle_offset_title\">Oneskorenie tituliek</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Použite to, ak sú uvedené titulky %d ms príliš skoro</string>\n    <string name=\"provider_languages_tip\">Sledujte videá v týchto jazykoch</string>\n    <string name=\"previous\">Predchádzajúci</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Ste si istí, že chcete trvalo odstrániť nasledujúce epizódy v %1$s?\\n\\n%2$s</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Načítané %s</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Ste si istí, že chcete trvalo odstrániť nasledujúce položky?\\n\\n%s</string>\n    <string name=\"downloads_delete_select\">Vyberte položky na odstránenie</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Použite to, ak sú uvedené titulky %d ms príliš neskoro</string>\n    <string name=\"preferred_media_subtext\">Čo chcete vidieť</string>\n    <string name=\"torrent_info\">Toto video je Torrent, to znamená, že vaša video aktivita je možné sledovať.\\nUistite sa, že ste pochopili Torrent pred pokračovaním.</string>\n    <string name=\"offline_file\">K dispozícii pre sledovanie offline</string>\n    <string name=\"player_load_one_subtitle_online\">Načítať prvé k dispozícii</string>\n    <string name=\"player_load_subtitles\">Načítať z súboru</string>\n    <string name=\"coming_soon\">Čoskoro…</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"error_invalid_id\">Neplatné ID</string>\n    <string name=\"none\">Žiadne</string>\n    <string name=\"title\">Titul</string>\n    <string name=\"resolution\">Rozlíšenie</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"disable\">Zakázať</string>\n    <string name=\"recommended\">Odporúčané</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Ste si istí, že chcete trvalo odstrániť všetky epizódy v nasledujúcej sérii?\\n\\n%s</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Nemohol sa prihlásiť v %s</string>\n    <string name=\"player_load_subtitles_online\">Načítať z internetu</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"extensions\">Rozšírenia</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Takisto aj trvalo odstránite všetky epizódy v nasledujúcej sérii:\\n\\n%s</string>\n    <string name=\"audio_book_singular\">Audio kniha</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s overené</string>\n    <string name=\"subtitles_example_text\">V kŕdli čajok švihol ďateľ v ústí milej obžerky</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Žiadne oneskorenie tituliek</string>\n    <string name=\"actor_supporting\">Podporuje</string>\n    <string name=\"error_invalid_data\">Neplatné dáta</string>\n    <string name=\"error_invalid_url\">Neplatná URL adresa</string>\n    <string name=\"subtitles_remove_captions\">Odstráňte uzavreté titulky od titulkov</string>\n    <string name=\"recommendations_tooltip\">Zobraziť odporúčania</string>\n    <string name=\"test_extensions\">Otestujte všetky rozšírenia</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Nadchádzajúce o %s</string>\n    <string name=\"qr_image\">QR kód obrázok</string>\n    <string name=\"open_local_video\">Otvoriť lokálne video</string>\n    <string name=\"test_warning\">Varovanie</string>\n    <string name=\"play_from_beginning_img_des\">Hrať od začiatku</string>\n    <string name=\"downloads_empty\">Momentálne nie sú žiadne stiahnutia.</string>\n    <string name=\"downloaded_file\">Stiahnutý súbor</string>\n    <string name=\"actor_main\">Hlavné</string>\n    <string name=\"speed_setting_summary\">Pridá možnosť rýchlosti do prehrávača</string>\n    <string name=\"resume_remaining\" formatted=\"true\">Zostáva\\n%s</string>\n    <string name=\"delete_files\">Odstrániť súbory</string>\n    <string name=\"delete_format\" formatted=\"true\">Odstrániť (%1$d | %2$s</string>\n    <string name=\"home_source\">Zdroj</string>\n    <string name=\"home_random\">Náhodné</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"next\">Ďalšie</string>\n    <string name=\"select_all\">Vybrať Všetko</string>\n    <string name=\"deselect_all\">Zrušiť výber všetkých</string>\n    <string name=\"audio_singluar\">Zvuk</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"all\">Všetko</string>\n    <string name=\"encoding_error\">Chyba kódovania</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+so/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"cast_format\" formatted=\"true\">Metalaya: %s</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dm %2$ds %3$dd</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$ds %2$dd</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dd</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Xlq %2$d</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Xalqadda %d waxa lasoo deyn doonaa</string>\n    <string name=\"download\">Daji</string>\n    <string name=\"download_failed\">Dejintii ma guulaysan</string>\n    <string name=\"search\">Raadi</string>\n    <string name=\"delete\">Tirtir</string>\n    <string name=\"cancel\">Jooji</string>\n    <string name=\"pause\">Haki</string>\n    <string name=\"queued\">Horran</string>\n    <string name=\"resize_fit\">Le-ekaysii shaashadda</string>\n    <string name=\"resize_fill\">Kala jiid</string>\n    <string name=\"resize_zoom\">Soo dhawee</string>\n    <string name=\"all\">Dhammaan</string>\n    <string name=\"tracks\">Muusik</string>\n    <string name=\"play_with_app_name\">Ku daawo CloudStream</string>\n    <string name=\"title_settings\">Habaynta</string>\n    <string name=\"filler\" formatted=\"true\">Buuxiye</string>\n    <string name=\"home_change_provider_img_des\">Beddel qaybiyaha</string>\n    <string name=\"app_name\">Cloudstream</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Xawaaraha (%.2fx)</string>\n    <string name=\"duration_format\" formatted=\"true\">%d dqq</string>\n    <string name=\"title_home\">Kadinka</string>\n    <string name=\"rated_format\" formatted=\"true\">Qiimaysan: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">App cusub baa soo baxay!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"title_downloads\">Soo dejinta</string>\n    <string name=\"title_search\">Raadi</string>\n    <string name=\"episode_more_options_des\">Dookhyo kale</string>\n    <string name=\"no_data\">Xog ma leh</string>\n    <string name=\"next_episode\">Xalqadda xigta</string>\n    <string name=\"type_watching\">Daawanaysid</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Raadi %s…</string>\n    <string name=\"result_tags\">Caynadda</string>\n    <string name=\"result_share\">Faafi</string>\n    <string name=\"result_open_in_browser\">Ku fur barawsarka</string>\n    <string name=\"skip_loading\">Is dhaafi soo kicitaanka</string>\n    <string name=\"loading\">Soo kacaya…</string>\n    <string name=\"search_hint\">Raadi…</string>\n    <string name=\"type_on_hold\">Kor u hay</string>\n    <string name=\"type_re_watching\">Dib u daawasho</string>\n    <string name=\"type_completed\">Dhamaystirmay</string>\n    <string name=\"type_dropped\">Soo dhacay</string>\n    <string name=\"type_plan_to_watch\">Ku talo jira</string>\n    <string name=\"play_movie_button\">Daaro filinka</string>\n    <string name=\"play_trailer_button\">Daar goos-gooska</string>\n    <string name=\"subs_window_color\">Midabka daaqadda</string>\n    <string name=\"popup_delete_file\">Saar faylka</string>\n    <string name=\"popup_play_file\">Daar faylka</string>\n    <string name=\"play_livestream_button\">Si toos u daawo</string>\n    <string name=\"play_torrent_button\">Daalaco toorentiga</string>\n    <string name=\"pick_subtitle\">Qrl-hoosaadka</string>\n    <string name=\"popup_resume_download\">Dib u bilow dejinta</string>\n    <string name=\"subs_background_color\">Midabka dambeedka</string>\n    <string name=\"pick_source\">Xigashooyinka</string>\n    <string name=\"reload_error\">Dib u xidhiidhinaya…</string>\n    <string name=\"go_back\">Dib u noqo</string>\n    <string name=\"play_episode\">Xalqadda daaro</string>\n    <string name=\"download_paused\">Waad hakisey la degista</string>\n    <string name=\"download_done\">Way dhamaatay dejintu</string>\n    <string name=\"download_storage_text\">Kaydka gudaha</string>\n    <string name=\"app_dubbed_text\">Trj</string>\n    <string name=\"download_started\">Way bilaabmatay soo dejintu</string>\n    <string name=\"stream\">Daalaco</string>\n    <string name=\"download_canceled\">Waa la joojiyey dejintan</string>\n    <string name=\"update_started\">Way bilaabantay cuaboonaysiintu</string>\n    <string name=\"error_loading_links_toast\">Soo raridda lifaaqyadu way fashilantay</string>\n    <string name=\"app_subbed_text\">Qrl</string>\n    <string name=\"home_expanded_hide\">Qari</string>\n    <string name=\"home_info\">Warbixin</string>\n    <string name=\"home_more_info\">Warbixin dheeraad ah</string>\n    <string name=\"subtitles_settings\">Habaynta Qoraal-hoosaadka</string>\n    <string name=\"subs_outline_color\">Midabka lakabka sare</string>\n    <string name=\"home_play\">Daar</string>\n    <string name=\"filter_bookmarks\">Shaandhee caalamad-sanayaasha</string>\n    <string name=\"error_bookmarks_text\">Calaamad-sanayaasha</string>\n    <string name=\"action_add_to_bookmarks\">Xagee marinaysaa</string>\n    <string name=\"sort_save\">Kaydi</string>\n    <string name=\"player_speed\">Xawaaraha daaraha</string>\n    <string name=\"subs_font_size\">Xajmiga farta</string>\n    <string name=\"popup_pause_download\">Haki dejinta</string>\n    <string name=\"sort_apply\">Ka dhig</string>\n    <string name=\"subs_text_color\">Midabka farta</string>\n    <string name=\"subs_hold_to_reset_to_default\">Xeji si aad asalkiisa ugu soo celiso</string>\n    <string name=\"sort_copy\">Koobi/ka reeb</string>\n    <string name=\"sort_close\">Xidh</string>\n    <string name=\"sort_clear\">Tirtir</string>\n    <string name=\"subs_edge_type\">Nooca cidhifyada</string>\n    <string name=\"use_system_brightness_settings_des\">Isticmaal xaddiga iftiinka ee moobilkaaga halkii aad adigu habayn lahayd ugu horreynba</string>\n    <string name=\"category_updates\">Gurmadka iyo cusbooneysiinta</string>\n    <string name=\"restore_success\">Waa la kaydiyet xogta gurmadka</string>\n    <string name=\"advanced_search_des\">Raadinta waxay kuugu kala qaybinaysaa mid kasta iyo qaybiyihiisa</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Way fashilantay in xogta laga soo celiyo faylka gurmadka%s</string>\n    <string name=\"apk_installer_settings_des\">Moobillada qaar ayaa awoodin iney Rakibaha cusub een isticmaalnay, kan ku day haddii cusbooneysiintu kuu shaqayn weydo.</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"backup_success\">Xogta waa la kaydiyey</string>\n    <string name=\"status\">Heerka</string>\n    <string name=\"backup_failed\">Ogolaanshaha lagu kaydinayo ma hayno. Fadlan isku day mar kale.</string>\n    <string name=\"category_account\">Koontooyinka</string>\n    <string name=\"settings_info\">Xog</string>\n    <string name=\"automatic_plugin_download\">Si iskii ah usoo deji sidkanaha</string>\n    <string name=\"pref_filter_search_quality\">Qari tayada muqaalka aad dooratay natiijada waxa aad raadiso</string>\n    <string name=\"advanced_search\">Raadin heer-sare ah</string>\n    <string name=\"show_fillers_settings\">Xalqad buuxis ah tusi anemiga</string>\n    <string name=\"benene\">Dhiseyaasha appka sii beniin</string>\n    <string name=\"storage_error\">Way fashilantay dejintu, hubi ogolaanshaha isticmaalka kaydka</string>\n    <string name=\"episode_action_chromecast_episode\">Xalqadda koromakaastiga</string>\n    <string name=\"episode_action_download_subtitle\">Soo dejiso Qoraal-hoosaadyada</string>\n    <string name=\"show_hd\">Summadda Tayada</string>\n    <string name=\"episode_action_chromecast_mirror\">Humaagga-bixinta koromokaastiga</string>\n    <string name=\"pref_category_defaults\">Asalkiisa</string>\n    <string name=\"episode_action_play_in_app\">Isla appkan ku daawo</string>\n    <string name=\"episode_action_play_in_format\">Ku daawo %s</string>\n    <string name=\"episode_action_auto_download\">Dejinta iskeed ah</string>\n    <string name=\"episode_action_download_mirror\">Deji toorentiga(mirror)</string>\n    <string name=\"episode_action_reload_links\">Cusbooneysii lifaaqyada</string>\n    <string name=\"check_for_update\">Eeg iney jirto cusbooneysiin</string>\n    <string name=\"show_dub\">Summadda codeynta</string>\n    <string name=\"show_sub\">Sumadda Qrl-hoosaadka</string>\n    <string name=\"show_title\">Ciwaanka</string>\n    <string name=\"poster_ui_settings\">Maxaa ka muuqan doona boodhka filinka</string>\n    <string name=\"no_update_found\">Ma jiro wax ku cusub Appka</string>\n    <string name=\"video_lock\">Quful</string>\n    <string name=\"video_aspect_ratio_resize\">Cabbirka</string>\n    <string name=\"video_source\">isha</string>\n    <string name=\"video_skip_op\">Is dhaafi</string>\n    <string name=\"dont_show_again\">Mar dambe ha i tusin</string>\n    <string name=\"skip_update\">Is dhaafi</string>\n    <string name=\"update\">Cusbooneysii</string>\n    <string name=\"watch_quality_pref\">Tayada aad doorbiddo</string>\n    <string name=\"pref_category_player_layout\">Qaabka</string>\n    <string name=\"emulator_layout\">Qaab emulator</string>\n    <string name=\"random_button_settings_desc\">Waxa uu ku tusayaa badhin aad si xukasho la\\'aan ah ugu dooran kartid</string>\n    <string name=\"subs_subtitle_elevation\">Kor-u-baxa Qrl-hoosaadka</string>\n    <string name=\"subs_font\">Farta</string>\n    <string name=\"preview_background_img_des\">Muuq dambeedka</string>\n    <string name=\"search_provider_text_providers\">Ku raadi qaybiyeyaasha</string>\n    <string name=\"search_provider_text_types\">Ku raadi noocyada</string>\n    <string name=\"benene_count_text\">%d oo beniin ayaad siisey dhiseyaasha</string>\n    <string name=\"benene_count_text_none\">Wax beniin ah maad bixin</string>\n    <string name=\"subs_auto_select_language\">Iskeed-u-doorashada luuqadda</string>\n    <string name=\"subs_download_languages\">Luuqadda dejinta</string>\n    <string name=\"subs_subtitle_languages\">Luuqadda Qoraal-hoosaadka</string>\n    <string name=\"provider_info_meta\">Xogta muqaalkan ma bixinno, ma shaqayn doonto haddii aannu weyno xogta muqaalka.</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Dhig nooca farta aad dooneyso %s</string>\n    <string name=\"continue_watching\">Sii wado daawashada</string>\n    <string name=\"action_remove_watching\">Ka saar</string>\n    <string name=\"action_open_watching\">Xog dheeri ah</string>\n    <string name=\"kitsu_settings\">Tusi Boodhka Kitsu</string>\n    <string name=\"automatic_plugin_updates\">Si iskii ah u cusbooneysii sidkanaha</string>\n    <string name=\"automatic_plugin_download_summary\">Si iskii ah usoo deji dhamaan sidkanayaasha aan weli lasoo dejin ee ku jira kaydka aad keentay.</string>\n    <string name=\"updates_settings_des\">Marka ugu horreysa ee aad appka furto ayaad arkaysaa haddii wax cusub yihiin</string>\n    <string name=\"lightnovel\">Light novel app, isla dhiseyaasha appkan baa leh</string>\n    <string name=\"updates_settings\">Tus wixii appka ku cusub</string>\n    <string name=\"redo_setup_process\">Dib uso bilow fadhiisinta appka</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"apk_installer_settings\">Rakibaha APKga</string>\n    <string name=\"status_ongoing\">Socda</string>\n    <string name=\"github\">Github</string>\n    <string name=\"movies_singular\">Filin</string>\n    <string name=\"anim\">Anime app, isla dhiseyaashan appkan baa leh</string>\n    <string name=\"no_season\">Kal ma leh</string>\n    <string name=\"discord\">Discord naga soo qabo</string>\n    <string name=\"benene_des\">Beeniinyada aad bixisey</string>\n    <string name=\"app_language\">Luuqadda</string>\n    <string name=\"no_chromecast_support_toast\">Bixiyahan kuma shaqeeyo koromakaastiga</string>\n    <string name=\"subs_default_reset_toast\">Asalkiisii hore kusoo celi</string>\n    <string name=\"synopsis\">Dulucuda</string>\n    <string name=\"season\">Kalka</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"episode\">Xalqad</string>\n    <string name=\"episodes\">Xalqado</string>\n    <string name=\"episodes_range\">%1$d illaa %2$d</string>\n    <string name=\"season_short\">K</string>\n    <string name=\"episode_short\">X</string>\n    <string name=\"cartoons\">Kartoon</string>\n    <string name=\"asian_drama_singular\">Daraamada eeshiyaanka</string>\n    <string name=\"delete_file\">Tirtir faylka</string>\n    <string name=\"resume\">Sii wado</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"delete_message\" formatted=\"true\">Dhamaantii waa la saari doona %s\n\\nSow ma hubtid?</string>\n    <string name=\"source_error\">Fashil ka yimi xigashada</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%ddq\n\\nAyaa hadhsan</string>\n    <string name=\"status_completed\">Dhamaystirmay</string>\n    <string name=\"year\">Sannadka</string>\n    <string name=\"rating\">Qiimaynta</string>\n    <string name=\"duration\">Muddada</string>\n    <string name=\"used_storage\">La isticmaalay</string>\n    <string name=\"no_subtitles\">Qrl-hoosaad ma leh</string>\n    <string name=\"action_default\">Sidiisaa</string>\n    <string name=\"free_storage\">Bilaash</string>\n    <string name=\"app_storage\">Appka</string>\n    <string name=\"cartoons_singular\">Kartoob</string>\n    <string name=\"anime\">Anemi</string>\n    <string name=\"unexpected_error\">Daaraha ayaa ku fashilmay</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"torrent_singular\">Toorenti</string>\n    <string name=\"livestreams\">Tooska</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"asian_drama\">Daraamada Eeshiyaanka</string>\n    <string name=\"limit_title_rez\">Daaraha korkiisa</string>\n    <string name=\"video_buffer_size_settings\">kaydka kumeelgaadhka</string>\n    <string name=\"add_site_pref\">Ka reebo fadhigan</string>\n    <string name=\"others\">Kuwa kale</string>\n    <string name=\"tv_series_singular\">Taxane</string>\n    <string name=\"anime_singular\">Anemi</string>\n    <string name=\"documentaries_singular\">Dhokumentari</string>\n    <string name=\"torrent\">Toorentiyo</string>\n    <string name=\"documentaries\">Dhokumentariyo</string>\n    <string name=\"live_singular\">Toos</string>\n    <string name=\"nsfw_singular\">CEEB</string>\n    <string name=\"other_singular\">Kuwa kale</string>\n    <string name=\"remote_error\">Fashil fog</string>\n    <string name=\"dns_pref\">DNS ka horreysi HTTPS</string>\n    <string name=\"pref_category_app_updates\">Maxaa ku cusub appka</string>\n    <string name=\"pref_category_backup\">Gurmad</string>\n    <string name=\"pref_category_extensions\">Kordhiyeyaal</string>\n    <string name=\"pref_category_subtitles\">Qoraal-hoosaadyada</string>\n    <string name=\"pref_category_looks\">Muqaal</string>\n    <string name=\"swipe_to_change_settings\">Jiid si aad u habaysato</string>\n    <string name=\"vpn_might_be_needed\">Laga yaabaa inaad u baahato VPN si qaybiyahan kuugu shaqeeyo</string>\n    <string name=\"vpn_torrent\">Qaybiyahan waa toorenti, inaad VPN isticmaasho ayaa wanaagsan</string>\n    <string name=\"picture_in_picture_des\">Ka sii wado daawashada daaqad yar oo appska kale dul istaagi doonta</string>\n    <string name=\"swipe_to_seek_settings\">Jiid si aad u dhaafiso</string>\n    <string name=\"show_log_cat\">Eeg xogaha hoose 🐈</string>\n    <string name=\"player_size_settings\">Badhinka xajmiga daaraha</string>\n    <string name=\"render_error\">Fashil ka yimi dhiibaha</string>\n    <string name=\"torrent_no_plot\">Sharraxaad ma leh</string>\n    <string name=\"torrent_plot\">Sharraxaadda</string>\n    <string name=\"normal_no_plot\">Duluc ma leh</string>\n    <string name=\"picture_in_picture\">Sawir-daaqadlaha</string>\n    <string name=\"player_subtitles_settings_des\">Habaynta Qrl-hoosaadka daaraha</string>\n    <string name=\"chromecast_subtitles_settings\">Qrl-hoosaadka koromakaastiga</string>\n    <string name=\"player_size_settings_des\">Hareeraha madow ka saar markaad daawanayso</string>\n    <string name=\"player_subtitles_settings\">Qoraal-hoosaadka</string>\n    <string name=\"chromecast_subtitles_settings_des\">Habaynta Qrl-hoosaadka Koromakaastiga</string>\n    <string name=\"eigengraumode_settings\">Habka Xawaare-kordhinta</string>\n    <string name=\"swipe_to_seek_settings_des\">Midig iyo bidix u jiid si aad marba dhinac ugu dhaafiso muqaalka</string>\n    <string name=\"double_tap_to_seek_settings_des\">Laba jeer taabo midig ama bidix si aad u dhaafiso ama ku ceshato</string>\n    <string name=\"double_tap_to_seek_settings\">Laba jeer taabo si aad u dhaafiso</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Inta aad is dhaafinayso</string>\n    <string name=\"double_tap_to_pause_settings\">Laba jeer taabo si aad u qallajiso</string>\n    <string name=\"double_tap_to_pause_settings_des\">Dhexda taabo si aad u qallajisato</string>\n    <string name=\"backup_settings\">Gurmad u samee xogta</string>\n    <string name=\"use_system_brightness_settings\">Iftiinka moobilka istcimaal</string>\n    <string name=\"episode_sync_settings\">Cusbooneysii marba halkaad marayso daawashada</string>\n    <string name=\"show_trailers_settings\">Tus goos-gooska</string>\n    <string name=\"backup_failed_error_format\">Waa fashilmay kaydinta gurmadku %s</string>\n    <string name=\"restore_settings\">Kasoo celi Xogta gurmadka aad kaydsatay</string>\n    <string name=\"video_buffer_length_settings\">Dhererka K. kumeelgaadhka ah</string>\n    <string name=\"preferred_media_settings\">Noocyada muqaal eed doorbiddo</string>\n    <string name=\"tv_layout\">Qaab TV</string>\n    <string name=\"video_buffer_disk_settings\">Heerka Kayd-yaraha</string>\n    <string name=\"video_buffer_clear_settings\">Masax kayd yaraha sawirrada/muqaalka</string>\n    <string name=\"video_ram_description\">Laga yaaba inuu appku duqeeyo haddii aad badiso.</string>\n    <string name=\"video_disk_description\">Laga yaabaa inuu wax xumeeyo haddii aad badiso, weliba aaladaha qaadka yar, sida Androyd tiifiiga.</string>\n    <string name=\"dns_pref_summary\">Wuxuu muhiim u yahay inaad dhaafto Xannibaadaha ISPga</string>\n    <string name=\"remove_site_pref\">Ka saar fadhigan</string>\n    <string name=\"add_site_summary\">Ku dar ka-reeb fadhi hore u jirey, laakiin hayb cusub wata</string>\n    <string name=\"legal_notice\">Aaraar</string>\n    <string name=\"nginx_url_pref\">Haybta Seerfarka NGINX</string>\n    <string name=\"display_subbed_dubbed_settings\">Tusi Anemaha Turjuman/Leh Qrl-hoosaad</string>\n    <string name=\"pref_category_links\">Lifaaqyada</string>\n    <string name=\"download_path_pref\">Barta kaydka</string>\n    <string name=\"pref_category_ui_features\">Astaamaha</string>\n    <string name=\"random_button_settings\">Badhinka X. la\\'aanta</string>\n    <string name=\"category_providers\">Qaybiyeyaasha</string>\n    <string name=\"automatic\">Iskii</string>\n    <string name=\"phone_layout\">Qaab moobil</string>\n    <string name=\"pref_category_actions\">Falal</string>\n    <string name=\"pref_category_cache\">Kayd-yare</string>\n    <string name=\"pref_category_gestures\">Ishaarooyinka</string>\n    <string name=\"pref_category_player_features\">Astaamaha daaraha</string>\n    <string name=\"category_general\">Guud</string>\n    <string name=\"enable_nsfw_on_providers\">Tusi CEEBta qaybiyayaasha ku shaqeeya</string>\n    <string name=\"category_ui\">Qaabka</string>\n    <string name=\"primary_color_settings\">Midab asaaska</string>\n    <string name=\"subtitles_encoding\">Horidda Qoraal-hoosaadka</string>\n    <string name=\"app_theme_settings\">Nashqadda Appka</string>\n    <string name=\"bottom_title_settings\">Goobta Cinwaanka boodhka</string>\n    <string name=\"downloaded\">La degtay</string>\n    <string name=\"downloading\">Soo degaya</string>\n    <string name=\"action_remove_from_bookmarks\">Ka Saar</string>\n    <string name=\"swipe_to_change_settings_des\">Kor ama hoos u jiid labada dhinaca ee daaraha si aad u maamusho codka ama iftiinka</string>\n    <string name=\"autoplay_next_settings\">Iskii-u-daarka xalqadda xigta</string>\n    <string name=\"autoplay_next_settings_des\">Si iskii ah ayuu u daarayaa xalqadda xigta marka aad dhamaysato kaad daawanayso</string>\n    <string name=\"episode_sync_settings_des\">Si iskii ah ha ula socdo appku hadba xalqadda aad marayso</string>\n    <string name=\"no_links_found_toast\">Lifaaq lagama helin</string>\n    <string name=\"copy_link_toast\">Waad koobiyeysay lifaaqa</string>\n    <string name=\"play_episode_toast\">Daari xalqaddan</string>\n    <string name=\"no_episodes_found\">Xalqado ma leh</string>\n    <string name=\"site\">Wabsaydka</string>\n    <string name=\"movies\">Filimaan</string>\n    <string name=\"tv_series\">Taxanayaal</string>\n    <string name=\"nsfw\">CEEB</string>\n    <string name=\"limit_title\">Tirada inta ka muuqanaysa magaca filinka</string>\n    <string name=\"provider_lang_settings\">Luuqadda bixiyaha</string>\n    <string name=\"app_layout\">Qaabka Appka</string>\n    <string name=\"action_remove_from_watched\">Ka saar kuwa la daawaday</string>\n    <string name=\"view_public_repositories_button\">Eeg Kuwa Dadka kale Rakibeen</string>\n    <string name=\"audio_tracks\">Codad kale</string>\n    <string name=\"uppercase_all_subtitles\">Far weyn ka dhig Qrl-hoosaadka</string>\n    <string name=\"extension_description\">Sharraxaad</string>\n    <string name=\"extension_status\">Xaaladda</string>\n    <string name=\"extension_size\">Xajmiga</string>\n    <string name=\"safe_mode_title\">Safe mode ayaa daaran</string>\n    <string name=\"safe_mode_description\">Dhammaan Kordhiyeyaasha waa la wada demiyey cillad timi aawadeed si aad u ogaato ka cillada sababaya.</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (La xayiray)</string>\n    <string name=\"apply_on_restart\">Marka dambe eed gasho isticmaal</string>\n    <string name=\"safe_mode_crash_info\">Eeg warbixinra Cilladda</string>\n    <string name=\"extension_rating\" formatted=\"true\">Qiimeynta: %s</string>\n    <string name=\"extension_authors\">Lahaanshaha</string>\n    <string name=\"extension_version\">Qaybtii</string>\n    <string name=\"hls_playlist\">HLS playlist</string>\n    <string name=\"extension_types\">Ku shaqeeya</string>\n    <string name=\"extension_language\">Luuqadda</string>\n    <string name=\"extension_install_first\">Rakib kordhiyahan ugu horreyn</string>\n    <string name=\"player_pref\">Muqaal daaraha aad doorbiddo</string>\n    <string name=\"clear_history\">Masax taariikhda</string>\n    <string name=\"history\">Taariikhda</string>\n    <string name=\"skip_type_intro\">Furitaanka</string>\n    <string name=\"clipboard_too_large\">Qoraalku wuu dheeryahay. Ma koobi garayn kartid.</string>\n    <string name=\"yes\">Haa</string>\n    <string name=\"enable_skip_op_from_database_des\">Tusi badhin aad iska dhaafin karto bilowga/dhamaadka</string>\n    <string name=\"action_mark_as_watched\">Ku caalamadi in la daawaday</string>\n    <string name=\"update_notification_downloading\">Dejinaya cusbooneysiinta appka…</string>\n    <string name=\"confirm_exit_dialog\">Ma hubtaa inaad ka baxdid?</string>\n    <string name=\"no\">May</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"update_notification_installing\">Rakibaya cusbooneysiinta…</string>\n    <string name=\"update_notification_failed\">Waa la rakibi kari waayay qaybtan cusub ee appka</string>\n    <string name=\"apk_installer_legacy\">Lagama-maarmaanka</string>\n    <string name=\"delayed_update_notice\">Marka aad ka baxdo baa ka cusbooneysiin doona appka</string>\n    <string name=\"bottom_title_settings_des\">Dhig ciwaanka boodhka hoostiisa</string>\n    <string name=\"account\">Akoonka</string>\n    <string name=\"login\">Soo gal</string>\n    <string name=\"add_account\">Akoon geli</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s xaqiijisan</string>\n    <string name=\"example_email\">iiwarran@sxb.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_username\">MagacKaYaabAh</string>\n    <string name=\"logout\">Ka bax</string>\n    <string name=\"example_site_url\">Tusaale.com</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Waxa lagu daray %s</string>\n    <string name=\"none\">Midna</string>\n    <string name=\"example_site_name\">Websaydkayga.com</string>\n    <string name=\"example_lang_name\">Koodhka Luuqadda (en)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"create_account\">Akoon samee</string>\n    <string name=\"upload_sync\">Talantaalli</string>\n    <string name=\"sync_score\">Qiimaysan</string>\n    <string name=\"switch_account\">Beddel akoonka</string>\n    <string name=\"add_sync\">Ku dar raad-raace</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Waa lagu guuldarraystey inaad ku gasho %s</string>\n    <string name=\"normal\">Caadi</string>\n    <string name=\"max\">Ugu weyn</string>\n    <string name=\"min\">Ugu yar</string>\n    <string name=\"subtitles_depressed\">Hoos u degsan</string>\n    <string name=\"subtitles_outline\">Lakabka sare</string>\n    <string name=\"subtitle_offset\">Hagaaji Qrl-hosaadka</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Isticmaal intan haddii Qrl-hoosaadku ay %d ms soo habsaanayaan</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"go_back_img_des\">Dib u noqo</string>\n    <string name=\"subtitles_shadow\">Hadhka</string>\n    <string name=\"subtitles_raised\">Kor-u-qaadan</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Isticmaal intan haddii Qrl-hoosaadku ay %d ms soo hordhacayaan</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"actor_main\">Ka guud</string>\n    <string name=\"actor_supporting\">La jilaya</string>\n    <string name=\"subtitles_example_text\">Sheekheenna wiilkiisa curad, gabadhiisu foox la\\'aan ma heesi karto</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"recommended\">Lagugula taliyey</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Waxa laso kiciyey %s</string>\n    <string name=\"player_load_subtitles\">Faylashaada ka keen</string>\n    <string name=\"player_load_subtitles_online\">Internetka ka keen</string>\n    <string name=\"downloaded_file\">Waa ka dejiyey faylka</string>\n    <string name=\"actor_background\">Wajhadda dambe</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"category_player\">Daaraha</string>\n    <string name=\"title\">Ciwaanka</string>\n    <string name=\"subtitles_remove_captions\">Ka saar Qrl-hoosaadka asalka ah</string>\n    <string name=\"subtitles_remove_bloat\">Ka saar bararsanaanta Qrl-hoosaadka</string>\n    <string name=\"coming_soon\">Goor dhow…</string>\n    <string name=\"home_source\">Xigashada</string>\n    <string name=\"home_random\">Xulasho la\\'aan</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"poster_image\">Sawirka Boodhka</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"error_invalid_url\">Hayb aan sax ahayn</string>\n    <string name=\"resolution_and_title\">Tayada iyo ciwaanka</string>\n    <string name=\"resolution\">Tayada</string>\n    <string name=\"error_invalid_id\">Aqoonsi aan sax ahayn</string>\n    <string name=\"error_invalid_data\">Xog ana sax ahayn</string>\n    <string name=\"error\">Xumaaday</string>\n    <string name=\"video_tracks\">Noocyada Muqaalka</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Waxba kamaad bedelin daahitaanka Qrl-hoosaadka</string>\n    <string name=\"subtitles_filter_lang\">U kala hor sida luuqadaha aad doorbidday</string>\n    <string name=\"home_next_random_img_des\">X.la\\'aanta xigta</string>\n    <string name=\"plugin_singular\">Sidkane</string>\n    <string name=\"plugin\">Sidkanayaasha</string>\n    <string name=\"delete_repository\">Saar kayd-weynaha</string>\n    <string name=\"setup_extensions_subtext\">Dejiso liiska websaydyada aad dooneyso</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Waxa la dejiyey: %d</string>\n    <string name=\"batch_download\">Dejin xidhmeed</string>\n    <string name=\"delete_repository_plugins\">Waxa la saarayaa dhammaan sidkanayaasha kayd-weynaha</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Xayiran: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Aan dejinayn: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Waxa la cusbooneysiiyey %d sidkane</string>\n    <string name=\"blank_repo_message\">Ugu horreyn cloudstream ma laha wax websaydyo uu filimaanta kasoo xigto, waxay noqonaysaa inaad adigu rakibato reboositarradooda...\n\\n\n\\nSababtuna waa in mar dhexdaas ah na dacweeyeen shirkadda Sky UK Limited🤮, markaa si aan mar dambe taasi u dhicin anagu kuma rakibi karno...\n\\n\n\\nDiscord naga soo qabo ama internetka ka baadh.</string>\n    <string name=\"download_all_plugins_from_repo\">Soo deji dhamaan sidkanayaasha reboositarkan?</string>\n    <string name=\"result_poster_img_des\">Boodhka</string>\n    <string name=\"episode_poster_img_des\">Boodhka xalqadda</string>\n    <string name=\"home_main_poster_img_des\">Boodhka weyn</string>\n    <string name=\"example_password\">Lambarkasirta123</string>\n    <string name=\"subtitle_offset_title\">Dib-u-dhaca Qrl-hoosaadka</string>\n    <string name=\"extras\">Dheeraadka</string>\n    <string name=\"trailer\">Goo-gooska</string>\n    <string name=\"network_adress_example\">Lifaaqa daalacashada</string>\n    <string name=\"referer\">Tixraacaha</string>\n    <string name=\"next\">Xiga</string>\n    <string name=\"provider_languages_tip\">Ku daawo muuqaallada luuqadahan</string>\n    <string name=\"previous\">Kii hore</string>\n    <string name=\"skip_setup\">Is dhaafi fadhiisintan</string>\n    <string name=\"app_layout_subtext\">Beddel sida appku u muuqdo si uu ugu habboonaado moobilekaaga</string>\n    <string name=\"preferred_media_subtext\">Maxaad rabtaa inaad daawato</string>\n    <string name=\"setup_done\">Dhan</string>\n    <string name=\"add_repository\">Ku dar kayd-weyne</string>\n    <string name=\"repository_name_hint\">Magaca kayd-weynaha</string>\n    <string name=\"repository_url_hint\">Haybta kayd-weynaha</string>\n    <string name=\"plugin_loaded\">Waa la keenay sidkanaha</string>\n    <string name=\"plugin_downloaded\">Waa ka dejiyey sidkanaha</string>\n    <string name=\"plugin_deleted\">Waa la tiray sidkanahan</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Waa ka keeni kari waayey %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Waa la dejinayaa %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Waa la dejiyey %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Dhammaan %s way dejisan yihiin</string>\n    <string name=\"extensions\">Kordhiyeyaasha</string>\n    <string name=\"view_public_repositories_button_short\">Liiska bulshada kale</string>\n    <string name=\"player_settings_play_in_app\">Muqaal daaraha appka</string>\n    <string name=\"app_not_found_error\">Kuuguma jiro appkaasi</string>\n    <string name=\"all_languages_preference\">Dhammaan luuqadaha</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Is dhaafi %s</string>\n    <string name=\"skip_type_ed\">Dhamaadka</string>\n    <string name=\"skip_type_recap\">Soo koobidda</string>\n    <string name=\"skip_type_mixed_ed\">Dhamaad isku qasan</string>\n    <string name=\"skip_type_op\">Bilowga</string>\n    <string name=\"skip_type_mixed_op\">Bilow isku qasan</string>\n    <string name=\"skip_type_creddits\">Qoraalka dhamaadka</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"rated_format\">Betygsatt: %.1f</string>\n    <string name=\"player_speed_text_format\">Hastighet (%.2fx)</string>\n    <string name=\"new_update_format\">Ny uppdatering hittad!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Hem</string>\n    <string name=\"title_search\">Sök</string>\n    <string name=\"title_downloads\">Nerladdningar</string>\n    <string name=\"title_settings\">Instälningar</string>\n    <string name=\"search_hint\">Sök…</string>\n    <string name=\"search_poster_img_des\">Affisch</string>\n    <string name=\"no_data\">Ingen Data</string>\n    <string name=\"episode_more_options_des\">Mer Instälningar</string>\n    <string name=\"go_back_img_des\">Gå tillbaka</string>\n    <string name=\"next_episode\">Nästa avsnitt</string>\n    <string name=\"result_poster_img_des\">Affisch</string>\n    <string name=\"result_tags\">Genrer</string>\n    <string name=\"result_share\">Dela</string>\n    <string name=\"result_open_in_browser\">Öppna i webbläsaren</string>\n    <string name=\"skip_loading\">Hoppa över</string>\n    <string name=\"loading\">Laddar…</string>\n    <string name=\"type_watching\">Tittar på</string>\n    <string name=\"type_on_hold\">Pausad</string>\n    <string name=\"type_completed\">Avslutad</string>\n    <string name=\"type_dropped\">Släppt</string>\n    <string name=\"type_plan_to_watch\">Planerad</string>\n    <string name=\"play_movie_button\">Spela Upp</string>\n    <string name=\"play_torrent_button\">Strömma Torrent</string>\n    <string name=\"pick_source\">Källor</string>\n    <string name=\"pick_subtitle\">Undertexter</string>\n    <string name=\"reload_error\">Försök ansluta igen…</string>\n    <string name=\"go_back\">Gå tillbaka</string>\n    <string name=\"episode_poster_img_des\">@string/result_poster_img_des</string>\n    <string name=\"play_episode\">Spela avsnitt</string>\n    <string name=\"download\">Ladda ner</string>\n    <string name=\"download_storage_text\">Intern lagring</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">Radera fil</string>\n    <string name=\"popup_play_file\">Spela upp fil</string>\n    <string name=\"home_more_info\">Mer information</string>\n    <string name=\"home_expanded_hide\">Göm</string>\n    <string name=\"home_main_poster_img_des\">@string/result_poster_img_des</string>\n    <string name=\"home_play\">Spela upp</string>\n    <string name=\"home_info\">Info</string>\n    <string name=\"home_next_random_img_des\">Nästa slumpvis</string>\n    <string name=\"home_change_provider_img_des\">Byt leverantör</string>\n    <string name=\"filter_bookmarks\">Filtrera bokmärken</string>\n    <string name=\"error_bookmarks_text\">Bokmärken</string>\n    <string name=\"action_remove_from_bookmarks\">Ta bort</string>\n    <string name=\"sort_apply\">Tillämpa</string>\n    <string name=\"player_speed\">Spelarhastighet</string>\n    <string name=\"subtitles_settings\">Undertextinställningar</string>\n    <string name=\"subs_text_color\">Textfärg</string>\n    <string name=\"subs_outline_color\">Konturfärg</string>\n    <string name=\"subs_background_color\">Bakgrundsfärg</string>\n    <string name=\"subs_window_color\">Fönster färg</string>\n    <string name=\"subs_edge_type\">Kanttyp</string>\n    <string name=\"subs_subtitle_elevation\">Undertextens höjd</string>\n    <string name=\"preview_background_img_des\">Förhandsgranska bakgrund</string>\n    <string name=\"subs_font\">Font</string>\n    <string name=\"search_provider_text_providers\">Sök med hjälp av leverantörer</string>\n    <string name=\"search_provider_text_types\">Sök med hjälp av typer</string>\n    <string name=\"benene_count_text\">%d bananer donerade till utvecklarna</string>\n    <string name=\"benene_count_text_none\">Inga bananer givna</string>\n    <string name=\"subs_auto_select_language\">Välj språk automatiskt</string>\n    <string name=\"subs_download_languages\">Ladda ner språk</string>\n    <string name=\"subs_hold_to_reset_to_default\">Håll ned för att återställa till standardinställningen</string>\n    <string name=\"continue_watching\">Fortsätt titta</string>\n    <string name=\"action_remove_watching\">Ta bort</string>\n    <string name=\"action_open_watching\">Mer info</string>\n    <string name=\"vpn_might_be_needed\">En VPN kan behövas för att den här leverantören ska fungera korrekt</string>\n    <string name=\"vpn_torrent\">Denna leverantör är en torrent, en VPN rekommenderas</string>\n    <string name=\"torrent_plot\">Beskrivning</string>\n    <string name=\"normal_no_plot\">Ingen sammanfattning hittades</string>\n    <string name=\"torrent_no_plot\">Ingen beskrivning hittades</string>\n    <string name=\"picture_in_picture\">Bild-i-bild</string>\n    <string name=\"picture_in_picture_des\">Fortsätter uppspelning i en miniatyrspelare ovanpå andra appar</string>\n    <string name=\"player_size_settings\">Lägger till en knapp för att justera bildförhållandet</string>\n    <string name=\"player_size_settings_des\">Ta bort de svarta kanterna</string>\n    <string name=\"player_subtitles_settings\">Undertexter</string>\n    <string name=\"player_subtitles_settings_des\">Inställningar för undertexter</string>\n    <string name=\"eigengraumode_settings\">Uppspelningshastighet</string>\n    <string name=\"swipe_to_seek_settings\">Svep för att strya tiden</string>\n    <string name=\"swipe_to_seek_settings_des\">Svep åt vänster eller höger för att styra tiden i videospelaren</string>\n    <string name=\"swipe_to_change_settings\">Svep för att ändra inställningar</string>\n    <string name=\"swipe_to_change_settings_des\">Svep på vänster eller höger sida för att ändra ljusstyrka eller volym</string>\n    <string name=\"double_tap_to_seek_settings\">Dubbeltryck för att hoppa fram eller bak</string>\n    <string name=\"double_tap_to_seek_settings_des\">Tryck två gånger på höger eller vänster sida för att hoppa fram eller bak</string>\n    <string name=\"search\">Sök</string>\n    <string name=\"settings_info\">Information</string>\n    <string name=\"advanced_search\">Avancerade sökresultat</string>\n    <string name=\"advanced_search_des\">Presenterar sökresultaten i flera olika rader baserat på leverantören</string>\n    <string name=\"updates_settings\">Visa appuppdateringar</string>\n    <string name=\"updates_settings_des\">Sök automatiskt efter nya uppdateringar vid start.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Lightnovel app av samma utvecklare</string>\n    <string name=\"anim\">Anime app av samma utvecklare</string>\n    <string name=\"discord\">Gå med i Discord-gruppen</string>\n    <string name=\"benene\">Ge en banan till utvecklarna</string>\n    <string name=\"benene_des\">Ge banan</string>\n    <string name=\"app_language\">Språk</string>\n    <string name=\"no_chromecast_support_toast\">Denna leverantör har inget Chromecast-stöd</string>\n    <string name=\"no_links_found_toast\">Inga länkar hittades</string>\n    <string name=\"copy_link_toast\">Länken kopierades till urklipp</string>\n    <string name=\"play_episode_toast\">Spela upp avsnitt</string>\n    <string name=\"subs_default_reset_toast\">Återställd till standardvärdet</string>\n    <string name=\"error_loading_links_toast\">Fel uppstod vid laddning av länkarna</string>\n    <string name=\"season\">Säsong</string>\n    <string name=\"no_season\">Ingen Säsong</string>\n    <string name=\"episode\">Avsnitt</string>\n    <string name=\"episodes\">Avsnitt</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">A</string>\n    <string name=\"delete_file\">Ta bort nerladdad fil</string>\n    <string name=\"delete\">Ta bort</string>\n    <string name=\"cancel\">Avbryt</string>\n    <string name=\"delete_message\">%s kommer att raderas permanent\n\\nÄr du helt säker?</string>\n    <string name=\"status_ongoing\">Pågående</string>\n    <string name=\"status_completed\">Färdig</string>\n    <string name=\"status\">Status</string>\n    <string name=\"year\">Publicerad</string>\n    <string name=\"rating\">Betyg</string>\n    <string name=\"duration\">Längd</string>\n    <string name=\"site\">Sida</string>\n    <string name=\"synopsis\">Sammanfattning</string>\n    <string name=\"queued\">på kö</string>\n    <string name=\"no_subtitles\">Inga undertexter</string>\n    <string name=\"action_default\">Standard</string>\n    <string name=\"free_storage\">Tillgängligt</string>\n    <string name=\"used_storage\">Använt</string>\n    <string name=\"app_storage\">App</string>\n    <string name=\"movies\">Filmer</string>\n    <string name=\"tv_series\">Tv Serier</string>\n    <string name=\"cartoons\">Cartoons</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrent</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecasta ett Avsnitt</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecasta en Länk</string>\n    <string name=\"episode_action_play_in_app\">Spela upp i appen</string>\n    <string name=\"episode_action_play_in_format\">Spela upp i %s</string>\n    <string name=\"episode_action_auto_download\">Automatisk nerladdning</string>\n    <string name=\"episode_action_download_mirror\">Ladda ner en specifik länk</string>\n    <string name=\"episode_action_reload_links\">Ladda om alla länkar</string>\n    <string name=\"no_update_found\">Ingen uppdatering hittad</string>\n    <string name=\"check_for_update\">Sök efter uppdatering</string>\n    <string name=\"video_lock\">Skärmlås</string>\n    <string name=\"video_aspect_ratio_resize\">Bildförhållande</string>\n    <string name=\"video_source\">Källa</string>\n    <string name=\"video_skip_op\">Hoppa över OP</string>\n    <string name=\"dont_show_again\">Visa inte igen</string>\n    <string name=\"update\">Uppdatera</string>\n    <string name=\"download_started\">Nedladdning startade</string>\n    <string name=\"download_failed\">Nerladdning misslyckades</string>\n    <string name=\"downloaded\">Nerladdad</string>\n    <string name=\"downloading\">Laddar ner</string>\n    <string name=\"download_paused\">Nerladdning pausad</string>\n    <string name=\"download_canceled\">Nerladdning avbruten</string>\n    <string name=\"download_done\">Nerladdning färdig</string>\n    <string name=\"popup_resume_download\">Återuppta nedladdning</string>\n    <string name=\"popup_pause_download\">Pausa nerladdning</string>\n    <string name=\"pause\">Pausa</string>\n    <string name=\"resume\">Återuppta</string>\n    <string name=\"storage_error\">Ett nerladdningsfel uppstod, kolla om appen har lagringsbehörigheter</string>\n    <string name=\"watch_quality_pref\">Föredragen videokvalitet (WiFi)</string>\n    <string name=\"category_general\">Allmänna Inställningar</string>\n    <string name=\"subs_font_size\">Fontstorlek</string>\n    <string name=\"use_system_brightness_settings\">Använd system ljusstyrka</string>\n    <string name=\"use_system_brightness_settings_des\">Använder systemets ljusstyrka instället för en svart överlaga</string>\n    <string name=\"show_fillers_settings\">Visa filler avsnitt för anime</string>\n    <string name=\"display_subbed_dubbed_settings\">Visa dubbad/undertextad anime</string>\n    <string name=\"resize_fit\">Anpassa till skärmstorlek</string>\n    <string name=\"provider_lang_settings\">Tilläggsspråk</string>\n    <string name=\"resize_fill\">Utsträckt</string>\n    <string name=\"resize_zoom\">Inzoomad</string>\n    <string name=\"unexpected_error\">Oförväntat uppspelingsfel</string>\n    <string name=\"source_error\">Källfel</string>\n    <string name=\"remote_error\">Fjärrfel</string>\n    <string name=\"render_error\">Renderingsfel</string>\n    <string name=\"subtitles_example_text\">Flygande bäckasiner söka hwila på mjuka tuvor</string>\n    <string name=\"subtitles_shadow\">Skugga</string>\n    <string name=\"subtitles_outline\">Kontur</string>\n    <string name=\"subtitles_depressed\">Nedsänkt</string>\n    <string name=\"subtitles_raised\">Upphöjd</string>\n    <string name=\"none\">Ingen</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">Allt</string>\n    <string name=\"max\">Min</string>\n    <string name=\"min\">Max</string>\n    <string name=\"add_account\">Lägg till konto</string>\n    <string name=\"switch_account\">Byt konto</string>\n    <string name=\"login\">Logga in</string>\n    <string name=\"logout\">Logga ut</string>\n    <string name=\"account\">konto</string>\n    <string name=\"download_path_pref\">Nerladdningsplats</string>\n    <string name=\"type_re_watching\">Ser om</string>\n    <string name=\"automatic\">Automatisk</string>\n    <string name=\"dns_pref\">DNS över HTTPS</string>\n    <string name=\"dns_pref_summary\">\" \"</string>\n    <string name=\"app_theme_settings\">Appens tema</string>\n    <string name=\"app_dub_sub_episode_text_format\">%1$s A%2$d</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"play_with_app_name\">Spela med CloudStream</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast-undertexter</string>\n    <string name=\"double_tap_to_pause_settings_des\">Dubbeltryck i mitten för att pausa</string>\n    <string name=\"restore_settings\">Återställ data från backup</string>\n    <string name=\"category_account\">Konton och säkerhet</string>\n    <string name=\"category_updates\">Uppdateringar och säkerhetskopiering</string>\n    <string name=\"automatic_plugin_updates\">Automatiska pluginuppdateringar</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Sök %s…</string>\n    <string name=\"sort_copy\">Kopiera</string>\n    <string name=\"sort_close\">Stäng</string>\n    <string name=\"double_tap_to_pause_settings\">Dubbeltryck för att pausa</string>\n    <string name=\"sort_save\">Spara</string>\n    <string name=\"subs_subtitle_languages\">Undertextspråk</string>\n    <string name=\"show_log_cat\">Visa Logcat 🐈</string>\n    <string name=\"autoplay_next_settings\">Autospela nästa episod</string>\n    <string name=\"play_trailer_button\">Spela Trailer</string>\n    <string name=\"autoplay_next_settings_des\">Starta nästa episod när nuvarande slutar</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episod %d kommer att släppas om</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"show_trailers_settings\">Visa trailers</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nåterstår</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"provider_info_meta\">Metadata är inte givet av sidan, videon kommer inte ladda om den inte existerar på sidan.</string>\n    <string name=\"automatic_plugin_download\">Automatiskt ladda ner plugin</string>\n    <string name=\"pref_filter_search_quality\">Dölj vald videokvalitet i sökresultat</string>\n    <string name=\"episode_action_download_subtitle\">Ladda ner undertexter</string>\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Serier</string>\n    <string name=\"skip_update\">Skippa denna uppdatering</string>\n    <string name=\"backup_failed\">Lagringsbehörigheter saknas. Var vänlig försök igen.</string>\n    <string name=\"no_episodes_found\">Inga episoder hittade</string>\n    <string name=\"kitsu_settings\">Visa bilder från Kitsu</string>\n    <string name=\"apk_installer_settings_des\">Vissa enheter stöjder inte den nya paketinstallatören. Prova alternativet för äldre versioner om uppdateringarna inte installeras.</string>\n    <string name=\"apk_installer_settings\">APK-installatör</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importera typsnitt genom att placera filerna i %s</string>\n    <string name=\"episode_sync_settings_des\">Automatiskt uppdatera antalet episoder sedda</string>\n    <string name=\"backup_settings\">Säkerhetskopiera data</string>\n    <string name=\"restore_success\">Läste in säkerhetskopia</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Misslyckades att återställa data från %s</string>\n    <string name=\"backup_success\">Data lagrad</string>\n    <string name=\"backup_failed_error_format\">Problem att säkerhetskopiera %s</string>\n    <string name=\"automatic_plugin_download_summary\">Installera automatiskt alla ännu inte installerade plugins från tillagda repositories.</string>\n    <string name=\"redo_setup_process\">Gör om installationsprocessen</string>\n    <string name=\"documentaries\">Dokumentärer</string>\n    <string name=\"asian_drama\">Asiatiska draman</string>\n    <string name=\"others\">Andra</string>\n    <string name=\"cartoons_singular\">Tecknade serier</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"documentaries_singular\">Dokumentär</string>\n    <string name=\"asian_drama_singular\">Asiatisk drama</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"show_hd\">Kvalitetsetikett</string>\n    <string name=\"show_title\">Titel</string>\n    <string name=\"poster_ui_settings\">Växla UI-element på affisch</string>\n    <string name=\"limit_title_rez\">Visa videospelarens information</string>\n    <string name=\"history\">Historik</string>\n    <string name=\"action_mark_as_watched\">Markera som sedd</string>\n    <string name=\"chromecast_subtitles_settings_des\">Inställningar för Chromecast-undertexter</string>\n    <string name=\"tv_layout\">TV-layout</string>\n    <string name=\"create_account\">Skapa konto</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Använd detta om undertexterna visas %d ms för tidigt</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"resolution_and_title\">Upplösning och titel</string>\n    <string name=\"error\">Fel</string>\n    <string name=\"referer\">Referent (valfritt)</string>\n    <string name=\"next\">Nästa</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"add_site_summary\">Lägga till en klon av en befintlig webbplats med en annan webbadress</string>\n    <string name=\"error_invalid_id\">Ogiltigt ID</string>\n    <string name=\"error_invalid_url\">Ogiltig webbadress</string>\n    <string name=\"video_ram_description\">Orsakar krascher om inställningen är för hög på enheter med lågt minne, t.ex. Android TV.</string>\n    <string name=\"video_disk_description\">Orsakar problem om inställningen är för hög på enheter med lågt lagringsutrymme, t.ex. Android TV.</string>\n    <string name=\"remove_site_pref\">Ta bort webbplats</string>\n    <string name=\"add_site_pref\">Klona webbplats</string>\n    <string name=\"phone_layout\">Telefonlayout</string>\n    <string name=\"primary_color_settings\">Primärfärg</string>\n    <string name=\"example_username\">Användarnamn</string>\n    <string name=\"example_email\">namn@email.se</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"home_source\">Källa</string>\n    <string name=\"home_random\">Slumpmässig</string>\n    <string name=\"coming_soon\">Kommer snart…</string>\n    <string name=\"subtitles_filter_lang\">Filtrera efter föredraget språk</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Kunde inte logga in på %s</string>\n    <string name=\"pref_category_looks\">Utseende</string>\n    <string name=\"category_ui\">Layout</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"app_layout_subtext\">Ändra appens utseende så att den passar din enhet</string>\n    <string name=\"cast_format\" formatted=\"true\">Skådespelare: %s</string>\n    <string name=\"play_livestream_button\">Spela Livestream</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Ingen undertextfördröjning</string>\n    <string name=\"pref_category_player_features\">Spelarfunktioner</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"app_layout\">Applayout</string>\n    <string name=\"pref_category_ui_features\">Funktioner</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">Språkkod (en)</string>\n    <string name=\"video_buffer_disk_settings\">Videocache på disken</string>\n    <string name=\"video_buffer_clear_settings\">Rensa video- och bildcache</string>\n    <string name=\"pref_category_links\">Länkar</string>\n    <string name=\"pref_category_app_updates\">Appuppdateringar</string>\n    <string name=\"pref_category_player_layout\">Layout</string>\n    <string name=\"title\">Titel</string>\n    <string name=\"skip_setup\">Hoppa över installationen</string>\n    <string name=\"setup_done\">Klar</string>\n    <string name=\"extensions\">Tillägg</string>\n    <string name=\"sort_clear\">Rensa</string>\n    <string name=\"live_singular\">Direktsändning</string>\n    <string name=\"limit_title\">Max tecken i videospelartiteln</string>\n    <string name=\"video_buffer_size_settings\">Videobuffertstorlek</string>\n    <string name=\"video_buffer_length_settings\">Videobuffertlängd</string>\n    <string name=\"legal_notice\">Ansvarsfriskrivning</string>\n    <string name=\"pref_category_extensions\">Tillägg</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_backup\">Säkerhetskopiering</string>\n    <string name=\"pref_category_subtitles\">Undertexter</string>\n    <string name=\"enable_nsfw_on_providers\">Aktivera NSFW på tillägg som stöds</string>\n    <string name=\"subtitles_encoding\">Undertextkodning</string>\n    <string name=\"example_password\">lösenord123</string>\n    <string name=\"subtitle_offset_title\">Fördröjning av undertexter</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Använd detta om undertexterna visas %d ms för sent</string>\n    <string name=\"player_load_subtitles\">Importera från fil</string>\n    <string name=\"player_load_subtitles_online\">Importera från Internet</string>\n    <string name=\"downloaded_file\">Nedladdad fil</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"resolution\">Upplösning</string>\n    <string name=\"error_invalid_data\">Ogiltig data</string>\n    <string name=\"subtitles_remove_captions\">Ta bort dold textning från undertexter</string>\n    <string name=\"provider_languages_tip\">Titta på videor på dessa språk</string>\n    <string name=\"previous\">Föregående</string>\n    <string name=\"tracks\">Spår</string>\n    <string name=\"update_started\">Uppdatering startad</string>\n    <string name=\"test_log\">Logg</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Videospelarens hoppsträcka (Sekunder)</string>\n    <string name=\"action_add_to_bookmarks\">Ange visningsstatus</string>\n    <string name=\"browser\">Webbläsare</string>\n    <string name=\"nginx_url_pref\">NGINX server URL</string>\n    <string name=\"emulator_layout\">Emulator-layout</string>\n    <string name=\"confirm_exit_dialog\">Är du säker på att du vill avsluta?</string>\n    <string name=\"update_notification_downloading\">Laddar ner uppdatering till appen…</string>\n    <string name=\"random_button_settings\">Slumpknapp</string>\n    <string name=\"show_sub\">Visa sub</string>\n    <string name=\"app_not_found_error\">Kunde inte öppna appen</string>\n    <string name=\"jsdelivr_proxy\">GitHub Proxy</string>\n    <string name=\"update_notification_installing\">Installerar uppdatering till appen…</string>\n    <string name=\"jsdelivr_enabled\">Kunde inte nå GitHub, sätter på jsDelivr proxy…</string>\n    <string name=\"category_providers\">Leverantörer</string>\n    <string name=\"example_site_name\">Nytt webbplatsnamn</string>\n    <string name=\"subtitles_remove_bloat\">Ta bort reklam från undertexter</string>\n    <string name=\"all_languages_preference\">Alla språk</string>\n    <string name=\"clear_history\">Rensa historik</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"library\">Bibliotek</string>\n    <string name=\"pref_category_defaults\">Standardvärden</string>\n    <string name=\"delayed_update_notice\">Appen kommer uppdateras efter avslut</string>\n    <string name=\"sort_by\">Sortera efter</string>\n    <string name=\"sort_rating_asc\">Betyg (Låg till Hög)</string>\n    <string name=\"sort_updated_new\">Senast uppdaterad (Ny till Gammal)</string>\n    <string name=\"sort_updated_old\">Senast uppdaterad (Gammal till Ny)</string>\n    <string name=\"sort_alphabetical_a\">Alfabetisk (A till Z)</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"test_passed\">Lyckades</string>\n    <string name=\"restart\">Starta om</string>\n    <string name=\"category_provider_test\">Testa leverantörer</string>\n    <string name=\"watch_quality_pref_data\">Föredragen videokvalitet (Mobildata)</string>\n    <string name=\"random_button_settings_desc\">Visa slumpmässig knapp på förstasidan och biblioteket</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"audio_tracks\">Ljudspår</string>\n    <string name=\"livestreams\">Direktsändningar</string>\n    <string name=\"category_player\">Videospelare</string>\n    <string name=\"open_with\">Öppna med</string>\n    <string name=\"subtitle_offset\">Synkronisera undertexter</string>\n    <string name=\"test_failed\">Misslyckades</string>\n    <string name=\"yes\">Ja</string>\n    <string name=\"video_tracks\">Videospår</string>\n    <string name=\"show_dub\">Visa dub</string>\n    <string name=\"apk_installer_legacy\">Gammal version</string>\n    <string name=\"uppercase_all_subtitles\">Undertexter skrivs med versaler</string>\n    <string name=\"no\">Nej</string>\n    <string name=\"profile_number\">Profil %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Mobildata</string>\n    <string name=\"use\">Använd</string>\n    <string name=\"edit\">Ändra</string>\n    <string name=\"recommended\">Rekommenderade</string>\n    <string name=\"sort\">Sortera</string>\n    <string name=\"update_notification_failed\">Kunde inte installera den nya uppdateringen</string>\n    <string name=\"sort_rating_desc\">Betyg (Hög till Låg)</string>\n    <string name=\"sort_alphabetical_z\">Alfabetisk (Z till A)</string>\n    <string name=\"profiles\">Profiler</string>\n    <string name=\"help\">Hjälp</string>\n    <string name=\"qualities\">Kvalitet</string>\n    <string name=\"stream\">Nätverksflöde</string>\n    <string name=\"repository_name_hint\">Databasens namn (valfritt)</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">All %s har redan laddats ner</string>\n    <string name=\"download_all_plugins_from_repo\">Varning: CloudStream tar inget ansvar för att använda tredjepartstillägg och ger inget stöd för dem!</string>\n    <string name=\"safe_mode_title\">Felsäkert läge på</string>\n    <string name=\"apply_on_restart\">Starta om appen för att se ändringar.</string>\n    <string name=\"player_settings_play_in_app\">Intern spelare</string>\n    <string name=\"quality_cam_hd\">Kamera HD</string>\n    <string name=\"plugin_downloaded\">Tillägg nedladdad</string>\n    <string name=\"repository_url_hint\">Lager URL eller Shortcode</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Börjat hämta %1$d %2$s…</string>\n    <string name=\"bottom_title_settings\">Affisch titel plats</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Laddat %s</string>\n    <string name=\"actor_main\">Huvudsaklig</string>\n    <string name=\"actor_supporting\">Stödjande</string>\n    <string name=\"actor_background\">Bakgrund</string>\n    <string name=\"view_public_repositories_button_short\">Offentlig lista</string>\n    <string name=\"extension_language\">Språk</string>\n    <string name=\"extension_install_first\">Installera tillägget först</string>\n    <string name=\"player_pref\">Önskad videospelare</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Spelare visas - Sök förlopp</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Sök förlopp som används när spelaren är synlig</string>\n    <string name=\"start\">Starta</string>\n    <string name=\"stop\">Stopp</string>\n    <string name=\"revert\">Återställ</string>\n    <string name=\"subscription_deleted\">Avslutat prenumerationen på %s</string>\n    <string name=\"subscription_episode_released\">Avsnitt %d släppt!</string>\n    <string name=\"empty_library_logged_in_message\">Den här listan är tom. Försök byta till en annan.</string>\n    <string name=\"plugin_deleted\">Tillägg borttagen</string>\n    <string name=\"plugin_loaded\">Tillägg laddad</string>\n    <string name=\"plugin_singular\">Tillägg</string>\n    <string name=\"backup_frequency\">Säkerhetskopierings antal</string>\n    <string name=\"episode_sync_settings\">Uppdatera visnings förlopp</string>\n    <string name=\"automatic_plugin_download_mode_title\">Välj läge för att filtrera nedladdning av plugins</string>\n    <string name=\"extension_version\">Utgåva</string>\n    <string name=\"extension_status\">Status</string>\n    <string name=\"enter_pin\">Ange PIN-kod</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Ange PIN-kod för %s</string>\n    <string name=\"enter_current_pin\">Ange aktuell PIN-kod</string>\n    <string name=\"lock_profile\">Lås profil</string>\n    <string name=\"pin_error_incorrect\">Felaktig PIN-kod. Försök igen.</string>\n    <string name=\"pin_error_length\">PIN-koden måste vara fyra tecken</string>\n    <string name=\"select_an_account\">Välj ett konto</string>\n    <string name=\"manage_accounts\">Hantera konton</string>\n    <string name=\"edit_account\">Redigera konto</string>\n    <string name=\"logged_account\" formatted=\"true\">Loggat in som %s</string>\n    <string name=\"skip_startup_account_select_pref\">Hoppa över val av konto vid start</string>\n    <string name=\"jsdelivr_proxy_summary\">Gå förbi blockering av rå GitHub-URL:er med jsDelivr. Kan göra att uppdateringar försenas med några dagar.</string>\n    <string name=\"pref_category_actions\">Funktion</string>\n    <string name=\"preferred_media_settings\">Önskad media</string>\n    <string name=\"bottom_title_settings_des\">Lägg titeln under affischen</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Tillagt %s</string>\n    <string name=\"add_sync\">Lägg till spårning</string>\n    <string name=\"sync_score\">Betygsatt</string>\n    <string name=\"disable\">Inaktivera</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Affischbild</string>\n    <string name=\"preferred_media_subtext\">Vad vill du se</string>\n    <string name=\"add_repository\">Lägg till tillägg</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Uppdaterade %d tillägg</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Nedladdat %1$d %2$s</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Inaktiverad: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Ej hämtad: %d</string>\n    <string name=\"view_public_repositories_button\">Visa community databaser</string>\n    <string name=\"skip_type_mixed_op\">Blandad inledning</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Skippa %s</string>\n    <string name=\"blank_repo_message\">CloudStream har inga webbplatser installerade som standard. Du måste installera webbplatser från arkiv.\n\\n\n\\nGå med i vår Discord eller sök online.</string>\n    <string name=\"select_library\">Välj bibliotek</string>\n    <string name=\"empty_library_no_accounts_message\">Ditt bibliotek är tomt :(\n\\nLogga in på ett bibliotekskonto eller lägg till program i ditt lokala bibliotek.</string>\n    <string name=\"enable_skip_op_from_database_des\">Visa hoppa över popups för introduktion/eftertexter</string>\n    <string name=\"action_remove_from_watched\">Ta bort från sett</string>\n    <string name=\"safe_mode_file\">Fil i säkertläge hittades!\n\\nLaddar inte några tillägg vid start tills filen har tagits bort.</string>\n    <string name=\"subscription_in_progress_notification\">Uppdaterar prenumererade program</string>\n    <string name=\"subscription_list_name\">Prenumererad</string>\n    <string name=\"action_subscribe\">Prenumerera</string>\n    <string name=\"unable_to_inflate\">UI kunde inte skapas korrekt, detta är en MASSIV BUG och bör rapporteras omedelbart %s</string>\n    <string name=\"already_voted\">Du har redan röstat</string>\n    <string name=\"action_unsubscribe\">Avprenumerera</string>\n    <string name=\"action_add_to_favorites\">Lägg till i favoriter</string>\n    <string name=\"duplicate_add\">Lägg till</string>\n    <string name=\"duplicate_title\">Potentiell Dublett Hittad</string>\n    <string name=\"action_remove_from_favorites\">Ta bort från favoriter</string>\n    <string name=\"duplicate_replace\">Ersätt</string>\n    <string name=\"duplicate_replace_all\">Ersätt alla</string>\n    <string name=\"filler\" formatted=\"true\">Filler</string>\n    <string name=\"pref_category_bypass\">Förbikoppla ISP</string>\n    <string name=\"quality_cam_rip\">Kamera</string>\n    <string name=\"quality_cam\">Kamera</string>\n    <string name=\"safe_mode_description\">Alla tillägg stängdes av på grund av en krasch för att hjälpa dig hitta det tillägget som orsakar problem.</string>\n    <string name=\"extension_size\">Storlek</string>\n    <string name=\"extension_authors\">Författarna</string>\n    <string name=\"extension_types\">Stödd</string>\n    <string name=\"no_plugins_found_error\">Inga tillägg hittades i databasen</string>\n    <string name=\"no_repository_found_error\">Databasen hittades inte, kontrollera URL:n och prova VPN</string>\n    <string name=\"batch_download\">Flerfils nedladdning</string>\n    <string name=\"plugin\">Tillägg</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Hämtat: %d</string>\n    <string name=\"extension_rating\" formatted=\"true\">Betyg: %s</string>\n    <string name=\"clipboard_too_large\">För mycket text. Det gick inte att spara till urklipp.</string>\n    <string name=\"quality_hq\">Hög kvalite</string>\n    <string name=\"upload_sync\">Synka</string>\n    <string name=\"skip_type_ed\">Slutet</string>\n    <string name=\"skip_type_mixed_ed\">Blandad avslut</string>\n    <string name=\"subscription_new\">Prenumererar på %s</string>\n    <string name=\"safe_mode_crash_info\">Visa krasch info</string>\n    <string name=\"hls_playlist\">HLS spellista</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Kunde inte ladda %s</string>\n    <string name=\"skip_type_op\">Inledning</string>\n    <string name=\"skip_type_recap\">Sammanfattning</string>\n    <string name=\"pref_category_gestures\">Gester</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s autentiserad</string>\n    <string name=\"extras\">Statister</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"delete_repository\">Radera databasen</string>\n    <string name=\"profile_background_des\">Profil bakgrund</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"auto_rotate_video\">Auto rotera</string>\n    <string name=\"rotate_video\">Rotera</string>\n    <string name=\"rotate_video_desc\">Visa en växlingsknapp för skärmorientering</string>\n    <string name=\"auto_rotate_video_desc\">Aktivera automatisk växling av skärmorientering baserat på videoorientering</string>\n    <string name=\"links_reloaded_toast\">Länkar omladdade</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Spelare dold - Sökförlopp</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"delete_repository_plugins\">Detta kommer också att ta bort alla tillägg för databasen</string>\n    <string name=\"setup_extensions_subtext\">Ladda ner listan över webbplatser du vill använda</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Inaktiverad)</string>\n    <string name=\"extension_description\">Beskrivning</string>\n    <string name=\"skip_type_creddits\">Eftertexter</string>\n    <string name=\"skip_type_intro\">Introduktion</string>\n    <string name=\"favorites_list_name\">Favoriter</string>\n    <string name=\"set_default\">Ange standard</string>\n    <string name=\"favorite_removed\">%s togs bort från favoriter</string>\n    <string name=\"favorite_added\">%s har lagts till i favoriter</string>\n    <string name=\"use_default_account\">Använd standard konto</string>\n    <string name=\"pin\">PIN-kod</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Sök mängden som används när spelaren är dold</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Det verkar som om ett potentiellt duplicerat objekt redan finns i ditt bibliotek:\n\\n\n\\n\\'%s.\\'\n\\n\n\\nVill du lägga till det här objektet ändå, ersätta det befintliga eller avbryta åtgärden?</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Det verkar som om ett potentiellt duplicerat objekt redan finns i ditt bibliotek: \\'%s.\\'\n\\n\n\\nVill du lägga till det här objektet ändå, ersätta det befintliga eller avbryta åtgärden?</string>\n    <string name=\"quality_profile_help\">Här kan du ändra hur källorna ska sorteras, om en video har högre prioritet visas den högre upp i källvalet. Summan av källprioriteten och kvalitetsprioriteten är videoprioriteten.\n\\n\n\\nKälla A: 3\n\\nKvalitet B: 7\n\\nKommer att ha en kombinerad videoprioritet på 10.\n\\n\n\\nOBS: Om summan är 10 eller mer kommer spelaren automatiskt att hoppa över laddningen när den länken laddas!</string>\n    <string name=\"subscribe_tooltip\">Avisering om nytt avsnitt</string>\n    <string name=\"result_search_tooltip\">Sök i andra tillägg</string>\n    <string name=\"recommendations_tooltip\">Visa rekommendationer</string>\n    <string name=\"speed_setting_summary\">Lägger till ett hastighetsalternativ i spelaren</string>\n    <string name=\"test_extensions\">Testa alla tillägg</string>\n    <string name=\"test_extensions_summary\">Detta test är endast avsett för utvecklare och verifierar eller förnekar inte att någon tillägg fungerar.</string>\n    <string name=\"biometric_setting\">Lås med biometrik</string>\n    <string name=\"password_pin_authentication_title\">Lösenord/PIN autentisering</string>\n    <string name=\"biometric_setting_summary\">Lås upp appen med Fingerprint, Face ID, PIN, mönster eller lösenord.</string>\n    <string name=\"biometric_authentication_title\">Lås upp CloudStream</string>\n    <string name=\"biometric_unsupported\">Biometrisk autentisering stöds inte på den här enheten</string>\n    <string name=\"biometric_prompt_description\">Efter några misslyckade försök stängs prompten. Starta bara om appen för att försöka igen.</string>\n    <string name=\"favorite\">Favorit</string>\n    <string name=\"unfavorite\">Ta bort från favoriter</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nkvarstår</string>\n    <string name=\"toast_copied\">kopierad!</string>\n    <string name=\"repo_copy_label\">Lagringsnamn och URL</string>\n    <string name=\"battery_dialog_message\">För att säkerställa oavbrutna nedladdningar och aviseringar för prenumererade tv-program behöver CloudStream tillstånd att köras i bakgrunden. Genom att trycka på OK kommer du få en förfrågningsdialogruta. Tryck då på \\'Tillåt\\'.\\n\\nObservera att denna behörighet inte betyder att CS3 kommer att tömma ditt batteri. Den fungerar bara i bakgrunden när det behövs, till exempel när du tar emot aviseringar eller laddar ner videor från officiella tillägg.</string>\n    <string name=\"biometric_warning\">Din CloudStream-data har säkerhetskopierats nu. Även om möjligheten till detta är mycket liten, kan alla enheter bete sig olika. I det sällsynta fallet att du blir utelåst från att komma åt appen, rensa appdata helt och återställ från en säkerhetskopia. Vi ber om ursäkt för eventuella besvär som detta uppstår.</string>\n    <string name=\"audio_book_singular\">Ljudbok</string>\n    <string name=\"clipboard_permission_error\">Det gick inte att komma åt urklipp. Försök igen.</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"battery_dialog_title\">Inaktivera batterioptimering</string>\n    <string name=\"app_unrestricted_toast\">Appens batterianvändning är redan inställd på obegränsad</string>\n    <string name=\"app_info_intent_error\">Det gick inte att öppna CloudStreams appinformation.</string>\n    <string name=\"music_singlar\">Musik</string>\n    <string name=\"reset_btn\">Återställ</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Kommer ut om %s</string>\n    <string name=\"clipboard_unknown_error\">Fel vid kopiering, kopiera logcat och kontakta appsupport.</string>\n    <string name=\"custom_media_singluar\">Media</string>\n    <string name=\"episode_action_cast_mirror\">Cast mirror</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Säsong %1$d Avsnitt %2$d kommer att släppas om</string>\n    <string name=\"player_settings_select_cast_device\">Välj cast-enhet</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"pref_category_accounts\">Konton</string>\n    <string name=\"pref_category_security\">Säkerhet</string>\n    <string name=\"dismiss\">Avfärda</string>\n    <string name=\"open_downloaded_repo\">Öppna databasen</string>\n    <string name=\"device_pin_counter_text\">Koden löper ut om %1$dm %2$ds</string>\n    <string name=\"test_warning\">Varning</string>\n    <string name=\"auth_locally\">Autentisera lokalt</string>\n    <string name=\"qr_image\">QR-kodbild</string>\n    <string name=\"device_pin_expired_message\">PIN-koden har upphört att gälla!</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Är du säker på att du vill radera följande avsnitt permanent i %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"preview_seekbar_desc\">Aktivera förhandsgranskningsminiatyr i sökfältet</string>\n    <string name=\"preview_seekbar\">Förhandsgranskning av sökfältet</string>\n    <string name=\"play_from_beginning_img_des\">Spela från början</string>\n    <string name=\"sort_release_date_new\">Releasedatum (Ny till äldre)</string>\n    <string name=\"sort_release_date_old\">Releasedatum (Äldre till nytt)</string>\n    <string name=\"select_all\">Välj alla</string>\n    <string name=\"open_local_video\">Öppna lokal video</string>\n    <string name=\"downloads_delete_select\">Välj objekt att ta bort</string>\n    <string name=\"downloads_empty\">Det finns för närvarande inga nedladdningar.</string>\n    <string name=\"offline_file\">Tillgänglig för att titta offline</string>\n    <string name=\"deselect_all\">Avmarkera alla</string>\n    <string name=\"delete_files\">Radera Filer</string>\n    <string name=\"delete_format\" formatted=\"true\">Radera (%1$d | %2$s)</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Är du säker på att du vill ta bort följande objekt permanent?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Du kommer också permanent att radera alla avsnitt i följande serie:\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Är du säker på att du permanent vill radera alla avsnitt i följande serie?\n\\n\n\\n%s</string>\n    <string name=\"delete_plugin\">Ta bort insticksprogram</string>\n    <string name=\"hide_player_control_names\">Dölj namnen på spelarens kontroller</string>\n    <string name=\"device_pin_url_message\">Besök <b>%s</b> på din smartphone eller dator och ange koden ovan</string>\n    <string name=\"device_pin_error_message\">Det går inte att hämta enhetens PIN-kod, prova lokal autentisering</string>\n    <string name=\"no_subtitles_loaded\">Inga undertexter laddade än</string>\n    <string name=\"torrent_info\">Den här videon är en torrent, det betyder att din videoaktivitet kan spåras.\\nFörsäkra dig om att du förstår Torrenting innan du fortsätter.</string>\n    <string name=\"confirm_before_exiting_title\">Bekräfta före stängning</string>\n    <string name=\"show\">Visa</string>\n    <string name=\"backup_path_title\">Säkerhetskopieringsmapp</string>\n    <string name=\"confirm_before_exiting_desc\">Visa dialogruta innan stängning av appen</string>\n    <string name=\"software_decoding_desc\">Mjukvaruavkodning tillåter spelaren att spela upp videofiler som inte stöds av din enhet, men kan orsaka ostadig uppspelning vid hög upplösning.</string>\n    <string name=\"audio_singluar\">Ljud</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"software_decoding\">Mjukvaruavkodning</string>\n    <string name=\"torrent_not_accepted\">Starta om appen och acceptera popup-fönstret för Stream Torrent för att fortsätta.</string>\n    <string name=\"torrent_preferred_media\">Aktivera torrent i Inställningar/Leverantörer/Föredragen media</string>\n    <string name=\"encoding_error\">Avkodningsfel</string>\n    <string name=\"player_load_one_subtitle_online\">Ladda in första möjliga</string>\n    <string name=\"dont_show\">Dölj</string>\n    <string name=\"subs_edge_size\">Kantstorlek</string>\n    <string name=\"custom\">Egen</string>\n    <string name=\"unsupported_error\">Stöds ej</string>\n    <string name=\"sort_episodes_number_asc\">Avsnitt (Stigande)</string>\n    <string name=\"sort_episodes_number_desc\">Avsnitt (Fallande)</string>\n    <string name=\"volume_exceeded_100\">Volymen har överskridit 100%</string>\n    <string name=\"sort_episodes_rating_high_low\">Betyg (Högsta)</string>\n    <string name=\"sort_button_date\">Datum%s</string>\n    <string name=\"update_plugins_manually\">Uppdatera Plugins manuellt</string>\n    <string name=\"speech_recognition_unavailable\">Röst igenkänning inte tillgänglig</string>\n    <string name=\"begin_speaking\">Börja Prata…</string>\n    <string name=\"sort_episodes_rating_low_high\">Betyg (Lägsta)</string>\n    <string name=\"sort_button_episode\">Ep %s</string>\n    <string name=\"sort_button_rating\">Betyg%s</string>\n    <string name=\"update_plugins\">Uppdatera Plugins</string>\n    <string name=\"go_to_downloads\">Gå till Hämtade filer</string>\n    <string name=\"download_parallel_settings_des\">Mängden av olika föremål som kan bli nedladdat i parallell</string>\n    <string name=\"parallel_downloads\">Parallel nedladdningar</string>\n    <string name=\"concurrent_connections\">Samtidiga anslutningar</string>\n    <string name=\"concurrent_connections_settings_des\">Mängden av samtidiga anslutningar varje nedladdning kan använda</string>\n    <string name=\"no_internet_connection\">Ingen anslutning. \\n\\nAnslut till ett nätverk och försök igen. Du kan titta på dina nedladdningar medan du inte är ansluten.</string>\n    <string name=\"overscan_settings_des\">Ändrar skärmens gränser</string>\n    <string name=\"overscan_settings\">Överskanning</string>\n    <string name=\"poster_size_settings_des\">Ändrar storleken på affischer</string>\n    <string name=\"poster_size_settings\">Affischstorlek</string>\n    <string name=\"speedup_title\">LångPress Hastighet Växling</string>\n    <string name=\"speedup_summary\">Tryck ner för 2x hastighet</string>\n    <string name=\"edit_profile_image_title\">Redigera Profil Bild</string>\n    <string name=\"edit_profile_image_hint\">Ange URL för Profil Bilden</string>\n    <string name=\"edit_profile_image_error_empty\">Inget URL hittades</string>\n    <string name=\"edit_profile_image_error_invalid\">Ogiltig URL eller Bild</string>\n    <string name=\"edit_profile_image_success\">Bilden ändrades</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Markera som \\\"sett fram\\\" till detta avsnitt</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Ta bort \\\"sett fram\\\" till detta avsnitt</string>\n    <string name=\"action_reload\">Omladdad</string>\n    <string name=\"reload_provider\">Ladda om leverantören</string>\n    <string name=\"name\">Namn</string>\n    <string name=\"source_name\">Källnamn</string>\n    <string name=\"resolution_and_name\">Upplösning och Namn</string>\n    <string name=\"download_all\">Ladda ned alla</string>\n    <string name=\"cancel_all\">Avbryt alla</string>\n    <string name=\"download_episode_range\">Vill du ladda ned avsnitt %s?</string>\n    <string name=\"cancel_queue_message\">Vill du avbryta alla köade hämtningar?</string>\n    <string name=\"subs_subtitle_alignment\">Justera undertexter</string>\n    <string name=\"bottom_left\">Nederst till vänster</string>\n    <string name=\"bottom_center\">Nederst i mitten</string>\n    <string name=\"bottom_right\">Nederst till höger</string>\n    <string name=\"middle_left\">Mitten vänster</string>\n    <string name=\"middle_center\">I mitten</string>\n    <string name=\"middle_right\">Mitten till höger</string>\n    <string name=\"top_left\">Övre vänster</string>\n    <string name=\"top_center\">Övre mitten</string>\n    <string name=\"top_right\">Övre höger</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d aktiv nedladdning</item>\n        <item quantity=\"other\">%d aktiva nedladdningar</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d nedladdning i kö</item>\n        <item quantity=\"other\">%d nedladdningar i kö</item>\n    </plurals>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"download_queue\">Nedladdningskö</string>\n    <string name=\"play_full_series_button\">Spela hela serierna</string>\n    <string name=\"queue_empty_message\">Det finns inga nedladdningar i kö just nu.</string>\n    <string name=\"extra_brightness_settings\">Extra ljusstyrka</string>\n    <string name=\"extra_brightness_settings_des\">Aktivera ljusstyrkefiltret när ljusstyrkan överstiger 100%</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"search_suggestions\">Sökförslag</string>\n    <string name=\"search_suggestions_des\">Visa sökförslag medan du skriver</string>\n    <string name=\"clear_suggestions\">Rensa förslag</string>\n    <string name=\"show_cast_in_details\">Visa skådespelarpanelen</string>\n    <string name=\"install_prerelease\">Installera förhandsversionen</string>\n    <string name=\"prerelease_already_installed\">Förhandsversionen är redan installerad.</string>\n    <string name=\"prerelease_install_failed\">Misslyckades med att installera förhandsversionen.</string>\n    <string name=\"episode_action_play_mirror\">Spela mirror</string>\"\n    <string name=\"show_rating\">Graderingstitel</string>\n    <string name=\"show_episode_text\">Avsnitt Text</string>\n    <string name=\"video_info\">Media Info</string>\n    <string name=\"player_settings_always_ask\">Fråga alltid</string>\n    <string name=\"sort_episodes_date_newest\">Sändningsdatum (nyast)</string>\n    <string name=\"sort_episodes_date_oldest\">Sändningsdatum (äldst)</string>\n    <string name=\"source_priority\">Källprioritet</string>\n    <string name=\"source_priority_help\">Välj hur videokällor ska sorteras i spelaren</string>\n    <string name=\"no_account\">Inget konto</string>\n    <string name=\"slide_up_again_to_exceed_100\">Dra uppåt igen för att gå över 100%</string>\n    <string name=\"starting_plugin_update_manually\">Startar plugin uppdateringsprocessen!</string>\n    <string name=\"plugins_updated_manually\">%d plugin(s) har uppdaterats!</string>\n    <string name=\"no_plugins_updated_manually\">Inga plugins blev uppdaterade.</string>\n    <string name=\"player_notification_channel_name\">Spelarnotiser</string>\n    <string name=\"player_notification_channel_description\">Spelarnotisen för att styra uppspelningen i bakgrunden</string>\n    <string name=\"subtitles_from_embedded\">Inbäddad</string>\n    <string name=\"subtitles_from_online\">Ansluten</string>\n    <string name=\"all_subtitles_bold\">Gör alla undertexter fetstilta</string>\n    <string name=\"all_subtitles_italic\">Gör alla undertexter kursivstila</string>\n    <string name=\"background_radius\">Bakgrundsradie</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ta/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"search_hint\">தேடுக…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">%s இல் தேடவும்…</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">விரைவு (%.2fx)</string>\n    <string name=\"title_home\">முகப்பு</string>\n    <string name=\"title_search\">தேடு</string>\n    <string name=\"title_downloads\">பதிவிறக்கம்</string>\n    <string name=\"no_data\">தரவு இல்லை</string>\n    <string name=\"episode_more_options_des\">மேலும் விருப்பங்கள்</string>\n    <string name=\"next_episode\">அடுத்த அத்தியாயம்</string>\n    <string name=\"result_tags\">வகைகள்</string>\n    <string name=\"result_share\">பங்கு</string>\n    <string name=\"result_open_in_browser\">உலாவியில் திற</string>\n    <string name=\"skip_loading\">ஏற்றுவதைத் தவிர்க்கவும்</string>\n    <string name=\"type_watching\">பார்த்து கொண்டிருப்பது</string>\n    <string name=\"type_on_hold\">ஆன்-ஓல்ட்</string>\n    <string name=\"type_completed\">முடிந்தது</string>\n    <string name=\"type_plan_to_watch\">பார்க்கத் திட்டமிடப்பட்டுள்ளது</string>\n    <string name=\"type_re_watching\">மீண்டும் பார்க்கத் தொடங்கியது</string>\n    <string name=\"play_torrent_button\">ச்ட்ரீம் டொரண்ட்</string>\n    <string name=\"pick_subtitle\">வசன வரிகள்</string>\n    <string name=\"go_back\">திரும்பிச் செல்லுங்கள்</string>\n    <string name=\"play_episode\">அத்தியாயத்தை இயக்கு</string>\n    <string name=\"download\">எபிசோட் பதிவிற்கான இசைவு கொடுக்கவும்</string>\n    <string name=\"downloaded\">பதிவிறக்கப்பட்டது</string>\n    <string name=\"downloading\">பதிவிறக்குகிறது</string>\n    <string name=\"download_paused\">பதிவிறக்கம் இடைநிறுத்தப்பட்டது</string>\n    <string name=\"download_started\">பதிவிறக்கம் தொடங்கியது</string>\n    <string name=\"download_failed\">பதிவிறக்கம் தோல்வியடைந்தது</string>\n    <string name=\"stream\">பிணையம் ச்ட்ரீம்</string>\n    <string name=\"download_storage_text\">உள் சேமிப்பு</string>\n    <string name=\"app_dubbed_text\">மொழிபெயர்க்கப்பட்டது</string>\n    <string name=\"popup_delete_file\">கோப்பை அழி</string>\n    <string name=\"popup_play_file\">கோப்பு</string>\n    <string name=\"popup_pause_download\">இடைநிறுத்தம் பதிவிறக்கம்</string>\n    <string name=\"home_more_info\">மேலும் செய்தி</string>\n    <string name=\"home_expanded_hide\">மறை</string>\n    <string name=\"action_remove_from_bookmarks\">அகற்று</string>\n    <string name=\"sort_clear\">தெளிவான</string>\n    <string name=\"sort_save\">சேமி</string>\n    <string name=\"subs_text_color\">உரை நிறம்</string>\n    <string name=\"subs_outline_color\">வெளிப்புற நிறம்</string>\n    <string name=\"subs_background_color\">பின்னணி நிறம்</string>\n    <string name=\"subs_subtitle_elevation\">வசன உயரம்</string>\n    <string name=\"subs_font\">எழுத்துரு</string>\n    <string name=\"search_provider_text_providers\">வழங்குபவர்கள் பயன்படுத்தி தேடுங்கள்</string>\n    <string name=\"search_provider_text_types\">வகைகளைப் பயன்படுத்தி தேடுங்கள்</string>\n    <string name=\"subs_download_languages\">மொழிகளைப் பதிவிறக்கவும்</string>\n    <string name=\"subs_subtitle_languages\">வசன மொழி</string>\n    <string name=\"continue_watching\">தொடர்ந்து பார்த்துக் கொள்ளுங்கள்</string>\n    <string name=\"vpn_might_be_needed\">முறையாக இயங்க vpn பயன்படுத்தவும்</string>\n    <string name=\"player_size_settings\">பிளேயர் மறுஅளவிடுதல் பொத்தானை</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast வசன வரிகள்</string>\n    <string name=\"swipe_to_change_settings\">அமைப்புகளை மாற்ற ச்வைப் செய்யவும்</string>\n    <string name=\"autoplay_next_settings\">தன்னியக்க அடுத்த அத்தியாயம்</string>\n    <string name=\"autoplay_next_settings_des\">தற்போதைய ஒன்று முடிவடையும் போது அடுத்த அத்தியாயத்தைத் தொடங்கவும்</string>\n    <string name=\"double_tap_to_seek_settings\">தேட இரட்டை தட்டு</string>\n    <string name=\"double_tap_to_seek_amount_settings\">வீரர் தொகை (விநாடிகள்)</string>\n    <string name=\"double_tap_to_pause_settings_des\">இடைநிறுத்த நடுவில் இரண்டு முறை தட்டவும்</string>\n    <string name=\"cast_format\" formatted=\"true\">நடிகர்கள்: %s</string>\n    <string name=\"go_back_img_des\">திரும்பிச் செல்லுங்கள்</string>\n    <string name=\"title_settings\">அமைப்புகள்</string>\n    <string name=\"loading\">ஏற்றுகிறது…</string>\n    <string name=\"type_dropped\">கைவிடப்பட்டது</string>\n    <string name=\"download_done\">பதிவிறக்கம் முடிந்தது</string>\n    <string name=\"reload_error\">இணைப்பை மீண்டும் முயலவும்…</string>\n    <string name=\"play_movie_button\">திரைப்படம் இயக்கு</string>\n    <string name=\"play_livestream_button\">லைவ்ச்ட்ரீம் விளையாடுங்கள்</string>\n    <string name=\"play_trailer_button\">டிரெய்லரை இயக்கு</string>\n    <string name=\"pick_source\">மூலங்கள்</string>\n    <string name=\"error_loading_links_toast\">இணைப்புகளை ஏற்றுவதில் பிழை</string>\n    <string name=\"home_play\">விளையாடுங்கள்</string>\n    <string name=\"download_canceled\">பதிவிறக்கம் ரத்து செய்யப்பட்டது</string>\n    <string name=\"subtitles_settings\">வசன அமைப்புகள்</string>\n    <string name=\"popup_resume_download\">பதிவிறக்கத்தை மீண்டும் தொடங்குங்கள்</string>\n    <string name=\"filter_bookmarks\">புக்மார்க்குகளை வடிகட்டவும்</string>\n    <string name=\"home_info\">செய்தி</string>\n    <string name=\"player_speed\">பிளேயர் விரைவு</string>\n    <string name=\"error_bookmarks_text\">புக்மார்க்குகள்</string>\n    <string name=\"sort_apply\">இடு</string>\n    <string name=\"sort_copy\">நகலெடு</string>\n    <string name=\"sort_close\">மூடு</string>\n    <string name=\"subs_font_size\">எழுத்துரு அளவு</string>\n    <string name=\"action_remove_watching\">அகற்று</string>\n    <string name=\"action_open_watching\">மேலும் செய்தி</string>\n    <string name=\"subs_auto_select_language\">தானாக தேர்ந்தெடுக்கப்பட்ட மொழி</string>\n    <string name=\"double_tap_to_seek_settings_des\">முன்னோக்கி அல்லது பின்னோக்கி தேட வலது அல்லது இடது பக்கத்தில் இரண்டு முறை தட்டவும்</string>\n    <string name=\"use_system_brightness_settings\">மொபைலில் பிரகாசத்தை பயன்படுத்த</string>\n    <string name=\"subs_hold_to_reset_to_default\">இயல்புநிலைக்கு மீட்டமைக்க பிடிக்கவும்</string>\n    <string name=\"vpn_torrent\">முறையாக இயங்க vpn பரிந்துரைக்கப்பட்டது</string>\n    <string name=\"player_size_settings_des\">கருப்பு எல்லைகளை அகற்றவும்</string>\n    <string name=\"torrent_plot\">விவரம்</string>\n    <string name=\"normal_no_plot\">கதை எதுவும் காணப்படவில்லை</string>\n    <string name=\"torrent_no_plot\">எந்த விளக்கமும் கிடைக்கவில்லை</string>\n    <string name=\"picture_in_picture\">படம்-படம்</string>\n    <string name=\"player_subtitles_settings_des\">பிளேயர் வசன வரிகள் அமைப்புகள்</string>\n    <string name=\"show_log_cat\">LOGCAT ஐக் காட்டு</string>\n    <string name=\"picture_in_picture_des\">மற்ற பயன்பாடுகளின் மேல் ஒரு மினியேச்சர் பிளேயரில் பிளேபேக்கைத் தொடர்கிறது</string>\n    <string name=\"player_subtitles_settings\">வசன வரிகள்</string>\n    <string name=\"swipe_to_seek_settings_des\">ஒரு வீடியோவில் உங்கள் நிலையைக் கட்டுப்படுத்த பக்கத்திலிருந்து பக்கமாக ச்வைப் செய்யவும்</string>\n    <string name=\"swipe_to_change_settings_des\">ஒளி அல்லது அளவை மாற்ற இடது அல்லது வலது பக்கத்தில் மேலே அல்லது கீழே சறுக்கி விடுங்கள்</string>\n    <string name=\"double_tap_to_pause_settings\">இடைநிறுத்த இரட்டை தட்டு</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast வசன வரிகள் அமைப்புகள்</string>\n    <string name=\"use_system_brightness_settings_des\">இருண்ட மேலடுக்கு பதிலாக ஆப் பிளேயரில் கணினி பிரகாசத்தைப் பயன்படுத்தவும்</string>\n    <string name=\"next_episode_format\" formatted=\"true\">அத்தியாயம் %d-இன் வெளியீட்டு நேரம்</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dம %2$dநி</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dநி</string>\n    <string name=\"home_next_random_img_des\">அடுத்து ஏதாவது</string>\n    <string name=\"browser\">உலாவி</string>\n    <string name=\"duration_format\" formatted=\"true\">%d நிமி</string>\n    <string name=\"play_with_app_name\">CloudStream-உடன் இயக்கு</string>\n    <string name=\"new_update_format\" formatted=\"true\">புதிய புதுப்பிப்பு உள்ளது\\n%1$s-&gt;%2$s</string>\n    <string name=\"filler\" formatted=\"true\">நிரப்பி</string>\n    <string name=\"search_poster_img_des\">போச்டர்</string>\n    <string name=\"episode_poster_img_des\">எபிசோட்டின் போச்டர்</string>\n    <string name=\"result_poster_img_des\">போச்டர்</string>\n    <string name=\"home_main_poster_img_des\">முதன்மையான போச்டர்</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s ep %2$d</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">%s ஏற்ற முடியவில்லை</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"pref_category_subtitles\">வசன வரிகள்</string>\n    <string name=\"skip_type_ed\">முடிவு</string>\n    <string name=\"setup_done\">முடிந்தது</string>\n    <string name=\"profile_number\">சுயவிவரம் %d</string>\n    <string name=\"wifi\">வைஃபை</string>\n    <string name=\"example_lang_name\">மொழி குறியீடு (en)</string>\n    <string name=\"test_log\">பதிவு</string>\n    <string name=\"show_dub\">டப் சிட்டை</string>\n    <string name=\"episode_sync_settings\">வாட்ச் முன்னேற்றத்தைப் புதுப்பிக்கவும்</string>\n    <string name=\"restore_success\">ஏற்றப்பட்ட காப்புப்பிரதி கோப்பு</string>\n    <string name=\"provider_lang_settings\">விரிவாக்க மொழிகள்</string>\n    <string name=\"category_account\">கணக்குகள் மற்றும் பாதுகாப்பு</string>\n    <string name=\"hls_playlist\">எச்.எல்.எச் பிளேலிச்ட்</string>\n    <string name=\"skip_type_mixed_ed\">கலப்பு முடிவு</string>\n    <string name=\"app_name\">கிளவுட்ச்ட்ரீம்</string>\n    <string name=\"benene_count_text_none\">பெனின்கள் எதுவும் கொடுக்கப்படவில்லை</string>\n    <string name=\"eigengraumode_settings\">பிளேபேக் விரைவு</string>\n    <string name=\"swipe_to_seek_settings\">தேட ச்வைப்</string>\n    <string name=\"backup_settings\">தரவை காப்புப் பிரதி எடுக்கவும்</string>\n    <string name=\"advanced_search\">மேம்பட்ட தேடல்</string>\n    <string name=\"automatic_plugin_download\">செருகுநிரல்களை தானாக பதிவிறக்கவும்</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">இது %s நிரந்தரமாக நீக்கும\\n நீ சொல்வது உறுதியா?</string>\n    <string name=\"year\">ஆண்டு</string>\n    <string name=\"unexpected_error\">எதிர்பாராத பிளேயர் பிழை</string>\n    <string name=\"episode_action_play_in_app\">பயன்பாட்டில் விளையாடுங்கள்</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast அத்தியாயம்</string>\n    <string name=\"video_disk_description\">ஆண்ட்ராய்டு டிவி போன்ற குறைந்த சேமிப்பு இடங்களைக் கொண்ட சாதனங்களில் மிக அதிகமாக அமைக்கப்பட்டால் சிக்கல்களை ஏற்படுத்துகிறது.</string>\n    <string name=\"pref_category_actions\">செயல்கள்</string>\n    <string name=\"bottom_title_settings_des\">தலைப்பை சுவரொட்டியின் கீழ் வைக்கவும்</string>\n    <string name=\"coming_soon\">விரைவில் வருகிறது…</string>\n    <string name=\"video_tracks\">வீடியோ தடங்கள்</string>\n    <string name=\"safe_mode_description\">சிக்கலை ஏற்படுத்தும் ஒரு விபத்து காரணமாக அனைத்து நீட்டிப்புகளும் அணைக்கப்பட்டன.</string>\n    <string name=\"plugin_downloaded\">சொருகி பதிவிறக்கம் செய்யப்பட்டது</string>\n    <string name=\"app_not_found_error\">பயன்பாடு கிடைக்கவில்லை</string>\n    <string name=\"android_tv_interface_on_seek_settings\">பிளேயர் காட்டப்பட்டுள்ளது - தொகையைத் தேடுங்கள்</string>\n    <string name=\"update_notification_downloading\">பயன்பாட்டு புதுப்பிப்பைப் பதிவிறக்குகிறது…</string>\n    <string name=\"jsdelivr_enabled\">கிட்அப்பை அடைய முடியவில்லை. Jsdelivr ப்ராக்சியை இயக்குதல்…</string>\n    <string name=\"stop\">நிறுத்து</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast கண்ணாடி</string>\n    <string name=\"example_email\">Hello@world.com</string>\n    <string name=\"test_failed\">தோல்வி</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"live_singular\">லைவ்ச்ட்ரீம்</string>\n    <string name=\"repo_copy_label\">களஞ்சிய பெயர் மற்றும் முகவரி</string>\n    <string name=\"toast_copied\">நகலெடுக்கப்பட்டது!</string>\n    <string name=\"clipboard_unknown_error\">நகலெடுப்பதில் பிழை, தயவுசெய்து LogCat ஐ நகலெடுத்து பயன்பாட்டு ஆதரவை தொடர்பு கொள்ளவும்.</string>\n    <string name=\"clipboard_permission_error\">கிளிப்போர்டை அணுகுவதில் பிழை, மீண்டும் முயற்சிக்கவும்.</string>\n    <string name=\"sort_alphabetical_a\">அகரவரிசை (A முதல் சட் வரை)</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">%s க்கு முள் உள்ளிடவும்</string>\n    <string name=\"enter_current_pin\">தற்போதைய முள் உள்ளிடவும்</string>\n    <string name=\"pin\">முள்</string>\n    <string name=\"pin_error_incorrect\">தவறான முள். தயவு செய்து மீண்டும் முயற்சிக்கவும்.</string>\n    <string name=\"show_title\">தலைப்பு</string>\n    <string name=\"plugin_deleted\">சொருகி நீக்கப்பட்டது</string>\n    <string name=\"site\">தளம்</string>\n    <string name=\"safe_mode_title\">பாதுகாப்பான பயன்முறை</string>\n    <string name=\"benene_des\">கொடுக்கப்பட்ட பெனீன்</string>\n    <string name=\"movies\">திரைப்படங்கள்</string>\n    <string name=\"no\">இல்லை</string>\n    <string name=\"discord\">முரண்பாட்டில் சேரவும்</string>\n    <string name=\"asian_drama\">ஆசிய நாடகங்கள்</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"rating\">செயல்வரம்பு</string>\n    <string name=\"search\">தேடல்</string>\n    <string name=\"show_trailers_settings\">டிரெய்லர்களைக் காட்டு</string>\n    <string name=\"no_links_found_toast\">இணைப்புகள் எதுவும் கிடைக்கவில்லை</string>\n    <string name=\"copy_link_toast\">கிளிப்போர்டில் இணைப்பு நகலெடுக்கப்பட்டது</string>\n    <string name=\"season_short\">கள்</string>\n    <string name=\"all\">அனைத்தும்</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">வசன நேரந்தவறுகை இல்லை</string>\n    <string name=\"clipboard_too_large\">அதிக உரை. கிளிப்போர்டில் சேமிக்க முடியவில்லை.</string>\n    <string name=\"action_mark_as_watched\">பார்த்தபடி குறி</string>\n    <string name=\"others\">மற்றவைகள்</string>\n    <string name=\"links_reloaded_toast\">இணைப்புகள் மீண்டும் ஏற்றப்பட்டன</string>\n    <string name=\"app_subbed_text\">துணை</string>\n    <string name=\"subs_window_color\">சாளரம் நிறம்</string>\n    <string name=\"subs_import_text\" formatted=\"true\">எழுத்துருக்களை %s இல் வைப்பதன் மூலம் இறக்குமதி செய்யுங்கள்</string>\n    <string name=\"provider_info_meta\">மேனிலை தரவு தளத்தால் வழங்கப்படவில்லை, தளத்தில் இல்லாவிட்டால் வீடியோ ஏற்றுதல் தோல்வியடையும்.</string>\n    <string name=\"backup_frequency\">காப்பு அதிர்வெண்</string>\n    <string name=\"backup_success\">தரவு சேமிக்கப்பட்டது</string>\n    <string name=\"backup_failed\">சேமிப்பக அனுமதிகள் இல்லை. தயவு செய்து மீண்டும் முயற்சிக்கவும்.</string>\n    <string name=\"poster_ui_settings\">சுவரொட்டியில் இடைமுகம் கூறுகளை மாற்றவும்</string>\n    <string name=\"check_for_update\">மேம்படுத்தல் சோதிக்க</string>\n    <string name=\"video_lock\">பூட்டு</string>\n    <string name=\"display_subbed_dubbed_settings\">அனிமேசன் டப்பிங்/துணை</string>\n    <string name=\"pref_category_gestures\">சைகைகள்</string>\n    <string name=\"subtitles_example_text\">விரைவான பழுப்பு நரி சோம்பேறி நாய் மீது குதிக்கிறது</string>\n    <string name=\"home_source\">மூலம்</string>\n    <string name=\"quality_cam_hd\">கேம்</string>\n    <string name=\"poster_image\">சுவரொட்டி படம்</string>\n    <string name=\"view_public_repositories_button_short\">பொது பட்டியல்</string>\n    <string name=\"extension_version\">பதிப்பு</string>\n    <string name=\"select_library\">நூலகத்தைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"action_subscribe\">பதிவு</string>\n    <string name=\"edit_account\">கணக்கைத் திருத்தவும்</string>\n    <string name=\"season_format\">%1$s %2$d %3$s</string>\n    <string name=\"cancel\">ரத்துசெய்</string>\n    <string name=\"action_default\">இயல்புநிலை</string>\n    <string name=\"ova_singular\">ஓவா</string>\n    <string name=\"torrent_singular\">டொரண்ட்</string>\n    <string name=\"documentaries_singular\">ஆவணப்படம்</string>\n    <string name=\"asian_drama_singular\">ஆசிய நாடகம்</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"video_source\">மூலம்</string>\n    <string name=\"watch_quality_pref_data\">விருப்பமான கண்காணிப்பு தகுதி (மொபைல் தரவு)</string>\n    <string name=\"resize_zoom\">பெரிதாக்கு</string>\n    <string name=\"pref_category_bypass\">ISP பைபாச்</string>\n    <string name=\"pref_category_extensions\">நீட்டிப்புகள்</string>\n    <string name=\"pref_category_player_features\">பிளேயர் நற்பொருத்தங்கள்</string>\n    <string name=\"pref_category_ui_features\">நற்பொருத்தங்கள்</string>\n    <string name=\"category_general\">பொது</string>\n    <string name=\"enable_nsfw_on_providers\">ஆதரிக்கப்பட்ட நீட்டிப்புகளில் NSFW ஐ இயக்கவும்</string>\n    <string name=\"primary_color_settings\">முதன்மை நிறம்</string>\n    <string name=\"app_theme_settings\">பயன்பாட்டு கருப்பொருள்</string>\n    <string name=\"bottom_title_settings\">சுவரொட்டி தலைப்பு இடம்</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s அங்கீகரிக்கப்பட்டவை</string>\n    <string name=\"subtitle_offset_title\">வசன நேரந்தவறுகை</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">வசன வரிகள் %d ms மிக விரைவாக காட்டப்பட்டால் இதைப் பயன்படுத்தவும்</string>\n    <string name=\"recommended\">பரிந்துரைக்கப்படுகிறது</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">ஏற்றப்பட்ட %s</string>\n    <string name=\"player_load_subtitles\">கோப்பிலிருந்து ஏற்றவும்</string>\n    <string name=\"player_load_subtitles_online\">இணையத்திலிருந்து ஏற்றவும்</string>\n    <string name=\"category_player\">ஆட்டக்காரர்</string>\n    <string name=\"resolution_and_title\">தீர்மானம் மற்றும் தலைப்பு</string>\n    <string name=\"title\">தலைப்பு</string>\n    <string name=\"subtitles_remove_captions\">வசன வரிகளிலிருந்து மூடிய தலைப்புகளை அகற்றவும்</string>\n    <string name=\"subtitles_remove_bloat\">வசனங்களிலிருந்து வீக்கத்தை அகற்று</string>\n    <string name=\"previous\">முந்தைய</string>\n    <string name=\"extensions\">நீட்டிப்புகள்</string>\n    <string name=\"repository_url_hint\">களஞ்சிய முகவரி அல்லது குறுக்குவழி</string>\n    <string name=\"plugin_loaded\">சொருகி ஏற்றப்பட்டது</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">%1$d %2$s ஐ பதிவிறக்கத் தொடங்கியது…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">பதிவிறக்கம் %1$d %2$s</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">பதிவிறக்கம்: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">முடக்கப்பட்டது: %d</string>\n    <string name=\"uppercase_all_subtitles\">அனைத்து வசன வரிகள்</string>\n    <string name=\"audio_tracks\">ஆடியோ தடங்கள்</string>\n    <string name=\"restart\">மறுதொடக்கம்</string>\n    <string name=\"extension_description\">விவரம்</string>\n    <string name=\"extension_authors\">ஆசிரியர்கள்</string>\n    <string name=\"skip_type_format\" formatted=\"true\">%s ஐத் தவிர்க்கவும்</string>\n    <string name=\"skip_type_recap\">மறுபரிசீலனை செய்யுங்கள்</string>\n    <string name=\"skip_type_intro\">அறிமுகம்</string>\n    <string name=\"clear_history\">வரலாற்றை அழிக்கவும்</string>\n    <string name=\"sort_alphabetical_z\">அகரவரிசை (z முதல் A வரை)</string>\n    <string name=\"open_with\">உடன் திறந்திருக்கும்</string>\n    <string name=\"qualities\">குணங்கள்</string>\n    <string name=\"duplicate_add\">கூட்டு</string>\n    <string name=\"duplicate_replace\">மாற்றவும்</string>\n    <string name=\"duplicate_replace_all\">அனைத்தையும் மாற்று</string>\n    <string name=\"action_add_to_bookmarks\">கடிகார நிலையை அமைக்கவும்</string>\n    <string name=\"subs_edge_type\">விளிம்பு வகை</string>\n    <string name=\"no_season\">பருவம் இல்லை</string>\n    <string name=\"episode\">அத்தியாயம்</string>\n    <string name=\"resume\">தற்குறிப்பு</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"other_singular\">ஒளிதோற்றம்</string>\n    <string name=\"limit_title_rez\">பிளேயர் தகவலைக் காட்டு</string>\n    <string name=\"video_buffer_size_settings\">வீடியோ இடையக அளவு</string>\n    <string name=\"add_site_pref\">நகலி தளம்</string>\n    <string name=\"jsdelivr_proxy\">அறிவிலிமையம் பதிலாள்</string>\n    <string name=\"jsdelivr_proxy_summary\">JSdelivr ஐப் பயன்படுத்தி மூல அறிவிலிமையம் முகவரி களின் பைபாச். புதுப்பிப்புகள் சில நாட்களுக்கு தாமதமாகிவிடும்.</string>\n    <string name=\"no_repository_found_error\">களஞ்சியம் கிடைக்கவில்லை, முகவரி ஐ சரிபார்த்து VPN ஐ முயற்சிக்கவும்</string>\n    <string name=\"batch_download\">தொகுதி பதிவிறக்கம்</string>\n    <string name=\"plugin_singular\">சொருகு</string>\n    <string name=\"download_all_plugins_from_repo\">எச்சரிக்கை: மூன்றாம் தரப்பு நீட்டிப்புகளைப் பயன்படுத்துவதற்கு CloudStream எந்தப் பொறுப்பையும் ஏற்காது, அவற்றிற்கு எந்த ஆதரவையும் வழங்காது!</string>\n    <string name=\"extension_language\">மொழி</string>\n    <string name=\"revert\">திரும்பவும்</string>\n    <string name=\"subscription_deleted\">%s இலிருந்து குழுவிலகப்பட்டது</string>\n    <string name=\"delete_repository_plugins\">இது அனைத்து களஞ்சிய செருகுநிரல்களையும் நீக்கிவிடும்</string>\n    <string name=\"setup_extensions_subtext\">நீங்கள் பயன்படுத்த விரும்பும் தளங்களின் பட்டியலைப் பதிவிறக்கவும்</string>\n    <string name=\"player_pref\">விருப்பமான வீடியோ பிளேயர்</string>\n    <string name=\"enable_skip_op_from_database_des\">திறப்பு/முடிவுக்கு ச்கிப் பாப்அப்களைக் காட்டு</string>\n    <string name=\"use\">பயன்படுத்தவும்</string>\n    <string name=\"edit\">தொகு</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"android_tv_interface_off_seek_settings\">பிளேயர் மறைக்கப்பட்டுள்ளது - தொகையைத் தேடுங்கள்</string>\n    <string name=\"nginx_url_pref\">Nginx சேவையக முகவரி</string>\n    <string name=\"actor_background\">பின்னணி</string>\n    <string name=\"confirm_exit_dialog\">நிச்சயமாக நீங்கள் வெளியேற வேண்டுமா?</string>\n    <string name=\"video_buffer_clear_settings\">வீடியோ மற்றும் பட தற்காலிக சேமிப்பை அழிக்கவும்</string>\n    <string name=\"action_remove_from_watched\">பார்த்ததிலிருந்து அகற்று</string>\n    <string name=\"apk_installer_settings\">APK நிறுவி</string>\n    <string name=\"pref_category_android_tv\">ஆண்ட்ராய்டு டிவி</string>\n    <string name=\"max\">அதிகபட்சம்</string>\n    <string name=\"quality_cam_rip\">கேம்</string>\n    <string name=\"normal\">சாதாரண</string>\n    <string name=\"tracks\">தடங்கள்</string>\n    <string name=\"github\">கிதப்</string>\n    <string name=\"episode_short\">இ</string>\n    <string name=\"add_site_summary\">வேறு முகவரி உடன் ஏற்கனவே இருக்கும் தளத்தின் குளோனைச் சேர்க்கவும்</string>\n    <string name=\"dns_pref\">Https க்கு மேல் dns</string>\n    <string name=\"episode_sync_settings_des\">உங்கள் தற்போதைய அத்தியாயம் முன்னேற்றத்தை தானாக ஒத்திசைக்கவும்</string>\n    <string name=\"synopsis\">சுருக்கம்</string>\n    <string name=\"no_chromecast_support_toast\">இந்த வழங்குநருக்கு Chromecast உதவி இல்லை</string>\n    <string name=\"next\">அடுத்தது</string>\n    <string name=\"error\">பிழை</string>\n    <string name=\"app_layout\">பயன்பாட்டு தளவமைப்பு</string>\n    <string name=\"pref_category_defaults\">இயல்புநிலை</string>\n    <string name=\"quality_ts\">டி.எச்</string>\n    <string name=\"account\">கணக்கு</string>\n    <string name=\"subtitles_encoding\">வசன குறியீட்டு</string>\n    <string name=\"app_language\">பயன்பாட்டு மொழி</string>\n    <string name=\"tv_layout\">டிவி தளவமைப்பு</string>\n    <string name=\"restore_settings\">காப்புப்பிரதியிலிருந்து தரவை மீட்டெடுக்கவும்</string>\n    <string name=\"backup_failed_error_format\">பிழை %s</string>\n    <string name=\"category_updates\">புதுப்பிப்புகள் மற்றும் காப்புப்பிரதி</string>\n    <string name=\"apk_installer_package_installer\">PackactionInstaller</string>\n    <string name=\"delayed_update_notice\">வெளியேறியதும் பயன்பாடு புதுப்பிக்கப்படும்</string>\n    <string name=\"sort_by\">வரிசைப்படுத்தவும்</string>\n    <string name=\"sort_updated_old\">புதுப்பிக்கப்பட்டது (பழையது முதல் புதியது)</string>\n    <string name=\"profile_background_des\">சுயவிவர பின்னணி</string>\n    <string name=\"already_voted\">நீங்கள் ஏற்கனவே வாக்களித்து விட்டீர்கள்</string>\n    <string name=\"favorites_list_name\">பிடித்தவை</string>\n    <string name=\"action_remove_from_favorites\">பிடித்தவைகளிலிருந்து அகற்று</string>\n    <string name=\"duplicate_title\">சாத்தியமான நகல் காணப்படுகிறது</string>\n    <string name=\"unfavorite\">மாறாத</string>\n    <string name=\"biometric_authentication_title\">கிளவுட்ச்ட்ரீமைத் திறக்கவும்</string>\n    <string name=\"biometric_setting\">பயோமெட்ரிக்சுடன் பூட்டு</string>\n    <string name=\"audio_book_singular\">ஆடியோ நூல்</string>\n    <string name=\"subscribe_tooltip\">புதிய அத்தியாயம் அறிவிப்பு</string>\n    <string name=\"result_search_tooltip\">பிற நீட்டிப்புகளில் தேடுங்கள்</string>\n    <string name=\"kitsu_settings\">கிட்சுவிலிருந்து சுவரொட்டிகளைக் காட்டு</string>\n    <string name=\"play_episode_toast\">அத்தியாயம் விளையாடுங்கள்</string>\n    <string name=\"subs_default_reset_toast\">இயல்புநிலை மதிப்புக்கு மீட்டமைக்கவும்</string>\n    <string name=\"season\">பருவம்</string>\n    <string name=\"status\">நிலை</string>\n    <string name=\"free_storage\">இலவசம்</string>\n    <string name=\"tv_series\">தொலைக்காட்சி தொடர்</string>\n    <string name=\"anime\">அனிம்</string>\n    <string name=\"dont_show_again\">மீண்டும் காட்ட வேண்டாம்</string>\n    <string name=\"resize_fill\">நீட்சி</string>\n    <string name=\"test_extensions\">அனைத்து நீட்டிப்புகளையும் சோதிக்கவும்</string>\n    <string name=\"test_extensions_summary\">இந்த சோதனை டெவலப்பர்களுக்கு மட்டுமே, எந்தவொரு நீட்டிப்பையும் சரிபார்க்கவோ மறுக்கவோ இல்லை.</string>\n    <string name=\"emulator_layout\">முன்மாதிரி தளவமைப்பு</string>\n    <string name=\"downloaded_file\">பதிவிறக்கம் செய்யப்பட்ட கோப்பு</string>\n    <string name=\"resolution\">பகுத்தல்</string>\n    <string name=\"empty_library_no_accounts_message\">உங்கள் நூலகம் காலியாக உள்ளது :(\n\\n நூலகக் கணக்கில் உள்நுழைக அல்லது உங்கள் உள்ளக நூலகத்தில் காட்சிகளைச் சேர்க்கவும்.</string>\n    <string name=\"action_unsubscribe\">குழுவிலகவும்</string>\n    <string name=\"profiles\">சுயவிவரங்கள்</string>\n    <string name=\"pin_error_length\">முள் 4 எழுத்துகளாக இருக்க வேண்டும்</string>\n    <string name=\"select_an_account\">ஒரு கணக்கைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"manage_accounts\">கணக்குகளை நிர்வகிக்கவும்</string>\n    <string name=\"plugin\">செருகுநிரல்கள்</string>\n    <string name=\"error_invalid_url\">தவறான வலைதள முகவரி</string>\n    <string name=\"automatic_plugin_updates\">தானியங்கி சொருகி புதுப்பிப்புகள்</string>\n    <string name=\"automatic_plugin_download_mode_title\">பதிவிறக்கத்தை வடிகட்ட பயன்முறையைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"reset_btn\">மீட்டமை</string>\n    <string name=\"no_plugins_found_error\">களஞ்சியத்தில் செருகுநிரல்கள் எதுவும் காணப்படவில்லை</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">சீசன் %1$d எபிசோட் %2$d வெளியிடப்படும்</string>\n    <string name=\"update_started\">புதுப்பிப்பு தொடங்கியது</string>\n    <string name=\"recommendations_tooltip\">பரிந்துரைகளைக் காட்டு</string>\n    <string name=\"benene_count_text\">டெவ்சுக்கு வழங்கப்பட்ட %d பெனின்கள்</string>\n    <string name=\"speed_setting_summary\">பிளேயரில் வேக விருப்பத்தை சேர்க்கிறது</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">கோப்பு %s இலிருந்து தரவை மீட்டெடுப்பதில் தோல்வி</string>\n    <string name=\"library\">நூலகம்</string>\n    <string name=\"settings_info\">செய்தி</string>\n    <string name=\"advanced_search_des\">வழங்குநரால் பிரிக்கப்பட்ட தேடல் முடிவுகளை உங்களுக்கு வழங்குகிறது</string>\n    <string name=\"pref_filter_search_quality\">தேடல் முடிவுகளில் தேர்ந்தெடுக்கப்பட்ட வீடியோ தரத்தை மறைக்கவும்</string>\n    <string name=\"updates_settings\">பயன்பாட்டு புதுப்பிப்புகளைக் காட்டு</string>\n    <string name=\"updates_settings_des\">பயன்பாட்டைத் தொடங்கிய பின் புதிய புதுப்பிப்புகளைத் தானாகவே தேடுங்கள்.</string>\n    <string name=\"redo_setup_process\">அமைவு செயல்முறை மீண்டும்</string>\n    <string name=\"lightnovel\">அதே தேவ்சின் ஒளி நாவல் பயன்பாடு</string>\n    <string name=\"benene\">தேவ்சுக்கு ஒரு பெனீன் கொடுங்கள்</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"no_episodes_found\">அத்தியாயங்கள் எதுவும் கிடைக்கவில்லை</string>\n    <string name=\"delete\">அழி</string>\n    <string name=\"delete_file\">கோப்பை அழி</string>\n    <string name=\"pause\">இடைநிறுத்தம்</string>\n    <string name=\"start\">தொடங்கு</string>\n    <string name=\"test_passed\">கடந்து சென்றது</string>\n    <string name=\"status_ongoing\">நடந்து கொண்டிருக்கிறது</string>\n    <string name=\"duration\">காலம்</string>\n    <string name=\"queued\">வரிசையில்</string>\n    <string name=\"used_storage\">பயன்படுத்தப்பட்டது</string>\n    <string name=\"app_storage\">பயன்பாடு</string>\n    <string name=\"documentaries\">ஆவணப்படங்கள்</string>\n    <string name=\"livestreams\">லைவ்ச்ட்ரீம்கள்</string>\n    <string name=\"tv_series_singular\">தொடர்</string>\n    <string name=\"cartoons_singular\">கார்ட்டூன்</string>\n    <string name=\"anime_singular\">அனிம்</string>\n    <string name=\"storage_error\">பிழையைப் பதிவிறக்குங்கள், சேமிப்பக அனுமதிகளை சரிபார்க்கவும்</string>\n    <string name=\"home_change_provider_img_des\">வழங்குநரை மாற்றவும்</string>\n    <string name=\"preview_background_img_des\">முன்னோட்டம் பின்னணி</string>\n    <string name=\"show_fillers_settings\">அனிமேசுக்கு நிரப்பு அத்தியாயத்தைக் காட்டு</string>\n    <string name=\"automatic_plugin_download_summary\">கூடுதல் களஞ்சியங்களிலிருந்து இன்னும் நிறுவப்படாத அனைத்து செருகுநிரல்களையும் தானாக நிறுவவும்.</string>\n    <string name=\"anim\">அதே தேவ்சின் அனிம் பயன்பாடு</string>\n    <string name=\"episodes\">அத்தியாயங்கள்</string>\n    <string name=\"status_completed\">முடிந்தது</string>\n    <string name=\"no_subtitles\">வசன வரிகள் இல்லை</string>\n    <string name=\"cartoons\">கார்ட்டூன்கள்</string>\n    <string name=\"torrent\">டொரண்ட்ச்</string>\n    <string name=\"movies_singular\">படம்</string>\n    <string name=\"episode_action_play_in_format\">%s இல் விளையாடுங்கள்</string>\n    <string name=\"source_error\">மூல பிழை</string>\n    <string name=\"remote_error\">தொலை பிழை</string>\n    <string name=\"render_error\">ரெண்டரர் பிழை</string>\n    <string name=\"episode_action_auto_download\">ஆட்டோ பதிவிறக்கம்</string>\n    <string name=\"episode_action_download_mirror\">கண்ணாடியைப் பதிவிறக்கவும்</string>\n    <string name=\"episode_action_reload_links\">இணைப்புகளை மீண்டும் ஏற்றவும்</string>\n    <string name=\"video_skip_op\">OP ஐத் தவிர்க்கவும்</string>\n    <string name=\"skip_update\">இந்த புதுப்பிப்பைத் தவிர்க்கவும்</string>\n    <string name=\"episode_action_download_subtitle\">வசன வரிகள் பதிவிறக்கவும்</string>\n    <string name=\"show_sub\">துணை சிட்டை</string>\n    <string name=\"video_aspect_ratio_resize\">மறுஅளவிடுங்கள்</string>\n    <string name=\"watch_quality_pref\">விருப்பமான கடிகார தகுதி (வைஃபை)</string>\n    <string name=\"limit_title\">வீடியோ பிளேயர் தலைப்பு மேக்ச் சார்ச்</string>\n    <string name=\"remove_site_pref\">தளத்தை அகற்று</string>\n    <string name=\"download_path_pref\">பாதை பதிவிறக்க</string>\n    <string name=\"video_buffer_length_settings\">வீடியோ இடையக நீளம்</string>\n    <string name=\"video_buffer_disk_settings\">வட்டில் வீடியோ கேச்</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">பிளேயர் தெரியும் போது பயன்படுத்தப்படும் தேடல் தொகை</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">பிளேயர் மறைக்கப்படும்போது பயன்படுத்தப்படும் தேடல் தொகை</string>\n    <string name=\"video_ram_description\">ஆண்ட்ராய்டு டிவி போன்ற குறைந்த நினைவகம் கொண்ட சாதனங்களில் மிக அதிகமாக அமைக்கப்பட்டால் செயலிழப்புகளை ஏற்படுத்துகிறது.</string>\n    <string name=\"dns_pref_summary\">ISP தொகுதிகளைத் தவிர்ப்பதற்கு பயனுள்ளதாக இருக்கும்</string>\n    <string name=\"resize_fit\">திரைக்கு பொருந்தும்</string>\n    <string name=\"legal_notice\">மறுப்பு</string>\n    <string name=\"pref_category_links\">இணைப்புகள்</string>\n    <string name=\"pref_category_app_updates\">பயன்பாட்டு புதுப்பிப்புகள்</string>\n    <string name=\"pref_category_backup\">காப்புப்பிரதி</string>\n    <string name=\"pref_category_cache\">கேச்</string>\n    <string name=\"pref_category_player_layout\">மனையமைவு</string>\n    <string name=\"pref_category_looks\">தெரிகிறது</string>\n    <string name=\"random_button_settings\">சீரற்ற பொத்தான்</string>\n    <string name=\"random_button_settings_desc\">முகப்புப்பக்கம் மற்றும் நூலகத்தில் சீரற்ற பொத்தானைக் காட்டு</string>\n    <string name=\"category_provider_test\">வழங்குநர் சோதனை</string>\n    <string name=\"category_ui\">மனையமைவு</string>\n    <string name=\"preferred_media_settings\">விருப்பமான மீடியா</string>\n    <string name=\"category_providers\">வழங்குநர்கள்</string>\n    <string name=\"automatic\">தானி</string>\n    <string name=\"phone_layout\">தொலைபேசி தளவமைப்பு</string>\n    <string name=\"example_password\">கடவுச்சொல் 123</string>\n    <string name=\"example_username\">பயனர்பெயர்</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"login\">புகுபதிகை</string>\n    <string name=\"add_account\">கணக்கு சேர்க்க</string>\n    <string name=\"create_account\">உங்கள் கணக்கை துவங்குங்கள்</string>\n    <string name=\"add_sync\">கண்காணிப்பைச் சேர்க்கவும்</string>\n    <string name=\"upload_sync\">ஒத்திசைவு</string>\n    <string name=\"sync_score\">மதிப்பிடப்பட்டது</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">%s இல் உள்நுழைய முடியவில்லை</string>\n    <string name=\"disable\">முடக்கு</string>\n    <string name=\"none\">எதுவுமில்லை</string>\n    <string name=\"min\">மணித்துளி</string>\n    <string name=\"subtitles_outline\">அவுட்லைன்</string>\n    <string name=\"subtitles_depressed\">மனச்சோர்வு</string>\n    <string name=\"subtitles_shadow\">நிழல்</string>\n    <string name=\"subtitles_raised\">எழுப்பப்பட்ட</string>\n    <string name=\"subtitle_offset\">ஒத்திசைவு துணை</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">வசன வரிகள் காட்டப்பட்டால் இதைப் பயன்படுத்தவும் %d ms மிகவும் தாமதமானது</string>\n    <string name=\"actor_main\">முக்கிய</string>\n    <string name=\"actor_supporting\">துணை</string>\n    <string name=\"quality_cam\">கேம்</string>\n    <string name=\"quality_tc\">டி.சி.</string>\n    <string name=\"quality_blueray\">ப்ளூ-ரே</string>\n    <string name=\"quality_workprint\">Wp</string>\n    <string name=\"quality_dvd\">டிவிடி</string>\n    <string name=\"quality_4k\">4 கே</string>\n    <string name=\"quality_sd\">எச்.டி.</string>\n    <string name=\"quality_uhd\">யுஎச்.டி</string>\n    <string name=\"quality_hdr\">எச்.டி.ஆர்</string>\n    <string name=\"quality_hd\">எச்டி</string>\n    <string name=\"quality_sdr\">எச்.டி.ஆர்</string>\n    <string name=\"error_invalid_id\">தவறான ஐடி</string>\n    <string name=\"error_invalid_data\">தவறான தரவு</string>\n    <string name=\"subtitles_filter_lang\">விருப்பமான ஊடக மொழியால் வடிகட்டவும்</string>\n    <string name=\"extras\">கூடுதல்</string>\n    <string name=\"trailer\">டிரெய்லர்</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"referer\">குறிப்பாளர் (விரும்பினால்)</string>\n    <string name=\"provider_languages_tip\">இந்த மொழிகளில் வீடியோக்களைப் பாருங்கள்</string>\n    <string name=\"view_public_repositories_button\">சமூக களஞ்சியங்களைக் காண்க</string>\n    <string name=\"apply_on_restart\">மாற்றங்களைக் காண பயன்பாட்டை மறுதொடக்கம் செய்யுங்கள்.</string>\n    <string name=\"safe_mode_crash_info\">செயலிழப்பு தகவலைக் காண்க</string>\n    <string name=\"delete_repository\">களஞ்சியத்தை நீக்கு</string>\n    <string name=\"blank_repo_message\">கிளவுட்ச்ட்ரீமில் இயல்புநிலையாக எந்தத் தளங்களும் நிறுவப்படவில்லை. நீங்கள் களஞ்சியங்களிலிருந்து தளங்களை நிறுவ வேண்டும். \\n\\n எங்கள் முரண்பாட்டில் சேரவும் அல்லது ஆன்லைனில் தேடுங்கள்.</string>\n    <string name=\"extension_status\">நிலை</string>\n    <string name=\"extension_size\">அளவு</string>\n    <string name=\"extension_types\">ஆதரிக்கப்பட்டது</string>\n    <string name=\"extension_install_first\">முதலில் நீட்டிப்பை நிறுவவும்</string>\n    <string name=\"player_settings_select_cast_device\">காச்ட் சாதனத்தைத் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"all_languages_preference\">அனைத்து மொழிகளும்</string>\n    <string name=\"yes\">ஆம்</string>\n    <string name=\"battery_dialog_title\">பேட்டரி தேர்வுமுறை முடக்கு</string>\n    <string name=\"enter_pin\">முள் உள்ளிடவும்</string>\n    <string name=\"lock_profile\">பூட்டு சுயவிவரம்</string>\n    <string name=\"logged_account\" formatted=\"true\">%s ஆக உள்நுழைந்துள்ளது</string>\n    <string name=\"skip_startup_account_select_pref\">தொடக்கத்தில் கணக்கு தேர்வைத் தவிர்க்கவும்</string>\n    <string name=\"use_default_account\">இயல்புநிலை கணக்கைப் பயன்படுத்தவும்</string>\n    <string name=\"password_pin_authentication_title\">கடவுச்சொல்/முள் ஏற்பு</string>\n    <string name=\"biometric_unsupported\">இந்த சாதனத்தில் பயோமெட்ரிக் ஏற்பு ஆதரிக்கப்படவில்லை</string>\n    <string name=\"biometric_setting_summary\">கைரேகை, முகம் ஐடி, முள், முறை மற்றும் கடவுச்சொல் மூலம் பயன்பாட்டைத் திறக்கவும்.</string>\n    <string name=\"biometric_prompt_description\">தோல்வியுற்ற சில முயற்சிகளுக்குப் பிறகு, வரியில் மூடப்படும். மீண்டும் முயற்சிக்க பயன்பாட்டை மறுதொடக்கம் செய்யுங்கள்.</string>\n    <string name=\"episode_action_cast_mirror\">காச்ட் மிரர்</string>\n    <string name=\"no_update_found\">புதுப்பிப்பு எதுவும் கிடைக்கவில்லை</string>\n    <string name=\"example_site_name\">செய்தித் பெயர்</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"switch_account\">கணக்கை மாற்றவும்</string>\n    <string name=\"subtitle_offset_hint\">1000 எம்.எச்</string>\n    <string name=\"home_random\">சீரற்ற</string>\n    <string name=\"quality_hq\">Hq</string>\n    <string name=\"skip_setup\">அமைப்பைத் தவிர்க்கவும்</string>\n    <string name=\"app_layout_subtext\">உங்கள் சாதனத்திற்கு ஏற்றவாறு பயன்பாட்டின் தோற்றத்தை மாற்றவும்</string>\n    <string name=\"preferred_media_subtext\">உனக்கு என்ன பார்க்க வேண்டும்</string>\n    <string name=\"add_repository\">களஞ்சியத்தைச் சேர்க்கவும்</string>\n    <string name=\"repository_name_hint\">களஞ்சிய பெயர் (விரும்பினால்)</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">பதிவிறக்கம் செய்யப்படவில்லை: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">புதுப்பிக்கப்பட்டது %d செருகுநிரல்கள்</string>\n    <string name=\"player_settings_play_in_app\">உள் வீரர்</string>\n    <string name=\"skip_type_op\">திறப்பு</string>\n    <string name=\"skip_type_mixed_op\">கலப்பு திறப்பு</string>\n    <string name=\"skip_type_creddits\">வரவு</string>\n    <string name=\"history\">வரலாறு</string>\n    <string name=\"ok\">சரி</string>\n    <string name=\"app_info_intent_error\">கிளவுட்ச்ட்ரீமின் பயன்பாட்டுத் தகவலைத் திறக்க முடியவில்லை.</string>\n    <string name=\"subscription_new\">%s க்கு குழுசேர்ந்தது</string>\n    <string name=\"help\">உதவி</string>\n    <string name=\"action_add_to_favorites\">பிடித்தவையில் சேர்</string>\n    <string name=\"rotate_video\">சுழற்றுங்கள்</string>\n    <string name=\"rotate_video_desc\">திரை நோக்குநிலைக்கு மாற்று பொத்தானைக் காண்பி</string>\n    <string name=\"auto_rotate_video_desc\">வீடியோ நோக்குநிலையின் அடிப்படையில் திரை நோக்குநிலையின் தானியங்கி மாறுவதை இயக்கவும்</string>\n    <string name=\"auto_rotate_video\">ஆட்டோ சுழலும்</string>\n    <string name=\"favorite\">பிடித்த</string>\n    <string name=\"music_singlar\">இசை</string>\n    <string name=\"ova\">ஓவா</string>\n    <string name=\"show_hd\">தரமான சிட்டை</string>\n    <string name=\"update\">புதுப்பிப்பு</string>\n    <string name=\"logout\">விடுபதிகை</string>\n    <string name=\"quality_webrip\">விரலிடைத் தோல்</string>\n    <string name=\"apk_installer_settings_des\">சில சாதனங்கள் புதிய தொகுப்பு நிறுவியை ஆதரிக்கவில்லை. புதுப்பிப்புகள் நிறுவப்படவில்லை என்றால், மரபு விருப்பத்தை முயற்சிக்கவும்.</string>\n    <string name=\"battery_dialog_message\">சந்தா தொலைக்காட்சி நிகழ்ச்சிகளுக்கான தடையற்ற பதிவிறக்கங்கள் மற்றும் அறிவிப்புகளை உறுதிப்படுத்த, கிளவுட்ச்ட்ரீம் பின்னணியில் இயங்க இசைவு தேவை. சரி என்பதை அழுத்துவதன் மூலம், உங்களுக்கு கோரிக்கை உரையாடல் காண்பிக்கப்படும். தயவுசெய்து \\'இசைவு\\' என்பதை அழுத்தவும். \\n\\nதயவுசெய்து கவனிக்கவும், இந்த இசைவு CS3 உங்கள் பேட்டரியை வெளியேற்றும் என்று அர்த்தமல்ல. அறிவிப்புகளைப் பெறும்போது அல்லது உத்தியோகபூர்வ நீட்டிப்புகளிலிருந்து வீடியோக்களைப் பதிவிறக்குவது போன்ற பின்னணியில் மட்டுமே இது செயல்படும்.</string>\n    <string name=\"app_unrestricted_toast\">பயன்பாட்டு பேட்டரி பயன்பாடு ஏற்கனவே கட்டுப்பாடற்றதாக அமைக்கப்பட்டுள்ளது</string>\n    <string name=\"update_notification_installing\">பயன்பாட்டு புதுப்பிப்பை நிறுவுகிறது…</string>\n    <string name=\"update_notification_failed\">பயன்பாட்டின் புதிய பதிப்பை நிறுவ முடியவில்லை</string>\n    <string name=\"apk_installer_legacy\">மரபு</string>\n    <string name=\"sort\">வரிசைப்படுத்து</string>\n    <string name=\"sort_rating_desc\">மதிப்பீடு (உயர் முதல் குறைந்த வரை)</string>\n    <string name=\"sort_rating_asc\">மதிப்பீடு (குறைந்த முதல் உயர் வரை)</string>\n    <string name=\"sort_updated_new\">புதுப்பிக்கப்பட்டது (பழையது புதியது)</string>\n    <string name=\"empty_library_logged_in_message\">இந்த பட்டியல் காலியாக உள்ளது. இன்னொரு இடத்திற்கு மாற முயற்சிக்கவும்.</string>\n    <string name=\"safe_mode_file\">பாதுகாப்பான பயன்முறை கோப்பு கிடைத்தது!\n\\n கோப்பு அகற்றப்படும் வரை தொடக்கத்தில் எந்த நீட்டிப்புகளையும் ஏற்றவில்லை.</string>\n    <string name=\"subscription_in_progress_notification\">சந்தா காட்சிகளைப் புதுப்பித்தல்</string>\n    <string name=\"subscription_list_name\">சந்தா</string>\n    <string name=\"subscription_episode_released\">எபிசோட் %d வெளியானது!</string>\n    <string name=\"mobile_data\">மொபைல் தரவு</string>\n    <string name=\"set_default\">இயல்புநிலையை அமைக்கவும்</string>\n    <string name=\"quality_profile_help\">ஆதாரங்கள் எவ்வாறு உத்தரவிடப்படுகின்றன என்பதை இங்கே மாற்றலாம். ஒரு வீடியோவுக்கு அதிக முன்னுரிமை இருந்தால், அது மூல தேர்வில் அதிகமாகத் தோன்றும். மூல முன்னுரிமையின் தொகை மற்றும் தரமான முன்னுரிமை ஆகியவை வீடியோ முன்னுரிமை. \\n\\n சான்று A: 3 \\n தகுதி பி: 7 \\n 10 இன் ஒருங்கிணைந்த வீடியோ முன்னுரிமை இருக்கும். \\n\\n குறிப்பு: தொகை 10 அல்லது அதற்கு மேற்பட்டதாக இருந்தால், அந்த இணைப்பு ஏற்றப்படும்போது பிளேயர் தானாகவே ஏற்றுவதைத் தவிர்க்கும்!</string>\n    <string name=\"biometric_warning\">உங்கள் கிளவுட்ச்ட்ரீம் தரவு இப்போது காப்புப் பிரதி எடுக்கப்பட்டுள்ளது. இதன் சாத்தியம் மிகக் குறைவு என்றாலும், எல்லா சாதனங்களும் வித்தியாசமாக நடந்து கொள்ளலாம். அரிய விசயத்தில், பயன்பாட்டை அணுகுவதிலிருந்து நீங்கள் பூட்டப்படுகிறீர்கள், பயன்பாட்டு தரவை முழுவதுமாக அழித்து, காப்புப்பிரதியிலிருந்து மீட்டெடுக்கவும். இதிலிருந்து எழும் ஏதேனும் சிரமத்திற்கு நாங்கள் மிகவும் வருந்துகிறோம்.</string>\n    <string name=\"custom_media_singluar\">ஊடகம்</string>\n    <string name=\"pref_category_accounts\">கணக்குகள்</string>\n    <string name=\"test_warning\">எச்சரிக்கை</string>\n    <string name=\"downloads_empty\">தற்போது பதிவிறக்கங்கள் எதுவும் இல்லை.</string>\n    <string name=\"sort_release_date_old\">வெளியீட்டு தேதி (பழையதிலிருந்து புதியது)</string>\n    <string name=\"dont_show\">காட்ட வேண்டாம்</string>\n    <string name=\"show\">காட்டு</string>\n    <string name=\"qr_image\">QR குறியீடு படம்</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">%s இல் வரவிருக்கும்</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">பின்வரும் தொடரில் உள்ள அனைத்து அத்தியாயங்களையும் நிரந்தரமாக நீக்க விரும்புகிறீர்களா?\\n\\n %s</string>\n    <string name=\"no_subtitles_loaded\">இதுவரை வசன வரிகள் எதுவும் ஏற்றப்படவில்லை</string>\n    <string name=\"confirm_before_exiting_title\">வெளியேறுவதற்கு முன் உறுதிப்படுத்தவும்</string>\n    <string name=\"favorite_added\">%s பிடித்தவைகளில் சேர்க்கப்படுகின்றன</string>\n    <string name=\"favorite_removed\">%s பிடித்தவைகளிலிருந்து அகற்றப்பட்டன</string>\n    <string name=\"play_from_beginning_img_des\">முதலில் இருந்து ஆரம்பி</string>\n    <string name=\"pref_category_security\">பாதுகாப்பு</string>\n    <string name=\"sort_release_date_new\">வெளியீட்டு தேதி (பழையது புதியது)</string>\n    <string name=\"select_all\">அனைத்தையும் தேர்ந்தெடுக்கவும்</string>\n    <string name=\"downloads_delete_select\">அழிப்பதற்கு தேர்ந்தெடுக்கவும்</string>\n    <string name=\"delete_files\">கோப்புகளை நீக்கு</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">இந்தத் தரவுகளை நிரந்தரமாக நீக்கலாமா?\\n\\n%s</string>\n    <string name=\"rated_format\" formatted=\"true\">மதிப்பிடப்பட்டது: %.1f</string>\n    <string name=\"added_sync_format\" formatted=\"true\">சேர்க்கப்பட்டது %s</string>\n    <string name=\"extension_rating\" formatted=\"true\">மதிப்பீடு: %s</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%d.எம\\n மீதமுள்ள</string>\n    <string name=\"unable_to_inflate\">இடைமுகம் ஐ சரியாக உருவாக்க முடியவில்லை, இது ஒரு பெரிய பிழை மற்றும் உடனடியாக %s தெரிவிக்க வேண்டும்</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\n மீதமுள்ள</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">அனைத்து %s ஏற்கனவே பதிவிறக்கம் செய்யப்பட்டுள்ளன</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (முடக்கப்பட்டவை)</string>\n    <string name=\"torrent_info\">இந்த வீடியோ ஒரு நீரோடை, இதன் பொருள் உங்கள் வீடியோ செயல்பாட்டைக் கண்காணிக்க முடியும்.\\n தொடர்வதற்கு முன் நீரோட்டத்தை நீங்கள் புரிந்துகொண்டுள்ளீர்கள் என்பதை உறுதிப்படுத்திக் கொள்ளுங்கள்.</string>\n    <string name=\"delete_plugin\">சொருகி நீக்கு</string>\n    <string name=\"preview_seekbar_desc\">சீக்பரில் முன்னோட்ட சிறுபடத்தை இயக்கவும்</string>\n    <string name=\"device_pin_counter_text\">குறியீடு %1$dm %2$ds இல் காலாவதியாகிறது</string>\n    <string name=\"confirm_before_exiting_desc\">பயன்பாட்டிலிருந்து வெளியேறுவதற்கு முன் உரையாடலைக் காட்டு</string>\n    <string name=\"auth_locally\">உள்நாட்டில் அங்கீகரிக்கவும்</string>\n    <string name=\"dismiss\">தள்ளுபடி</string>\n    <string name=\"device_pin_url_message\">உங்கள் ச்மார்ட்போன் அல்லது கணினியில் <b>%s </b> ஐப் பார்வையிட்டு மேலே உள்ள குறியீட்டை உள்ளிடவும்</string>\n    <string name=\"device_pin_error_message\">சாதன முள் குறியீட்டைப் பெற முடியாது, உள்ளக அங்கீகாரத்தை முயற்சிக்கவும்</string>\n    <string name=\"device_pin_expired_message\">முள் குறியீடு இப்போது காலாவதியானது!</string>\n    <string name=\"subs_edge_size\">விளிம்பு அளவு</string>\n    <string name=\"cs3wiki\">கிளவுட்ச்ட்ரீம் விக்கி</string>\n    <string name=\"preview_seekbar\">சீக்பார் முன்னோட்டம்</string>\n    <string name=\"backup_path_title\">காப்பு கோப்புறை இருப்பிடம்</string>\n    <string name=\"open_local_video\">உள்ளக வீடியோவைத் திறக்கவும்</string>\n    <string name=\"open_downloaded_repo\">திறந்த களஞ்சியம்</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">உங்கள் நூலகத்தில் ஏற்கனவே ஒரு நகல் உருப்படி இருப்பதாகத் தெரிகிறது: \\'%s.\\'\\n\\n இந்த உருப்படியை எப்படியும் சேர்க்க விரும்புகிறீர்களா, இருக்கும் ஒன்றை மாற்ற விரும்புகிறீர்களா அல்லது செயலை ரத்து செய்ய விரும்புகிறீர்களா?</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">உங்கள் நூலகத்தில் சாத்தியமான நகல் உருப்படிகள் கண்டறியப்பட்டுள்ளன:\\n\\n %s\\n\\n இந்த உருப்படியை எப்படியும் சேர்க்க விரும்புகிறீர்களா, ஏற்கனவே உள்ளவற்றை மாற்ற விரும்புகிறீர்களா அல்லது செயலை ரத்து செய்ய விரும்புகிறீர்களா?</string>\n    <string name=\"hide_player_control_names\">வீரரின் கட்டுப்பாடுகளின் பெயர்களை மறைக்கவும்</string>\n    <string name=\"custom\">தனிப்பயன்</string>\n    <string name=\"deselect_all\">அனைத்தையும் தேர்வு செய்யுங்கள்</string>\n    <string name=\"offline_file\">ஆஃப்லைனில் பார்ப்பதற்கு கிடைக்கிறது</string>\n    <string name=\"delete_format\" formatted=\"true\">நீக்கு ( %1$d | %2$s)</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">பின்வரும் அத்தியாயங்களை %1$s இல் நிரந்தரமாக நீக்க விரும்புகிறீர்களா?\\n\\n %2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">பின்வரும் தொடரில் உள்ள அனைத்து அத்தியாயங்களையும் நீங்கள் நிரந்தரமாக நீக்குவீர்கள்:\\n\\n %s</string>\n    <string name=\"speech_recognition_unavailable\">பேச்சு ஏற்பு கிடைக்கவில்லை</string>\n    <string name=\"begin_speaking\">பேசத் தொடங்குங்கள்…</string>\n    <string name=\"audio_singluar\">ஆடியோ</string>\n    <string name=\"podcast_singluar\">போட்காச்ட்</string>\n    <string name=\"encoding_error\">குறியீட்டு பிழை</string>\n    <string name=\"unsupported_error\">ஆதரிக்கப்படாத பிழை</string>\n    <string name=\"player_load_one_subtitle_online\">முதலில் கிடைக்கிறது</string>\n    <string name=\"sort_episodes_number_asc\">அத்தியாயம் (ஏறுதல்)</string>\n    <string name=\"sort_episodes_number_desc\">அத்தியாயம் (இறங்கு)</string>\n    <string name=\"sort_episodes_rating_high_low\">மதிப்பீடு (மிக உயர்ந்த)</string>\n    <string name=\"sort_episodes_rating_low_high\">மதிப்பீடு (மிகக் குறைந்த)</string>\n    <string name=\"sort_episodes_date_newest\">காற்று தேதி (புதியது)</string>\n    <string name=\"sort_episodes_date_oldest\">காற்று தேதி (பழமையானது)</string>\n    <string name=\"sort_button_episode\">பாகம் %s</string>\n    <string name=\"sort_button_rating\">மதிப்பீடு %s</string>\n    <string name=\"sort_button_date\">தேதி %s</string>\n    <string name=\"torrent_preferred_media\">அமைப்புகள்/வழங்குநர்கள்/விருப்பமான ஊடகங்களில் டொரெண்டை இயக்கவும்</string>\n    <string name=\"torrent_not_accepted\">பயன்பாட்டை மறுதொடக்கம் செய்து, தொடர ச்ட்ரீம் டொரண்ட் பாப்-அப் ஏற்றுக்கொள்ளுங்கள்.</string>\n    <string name=\"software_decoding\">மென்பொருள் டிகோடிங்</string>\n    <string name=\"software_decoding_desc\">மென்பொருள் டிகோடிங் உங்கள் சாதனத்தால் ஆதரிக்கப்படாத வீடியோ கோப்புகளை பிளேயருக்கு இயக்க உதவுகிறது, ஆனால் உயர் தெளிவுத்திறனில் பின்னடைவு அல்லது நிலையற்ற பிளேபேக்கை ஏற்படுத்தலாம்.</string>\n    <string name=\"volume_exceeded_100\">தொகுதி 100% ஐ தாண்டியுள்ளது</string>\n    <string name=\"slide_up_again_to_exceed_100\">100% க்கு அப்பால் செல்ல மீண்டும் சறுக்கவும்</string>\n    <string name=\"update_plugins\">செருகுநிரல்களைப் புதுப்பிக்கவும்</string>\n    <string name=\"update_plugins_manually\">செருகுநிரல்களை கைமுறையாக புதுப்பிக்கவும்</string>\n    <string name=\"starting_plugin_update_manually\">சொருகி புதுப்பிப்பு செயல்முறையைத் தொடங்குகிறது!</string>\n    <string name=\"plugins_updated_manually\">வெற்றிகரமாக புதுப்பிக்கப்பட்டது %d சொருகி (கள்)!</string>\n    <string name=\"no_plugins_updated_manually\">செருகுநிரல்கள் எதுவும் புதுப்பிக்கப்படவில்லை.</string>\n    <string name=\"player_notification_channel_name\">பிளேயர் அறிவிப்புகள்</string>\n    <string name=\"player_notification_channel_description\">பின்னணியில் இருந்து பின்னணியைக் கட்டுப்படுத்துவதற்கான பிளேயர் அறிவிப்பு</string>\n    <string name=\"subtitles_from_embedded\">உட்பொதிக்கப்பட்டது</string>\n    <string name=\"subtitles_from_online\">ஆன்லைனில்</string>\n    <string name=\"all_subtitles_bold\">அனைத்து வசனங்களையும் தைரியமாக ஆக்குங்கள்</string>\n    <string name=\"all_subtitles_italic\">அனைத்து வசன வரிகளையும் சாய்வு செய்யுங்கள்</string>\n    <string name=\"background_radius\">பின்னணி ஆரம்</string>\n    <string name=\"download_parallel_settings_des\">எத்தனை வெவ்வேறு உருப்படிகளை இணையாக பதிவிறக்கம் செய்யலாம்</string>\n    <string name=\"parallel_downloads\">இணை பதிவிறக்கங்கள்</string>\n    <string name=\"concurrent_connections\">ஒரே நேரத்தில் இணைப்புகள்</string>\n    <string name=\"concurrent_connections_settings_des\">பதிவிறக்கும் போது ஒவ்வொரு பதிவிறக்கமும் எத்தனை ஒரே நேரத்தில் இணைப்புகளைப் பயன்படுத்தலாம்</string>\n    <string name=\"go_to_downloads\">பதிவிறக்கங்களுக்குச் செல்லுங்கள்</string>\n    <string name=\"no_internet_connection\">இணைய இணைப்பு இல்லை. \\n\\nதயவுசெய்து இணையத்துடன் இணைத்து மீண்டும் முயற்சிக்கவும், அல்லது நீங்கள் ஆஃப்லைனில் இருக்கும்போது உங்கள் பதிவிறக்கங்களைப் பாருங்கள்.</string>\n    <string name=\"overscan_settings_des\">திரையின் எல்லைகளை மாற்றுகிறது</string>\n    <string name=\"overscan_settings\">ஓவர்ச்கான்</string>\n    <string name=\"poster_size_settings_des\">சுவரொட்டிகளின் அளவை மாற்றுகிறது</string>\n    <string name=\"poster_size_settings\">சுவரொட்டி அளவு</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$d மணி %2$d நிமிடம் %3$d விநாடி</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$d நிமிடம் %2$d விநாடி</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d விநாடி</string>\n    <string name=\"download_queue\">பதிவிறக்க வரிசை</string>\n    <string name=\"play_full_series_button\">முழு தொடரையும் விளையாடு</string>\n    <string name=\"queue_empty_message\">தற்போது வரிசைப்படுத்தப்பட்ட பதிவிறக்கங்கள் எதுவும் இல்லை.</string>\n    <string name=\"extra_brightness_settings\">கூடுதல் ஒளி</string>\n    <string name=\"extra_brightness_settings_des\">100% காட்சி பிரகாசத்தை மீறும் போது பிரகாச வடிப்பானை இயக்கவும்</string>\n    <string name=\"extra_brightness_key\">கூடுதல்_பிரகாசம்_செயல்படுத்தப்பட்டது</string>\n    <string name=\"search_suggestions\">தேடல் பரிந்துரைகள்</string>\n    <string name=\"search_suggestions_des\">தட்டச்சு செய்யும் போது தேடல் பரிந்துரைகளைக் காட்டு</string>\n    <string name=\"clear_suggestions\">தெளிவான பரிந்துரைகள்</string>\n    <string name=\"show_cast_in_details\">காச்ட் பேனலைக் காட்டு</string>\n    <string name=\"install_prerelease\">வெளியீட்டிற்கு முந்தைய பதிப்பை நிறுவவும்</string>\n    <string name=\"prerelease_already_installed\">முன் வெளியீடு ஏற்கனவே நிறுவப்பட்டுள்ளது.</string>\n    <string name=\"prerelease_install_failed\">முன் வெளியீட்டை நிறுவுவதில் தோல்வி.</string>\n    <string name=\"episode_action_play_mirror\">கண்ணாடியை விளையாடு</string>\"\n    <string name=\"show_rating\">மதிப்பீடு சிட்டை</string>\n    <string name=\"show_episode_text\">எபிசோட் உரை</string>\n    <string name=\"video_info\">மீடியா செய்தி</string>\n    <string name=\"player_settings_always_ask\">எப்போதும் கேளுங்கள்</string>\n    <string name=\"source_priority\">மூல முன்னுரிமை</string>\n    <string name=\"source_priority_help\">பிளேயரில் வீடியோ ஆதாரங்கள் எவ்வாறு வரிசைப்படுத்தப்பட வேண்டும் என்பதைத் தீர்மானிக்கவும்</string>\n    <string name=\"no_account\">கணக்கு இல்லை</string>\n    <string name=\"speedup_title\">LongPress விரைவு மாற்று</string>\n    <string name=\"speedup_summary\">2x வேகத்தைப் பெற அழுத்திப் பிடிக்கவும்</string>\n    <string name=\"edit_profile_image_title\">சுயவிவரப் படத்தைத் திருத்து</string>\n    <string name=\"edit_profile_image_hint\">சுயவிவரப் பட முகவரி ஐ உள்ளிடவும்</string>\n    <string name=\"edit_profile_image_error_empty\">முகவரி இல்லை</string>\n    <string name=\"edit_profile_image_error_invalid\">தவறான முகவரி அல்லது படம்</string>\n    <string name=\"edit_profile_image_success\">படம் வெற்றிகரமாக புதுப்பிக்கப்பட்டது</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">இந்த எபிசோட் வரை பார்த்ததாகக் குறிக்கவும்</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">இந்த எபிசோட் வரை பார்த்ததை அகற்று</string>\n    <string name=\"action_reload\">மீண்டும் ஏற்றப்பட்டது</string>\n    <string name=\"reload_provider\">மறுஏற்றம் வழங்குநர்</string>\n    <string name=\"name\">பெயர்</string>\n    <string name=\"source_name\">மூலப் பெயர்</string>\n    <string name=\"resolution_and_name\">தீர்மானம் மற்றும் பெயர்</string>\n    <string name=\"download_all\">அனைத்தையும் பதிவிறக்கவும்</string>\n    <string name=\"cancel_all\">அனைத்தையும் ரத்து வெற்றி</string>\n    <string name=\"download_episode_range\">அத்தியாயம் %s ஐ பதிவிறக்க விரும்புகிறீர்களா?</string>\n    <string name=\"cancel_queue_message\">வரிசைப்படுத்தப்பட்ட அனைத்து பதிவிறக்கங்களையும் ரத்துசெய்ய விரும்புகிறீர்களா?</string>\n    <string name=\"subs_subtitle_alignment\">வசன சீரமைப்பு</string>\n    <string name=\"bottom_left\">கீழே இடது</string>\n    <string name=\"bottom_center\">கீழ் நடுவண்</string>\n    <string name=\"bottom_right\">கீழ் வலது</string>\n    <string name=\"middle_left\">நடுத்தர இடது</string>\n    <string name=\"middle_center\">நடுத்தர நடுவண்</string>\n    <string name=\"middle_right\">நடுத்தர வலது</string>\n    <string name=\"top_left\">மேல் இடது</string>\n    <string name=\"top_center\">மேல் நடுவண்</string>\n    <string name=\"top_right\">மேல் வலது</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d செயலில் பதிவிறக்கம்</item>\n        <item quantity=\"other\">%d செயலில் உள்ள பதிவிறக்கங்கள்</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d பதிவிறக்கம் வரிசையில் உள்ளது</item>\n        <item quantity=\"other\">%d பதிவிறக்கங்கள் வரிசையில் உள்ளன</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ti/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s ክፋል %2$d</string>\n    <string name=\"next_episode_format\" formatted=\"true\">ክፋል %d በ ላይ ይወጣል</string>\n    <string name=\"cast_format\" formatted=\"true\">ተዋሳእቲ፡ %s</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+tl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- KEYS DON'T TRANSLATE -->\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\">%1$s Ep %2$d</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">@string/result_poster_img_des</string>\n    <string name=\"episode_poster_img_des\">Episode Poster</string>\n    <string name=\"home_main_poster_img_des\">Main Poster</string>\n    <string name=\"home_next_random_img_des\">Next Random</string>\n    <string name=\"go_back_img_des\">Go back</string>\n    <string name=\"home_change_provider_img_des\">Change Provider</string>\n    <string name=\"preview_background_img_des\">Preview Background</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Bilis (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Rated: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Bagong update!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"title_home\">Home</string>\n    <string name=\"title_search\">Maghanap</string>\n    <string name=\"title_downloads\">Mga Downloads</string>\n    <string name=\"title_settings\">Mga Settings</string>\n    <string name=\"search_hint\">Maghanap…</string>\n    <string name=\"no_data\">Walang datos</string>\n    <string name=\"episode_more_options_des\">Opsyon</string>\n    <string name=\"next_episode\">Susunod na Episode</string>\n    <string name=\"result_tags\">Genres</string>\n    <string name=\"result_share\">I-share</string>\n    <string name=\"result_open_in_browser\">Buksan sa browser</string>\n    <string name=\"skip_loading\">Skip Loading…</string>\n    <string name=\"loading\">Loading…</string>\n    <string name=\"type_watching\">Pinapanood</string>\n    <string name=\"type_on_hold\">Inihinto</string>\n    <string name=\"type_completed\">Tapos nang panoorin</string>\n    <string name=\"type_dropped\">Ayaw nang panoorin</string>\n    <string name=\"type_plan_to_watch\">Balak panoorin</string>\n    <string name=\"play_movie_button\">I-play ang Movie</string>\n    <string name=\"play_torrent_button\">Stream Torrent</string>\n    <string name=\"pick_source\">Sources</string>\n    <string name=\"pick_subtitle\">Subtitles</string>\n    <string name=\"reload_error\">Retry connection…</string>\n    <string name=\"go_back\">Go back</string>\n    <string name=\"play_episode\">I-play ang episode</string>\n    <!--<string name=\"need_storage\">Payagan sa Itabi</string>-->\n    <string name=\"download\">Download</string>\n    <string name=\"downloaded\">Downloaded</string>\n    <string name=\"downloading\">Downloading</string>\n    <string name=\"download_paused\">Download Paused</string>\n    <string name=\"download_started\">Download Started</string>\n    <string name=\"download_failed\">Download Failed</string>\n    <string name=\"download_canceled\">Download Canceled</string>\n    <string name=\"download_done\">Download Done</string>\n    <string name=\"error_loading_links_toast\">Error Loading Links</string>\n    <string name=\"download_storage_text\">Internal Storage</string>\n    <string name=\"app_dubbed_text\">Dub</string>\n    <string name=\"app_subbed_text\">Sub</string>\n    <string name=\"popup_delete_file\">I-delete ang file</string>\n    <string name=\"popup_play_file\">I-play ang file</string>\n    <string name=\"popup_resume_download\">I-resume ang download</string>\n    <string name=\"popup_pause_download\">I-pause ang download</string>\n    <string name=\"home_more_info\">More Info</string>\n    <string name=\"home_expanded_hide\">Itago</string>\n    <string name=\"home_play\">I-play</string>\n    <string name=\"home_info\">Impormasyon</string>\n    <string name=\"filter_bookmarks\">Filter Bookmarks</string>\n    <string name=\"error_bookmarks_text\">Bookmark</string>\n    <string name=\"action_remove_from_bookmarks\">Tanggalin</string>\n    <string name=\"sort_apply\">Kumpirmahin</string>\n    <string name=\"player_speed\">Bilis ng Playback</string>\n    <string name=\"subtitles_settings\">Subtitle Setting</string>\n    <string name=\"subs_text_color\">Kulay ng Teksto</string>\n    <string name=\"subs_outline_color\">Kulay ng Outline</string>\n    <string name=\"subs_background_color\">Kulay ng Background</string>\n    <string name=\"subs_window_color\">Window Color</string>\n    <string name=\"subs_edge_type\">Edge Type</string>\n    <string name=\"subs_subtitle_elevation\">Subtitle Elevation</string>\n    <string name=\"subs_font\">Istilo ng Font</string>\n    <string name=\"subs_font_size\">Laki ng Font</string>\n    <string name=\"search_provider_text_providers\">Search using providers</string>\n    <string name=\"search_provider_text_types\">Search using types</string>\n    <string name=\"benene_count_text\">%d Benenes na ibinigay sa mga devs</string>\n    <string name=\"benene_count_text_none\">Walang Benenes na binigay</string>\n    <string name=\"subs_auto_select_language\">Awtomatikong magpili ng lenggwahe</string>\n    <string name=\"subs_download_languages\">I-download ang mga Wika</string>\n    <string name=\"subs_hold_to_reset_to_default\">Pindutin nang matagal upang i-reset sa default</string>\n    <string name=\"continue_watching\">Ipagpatuloy ang pinapanood</string>\n    <string name=\"action_remove_watching\">Tanggalin</string>\n    <string name=\"action_open_watching\">Impormasyon</string>\n    <string name=\"vpn_might_be_needed\">Maaaring nangangailangan gumamit ng VPN upang gumana ito</string>\n    <string name=\"vpn_torrent\">Ito ay torrent, inirerekomenda ang paggamit ng VPN</string>\n    <string name=\"torrent_plot\">Deskripsyon</string>\n    <string name=\"normal_no_plot\">Walang nakitang plot</string>\n    <string name=\"torrent_no_plot\">Walang nakitang deskripsyon</string>\n    <string name=\"picture_in_picture\">Picture-in-picture</string>\n    <string name=\"picture_in_picture_des\">Magpatuloy ang playback sa isang maliit na player sa ibabaw ng ibang apps</string>\n    <string name=\"player_size_settings\">Pindutan upang baguhin ang laki</string>\n    <string name=\"player_size_settings_des\">Alisin ang black borders</string>\n    <string name=\"player_subtitles_settings\">Subtitles</string>\n    <string name=\"player_subtitles_settings_des\">Player subtitles settings</string>\n    <string name=\"eigengraumode_settings\">Eigengravy Mode</string>\n    <string name=\"swipe_to_seek_settings\">Swipe to seek</string>\n    <string name=\"swipe_to_seek_settings_des\">Swipe pakanan o pakaliwa upang makontrol ang oras ng pinapanood</string>\n    <string name=\"swipe_to_change_settings\">Swipe to change settings</string>\n    <string name=\"swipe_to_change_settings_des\">Swipe pataas/pababa sa kanan o kaliwang bahagi ng player upang dagdagan/bawasan ang brightness/volume</string>\n    <string name=\"double_tap_to_seek_settings\">Double tap to seek</string>\n    <string name=\"double_tap_to_seek_settings_des\">Tapikin ng dalawang beses sa kanan o kaliwang bahagi ng player upang mag-forward/backward</string>\n    <string name=\"use_system_brightness_settings\">Gamitin ang brightness ng system</string>\n    <string name=\"use_system_brightness_settings_des\">Gamitin ang brightness ng system para sa player</string>\n    <string name=\"search\">Maghanap</string>\n    <string name=\"settings_info\">Impormasyon</string>\n    <string name=\"advanced_search\">Adbans na maghanap</string>\n    <string name=\"advanced_search_des\">Magbibigay ng pinaghiwa-hiwalay na resulta</string>\n    <string name=\"show_fillers_settings\">Ipakita ang filler episode sa anime</string>\n    <string name=\"updates_settings\">Ipakita kung may bagong update</string>\n    <string name=\"updates_settings_des\">Awtomatikong mag-check ng bagong update pagbukas ng app</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Light novel app ng parehong devs</string>\n    <string name=\"anim\">Anime app ng parehong devs</string>\n    <string name=\"discord\">Sumali sa Discord</string>\n    <string name=\"benene\">Magbigay ng benene sa ang devs</string>\n    <string name=\"benene_des\">Sumali benene</string>\n    <string name=\"app_language\">Wika</string>\n    <string name=\"no_chromecast_support_toast\">Walang chromecast support ang provider na ito</string>\n    <string name=\"no_links_found_toast\">Walang link na nakita</string>\n    <string name=\"copy_link_toast\">Link copied to clipboard</string>\n    <string name=\"play_episode_toast\">Play Episode</string>\n    <string name=\"subs_default_reset_toast\">I-reset sa default value</string>\n    <string name=\"season\">Season</string>\n    <string name=\"no_season\">No season</string>\n    <string name=\"episode\">Episode</string>\n    <string name=\"episodes\">Episodes</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"delete_file\">Burahin ang file</string>\n    <string name=\"delete\">Tanggalin</string>\n    <string name=\"cancel\">Kanselahin</string>\n    <string name=\"pause\">I-pause</string>\n    <string name=\"resume\">I-resume</string>\n    <string name=\"delete_message\">This will permanently delete %s\n\\nAre you sure?</string>\n    <string name=\"status_ongoing\">Patuloy</string>\n    <string name=\"status_completed\">Tapos na</string>\n    <string name=\"status\">Katayuan</string>\n    <string name=\"year\">Taon</string>\n    <string name=\"rating\">Marka</string>\n    <string name=\"duration\">Tagal</string>\n    <string name=\"site\">Site</string>\n    <string name=\"synopsis\">Sinopsis</string>\n    <string name=\"queued\">nakapila</string>\n    <string name=\"no_subtitles\">walang subtitles</string>\n    <string name=\"action_default\">Default</string>\n    <string name=\"free_storage\">Bakante</string>\n    <string name=\"used_storage\">Gamit</string>\n    <string name=\"app_storage\">App</string>\n    <string name=\"movies\">Pelikula</string>\n    <string name=\"tv_series\">Palabas sa TV</string>\n    <string name=\"cartoons\">Cartoons</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"torrent\">Torrent</string>\n    <string name=\"source_error\">Source error</string>\n    <string name=\"remote_error\">Remote error</string>\n    <string name=\"render_error\">Renderer error</string>\n    <string name=\"unexpected_error\">Unexpected player error</string>\n    <string name=\"storage_error\">Download error, check storage permissions</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast Episode</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast Mirror</string>\n    <string name=\"episode_action_play_in_app\">I-play sa App</string>\n    <string name=\"episode_action_play_in_format\">I-play sa %s</string>\n    <string name=\"episode_action_auto_download\">Awtomatiking i-download</string>\n    <string name=\"episode_action_download_mirror\">Download mirror</string>\n    <string name=\"episode_action_reload_links\">Subukan muli</string>\n    <string name=\"no_update_found\">Walang bagong update</string>\n    <string name=\"check_for_update\">Tingnan kung may bagong update</string>\n    <string name=\"video_lock\">I-lock</string>\n    <string name=\"video_aspect_ratio_resize\">Palakihin</string>\n    <string name=\"video_source\">Source</string>\n    <string name=\"video_skip_op\">Skip OP</string>\n    <string name=\"dont_show_again\">Huwag nang ipakita ulit</string>\n    <string name=\"update\">Update</string>\n    <string name=\"watch_quality_pref\">Preferred watch quality</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"dns_pref_summary\">Mainam gamitin sa pag-bypass ng ISP blocks</string>\n    <string name=\"display_subbed_dubbed_settings\">Display Dubbed/Subbed Anime</string>\n    <string name=\"resize_fit\">Fit to screen</string>\n    <string name=\"resize_fill\">Punan ang buong screen</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"category_general\">Pangkalahatan</string>\n    <string name=\"provider_lang_settings\">Wika ng Provider</string>\n    <string name=\"app_layout\">App Layout</string>\n    <string name=\"automatic\">Awtomatik</string>\n    <string name=\"tv_layout\">TV Layout</string>\n    <string name=\"phone_layout\">Phone Layout</string>\n    <string name=\"primary_color_settings\">Pangunahin Kulay</string>\n    <string name=\"app_theme_settings\">Tema ng app</string>\n    <string name=\"preferred_media_settings\">Preferred Media</string>\n    <string name=\"subs_subtitle_languages\">Wika ng Subtitle</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Mag-Import ng font na nakalagay sa %s</string>\n    <string name=\"show_log_cat\">Ipakita ang Logcat 🐈</string>\n    <string name=\"autoplay_next_settings\">Kusang i-play ang next episode</string>\n    <string name=\"enable_nsfw_on_providers\">Payagan ang NSFW sa mga suportadong providers</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"cast_format\" formatted=\"true\">I-Cast: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Episode %d ay ipapalabas sa loob ng</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Hanapin ang %s…</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd, %2$dh:%3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh : %2$dm</string>\n    <string name=\"play_with_app_name\">I-play gamit ang CloudStream</string>\n    <string name=\"type_re_watching\">Pinapanuod Uli</string>\n    <string name=\"play_livestream_button\">Panuorin ang Livestream</string>\n    <string name=\"action_add_to_bookmarks\">I-set ang Status</string>\n    <string name=\"sort_copy\">Kopyahin</string>\n    <string name=\"sort_close\">Isara</string>\n    <string name=\"sort_clear\">Tanggalin Lahat</string>\n    <string name=\"sort_save\">I-save</string>\n    <string name=\"provider_info_meta\">Ang Metadata ay di galing sa site, mag-fail ang pag load ng video pag wala ito sa site.</string>\n    <string name=\"autoplay_next_settings_des\">Simulan ang susunod na episode kapag natapos ang kasalukuyan</string>\n    <string name=\"restore_settings\">Ibalik ang data gamit ang backup</string>\n    <string name=\"backup_settings\">I-backup ang data</string>\n    <string name=\"restore_success\">Nabuksan ang backup file</string>\n    <string name=\"backup_success\">Naitabi ang Data</string>\n    <string name=\"backup_failed_error_format\">Nagka error sa pag backup ng %s</string>\n    <string name=\"show_trailers_settings\">Ipakita ang trailers</string>\n    <string name=\"kitsu_settings\">Ipakita ang posters mula sa Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Wag ipakita ang mga video quality sa search results</string>\n    <string name=\"automatic_plugin_updates\">Kusang i-update ang plugins</string>\n    <string name=\"automatic_plugin_download\">Kusang i-download ang plugins</string>\n    <string name=\"bottom_title_settings\">Lokasyon ng Poster title</string>\n    <string name=\"bottom_title_settings_des\">Ilagay ang title sa ibaba ng poster</string>\n    <string name=\"logout\">Mag log out</string>\n    <string name=\"automatic_plugin_download_summary\">Kusang install ang mga di naka install na plugins mula sa repositories.</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"others\">Iba pa</string>\n    <string name=\"documentaries_singular\">Dokumentaryo</string>\n    <string name=\"episode_action_download_subtitle\">I-download ang subtitles</string>\n    <string name=\"add_site_summary\">Maglagay ng ibang url para sa site na meron na.</string>\n    <string name=\"random_button_settings_desc\">Ipakita ang Random Button sa Homepage</string>\n    <string name=\"example_lang_name\">Language code (tl)</string>\n    <string name=\"add_sync\">Magdagdag ng tracking</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Dinagdag ang %s</string>\n    <string name=\"backup_failed\">Walang Storage permissions. Paki subukan muli.</string>\n    <string name=\"documentaries\">Dokumentaryo</string>\n    <string name=\"no_episodes_found\">Walang nakita na Episode</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Nagkamali sa pagbalik ng data galing sa file na %s</string>\n    <string name=\"video_buffer_clear_settings\">Linisin ang video at image cache</string>\n    <string name=\"switch_account\">Magpalit ng account</string>\n    <string name=\"video_ram_description\">Magkakaron ng crashes kapag sobrang taas. Iwan lang kapag mababa ang memory ng iyong device.</string>\n    <string name=\"video_disk_description\">Posibleng magka problema kapag sobrang taas kapag mababa ang storage ng device (tulad ng Android TV)</string>\n    <string name=\"create_account\">Gumawa ng account</string>\n    <string name=\"add_account\">Magdagdag ng Account</string>\n    <string name=\"history\">Kasaysayan</string>\n    <string name=\"action_mark_as_watched\">I-tanda bilang napanood na</string>\n    <string name=\"update_started\">Nagsimula ang Update</string>\n    <string name=\"chromecast_subtitles_settings\">Mga Subtitle ng Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Mga setting ng mga subtitle ng Chromecast</string>\n    <string name=\"play_trailer_button\">Maglaro ng Trailer</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+tr/array.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <array name=\"cast_mini_controller_control_buttons\">\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_play_pause_toggle</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n    <array name=\"cast_expanded_controller_control_buttons\">\n        <!-- Fake sources button -->\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n        <!-- Actually fake to make the skip op button the same style -->\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n\n    <array name=\"dns_pref\">\n        <item>@string/none</item>\n        <item>Google</item>\n        <item>Cloudflare</item>\n        <!--        <item>OpenDns</item>-->\n        <item>AdGuard</item>\n        <item>DNS.WATCH</item>\n        <item>Quad9</item>\n        <item>DNS.SB</item>\n        <item>Canadian Shield</item>\n    </array>\n    <array name=\"dns_pref_values\">\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n        <!--        <item>3</item>-->\n        <item>4</item>\n        <item>5</item>\n        <item>6</item>\n        <item>7</item>\n        <item>8</item>\n    </array>\n\n    <array name=\"title_info_pref_names\">\n        <item>@string/source_name</item>\n        <item>@string/resolution</item>\n        <item>@string/video_info</item>\n    </array>\n\n    <array name=\"title_info_pref_values\">\n        <item>@string/show_name_key</item>\n        <item>@string/show_resolution_key</item>\n        <item>@string/show_media_info_key</item>\n    </array>\n\n\n    <array name=\"limit_title_pref_names\">\n        <item>@string/none</item>\n        <item>16 karakter</item>\n        <item>32 karakter</item>\n        <item>64 karakter</item>\n        <item>128 karakter</item>\n        <item>Başlığı gizle</item>\n    </array>\n    <array name=\"limit_title_pref_values\">\n        <item>0</item>\n        <item>16</item>\n        <item>32</item>\n        <item>64</item>\n        <item>128</item>\n        <item>-1</item>\n    </array>\n\n    <array name=\"skip_sec_values\">\n        <item>5</item>\n        <item>10</item>\n        <item>15</item>\n        <item>20</item>\n        <item>25</item>\n        <item>30</item>\n    </array>\n\n    <array name=\"video_buffer_length_names\">\n        <item>@string/automatic</item>\n        <item>1dk</item>\n        <item>1dk 30sn</item>\n        <item>2dk</item>\n        <item>2dk 30sn</item>\n        <item>3dk</item>\n        <item>3dk 30sn</item>\n        <item>4dk</item>\n        <item>5dk</item>\n        <item>6dk</item>\n        <item>7dk</item>\n        <item>8dk</item>\n        <item>9dk</item>\n        <item>10dk</item>\n        <item>15dk</item>\n        <item>20dk</item>\n        <item>30dk</item>\n    </array>\n\n    <array name=\"video_buffer_length_values\">\n        <item>0</item>\n        <item>60</item>\n        <item>90</item>\n        <item>120</item>\n        <item>150</item>\n        <item>180</item>\n        <item>210</item>\n        <item>240</item>\n        <item>300</item>\n        <item>360</item>\n        <item>420</item>\n        <item>480</item>\n        <item>540</item>\n        <item>600</item>\n        <item>900</item>\n        <item>1200</item>\n        <item>1800</item>\n    </array>\n\n    <array name=\"video_buffer_size_names\">\n        <item>@string/automatic</item>\n        <item>10MB</item>\n        <item>20MB</item>\n        <item>30MB</item>\n        <item>40MB</item>\n        <item>50MB</item>\n        <item>60MB</item>\n        <item>70MB</item>\n        <item>80MB</item>\n        <item>90MB</item>\n        <item>100MB</item>\n        <item>150MB</item>\n        <item>200MB</item>\n        <item>250MB</item>\n        <item>300MB</item>\n        <item>350MB</item>\n        <item>400MB</item>\n        <item>450MB</item>\n        <item>500MB</item>\n    </array>\n\n    <array name=\"video_buffer_size_values\">\n        <item>0</item>\n        <item>10</item>\n        <item>20</item>\n        <item>30</item>\n        <item>40</item>\n        <item>50</item>\n        <item>60</item>\n        <item>70</item>\n        <item>80</item>\n        <item>90</item>\n        <item>100</item>\n        <item>150</item>\n        <item>200</item>\n        <item>250</item>\n        <item>300</item>\n        <item>350</item>\n        <item>400</item>\n        <item>450</item>\n        <item>500</item>\n    </array>\n\n    <array name=\"poster_ui_options\">\n        <item>@string/show_hd</item>\n        <item>@string/show_dub</item>\n        <item>@string/show_sub</item>\n        <item>@string/show_rating</item>\n        <item>@string/show_title</item>\n        <item>@string/show_episode_text</item>\n    </array>\n\n    <array name=\"poster_ui_options_values\">\n        <item>@string/show_hd_key</item>\n        <item>@string/show_dub_key</item>\n        <item>@string/show_sub_key</item>\n        <item>@string/show_rating_key</item>\n        <item>@string/show_title_key</item>\n        <item>@string/show_episode_text_key</item>\n    </array>\n    <array name=\"app_layout\">\n        <item>@string/automatic</item>\n        <item>@string/phone_layout</item>\n        <item>@string/tv_layout</item>\n        <item>@string/emulator_layout</item>\n    </array>\n\n    <array name=\"app_layout_values\">\n        <item>-1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n    </array>\n\n    <string-array name=\"themes_overlay_names\">\n        <item>Normal</item>\n        <item>Karahindiba sarı</item>\n        <item>Karanfil Pembesi</item>\n        <item>Turuncu</item>\n        <item>Koyu Yeşil</item>\n        <item>Kestane</item>\n        <item>Lacivert</item>\n        <item>Gri</item>\n        <item>Beyaz</item>\n        <item>Soğuk Mavi</item>\n        <item>Kahverengi</item>\n        <item>Soğuk</item>\n        <item>Ateş</item>\n        <item>Mor</item>\n        <item>Yeşil</item>\n        <item>Elma</item>\n        <item>Muz</item>\n        <item>Parti</item>\n        <item>Pembe</item>\n        <item>Lavanta</item>\n        <item>Material You</item>\n        <item>Material You (İkincil)</item>\n    </string-array>\n    <string-array name=\"themes_overlay_names_values\">\n        <item>Normal</item>\n        <item>DandelionYellow</item>\n        <item>CarnationPink</item>\n        <item>Orange</item>\n        <item>DarkGreen</item>\n        <item>Maroon</item>\n        <item>NavyBlue</item>\n        <item>Grey</item>\n        <item>White</item>\n        <item>CoolBlue</item>\n        <item>Brown</item>\n        <item>Blue</item>\n        <item>Red</item>\n        <item>Purple</item>\n        <item>Green</item>\n        <item>GreenApple</item>\n        <item>Banana</item>\n        <item>Party</item>\n        <item>Pink</item>\n        <item>Lavender</item>\n        <item>Monet</item>\n        <item>Monet2</item>\n    </string-array>\n\n    <string-array name=\"themes_names\">\n        <item>Koyu</item>\n        <item>Gri</item>\n        <item>Amoled</item>\n        <item>Flaş Bombası</item>\n        <item>Sistem</item>\n        <item>Material You</item>\n        <item>Dracula</item>\n        <item>Lavanta Rüyası</item>\n        <item>Sessiz Mavi</item>\n    </string-array>\n    <string-array name=\"themes_names_values\">\n        <item>AmoledLight</item>\n        <item>Black</item>\n        <item>Amoled</item>\n        <item>Light</item>\n        <item>System</item>\n        <item>Monet</item>\n        <item>Dracula</item>\n        <item>Lavender</item>\n        <item>SilentBlue</item>\n    </string-array>\n\n    <string-array name=\"extension_statuses\">\n        <item>Çöktü</item>\n        <!-- \"Ok\" is usually capitalized as \"OK\". Ok android studio 🤓-->\n        <item>Ok</item>\n        <item>Yavaş</item>\n        <item>Beta</item>\n    </string-array>\n\n    <!--https://github.com/videolan/vlc-android/blob/72ccfb93db027b49855760001d1a930fa657c5a8/application/resources/src/main/res/values/arrays.xml#L266-->\n    <string-array name=\"subtitles_encoding_list\" tools:ignore=\"TypographyDashes\">\n        <item>@string/automatic</item>\n        <item>Universal (UTF-8)</item>\n        <item>Universal (UTF-16)</item>\n        <item>Universal (big endian UTF-16)</item>\n        <item>Universal (little endian UTF-16)</item>\n        <item>Universal, Chinese (GB18030)</item>\n        <item>Western European (Latin-9)</item>\n        <item>Western European (Windows-1252)</item>\n        <item>Western European (IBM 00850)</item>\n        <item>Eastern European (Latin-2)</item>\n        <item>Eastern European (Windows-1250)</item>\n        <item>Esperanto (Latin-3)</item>\n        <item>Nordic (Latin-6)</item>\n        <item>Cyrillic (Windows-1251)</item>\n        <item>Russian (KOI8-R)</item>\n        <item>Ukrainian (KOI8-U)</item>\n        <item>Arabic (ISO 8859-6)</item>\n        <item>Arabic (Windows-1256)</item>\n        <item>Greek (ISO 8859-7)</item>\n        <item>Greek (Windows-1253)</item>\n        <item>Hebrew (ISO 8859-8)</item>\n        <item>Hebrew (Windows-1255)</item>\n        <item>Turkish (ISO 8859-9)</item>\n        <item>Turkish (Windows-1254)</item>\n        <item>Thai (TIS 620-2533/ISO 8859-11)</item>\n        <item>Thai (Windows-874)</item>\n        <item>Baltic (Latin-7)</item>\n        <item>Baltic (Windows-1257)</item>\n        <item>Celtic (Latin-8)</item>\n        <item>South-Eastern European (Latin-10)</item>\n        <item>Simplified Chinese (ISO-2022-CN-EXT)</item>\n        <item>Simplified Chinese Unix (EUC-CN)</item>\n        <item>Japanese (7-bits JIS/ISO-2022-JP-2)</item>\n        <item>Japanese Unix (EUC-JP)</item>\n        <item>Japanese (Shift JIS)</item>\n        <item>Korean (EUC-KR/CP949)</item>\n        <item>Korean (ISO-2022-KR)</item>\n        <item>Traditional Chinese (Big5)</item>\n        <item>Traditional Chinese Unix (EUC-TW)</item>\n        <item>Hong-Kong Supplementary (HKSCS)</item>\n        <item>Vietnamese (VISCII)</item>\n        <item>Vietnamese (Windows-1258)</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+tr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s B. %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Oyuncular: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">%d. Bölüm şu tarihte yayınlanacak</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dg %2$dsa %3$ddk</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dsa %2$ddk</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%ddk</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Afiş</string>\n    <string name=\"search_poster_img_des\">Afiş</string>\n    <string name=\"episode_poster_img_des\">Bölüm Afişi</string>\n    <string name=\"home_main_poster_img_des\">Ana Afiş</string>\n    <string name=\"home_next_random_img_des\">Sonraki Rastgele</string>\n    <string name=\"go_back_img_des\">Geri dön</string>\n    <string name=\"home_change_provider_img_des\">Sağlayıcıyı Değiştir</string>\n    <string name=\"preview_background_img_des\">Arkaplanı Önizle</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Hız (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Puan: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Yeni güncelleme bulundu!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Dolgu</string>\n    <string name=\"duration_format\" formatted=\"true\">%d dakika</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">CloudStream ile oynat</string>\n    <string name=\"title_home\">Ana sayfa</string>\n    <string name=\"title_search\">Ara</string>\n    <string name=\"title_downloads\">İndirilenler</string>\n    <string name=\"title_settings\">Ayarlar</string>\n    <string name=\"search_hint\">Ara…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">%s sağlayıcısında ara…</string>\n    <string name=\"no_data\">Veri Yok</string>\n    <string name=\"episode_more_options_des\">Daha Fazla Seçenek</string>\n    <string name=\"next_episode\">Sonraki bölüm</string>\n    <string name=\"result_tags\">Türler</string>\n    <string name=\"result_share\">Paylaş</string>\n    <string name=\"result_open_in_browser\">Tarayıcıda aç</string>\n    <string name=\"skip_loading\">Yüklemeyi Atla</string>\n    <string name=\"loading\">Yükleniyor…</string>\n    <string name=\"type_watching\">İzleniyor</string>\n    <string name=\"type_on_hold\">Beklemede</string>\n    <string name=\"type_completed\">Tamamlandı</string>\n    <string name=\"type_dropped\">Bırakıldı</string>\n    <string name=\"type_plan_to_watch\">Planlandı</string>\n    <string name=\"type_re_watching\">Yeniden izleniyor</string>\n    <string name=\"play_movie_button\">Filmi Oynat</string>\n    <string name=\"play_livestream_button\">Canlı Yayını Oynat</string>\n    <string name=\"play_torrent_button\">Torrent Oynat</string>\n    <string name=\"pick_source\">Kaynaklar</string>\n    <string name=\"pick_subtitle\">Altyazılar</string>\n    <string name=\"reload_error\">Yeniden bağlan…</string>\n    <string name=\"go_back\">Geri Dön</string>\n    <string name=\"play_episode\">Bölümü Oynat</string>\n    <!--<string name=\"need_storage\">Allow to download episodes</string>-->\n    <string name=\"download\">İndir</string>\n    <string name=\"downloaded\">İndirildi</string>\n    <string name=\"downloading\">İndiriliyor</string>\n    <string name=\"download_paused\">İndirme Duraklatıldı</string>\n    <string name=\"download_started\">İndirme Başladı</string>\n    <string name=\"download_failed\">İndirme Başarısız</string>\n    <string name=\"download_canceled\">İndirme İptal Edildi</string>\n    <string name=\"download_done\">İndirme Tamamlandı</string>\n    <string name=\"stream\">Ağ akışı</string>\n    <string name=\"error_loading_links_toast\">Bağlantılar yüklenirken hata oluştu</string>\n    <string name=\"download_storage_text\">Dahili Depolama</string>\n    <string name=\"app_dubbed_text\">Dublajlı</string>\n    <string name=\"app_subbed_text\">Altyazılı</string>\n    <string name=\"popup_delete_file\">Dosyayı Sil</string>\n    <string name=\"popup_play_file\">Dosyayı Oynat</string>\n    <string name=\"popup_resume_download\">İndirmeyi Sürdür</string>\n    <string name=\"popup_pause_download\">İndirmeyi Duraklat</string>\n    <string name=\"home_more_info\">Daha fazla bilgi</string>\n    <string name=\"home_expanded_hide\">Gizle</string>\n    <string name=\"home_play\">Oynat</string>\n    <string name=\"home_info\">Bilgi</string>\n    <string name=\"filter_bookmarks\">Yer İmlerini Filtrele</string>\n    <string name=\"error_bookmarks_text\">Yer imleri</string>\n    <string name=\"action_remove_from_bookmarks\">Kaldır</string>\n    <string name=\"action_add_to_bookmarks\">İzleme durumunu ayarla</string>\n    <string name=\"sort_apply\">Uygula</string>\n    <string name=\"sort_copy\">Kopyala</string>\n    <string name=\"sort_close\">Kapat</string>\n    <string name=\"sort_clear\">Temizle</string>\n    <string name=\"sort_save\">Kaydet</string>\n    <string name=\"player_speed\">Oynatıcı Hızı</string>\n    <string name=\"subtitles_settings\">Altyazı Ayarları</string>\n    <string name=\"subs_text_color\">Yazı Rengi</string>\n    <string name=\"subs_outline_color\">Dış Hat Rengi</string>\n    <string name=\"subs_background_color\">Arka Plan Rengi</string>\n    <string name=\"subs_window_color\">Pencere Rengi</string>\n    <string name=\"subs_edge_type\">Kenar Türü</string>\n    <string name=\"subs_subtitle_elevation\">Altyazı Yüksekliği</string>\n    <string name=\"subs_font\">Yazı Tipi</string>\n    <string name=\"subs_font_size\">Yazı Boyutu</string>\n    <string name=\"search_provider_text_providers\">Sağlayıcıları kullanarak ara</string>\n    <string name=\"search_provider_text_types\">Türleri kullanarak ara</string>\n    <string name=\"benene_count_text\">Geliştiricilere %d muz verildi</string>\n    <string name=\"benene_count_text_none\">Hiç muz verilmedi</string>\n    <string name=\"subs_auto_select_language\">Otomatik Seçilecek Dil</string>\n    <string name=\"subs_download_languages\">İndirilecek Diller</string>\n    <string name=\"subs_subtitle_languages\">Altyazı Dili</string>\n    <string name=\"subs_hold_to_reset_to_default\">Varsayılana sıfırlamak için basılı tutun</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Fontları içe aktarmak için %s konumuna yerleştirin</string>\n    <string name=\"continue_watching\">İzlemeye Devam Et</string>\n    <string name=\"action_remove_watching\">Kaldır</string>\n    <string name=\"action_open_watching\">Daha Fazla Bilgi</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Bu sağlayıcının düzgün çalışması için bir VPN gerekebilir</string>\n    <string name=\"vpn_torrent\">Bu sağlayıcı torrent kullanıyor, bir VPN önerilir</string>\n    <string name=\"provider_info_meta\">Metadata site tarafından sağlanmamış, veri site\\'de bulunmuyorsa video yüklenmesi başarısız olacak.</string>\n    <string name=\"torrent_plot\">Açıklama</string>\n    <string name=\"normal_no_plot\">Konu Bulunamadı</string>\n    <string name=\"torrent_no_plot\">Açıklama Bulunamadı</string>\n    <string name=\"show_log_cat\">Logcat görüntüle 🐈</string>\n    <string name=\"picture_in_picture\">Resim içinde resim</string>\n    <string name=\"picture_in_picture_des\">İçerik diğer uygulamaların üzerinde küçük bir pencerede oynatılmaya devam eder</string>\n    <string name=\"player_size_settings\">Oynatıcı yeniden boyutlandırma butonu</string>\n    <string name=\"player_size_settings_des\">Siyah kenarlıkları kaldır</string>\n    <string name=\"player_subtitles_settings\">Altyazılar</string>\n    <string name=\"player_subtitles_settings_des\">Oynatıcı altyazı ayarları</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast altyazıları</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast altyazı ayarları</string>\n    <string name=\"eigengraumode_settings\">Oynatma hızı</string>\n    <string name=\"swipe_to_seek_settings\">Atlamak için kaydır</string>\n    <string name=\"swipe_to_seek_settings_des\">Zamanı ayarlamak için yanlardan kaydır</string>\n    <string name=\"swipe_to_change_settings\">Ayarları değiştirmek için kaydır</string>\n    <string name=\"swipe_to_change_settings_des\">Sol ve sağ taraftan yukarı kaydırarak ekran parlaklığı ve sesi ayarla</string>\n    <string name=\"autoplay_next_settings\">Sonraki bölümü otomatik oynat</string>\n    <string name=\"autoplay_next_settings_des\">Mevcut bölüm bittiğinde sonraki bölüme başla</string>\n    <string name=\"double_tap_to_seek_settings\">Çift dokunarak atla</string>\n    <string name=\"double_tap_to_pause_settings\">İki kez dokunarak duraklat</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Atlanacak süre (Saniye)</string>\n    <string name=\"double_tap_to_seek_settings_des\">İleri ve geri atlamak için sağa ve sola iki kez dokun</string>\n    <string name=\"double_tap_to_pause_settings_des\">Durdurmak için ekranın ortasına çift dokun</string>\n    <string name=\"use_system_brightness_settings\">Sistem parlaklığını kullan</string>\n    <string name=\"use_system_brightness_settings_des\">Oynatıcıyı karartmak yerine sistem parlaklığını kullan</string>\n    <string name=\"episode_sync_settings\">İzleme ilerlemesini güncelle</string>\n    <string name=\"episode_sync_settings_des\">Mevcut bölüm ilerlemesini otomatik eşitle</string>\n    <string name=\"restore_settings\">Verileri yedekten geri yükle</string>\n    <string name=\"backup_settings\">Verileri yedekle</string>\n    <string name=\"restore_success\">Yedek dosyası yüklendi</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Geri yükleme başarısız oldu: %s</string>\n    <string name=\"backup_success\">Başarıyla yedeklendi</string>\n    <string name=\"backup_failed\">Depolama izinleri eksik. Lütfen tekrar deneyin.</string>\n    <string name=\"backup_failed_error_format\">%s yedeklenirken hata</string>\n    <string name=\"search\">Ara</string>\n    <string name=\"category_account\">Hesaplar ve Güvenlik</string>\n    <string name=\"category_updates\">Güncellemeler ve Yedekleme</string>\n    <string name=\"settings_info\">Bilgi</string>\n    <string name=\"advanced_search\">Gelişmiş arama</string>\n    <string name=\"advanced_search_des\">Arama sonuçlarını sağlayıcıya göre ayırır</string>\n    <string name=\"show_fillers_settings\">Anime için dolgu bölümünü göster</string>\n    <string name=\"show_trailers_settings\">Fragmanları göster</string>\n    <string name=\"kitsu_settings\">Kitsu posterlerini göster</string>\n    <string name=\"pref_filter_search_quality\">Seçili video kalitesini arama sonuçlarında gizle</string>\n    <string name=\"automatic_plugin_updates\">Otomatik eklenti güncellemeleri</string>\n    <string name=\"updates_settings\">Uygulama güncellemelerini göster</string>\n    <string name=\"updates_settings_des\">Uygulama başlatıldıktan sonra güncellemeleri ara.</string>\n    <string name=\"github\">GitHub</string>\n    <string name=\"lightnovel\">Aynı geliştiricilerin Lightnovel Crawler uygulaması</string>\n    <string name=\"anim\">Aynı geliştiricilerin anime uygulaması</string>\n    <string name=\"discord\">Discord\\'a katıl</string>\n    <string name=\"benene\">Geliştiricilere muz ver</string>\n    <string name=\"benene_des\">Verilen muz</string>\n    <string name=\"app_language\">Uygulama dili</string>\n    <string name=\"no_chromecast_support_toast\">Bu sağlayıcının Chromecast desteği yok</string>\n    <string name=\"no_links_found_toast\">Bağlantı bulunamadı</string>\n    <string name=\"copy_link_toast\">Bağlantı panoya kopyalandı</string>\n    <string name=\"play_episode_toast\">Bölümü oynat</string>\n    <string name=\"subs_default_reset_toast\">Varsayılan değere sıfırla</string>\n    <string name=\"season\">Sezon</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Sezon yok</string>\n    <string name=\"episode\">Bölüm</string>\n    <string name=\"episodes\">Bölüm</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">B</string>\n    <string name=\"no_episodes_found\">Bölüm bulunamadı</string>\n    <string name=\"delete_file\">Dosyayı sil</string>\n    <string name=\"delete\">Sil</string>\n    <string name=\"cancel\">İptal</string>\n    <string name=\"pause\">Duraklat</string>\n    <string name=\"resume\">Sürdür</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">%s tamamen silinecek\n\\nEmin misiniz?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dd \\nkaldı</string>\n    <string name=\"status_ongoing\">Devam ediyor</string>\n    <string name=\"status_completed\">Tamamlandı</string>\n    <string name=\"status\">Durum</string>\n    <string name=\"year\">Yıl</string>\n    <string name=\"rating\">Puan</string>\n    <string name=\"duration\">Süre</string>\n    <string name=\"site\">Site</string>\n    <string name=\"synopsis\">Özet</string>\n    <string name=\"queued\">Sıraya alındı</string>\n    <string name=\"no_subtitles\">Altyazı yok</string>\n    <string name=\"action_default\">Varsayılan</string>\n    <string name=\"free_storage\">Boş</string>\n    <string name=\"used_storage\">Kullanılan</string>\n    <string name=\"app_storage\">Uygulama</string>\n    <!--plural-->\n    <string name=\"movies\">Filmler</string>\n    <string name=\"tv_series\">Diziler</string>\n    <string name=\"cartoons\">Çizgi filmler</string>\n    <string name=\"anime\">Animeler</string>\n    <string name=\"torrent\">Torrentler</string>\n    <string name=\"documentaries\">Belgeseller</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Asya dizileri</string>\n    <string name=\"livestreams\">Canlı yayınlar</string>\n    <string name=\"nsfw\">+18</string>\n    <string name=\"others\">Diğerleri</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Film</string>\n    <string name=\"tv_series_singular\">Dizi</string>\n    <string name=\"cartoons_singular\">Çizgi film</string>\n    <string name=\"anime_singular\">@string/anime</string>\n    <string name=\"ova_singular\">@string/ova</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Belgesel</string>\n    <string name=\"asian_drama_singular\">Asya dizisi</string>\n    <string name=\"live_singular\">Canlı yayın</string>\n    <string name=\"nsfw_singular\">+18</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"source_error\">Kaynak hatası</string>\n    <string name=\"remote_error\">Sunucu hatası</string>\n    <string name=\"render_error\">İşleyici hatası</string>\n    <string name=\"unexpected_error\">Beklenmeyen oynatıcı hatası</string>\n    <string name=\"storage_error\">İndirme hatası, depolama izinlerini kontrol edin</string>\n    <string name=\"episode_action_chromecast_episode\">Bölümü Chromecast ile yayınla</string>\n    <string name=\"episode_action_chromecast_mirror\">Bağlantıyı Chromecast ile yayınla</string>\n    <string name=\"episode_action_play_in_app\">Burada oynat</string>\n    <string name=\"episode_action_play_in_format\">%s üzerinden oynat</string>\n    <string name=\"episode_action_auto_download\">Otomatik indir</string>\n    <string name=\"episode_action_download_mirror\">Şu kaynaktan indir</string>\n    <string name=\"episode_action_reload_links\">Bağlantıları yenile</string>\n    <string name=\"episode_action_download_subtitle\">Altyazıları indir</string>\n    <string name=\"show_hd\">Kalite etiketi</string>\n    <string name=\"show_dub\">Dublaj etiketi</string>\n    <string name=\"show_sub\">Altyazı etiketi</string>\n    <string name=\"show_title\">Başlık</string>\n    <string name=\"poster_ui_settings\">Afiş üzerindeki öğeleri değiştir</string>\n    <string name=\"no_update_found\">Güncelleme bulunamadı</string>\n    <string name=\"check_for_update\">Güncellemeleri denetle</string>\n    <string name=\"video_lock\">Kilitle</string>\n    <string name=\"video_aspect_ratio_resize\">Yeniden boyutlandır</string>\n    <string name=\"video_source\">Kaynak</string>\n    <string name=\"video_skip_op\">Jeneriği geç</string>\n    <string name=\"dont_show_again\">Bir daha gösterme</string>\n    <string name=\"skip_update\">Bu güncellemeyi atla</string>\n    <string name=\"update\">Güncelle</string>\n    <string name=\"watch_quality_pref\">Tercih edilen görüntü kalitesi (WiFi)</string>\n    <string name=\"limit_title\">Video oynatıcı başlığı karakter üst sınırı</string>\n    <string name=\"limit_title_rez\">Oynatıcı bilgisini göster</string>\n    <string name=\"video_buffer_size_settings\">Video arabellek boyutu</string>\n    <string name=\"video_buffer_length_settings\">Video arabellek uzunluğu</string>\n    <string name=\"video_buffer_disk_settings\">Diskteki video önbelleği</string>\n    <string name=\"video_buffer_clear_settings\">Video ve resim önbelleğini temizle</string>\n    <string name=\"video_ram_description\">Çok yükseğe ayarlanırsa düşük belleğe sahip cihazlarda çökmelere neden olur (örn. Android TV).</string>\n    <string name=\"video_disk_description\">Çok yükseğe ayarlanırsa düşük depolama alanına sahip sistemlerde sorunlara neden olur (örn. Android TV).</string>\n    <string name=\"dns_pref\">HTTPS üzerinden DNS</string>\n    <string name=\"dns_pref_summary\">İnernet servis sağlayıcı kısıtlamalarını aşmak için kullanışlıdır</string>\n    <string name=\"add_site_pref\">Siteyi klonla</string>\n    <string name=\"remove_site_pref\">Siteyi kaldır</string>\n    <string name=\"add_site_summary\">Mevcut bir sitenin farklı bir URL üstündeki kopyasını ekleyin</string>\n    <string name=\"download_path_pref\">İndirme konumu</string>\n    <string name=\"nginx_url_pref\">NGINX sunucu URL\\'si</string>\n    <string name=\"display_subbed_dubbed_settings\">Dublajlı/Altyazılı animeleri görüntüle</string>\n    <string name=\"resize_fit\">Ekrana sığdır</string>\n    <string name=\"resize_fill\">Uzat</string>\n    <string name=\"resize_zoom\">Yakınlaştır</string>\n    <string name=\"legal_notice\">Yasal uyarı</string>\n    <string name=\"category_general\">Genel</string>\n    <string name=\"random_button_settings\">Rastgele düğmesi</string>\n    <string name=\"random_button_settings_desc\">Ana sayfa ve kütüphane üstünde rastgele düğmesini göster</string>\n    <string name=\"provider_lang_settings\">Uzantı dilleri</string>\n    <string name=\"app_layout\">Uygulama düzeni</string>\n    <string name=\"preferred_media_settings\">Tercih edilen medya</string>\n    <string name=\"enable_nsfw_on_providers\">Desteklenen uzantılarda NSFW etkinleştir</string>\n    <string name=\"subtitles_encoding\">Altyazı kodlaması</string>\n    <string name=\"category_providers\">Sağlayıcılar</string>\n    <string name=\"category_ui\">Düzen</string>\n    <string name=\"automatic\">Otomatik</string>\n    <string name=\"tv_layout\">TV düzeni</string>\n    <string name=\"phone_layout\">Telefon düzeni</string>\n    <string name=\"emulator_layout\">Emülatör düzeni</string>\n    <string name=\"primary_color_settings\">Birincil renk</string>\n    <string name=\"app_theme_settings\">Uygulama teması</string>\n    <string name=\"bottom_title_settings\">Afiş başlık konumu</string>\n    <string name=\"bottom_title_settings_des\">Başlığı afişin altına yerleştir</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">şifre123</string>\n    <string name=\"example_username\">Kullanıcı Adı</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">YeniSiteAdı</string>\n    <string name=\"example_site_url\">https://ornek.com</string>\n    <string name=\"example_lang_name\">Dil kodu (tr)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">hesap</string>\n    <string name=\"logout\">Çıkış yap</string>\n    <string name=\"login\">Giriş yap</string>\n    <string name=\"switch_account\">Hesap değiştir</string>\n    <string name=\"add_account\">Hesap ekle</string>\n    <string name=\"create_account\">Hesap oluştur</string>\n    <string name=\"add_sync\">Bölüm takibi ekle</string>\n    <string name=\"added_sync_format\" formatted=\"true\">%s eklendi</string>\n    <string name=\"upload_sync\">Senkronize et</string>\n    <string name=\"sync_score\">Puan</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s başarıyla doğrulandı</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">%s ile giriş yapılamadı</string>\n    <!-- ============ -->\n    <string name=\"none\">Yok</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">Tümü</string>\n    <string name=\"max\">Azami</string>\n    <string name=\"min\">Asgari</string>\n    <string name=\"subtitles_outline\">Dış hat</string>\n    <string name=\"subtitles_depressed\">Çökmüş</string>\n    <string name=\"subtitles_shadow\">Gölge</string>\n    <string name=\"subtitles_raised\">Yükseltilmiş</string>\n    <string name=\"subtitle_offset\">Altyazı senkronu</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">Altyazı gecikmesi</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Altyazılar %d ms erken görüntüleniyorsa bunu kullanın</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Altyazılar %d ms geç gözüküyorsa bunu kullanın</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Altyazı gecikmesi yok</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">Pijamalı hasta yağız şoföre çabucak güvendi</string>\n    <string name=\"recommended\">Önerilen</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">%s eklendi</string>\n    <string name=\"player_load_subtitles\">Dosyadan yükle</string>\n    <string name=\"player_load_subtitles_online\">İnternetten yükle</string>\n    <string name=\"downloaded_file\">İndirilen dosya</string>\n    <string name=\"actor_main\">Baş</string>\n    <string name=\"actor_supporting\">Yardımcı</string>\n    <string name=\"actor_background\">Geri plan</string>\n    <string name=\"home_source\">Kaynak</string>\n    <string name=\"home_random\">Rastgele</string>\n    <string name=\"coming_soon\">Çok yakında…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Afiş Resmi</string>\n    <string name=\"category_player\">Oynatıcı</string>\n    <string name=\"resolution_and_title\">Çözünürlük ve başlık</string>\n    <string name=\"title\">Başlık</string>\n    <string name=\"resolution\">Çözünürlük</string>\n    <string name=\"error_invalid_id\">Geçersiz ID</string>\n    <string name=\"error_invalid_data\">Geçersiz veri</string>\n    <string name=\"error_invalid_url\">Geçersiz URL</string>\n    <string name=\"error\">Hata</string>\n    <string name=\"subtitles_remove_captions\">Altyazılardan seçmeli altyazıyı (CC) kaldır</string>\n    <string name=\"subtitles_remove_bloat\">Altyazılardaki şişkinliği kaldır</string>\n    <string name=\"subtitles_filter_lang\">Tercih edilen medya diline göre filtrele</string>\n    <string name=\"extras\">Ek içerikler</string>\n    <string name=\"trailer\">Fragman</string>\n    <string name=\"network_adress_example\">https://ornek.com/ornek.mp4</string>\n    <string name=\"referer\">Yönlendiren (opsiyonel)</string>\n    <string name=\"next\">Sonraki</string>\n    <string name=\"provider_languages_tip\">Videoları bu dillerde izle</string>\n    <string name=\"previous\">Önceki</string>\n    <string name=\"skip_setup\">Kurulumu atla</string>\n    <string name=\"app_layout_subtext\">Cihazınıza uygun uygulama görünümünü seçin</string>\n    <string name=\"preferred_media_subtext\">Ne izlemek istiyorsunuz</string>\n    <string name=\"setup_done\">Bitti</string>\n    <string name=\"extensions\">Eklentiler</string>\n    <string name=\"add_repository\">Depo ekle</string>\n    <string name=\"repository_name_hint\">Depo adı (İsteğe bağlı)</string>\n    <string name=\"repository_url_hint\">Depo URL veya Kısa Kodu</string>\n    <string name=\"plugin_loaded\">Eklenti Yüklendi</string>\n    <string name=\"plugin_deleted\">Eklenti Silindi</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">%s yüklenemedi</string>\n    <string name=\"is_adult\">+18</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">%1$d %2$s indirilmeye başlandı…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">%1$d %2$s indirildi</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">%s\\'nin tamamı zaten indirildi</string>\n    <string name=\"batch_download\">Toplu indir</string>\n    <string name=\"plugin_singular\">eklenti</string>\n    <string name=\"plugin\">eklentiler</string>\n    <string name=\"delete_repository_plugins\">Bu aynı zamanda tüm depo eklentilerini de siler</string>\n    <string name=\"delete_repository\">Depoyu sil</string>\n    <string name=\"setup_extensions_subtext\">Kullanmak istediğiniz sitelerin listesini indirin</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">İndirilen: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Devre dışı: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">İndirilmeyen: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">%d eklentiler güncellendi</string>\n    <string name=\"blank_repo_message\">CloudStream, varsayılan olarak hiçbir site ile gelmez. Siteleri depolardan kurmanız gerekir.\n\\n\n\\nDiscord\\'umuza katılın veya çevrimiçi arama yapın.</string>\n    <string name=\"view_public_repositories_button\">Topluluk depolarını görüntüle</string>\n    <string name=\"view_public_repositories_button_short\">Herkese açık liste</string>\n    <string name=\"uppercase_all_subtitles\">Tüm altyazılar büyük harf</string>\n    <string name=\"download_all_plugins_from_repo\">Uyarı: CloudStream 3, üçüncü taraf uzantıların kullanımı için herhangi bir sorumluluk kabul etmez ve bunlar için herhangi bir destek sağlamaz!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Devre dışı)</string>\n    <string name=\"tracks\">Parçalar</string>\n    <string name=\"audio_tracks\">Ses parçaları</string>\n    <string name=\"video_tracks\">Video parçaları</string>\n    <string name=\"apply_on_restart\">Değişiklikleri görmek için uygulamayı yeniden başlatın.</string>\n    <string name=\"safe_mode_title\">Güvenli mod açık</string>\n    <string name=\"safe_mode_description\">Çöküşe neden olan eklentiyi bulmaya yardımcı olabilmek için tüm eklentiler kapatıldı.</string>\n    <string name=\"safe_mode_crash_info\">Çökme bilgisini göster</string>\n    <string name=\"extension_rating\" formatted=\"true\">Puan: %s</string>\n    <string name=\"extension_description\">Açıklama</string>\n    <string name=\"extension_version\">Sürüm</string>\n    <string name=\"extension_status\">Durum</string>\n    <string name=\"extension_size\">Boyut</string>\n    <string name=\"extension_authors\">Geliştiriciler</string>\n    <string name=\"extension_types\">Desteklenen</string>\n    <string name=\"extension_language\">Dil</string>\n    <string name=\"extension_install_first\">Önce eklentiyi yükleyin</string>\n    <string name=\"hls_playlist\">HLS Oynatma Listesi</string>\n    <string name=\"player_pref\">Tercih edilen video oynatıcısı</string>\n    <string name=\"player_settings_play_in_app\">Dahili oynatıcı</string>\n    <string name=\"app_not_found_error\">Uygulama bulunamadı</string>\n    <string name=\"history\">Geçmiş</string>\n    <string name=\"action_mark_as_watched\">İzlendi olarak işaretle</string>\n    <string name=\"update_notification_installing\">Uygulama güncellemesi kuruluyor…</string>\n    <string name=\"redo_setup_process\">Kurulum işlemini tekrarla</string>\n    <string name=\"play_trailer_button\">Fragmanı Oynat</string>\n    <string name=\"automatic_plugin_download_summary\">Eklenmiş depolardan henüz kurulmamış tüm eklentileri otomatik olarak kur.</string>\n    <string name=\"update_started\">Güncelleme Başladı</string>\n    <string name=\"apk_installer_settings_des\">Bazı cihazlar yeni paket yükleyiciyi desteklemiyor. Güncellemeler yüklenmezse eski seçeneği deneyin.</string>\n    <string name=\"automatic_plugin_download\">Eklentileri otomatik olarak indir</string>\n    <string name=\"apk_installer_settings\">APK kurucu</string>\n    <string name=\"pref_category_links\">Bağlantılar</string>\n    <string name=\"pref_category_app_updates\">Uygulama güncellemeleri</string>\n    <string name=\"pref_category_backup\">Yedek</string>\n    <string name=\"pref_category_player_features\">Oynatıcı özellikleri</string>\n    <string name=\"pref_category_subtitles\">Altyazılar</string>\n    <string name=\"pref_category_player_layout\">Düzen</string>\n    <string name=\"pref_category_defaults\">Varsayılanlar</string>\n    <string name=\"pref_category_extensions\">Eklentiler</string>\n    <string name=\"pref_category_cache\">Önbellek</string>\n    <string name=\"pref_category_looks\">Görünüm</string>\n    <string name=\"pref_category_ui_features\">Özellikler</string>\n    <string name=\"delayed_update_notice\">Uygulama çıkışta güncellenecektir</string>\n    <string name=\"skip_type_ed\">Bitiş</string>\n    <string name=\"skip_type_op\">Açılış</string>\n    <string name=\"no\">Hayır</string>\n    <string name=\"skip_type_recap\">Özet</string>\n    <string name=\"confirm_exit_dialog\">Çıkmak istediğinize emin misin?</string>\n    <string name=\"yes\">Evet</string>\n    <string name=\"update_notification_downloading\">Uygulama güncellemesi indiriliyor…</string>\n    <string name=\"update_notification_failed\">Uygulamanın yeni sürümü kurulamadı</string>\n    <string name=\"clear_history\">Geçmişi temizle</string>\n    <string name=\"apk_installer_package_installer\">PaketKurucu</string>\n    <string name=\"apk_installer_legacy\">Eski</string>\n    <string name=\"pref_category_gestures\">Hareketler</string>\n    <string name=\"all_languages_preference\">Tüm Diller</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Geç %s</string>\n    <string name=\"action_remove_from_watched\">İzlenenlerden kaldır</string>\n    <string name=\"skip_type_mixed_ed\">Karışık son</string>\n    <string name=\"skip_type_mixed_op\">Karışık başlangıç</string>\n    <string name=\"skip_type_creddits\">Katkıda Bulunanlar</string>\n    <string name=\"skip_type_intro\">Giriş</string>\n    <string name=\"plugin_downloaded\">Eklenti İndirildi</string>\n    <string name=\"pref_category_actions\">Eylemler</string>\n    <string name=\"enable_skip_op_from_database_des\">Açılış/bitiş için atlama açılır pencerelerini göster</string>\n    <string name=\"clipboard_too_large\">Çok fazla metin. Panoya kaydedilemiyor.</string>\n    <string name=\"library\">Kütüphane</string>\n    <string name=\"browser\">Tarayıcı</string>\n    <string name=\"empty_library_no_accounts_message\">Kütüphaneniz boş :(\n\\nBir kütüphane hesabında oturum açın veya yerel kütüphanenize programlar ekleyin.</string>\n    <string name=\"safe_mode_file\">Güvenli mod dosyası bulundu!\n\\nDosya kaldırılana kadar başlangıçta herhangi bir uzantı yüklenmiyor.</string>\n    <string name=\"sort_by\">Şuna Göre Sırala</string>\n    <string name=\"sort\">Sırala</string>\n    <string name=\"sort_updated_new\">Güncellenme (Yeniden Eskiye)</string>\n    <string name=\"sort_updated_old\">Güncellenme (Eskiden Yeniye)</string>\n    <string name=\"sort_alphabetical_a\">Alfabetik (A\\'dan Z’ye)</string>\n    <string name=\"sort_alphabetical_z\">Alfabetik (Z - A)</string>\n    <string name=\"select_library\">Kütüphane Seçin</string>\n    <string name=\"open_with\">Şununla aç</string>\n    <string name=\"empty_library_logged_in_message\">Görünüşe göre bu liste boş, başka bir listeye geçmeyi deneyin.</string>\n    <string name=\"sort_rating_desc\">Derecelendirme (Yüksekten Düşüğe)</string>\n    <string name=\"sort_rating_asc\">Derecelendirme (Düşükten Yükseğe)</string>\n    <string name=\"restart\">Yeniden başlat</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Oynatıcı gizlenmişken atlanacak süre</string>\n    <string name=\"pref_category_bypass\">İSS Kısıtlamaları</string>\n    <string name=\"jsdelivr_enabled\">GitHub\\'a ulaşılamadı. jsDelivr vekil sunucusu etkinleştiriliyor…</string>\n    <string name=\"start\">Başlat</string>\n    <string name=\"test_passed\">Başarılı</string>\n    <string name=\"jsdelivr_proxy\">GitHub vekil sunucu</string>\n    <string name=\"watch_quality_pref_data\">Tercih edilen görüntü kalitesi (Mobil veri)</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Oynatıcı görünürken atlanacak süre</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Oynatıcı gizli durumdayken atlanacak süre miktarı</string>\n    <string name=\"jsdelivr_proxy_summary\">jsDelivr kullanarak ham github URL\\'lerinin engellenmesini atlayın. Güncellemelerin birkaç gün gecikmesine neden olabilir.</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"subscription_episode_released\">Yeni bölüm %d yayınlandı!</string>\n    <string name=\"category_provider_test\">Sağlayıcı testi</string>\n    <string name=\"test_failed\">Başarısız</string>\n    <string name=\"stop\">Durdur</string>\n    <string name=\"revert\">Geri al</string>\n    <string name=\"subscription_in_progress_notification\">Abone olunan gösteriler güncelleniyor</string>\n    <string name=\"subscription_list_name\">Abone olunan</string>\n    <string name=\"subscription_new\">%s kanalına abone olundu</string>\n    <string name=\"subscription_deleted\">%s kanalı aboneliğinden çıkıldı</string>\n    <string name=\"test_log\">Günlük</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Oynatıcı görünür durumdayken atlanacak süre miktarı</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"profiles\">Profiller</string>\n    <string name=\"help\">Yardım</string>\n    <string name=\"profile_number\">Profil %d</string>\n    <string name=\"use\">Kullan</string>\n    <string name=\"mobile_data\">Mobil veri</string>\n    <string name=\"set_default\">Varsayılanı ayarla</string>\n    <string name=\"edit\">Düzenle</string>\n    <string name=\"quality_profile_help\">Burada kaynakların nasıl sıralandığını değiştirebilirsiniz. Bir video daha yüksek bir önceliğe sahipse, kaynak seçiminde daha yüksek görünecektir. Kaynak önceliği ve kalite önceliğinin toplamı video önceliğidir.\n\\n\n\\nKaynak A: 3\n\\nKalite B: 7\n\\nBirleştirilmiş video önceliği 10 olacaktır.\n\\n\n\\nNOT: Toplam 10 veya daha fazlaysa, bu bağlantı yüklendiğinde oynatıcı otomatik olarak yüklemeyi atlayacaktır!</string>\n    <string name=\"qualities\">Kaliteler</string>\n    <string name=\"profile_background_des\">Profil arkaplanı</string>\n    <string name=\"unable_to_inflate\">UI was unable to be created correctly, this is a MAJOR BUG and should be reported immediately %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Eklenti indirmeyi filtrelemek için mod seç</string>\n    <string name=\"favorite_removed\">%s favorilerden çıkarıldı</string>\n    <string name=\"favorites_list_name\">Favoriler</string>\n    <string name=\"favorite_added\">%s favorilere eklendi</string>\n    <string name=\"logged_account\" formatted=\"true\">%s olarak giriş yapıldı</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Kütüphanenizde potensiyel kopya ürünler bulundu:\n\\n\n\\n%s\n\\n\n\\nYine de ekleyerek var olanları değiştirmek mi istersiniz, yoksa iptal etmek mi?</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">%s için PIN girin</string>\n    <string name=\"backup_frequency\">Yedekleme sıklığı</string>\n    <string name=\"duplicate_title\">Potensiyel Kopya Bulundu</string>\n    <string name=\"lock_profile\">Profili Kilitle</string>\n    <string name=\"use_default_account\">Varsayılan Hesabı Kullan</string>\n    <string name=\"skip_startup_account_select_pref\">Başlangıçta hesap seçimini atla</string>\n    <string name=\"action_add_to_favorites\">Favorilere ekle</string>\n    <string name=\"manage_accounts\">Hesapları Yönet</string>\n    <string name=\"duplicate_replace_all\">Tümünü Değiştir</string>\n    <string name=\"edit_account\">Hesabı düzenle</string>\n    <string name=\"pin_error_incorrect\">Yanlış PIN. Lütfen tekrar deneyin.</string>\n    <string name=\"action_unsubscribe\">Abonelikten çık</string>\n    <string name=\"pin_error_length\">PIN 4 karakterden oluşmalı</string>\n    <string name=\"duplicate_replace\">Değiştir</string>\n    <string name=\"duplicate_add\">Ekle</string>\n    <string name=\"action_subscribe\">Abone ol</string>\n    <string name=\"action_remove_from_favorites\">Favorilerden çıkar</string>\n    <string name=\"select_an_account\">Hesap Seç</string>\n    <string name=\"disable\">Devre dışı bırak</string>\n    <string name=\"no_repository_found_error\">Depo bulunamadı, bağlantı adresini kontrol edin ve VPN deneyin</string>\n    <string name=\"already_voted\">Zaten oyladınız</string>\n    <string name=\"no_plugins_found_error\">Depoda eklenti bulunamadı</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Görünüşe göre potansiyel bir kopya kütüphanenizde zaten bulunuyor: \\'%s\\'\n\\n\n\\nYine de ekleyerek var olanı değiştirmek mi istersiniz, yoksa iptal etmek mi?</string>\n    <string name=\"enter_pin\">PIN girin</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">Geçerli PIN\\'i Giriniz</string>\n    <string name=\"rotate_video_desc\">Ekran yönü için bir geçiş düğmesi göster</string>\n    <string name=\"auto_rotate_video\">Otomatik döndür</string>\n    <string name=\"rotate_video\">Döndür</string>\n    <string name=\"auto_rotate_video_desc\">Video yönüne göre ekran yönünün otomatik olarak değişmesini sağla</string>\n    <string name=\"links_reloaded_toast\">Bağlantılar Yeniden Yüklendi</string>\n    <string name=\"result_search_tooltip\">Diğer uzantılarda ara</string>\n    <string name=\"recommendations_tooltip\">Önerileri göster</string>\n    <string name=\"speed_setting_summary\">Oynatıcıya bir hız seçeneği ekler</string>\n    <string name=\"test_extensions\">Tüm uzantıları test et</string>\n    <string name=\"test_extensions_summary\">Bu test geliştiriciler içindir ve herhangi bir uzantının çalışmasını doğrulamaz veya reddetmez.</string>\n    <string name=\"subscribe_tooltip\">Yeni bölüm bildirimi</string>\n    <string name=\"biometric_authentication_title\">CloudStream kilidini aç</string>\n    <string name=\"biometric_setting\">Biyometri ile kilitle</string>\n    <string name=\"password_pin_authentication_title\">Şifre/PIN Kimlik Doğrulama</string>\n    <string name=\"biometric_unsupported\">Biyometrik kimlik doğrulama bu cihazda desteklenmiyor</string>\n    <string name=\"biometric_setting_summary\">Parmak İzi, Yüz Kimliği, PIN, Desen ve Parola ile uygulamanın kilidini açın.</string>\n    <string name=\"biometric_prompt_description\">Birkaç başarısız denemeden sonra istem kapanacaktır. Tekrar denemek için uygulamayı yeniden başlatmanız yeterlidir.</string>\n    <string name=\"biometric_warning\">CloudStream verileriniz artık yedeklenmiştir. Bunun olasılığı çok düşük olsa da tüm cihazlar farklı davranabilir. Nadiren de olsa uygulamaya erişiminizin kilitlenmesi durumunda, uygulama verilerini tamamen temizleyin ve bir yedekten geri yükleyin. Bu durumdan kaynaklanan rahatsızlıklardan dolayı çok üzgünüz.</string>\n    <string name=\"favorite\">Favori</string>\n    <string name=\"unfavorite\">Favorilerden kaldır</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s \\nkaldı</string>\n    <string name=\"repo_copy_label\">Depo adı ve URL\\'si</string>\n    <string name=\"toast_copied\">kopyalandı!</string>\n    <string name=\"clipboard_permission_error\">Panoya erişimde hata oluştu. Lütfen tekrar deneyin.</string>\n    <string name=\"clipboard_unknown_error\">Kopyalama hatası. Lütfen logcat\\'i kopyalayın ve uygulama desteğiyle iletişime geçin.</string>\n    <string name=\"ok\">Tamam</string>\n    <string name=\"battery_dialog_title\">Pil optimizasyonunu devre dışı bırak</string>\n    <string name=\"app_info_intent_error\">CloudStream\\'in Uygulama bilgileri açılamıyor.</string>\n    <string name=\"music_singlar\">Müzik</string>\n    <string name=\"audio_book_singular\">Sesli Kitap</string>\n    <string name=\"custom_media_singluar\">Medya</string>\n    <string name=\"battery_dialog_message\">Abone olunan TV programları için kesintisiz indirme ve bildirimler sağlamak için CloudStream\\'in arka planda çalışma iznine ihtiyacı var. Tamam\\'a basarak bir istek iletişim kutusu göreceksiniz. Lütfen \\'İzin Ver\\'e basın.\\n\\nLütfen unutmayın, bu izin CS3’ün pilinizi tüketeceği anlamına gelmez. Yalnızca gerektiğinde, örneğin bildirim alırken veya resmi uzantılardan video indirirken arka planda çalışır.</string>\n    <string name=\"app_unrestricted_toast\">Uygulama pil kullanımı zaten sınırsız olarak ayarlanmış</string>\n    <string name=\"reset_btn\">Sıfırla</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">%s içinde yaklaşıyor</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">%1$d. Sezon %2$d. Bölüm şu tarihte yayınlanacak</string>\n    <string name=\"player_settings_select_cast_device\">Yansıtılacak cihaz seç</string>\n    <string name=\"episode_action_cast_mirror\">Ekran yansıtma</string>\n    <string name=\"cs3wiki\">CloudStream bilgi</string>\n    <string name=\"pref_category_security\">Güvenlik</string>\n    <string name=\"pref_category_accounts\">Hesaplar</string>\n    <string name=\"auth_locally\">Yerel Olarak Doğrula</string>\n    <string name=\"qr_image\">QR Kod Görüntüsü</string>\n    <string name=\"dismiss\">Yoksay</string>\n    <string name=\"open_downloaded_repo\">Depoyu aç</string>\n    <string name=\"device_pin_url_message\">Akıllı telefonunuzda veya bilgisayarınızda <b>%s</b> adresini ziyaret edin ve yukarıdaki kodu girin</string>\n    <string name=\"device_pin_error_message\">Cihaz PIN kodu alınamıyor, yerel kimlik doğrulamayı deneyin</string>\n    <string name=\"device_pin_expired_message\">PIN kodunun süresi doldu!</string>\n    <string name=\"device_pin_counter_text\">Kodun süresi %1$dm %2$ds içinde doluyor</string>\n    <string name=\"downloads_empty\">Şu an hiç bir indirme bulunmamaktadır.</string>\n    <string name=\"delete_plugin\">Eklentiyi sil</string>\n    <string name=\"open_local_video\">Yerel videoyu aç</string>\n    <string name=\"test_warning\">Uyarı</string>\n    <string name=\"sort_release_date_new\">Yayınlanma Tarihi (Yeniden Eskiye)</string>\n    <string name=\"sort_release_date_old\">Yayınlanma Tarihi (Eskiden Yeniye)</string>\n    <string name=\"hide_player_control_names\">Oynatıcı kontrolünün adlarını gizle</string>\n    <string name=\"play_from_beginning_img_des\">Baştan Oynat</string>\n    <string name=\"select_all\">Tümünü Seç</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Aşağıdaki öğeleri kalıcı olarak silmek istediğinizden emin misiniz?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">%1$s içindeki aşağıdaki bölümleri kalıcı olarak silmek istediğinizden emin misiniz?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_files\">Dosyaları Silin</string>\n    <string name=\"delete_format\" formatted=\"true\">Sil (%1$d | %2$s)</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Aşağıdaki dizideki tüm bölümleri kalıcı olarak silmek istediğinizden emin misiniz?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Ayrıca aşağıdaki dizideki tüm bölümleri kalıcı olarak sileceksiniz:\n\\n\n\\n%s</string>\n    <string name=\"downloads_delete_select\">Silinecek Öğeleri Seçin</string>\n    <string name=\"deselect_all\">Tüm Seçimi Kaldır</string>\n    <string name=\"offline_file\">Çevrimdışı izlemek için kullanılabilir</string>\n    <string name=\"preview_seekbar\">Arama çubuğu önizlemesi</string>\n    <string name=\"preview_seekbar_desc\">Arama çubuğunda önizleme küçük resmini etkinleştir</string>\n    <string name=\"no_subtitles_loaded\">Henüz altyazı yüklenmedi</string>\n    <string name=\"backup_path_title\">Yedekleme klasörü konumu</string>\n    <string name=\"custom\">Özel</string>\n    <string name=\"confirm_before_exiting_title\">Çıkmadan önce onayla</string>\n    <string name=\"show\">Göster</string>\n    <string name=\"confirm_before_exiting_desc\">Uygulamadan çıkmadan önce iletişim kutusunu göster</string>\n    <string name=\"dont_show\">Gizle</string>\n    <string name=\"subs_edge_size\">Köşe Boyutu</string>\n    <string name=\"torrent_info\">Bu video Torrent\\'tir, bu video aktivitenizin takip edilebileceği anlamına gelir.\\nDevam etmeden önce Torrentlemeyi iyi anladığınızdan emin olun.</string>\n    <string name=\"unsupported_error\">Desteklenmeyen hata</string>\n    <string name=\"encoding_error\">Kodlama hatası</string>\n    <string name=\"player_load_one_subtitle_online\">İlk kullanılabiliri yükle</string>\n    <string name=\"audio_singluar\">Ses</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"torrent_preferred_media\">Ayarlar/Sağlayıcılar/Tercih edilen medya bölümünden torrenti etkinleştirin</string>\n    <string name=\"torrent_not_accepted\">Uygulamayı yeniden başlatın ve devam etmek için Stream Torrent açılır penceresini kabul edin.</string>\n    <string name=\"software_decoding\">Yazılımsal çözücü</string>\n    <string name=\"software_decoding_desc\">Yazılımsal kod çözücü, oynatıcının cihazınız tarafından desteklenmeyen video dosyalarını oynatmasını sağlar, ancak yüksek çözünürlükte gecikmeli veya dengesiz oynatmaya neden olabilir.</string>\n    <string name=\"sort_episodes_number_asc\">Bölüm (Artan)</string>\n    <string name=\"sort_episodes_number_desc\">Bölüm (Azalan)</string>\n    <string name=\"sort_episodes_rating_high_low\">Puanlama (En Yüksek)</string>\n    <string name=\"sort_episodes_rating_low_high\">Puanlama (En Düşük)</string>\n    <string name=\"sort_episodes_date_newest\">Yayınlanma Tarihi (En Yeni)</string>\n    <string name=\"sort_episodes_date_oldest\">Yayınlanma Tarihi (En Eski)</string>\n    <string name=\"sort_button_episode\">Bölüm %s</string>\n    <string name=\"sort_button_rating\">Puanlama %s</string>\n    <string name=\"sort_button_date\">Tarih %s</string>\n    <string name=\"update_plugins\">Eklentileri Güncelle</string>\n    <string name=\"starting_plugin_update_manually\">Eklenti güncellemesi başlıyor!</string>\n    <string name=\"plugins_updated_manually\">%d eklenti başarıyla güncellendi!</string>\n    <string name=\"no_plugins_updated_manually\">Hiçbir eklenti güncellenmedi.</string>\n    <string name=\"update_plugins_manually\">Eklentileri el ile güncelle</string>\n    <string name=\"player_notification_channel_description\">Oynatıcı bildirimi arka planda oynatmasını kontrol etmek içindir</string>\n    <string name=\"player_notification_channel_name\">Oynatıcı bildirimleri</string>\n    <string name=\"subtitles_from_embedded\">Yerleştir</string>\n    <string name=\"subtitles_from_online\">Çevrimiçi</string>\n    <string name=\"speech_recognition_unavailable\">Konuşma tanıma özelliği mevcut değil</string>\n    <string name=\"begin_speaking\">Konuşmaya Başlayın…</string>\n    <string name=\"volume_exceeded_100\">Ses %100 oranını aştı</string>\n    <string name=\"slide_up_again_to_exceed_100\">%100 üzerine çıkmak için yukarı kaydır</string>\n    <string name=\"all_subtitles_bold\">Tüm altyazıları kalın yap</string>\n    <string name=\"all_subtitles_italic\">Tüm altyazıları italik yap</string>\n    <string name=\"background_radius\">Arka Plan Yarıçapı</string>\n    <string name=\"overscan_settings\">Ekran sığdırma</string>\n    <string name=\"parallel_downloads\">Eşzamanlı indirmeler</string>\n    <string name=\"concurrent_connections\">Eşzamanlı bağlantılar</string>\n    <string name=\"no_internet_connection\">İnternet bağlantısı yok.\\n\\nLütfen internete bağlanıp tekrar deneyin ya da çevrimdışıyken indirdiğiniz içerikleri izleyin.</string>\n    <string name=\"go_to_downloads\">İndirilenlere Git</string>\n    <string name=\"download_parallel_settings_des\">Aynı anda kaç farklı öğe indirilebilir</string>\n    <string name=\"overscan_settings_des\">Ekranın sınırlarını değiştirir</string>\n    <string name=\"concurrent_connections_settings_des\">Her indirme sırasında kaç eşzamanlı bağlantı kullanılabilir</string>\n    <string name=\"poster_size_settings\">Afiş boyutu</string>\n    <string name=\"poster_size_settings_des\">Afişlerin boyutlarını değiştir</string>\n    <string name=\"player_settings_always_ask\">Her zaman sor</string>\n    <string name=\"speedup_title\">Uzun basma hızını değiştir</string>\n    <string name=\"speedup_summary\">2x hız için basılı tut</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dsa %2$ddk %3$dsn</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$ddk %2$dsn</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$dsn</string>\n    <string name=\"show_rating\">Reyting etiketi</string>\n    <string name=\"no_account\">hesap yok</string>\n    <string name=\"edit_profile_image_title\">Profil Resmini düzenle</string>\n    <string name=\"edit_profile_image_hint\">Profil Resmi Bağlantısını Girin</string>\n    <string name=\"edit_profile_image_error_empty\">URL bulunamadı</string>\n    <string name=\"edit_profile_image_error_invalid\">Geçersiz Bağlantı veya Görsel</string>\n    <string name=\"edit_profile_image_success\">Görsel Başarıyla Güncellendi</string>\n    <string name=\"episode_action_play_mirror\">Ekranda oynat</string>\"\n    <string name=\"action_mark_watched_up_to_this_episode\">Bu bölüme kadar izlenmiş olarak işaretle</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Bu bölümü izlenmemiş olarak işaretle</string>\n    <string name=\"action_reload\">Yeniden yükle</string>\n    <string name=\"reload_provider\">Sağlayıcıyı yeniden yükle</string>\n    <string name=\"name\">Ad</string>\n    <string name=\"resolution_and_name\">Çözünürlük ve ad</string>\n    <string name=\"bottom_left\">Sol alt</string>\n    <string name=\"bottom_center\">Alt orta</string>\n    <string name=\"bottom_right\">Sağ alt</string>\n    <string name=\"middle_left\">Orta sol</string>\n    <string name=\"middle_center\">Orta merkez</string>\n    <string name=\"middle_right\">Orta sağ</string>\n    <string name=\"top_left\">Sol üst</string>\n    <string name=\"top_center\">Üst orta</string>\n    <string name=\"top_right\">Sağ üst</string>\n    <string name=\"subs_subtitle_alignment\">Altyazı Hizalama</string>\n    <string name=\"play_full_series_button\">Tüm Seriyi Oynat</string>\n    <string name=\"install_prerelease\">Ön sürümünü yükleyin</string>\n    <string name=\"prerelease_already_installed\">Ön sürüm zaten indirilmiş.</string>\n    <string name=\"prerelease_install_failed\">Ön sürüm indirmesi başarısız oldu.</string>\n    <string name=\"show_episode_text\">Bölüm Başlığı</string>\n    <string name=\"search_suggestions\">Arama Önerileri</string>\n    <string name=\"search_suggestions_des\">Yazarken arama önerilerini göster</string>\n    <string name=\"clear_suggestions\">Önerileri Temizle</string>\n    <string name=\"show_cast_in_details\">Yayın panelini göster</string>\n    <string name=\"extra_brightness_settings\">Ekstra parlaklık</string>\n    <string name=\"extra_brightness_settings_des\">Görüntü parlaklığı %100\\'ü geçerse parlaklık filtresini aktifleştir</string>\n    <string name=\"extra_brightness_key\">Ekstra parlaklık aktifleştirildi</string>\n    <string name=\"video_info\">Medya bilgisi</string>\n    <string name=\"source_name\">Kaynağın adı</string>\n    <string name=\"download_queue\">İndirme kuyruğu</string>\n    <string name=\"queue_empty_message\">Şu anda bekleyen indirme yok.</string>\n    <string name=\"download_all\">Tümünü indir</string>\n    <string name=\"cancel_all\">Tümünü iptal et</string>\n    <string name=\"download_episode_range\">%s numaralı bölümü indirmek istiyor musunuz?</string>\n    <string name=\"cancel_queue_message\">Kuyruktaki tüm indirmeleri iptal etmek istiyor musunuz?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d aktif indirme</item>\n        <item quantity=\"other\">%d aktif indirmeler</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d indirme kuyrukta</item>\n        <item quantity=\"other\">%d indirilecekler kuyruğa alındı</item>\n    </plurals>\n    <string name=\"source_priority\">Öncelikli kaynak</string>\n    <string name=\"source_priority_help\">Oynatıcıda video kaynaklarının nasıl sıralanacağını belirleyin</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+uk/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"search_poster_img_des\">Плакат</string>\n    <string name=\"episode_poster_img_des\">Постер Епізоду</string>\n    <string name=\"download_canceled\">Завантаження Скасовано</string>\n    <string name=\"home_change_provider_img_des\">Змінити Постачальника</string>\n    <string name=\"go_back_img_des\">Назад</string>\n    <string name=\"rated_format\" formatted=\"true\">Рейтинг: %.1f</string>\n    <string name=\"cast_format\" formatted=\"true\">Актори: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Епізод %d вийде через</string>\n    <string name=\"result_poster_img_des\">Плакат</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Еп. %2$d</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dд %2$dгод %3$dхв</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dгод %2$dхв</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dхв</string>\n    <string name=\"home_main_poster_img_des\">Головний Постер</string>\n    <string name=\"home_next_random_img_des\">Наступний Випадковий</string>\n    <string name=\"preview_background_img_des\">Попередній Перегляд Заднього Фону</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Швидкість (%.2fx)</string>\n    <string name=\"new_update_format\" formatted=\"true\">Знайдено нове оновлення!\\n%1$s –&gt; %2$s</string>\n    <string name=\"title_search\">Пошук</string>\n    <string name=\"title_downloads\">Завантаження</string>\n    <string name=\"duration_format\" formatted=\"true\">%d хв</string>\n    <string name=\"title_settings\">Налаштування</string>\n    <string name=\"search_hint\">Пошук…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Пошук на %s…</string>\n    <string name=\"no_data\">Немає Даних</string>\n    <string name=\"episode_more_options_des\">Більше Опцій</string>\n    <string name=\"next_episode\">Наступний епізод</string>\n    <string name=\"result_tags\">Жанри</string>\n    <string name=\"result_open_in_browser\">Відкрити в Браузері</string>\n    <string name=\"skip_loading\">Пропустити Завантаження</string>\n    <string name=\"loading\">Завантаження…</string>\n    <string name=\"type_completed\">Завершено</string>\n    <string name=\"type_plan_to_watch\">Планую Дивитися</string>\n    <string name=\"type_dropped\">Скинуто</string>\n    <string name=\"play_movie_button\">Відтворити Фільм</string>\n    <string name=\"play_trailer_button\">Відтворити Трейлер</string>\n    <string name=\"play_torrent_button\">Транслювати Торрент</string>\n    <string name=\"reload_error\">Повторити з’єднання…</string>\n    <string name=\"go_back\">Назад</string>\n    <string name=\"play_episode\">Відтворити Епізод</string>\n    <string name=\"downloaded\">Завантажено</string>\n    <string name=\"downloading\">Завантаження</string>\n    <string name=\"download_done\">Завантаження Завершено</string>\n    <string name=\"app_dubbed_text\">Дуб.</string>\n    <string name=\"app_subbed_text\">Суб.</string>\n    <string name=\"popup_delete_file\">Видалити файл</string>\n    <string name=\"popup_resume_download\">Відновити завантаження</string>\n    <string name=\"home_expanded_hide\">Приховати</string>\n    <string name=\"home_play\">Переглянути</string>\n    <string name=\"home_info\">Подробиці</string>\n    <string name=\"error_bookmarks_text\">Закладки</string>\n    <string name=\"action_remove_from_bookmarks\">Вилучити</string>\n    <string name=\"action_add_to_bookmarks\">Змінити стан перегляду</string>\n    <string name=\"sort_apply\">Застосувати</string>\n    <string name=\"sort_copy\">Скопіювати</string>\n    <string name=\"sort_close\">Закрити</string>\n    <string name=\"sort_save\">Зберегти</string>\n    <string name=\"player_speed\">Швидкість плеєра</string>\n    <string name=\"subs_window_color\">Колір вікна</string>\n    <string name=\"subs_edge_type\">Тип обведення</string>\n    <string name=\"subs_font\">Шрифт</string>\n    <string name=\"subs_font_size\">Розмір шрифту</string>\n    <string name=\"search_provider_text_providers\">Пошук за постачальниками</string>\n    <string name=\"search_provider_text_types\">Пошук за типами</string>\n    <string name=\"benene_count_text_none\">Жодного банана не надано</string>\n    <string name=\"subs_auto_select_language\">Автовибір мови</string>\n    <string name=\"subs_download_languages\">Завантажити мови</string>\n    <string name=\"subs_subtitle_languages\">Мова субтитрів</string>\n    <string name=\"subs_hold_to_reset_to_default\">Утримуйте, щоби скинути до типових налаштувань</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Імпортуйте шрифти, помістивши їх до %s</string>\n    <string name=\"continue_watching\">Продовжити перегляд</string>\n    <string name=\"action_remove_watching\">Вилучити</string>\n    <string name=\"action_open_watching\">Докладніше</string>\n    <string name=\"vpn_torrent\">Цей постачальник є торентом, рекомендується використовувати VPN</string>\n    <string name=\"torrent_plot\">Опис</string>\n    <string name=\"normal_no_plot\">Сюжет не знайдено</string>\n    <string name=\"torrent_no_plot\">Опис не знайдено</string>\n    <string name=\"show_log_cat\">Показати Logcat 🐈</string>\n    <string name=\"picture_in_picture_des\">Продовжувати відтворення в малому програвачі поверх інших застосунків</string>\n    <string name=\"player_size_settings_des\">Прибрати чорні смуги</string>\n    <string name=\"player_subtitles_settings\">Субтитри</string>\n    <string name=\"chromecast_subtitles_settings\">Субтитри Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Налаштування субтитрів Chromecast</string>\n    <string name=\"eigengraumode_settings\">Швидкість відтворення</string>\n    <string name=\"swipe_to_change_settings\">Провести, щоби змінити налаштування</string>\n    <string name=\"swipe_to_change_settings_des\">Проведіть угору або вниз із лівого або правого боку, щоби змінити яскравість або гучність</string>\n    <string name=\"autoplay_next_settings_des\">Відтворювати наступний епізод після закінчення поточного</string>\n    <string name=\"title_home\">Головна</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"filler\" formatted=\"true\">Філлер</string>\n    <string name=\"play_with_app_name\">Відтворити в CloudStream</string>\n    <string name=\"stream\">Мережева трансляція</string>\n    <string name=\"type_watching\">Переглядання</string>\n    <string name=\"result_share\">Поділитися</string>\n    <string name=\"type_on_hold\">Відкладено</string>\n    <string name=\"type_re_watching\">Переглядаю Повторно</string>\n    <string name=\"download\">Завантажити</string>\n    <string name=\"play_livestream_button\">Відтворити Трансляцію</string>\n    <string name=\"pick_source\">Джерела</string>\n    <string name=\"pick_subtitle\">Субтитри</string>\n    <string name=\"download_storage_text\">Внутрішнє Сховище</string>\n    <string name=\"download_paused\">Завантаження Призупинено</string>\n    <string name=\"download_started\">Завантаження Розпочато</string>\n    <string name=\"download_failed\">Завантаження не Вдалося</string>\n    <string name=\"update_started\">Оновлення Розпочато</string>\n    <string name=\"error_loading_links_toast\">Помилка Завантаження Посилань</string>\n    <string name=\"popup_pause_download\">Призупинити завантаження</string>\n    <string name=\"popup_play_file\">Переглянути файл</string>\n    <string name=\"home_more_info\">Докладніше</string>\n    <string name=\"filter_bookmarks\">Фільтр закладок</string>\n    <string name=\"sort_clear\">Очистити</string>\n    <string name=\"subtitles_settings\">Налаштування субтитрів</string>\n    <string name=\"subs_background_color\">Колір тла</string>\n    <string name=\"subs_subtitle_elevation\">Висота субтитрів</string>\n    <string name=\"subs_text_color\">Колір тексту</string>\n    <string name=\"subs_outline_color\">Колір обведення</string>\n    <string name=\"autoplay_next_settings\">Автовідтворення наступного епізоду</string>\n    <string name=\"swipe_to_seek_settings_des\">Проведіть збоку в бік, щоби керувати часом відтворення у відео</string>\n    <string name=\"benene_count_text\">%d бананів надано розробникам</string>\n    <string name=\"player_size_settings\">Кнопка зміни розміру програвача</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Для коректної роботи цього постачальника може знадобитися VPN</string>\n    <string name=\"provider_info_meta\">Метадані не надаються сайтом, завантаження відео не відбудеться, якщо їх немає на сайті.</string>\n    <string name=\"picture_in_picture\">Картинка в картинці</string>\n    <string name=\"player_subtitles_settings_des\">Налаштування субтитрів програвача</string>\n    <string name=\"swipe_to_seek_settings\">Провести, щоби перемотати</string>\n    <string name=\"double_tap_to_seek_settings\">Натиснути двічі, щоби перемотати</string>\n    <string name=\"double_tap_to_pause_settings\">Натиснути двічі, щоби призупинити</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Крок перемотування (у секундах)</string>\n    <string name=\"double_tap_to_pause_settings_des\">Натисніть двічі посередині, щоби призупинити відтворення</string>\n    <string name=\"use_system_brightness_settings\">Використовувати системну яскравість</string>\n    <string name=\"episode_sync_settings\">Оновлювати прогрес перегляду</string>\n    <string name=\"restore_settings\">Відновлення даних із резервної копії</string>\n    <string name=\"backup_settings\">Резервне копіювання даних</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Не вдалося відновити дані з файлу %s</string>\n    <string name=\"backup_success\">Дані збережено</string>\n    <string name=\"backup_failed_error_format\">Помилка резервного копіювання %s</string>\n    <string name=\"search\">Пошук</string>\n    <string name=\"category_account\">Облікові записи та безпека</string>\n    <string name=\"category_updates\">Оновлення та резервне копіювання</string>\n    <string name=\"settings_info\">Подробиці</string>\n    <string name=\"advanced_search\">Розширений пошук</string>\n    <string name=\"advanced_search_des\">Показувати результати пошуку, розділені за постачальниками</string>\n    <string name=\"show_fillers_settings\">Показувати наповнювачі для аніме</string>\n    <string name=\"show_trailers_settings\">Показувати трейлери</string>\n    <string name=\"pref_filter_search_quality\">Приховати вибрану якість відео у результатах пошуку</string>\n    <string name=\"automatic_plugin_download\">Автозавантаження розширень</string>\n    <string name=\"updates_settings\">Показувати оновлення застосунку</string>\n    <string name=\"redo_setup_process\">Налаштувати повторно</string>\n    <string name=\"apk_installer_settings\">Установлювач APK</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Застосунок для ранобе від тих самих розробників</string>\n    <string name=\"anim\">Застосунок для аніме від тих самих розробників</string>\n    <string name=\"benene\">Дати банан розробникам</string>\n    <string name=\"app_language\">Мова застосунку</string>\n    <string name=\"no_chromecast_support_toast\">Цей постачальник не має підтримування Chromecast</string>\n    <string name=\"no_links_found_toast\">Посилань не знайдено</string>\n    <string name=\"play_episode_toast\">Переглянути епізод</string>\n    <string name=\"subs_default_reset_toast\">Скинути до типових значень</string>\n    <string name=\"no_season\">Немає сезона</string>\n    <string name=\"episodes\">Епізодів</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">С</string>\n    <string name=\"episode_short\">Е</string>\n    <string name=\"delete_file\">Видалити файл</string>\n    <string name=\"delete\">Видалити</string>\n    <string name=\"cancel\">Скасувати</string>\n    <string name=\"resume\">Відновити</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"delete_message\" formatted=\"true\">Це назавжди видалить %s\\nВи впевнені?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dхв\\nзалишилося</string>\n    <string name=\"status_ongoing\">Триває</string>\n    <string name=\"status_completed\">Завершено</string>\n    <string name=\"rating\">Рейтинг</string>\n    <string name=\"duration\">Тривалість</string>\n    <string name=\"queued\">у черзі</string>\n    <string name=\"no_subtitles\">Немає субтитрів</string>\n    <string name=\"action_default\">Типово</string>\n    <string name=\"free_storage\">Вільно</string>\n    <string name=\"used_storage\">Зайнято</string>\n    <string name=\"app_storage\">Застосунок</string>\n    <string name=\"tv_series\">Телесеріали</string>\n    <string name=\"cartoons\">Мультфільми</string>\n    <string name=\"anime\">Аніме</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Азіатські драми</string>\n    <string name=\"livestreams\">Прямі трансляції</string>\n    <string name=\"others\">Інші</string>\n    <string name=\"tv_series_singular\">Серіал</string>\n    <string name=\"cartoons_singular\">Мультфільм</string>\n    <string name=\"anime_singular\">Аніме</string>\n    <string name=\"documentaries_singular\">Документальний фільм</string>\n    <string name=\"asian_drama_singular\">Азіатська драма</string>\n    <string name=\"live_singular\">Пряма трансляція</string>\n    <string name=\"other_singular\">Відео</string>\n    <string name=\"source_error\">Помилка джерела</string>\n    <string name=\"remote_error\">Віддалена помилка</string>\n    <string name=\"render_error\">Помилка показу</string>\n    <string name=\"episode_action_chromecast_mirror\">Дзеркало Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Переглянути в застосунку</string>\n    <string name=\"episode_action_play_in_format\">Переглянути в %s</string>\n    <string name=\"episode_action_auto_download\">Автозавантаження</string>\n    <string name=\"episode_action_download_mirror\">Завантажити дзеркало</string>\n    <string name=\"check_for_update\">Перевірити наявність оновлень</string>\n    <string name=\"video_lock\">Забл./Розбл.</string>\n    <string name=\"video_skip_op\">Пропустити ОП</string>\n    <string name=\"dont_show_again\">Не показувати знову</string>\n    <string name=\"update\">Оновити</string>\n    <string name=\"watch_quality_pref\">Бажана якість перегляду (WiFi)</string>\n    <string name=\"show_title\">Заголовок</string>\n    <string name=\"poster_ui_settings\">Перемкнути елементи інтерфейсу на плакаті</string>\n    <string name=\"no_update_found\">Оновлення не знайдено</string>\n    <string name=\"double_tap_to_seek_settings_des\">Натисніть двічі праворуч або ліворуч, щоби перемотати вперед або назад</string>\n    <string name=\"use_system_brightness_settings_des\">Використовувати системну яскравість у програвачі замість темного накладання</string>\n    <string name=\"restore_success\">Завантажено файл резервної копії</string>\n    <string name=\"torrent\">Торенти</string>\n    <string name=\"episode_sync_settings_des\">Автоматично синхронізувати прогрес поточного епізоду</string>\n    <string name=\"backup_failed\">Немає дозволу на зберігання. Спробуйте ще раз.</string>\n    <string name=\"kitsu_settings\">Показувати плакати від Kitsu</string>\n    <string name=\"automatic_plugin_updates\">Автооновлення розширень</string>\n    <string name=\"automatic_plugin_download_summary\">Автоматично встановлювати всі розширення, які ще не встановлено, з доданих репозиторіїв.</string>\n    <string name=\"updates_settings_des\">Автоматично перевіряти нові оновлення після запуску застосунку.</string>\n    <string name=\"copy_link_toast\">Покликання скопійовано до буфера обміну</string>\n    <string name=\"apk_installer_settings_des\">Деякі пристрої не підтримують новий інсталятор пакетів. Спробуйте старий варіант, якщо оновлення не встановлюються.</string>\n    <string name=\"discord\">Приєднуйтеся до Discord</string>\n    <string name=\"benene_des\">Дано бананів</string>\n    <string name=\"year\">Рік</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"episode\">Епізод</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"no_episodes_found\">Епізодів не знайдено</string>\n    <string name=\"pause\">Призупинити</string>\n    <string name=\"season\">Сезон</string>\n    <string name=\"status\">Стан</string>\n    <string name=\"site\">Сайт</string>\n    <string name=\"video_aspect_ratio_resize\">Змінити розмір</string>\n    <string name=\"synopsis\">Стислий зміст</string>\n    <string name=\"movies\">Фільми</string>\n    <string name=\"episode_action_reload_links\">Перезавантажити покликання</string>\n    <string name=\"documentaries\">Документальні фільми</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"movies_singular\">Фільм</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Торент</string>\n    <string name=\"show_hd\">Мітка якості</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"unexpected_error\">Несподівана помилка програвача</string>\n    <string name=\"storage_error\">Помилка завантаження, перевірте дозвіл на зберігання</string>\n    <string name=\"episode_action_chromecast_episode\">Дивитися через Chromecast</string>\n    <string name=\"show_sub\">Мітка субтитрів</string>\n    <string name=\"video_source\">Джерело</string>\n    <string name=\"episode_action_download_subtitle\">Завантажити субтитри</string>\n    <string name=\"show_dub\">Мітка дубляжу</string>\n    <string name=\"skip_update\">Пропустити це оновлення</string>\n    <string name=\"all\">Усе</string>\n    <string name=\"resize_fit\">На весь екран</string>\n    <string name=\"resize_fill\">Заповнити</string>\n    <string name=\"resize_zoom\">Збільшити</string>\n    <string name=\"tracks\">Доріжки</string>\n    <string name=\"pref_category_app_updates\">Оновлення застосунку</string>\n    <string name=\"pref_category_cache\">Кеш</string>\n    <string name=\"pref_category_gestures\">Жести</string>\n    <string name=\"pref_category_player_features\">Особливості програвача</string>\n    <string name=\"pref_category_subtitles\">Субтитри</string>\n    <string name=\"pref_category_defaults\">Типово</string>\n    <string name=\"pref_category_looks\">Вигляд</string>\n    <string name=\"pref_category_ui_features\">Особливості</string>\n    <string name=\"category_general\">Загальні</string>\n    <string name=\"random_button_settings\">Випадкова кнопка</string>\n    <string name=\"random_button_settings_desc\">Показувати кнопку випадкового вибору на головній сторінці та бібліотеці</string>\n    <string name=\"provider_lang_settings\">Мови розширень</string>\n    <string name=\"app_layout\">Макет застосунку</string>\n    <string name=\"preferred_media_settings\">Бажані медіа</string>\n    <string name=\"automatic\">Автоматично</string>\n    <string name=\"tv_layout\">Макет телевізора</string>\n    <string name=\"phone_layout\">Макет телефону</string>\n    <string name=\"emulator_layout\">Макет емулятора</string>\n    <string name=\"primary_color_settings\">Основний колір</string>\n    <string name=\"app_theme_settings\">Тема застосунку</string>\n    <string name=\"bottom_title_settings\">Розташування назви плаката</string>\n    <string name=\"bottom_title_settings_des\">Розмістити назву під плакатом</string>\n    <string name=\"example_password\">Пароль123</string>\n    <string name=\"example_username\">Імʼя користувача</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_site_name\">НоваНазваСайту</string>\n    <string name=\"example_lang_name\">Код мови (uk)</string>\n    <string name=\"logout\">Вийти</string>\n    <string name=\"login\">Увійти</string>\n    <string name=\"switch_account\">Змінити обліковий запис</string>\n    <string name=\"add_account\">Додати обліковий запис</string>\n    <string name=\"add_sync\">Додати відстеження</string>\n    <string name=\"upload_sync\">Синхронізація</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s автентифіковано</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Не вдалося ввійти в %s</string>\n    <string name=\"none\">Нічого</string>\n    <string name=\"normal\">Звичайний</string>\n    <string name=\"min\">Мін.</string>\n    <string name=\"subtitles_outline\">Обведення</string>\n    <string name=\"subtitles_shadow\">Тінь</string>\n    <string name=\"subtitles_raised\">Підняті</string>\n    <string name=\"subtitle_offset\">Синхронізувати субтитри</string>\n    <string name=\"subtitle_offset_title\">Затримка субтитрів</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Без затримки субтитрів</string>\n    <string name=\"recommended\">Рекомендовано</string>\n    <string name=\"player_load_subtitles_online\">Завантажити з інтернету</string>\n    <string name=\"downloaded_file\">Завантажений файл</string>\n    <string name=\"actor_main\">Головний</string>\n    <string name=\"home_source\">Джерело</string>\n    <string name=\"home_random\">Випадковий</string>\n    <string name=\"coming_soon\">Скоро буде…</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Зображення плаката</string>\n    <string name=\"category_player\">Програвач</string>\n    <string name=\"resolution_and_title\">Роздільна здатність та заголовок</string>\n    <string name=\"error_invalid_id\">Недійсний ID</string>\n    <string name=\"error_invalid_url\">Недійсна URL-адреса</string>\n    <string name=\"pref_category_backup\">Резервне копіювання</string>\n    <string name=\"limit_title\">Макс. кількість символів у заголовку програвача</string>\n    <string name=\"video_buffer_size_settings\">Розмір буфера відео</string>\n    <string name=\"video_buffer_disk_settings\">Кеш відео на диску</string>\n    <string name=\"add_site_pref\">Клонувати сайт</string>\n    <string name=\"remove_site_pref\">Видалити сайт</string>\n    <string name=\"nginx_url_pref\">URL-адреса сервера NGINX</string>\n    <string name=\"pref_category_links\">Покликання</string>\n    <string name=\"limit_title_rez\">Показувати інформацію про програвач</string>\n    <string name=\"video_buffer_length_settings\">Довжина буфера відео</string>\n    <string name=\"video_buffer_clear_settings\">Очистити кеш відео та зображень</string>\n    <string name=\"video_ram_description\">Спричиняє збої, якщо встановлено занадто високе значення на пристроях із малим об’ємом пам’яті, таких як Android TV.</string>\n    <string name=\"dns_pref_summary\">Корисно для обходу блокувань провайдера</string>\n    <string name=\"video_disk_description\">Спричиняє збої, якщо встановлено занадто високе значення на пристроях із малим об’ємом вільної пам’яті, таких як Android TV.</string>\n    <string name=\"dns_pref\">DNS через HTTPS</string>\n    <string name=\"download_path_pref\">Шлях завантаження</string>\n    <string name=\"add_site_summary\">Додайте двійника наявного сайту, з іншою URL-адресою</string>\n    <string name=\"display_subbed_dubbed_settings\">Показувати мітку Дубляж/Субтитри для аніме</string>\n    <string name=\"legal_notice\">Застереження</string>\n    <string name=\"pref_category_extensions\">Розширення</string>\n    <string name=\"pref_category_actions\">Дії</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"pref_category_player_layout\">Макет</string>\n    <string name=\"subtitles_encoding\">Кодування субтитрів</string>\n    <string name=\"enable_nsfw_on_providers\">Увімкнути NSFW вміст на підтримуваних розширеннях</string>\n    <string name=\"category_ui\">Макет</string>\n    <string name=\"category_providers\">Постачальники</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"login_format\" formatted=\"true\">%2$s %1$s</string>\n    <string name=\"subtitles_depressed\">Опущені</string>\n    <string name=\"account\">обліковий запис</string>\n    <string name=\"create_account\">Створити</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Додано %s</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_score\">Рейтинг</string>\n    <string name=\"player_load_subtitles\">Завантажити з файлу</string>\n    <string name=\"max\">Макс.</string>\n    <string name=\"subtitles_example_text\">Щастям б’єш жук їх глицю в фон й ґедзь пріч</string>\n    <string name=\"subtitle_offset_hint\">1000 мс</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Використовуйте це, якщо субтитри з’являються раніше на %d мс</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Використовуйте це, якщо субтитри з’являються запізно на %d мс</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Завантажено %s</string>\n    <string name=\"actor_supporting\">Другорядний</string>\n    <string name=\"actor_background\">Тло</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"subtitles_remove_captions\">Вилучати закриті титри із субтитрів</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"error_invalid_data\">Недійсні дані</string>\n    <string name=\"subtitles_filter_lang\">Фільтрувати за бажаною мовою медіа</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"title\">Заголовок</string>\n    <string name=\"resolution\">Роздільна здатність</string>\n    <string name=\"error\">Помилка</string>\n    <string name=\"trailer\">Трейлер</string>\n    <string name=\"extras\">Додатково</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"subtitles_remove_bloat\">Вилучати роздуття субтитрів</string>\n    <string name=\"referer\">Referer (необов’язково)</string>\n    <string name=\"next\">Далі</string>\n    <string name=\"provider_languages_tip\">Переглядайте відео на цих мовах</string>\n    <string name=\"skip_setup\">Пропустити налаштування</string>\n    <string name=\"preferred_media_subtext\">Що ви хочете побачити</string>\n    <string name=\"setup_done\">Готово</string>\n    <string name=\"extensions\">Розширення</string>\n    <string name=\"add_repository\">Додати репозиторій</string>\n    <string name=\"repository_name_hint\">Назва репозиторію (необов’язково)</string>\n    <string name=\"repository_url_hint\">URL-адреса репозиторію або короткий код</string>\n    <string name=\"plugin_loaded\">Розширення завантажено</string>\n    <string name=\"plugin_downloaded\">Розширення завантажено</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Не вдалося завантажити %s</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Почалося завантаження %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Завантажено %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Усі %s вже завантажено</string>\n    <string name=\"batch_download\">Завантажити пакунки</string>\n    <string name=\"plugin_singular\">розширення</string>\n    <string name=\"plugin\">розширень</string>\n    <string name=\"delete_repository\">Видалити репозиторій</string>\n    <string name=\"setup_extensions_subtext\">Завантажте список сайтів, які ви хочете використовувати</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Завантажено: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Вимкнено: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Не завантажено: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Оновлено %d розширень</string>\n    <string name=\"blank_repo_message\">Типово у CloudStream немає жодного встановленого сайту. Вам потрібно встановити сайти з репозиторіїв.\\n\\nПриєднуйтеся до нашого Discord або шукайте в інтернеті.</string>\n    <string name=\"view_public_repositories_button\">Переглянути репозиторії спільноти</string>\n    <string name=\"view_public_repositories_button_short\">Публічний список</string>\n    <string name=\"uppercase_all_subtitles\">Усі субтитри великими літерами</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (вимкнено)</string>\n    <string name=\"video_tracks\">Відеодоріжки</string>\n    <string name=\"apply_on_restart\">Перезапустіть застосунок, щоби побачити зміни.</string>\n    <string name=\"safe_mode_crash_info\">Переглянути подробиці про збій</string>\n    <string name=\"extension_rating\" formatted=\"true\">Рейтинг: %s</string>\n    <string name=\"extension_description\">Опис</string>\n    <string name=\"extension_version\">Версія</string>\n    <string name=\"extension_status\">Стан</string>\n    <string name=\"extension_size\">Розмір</string>\n    <string name=\"extension_types\">Підтримується</string>\n    <string name=\"extension_language\">Мова</string>\n    <string name=\"extension_install_first\">Спочатку встановіть розширення</string>\n    <string name=\"hls_playlist\">Список відтворення HLS</string>\n    <string name=\"player_settings_play_in_app\">Вбудований програвач</string>\n    <string name=\"skip_type_ed\">Ендінґ</string>\n    <string name=\"skip_type_recap\">Коротке повторення</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Пропустити %s</string>\n    <string name=\"skip_type_mixed_ed\">Змішаний ендінґ</string>\n    <string name=\"skip_type_creddits\">Подяки</string>\n    <string name=\"skip_type_op\">Опенінґ</string>\n    <string name=\"skip_type_intro\">Вступ</string>\n    <string name=\"clear_history\">Очистити історію</string>\n    <string name=\"history\">Історія</string>\n    <string name=\"enable_skip_op_from_database_des\">Показувати спливне вікно для пропуску опенінґу / ендінґу</string>\n    <string name=\"clipboard_too_large\">Забагато тексту. Не вдалося зберегти до буфера обміну.</string>\n    <string name=\"action_mark_as_watched\">Позначити як переглянуте</string>\n    <string name=\"confirm_exit_dialog\">Ви впевнені, що хочете вийти?</string>\n    <string name=\"yes\">Так</string>\n    <string name=\"no\">Ні</string>\n    <string name=\"update_notification_installing\">Установлення оновлення застосунку…</string>\n    <string name=\"update_notification_failed\">Не вдалося встановити нову версію застосунку</string>\n    <string name=\"apk_installer_legacy\">Застарілий</string>\n    <string name=\"apk_installer_package_installer\">Установлювач пакунків</string>\n    <string name=\"delayed_update_notice\">Застосунок буде оновлено після виходу</string>\n    <string name=\"delete_repository_plugins\">Це також призведе до видалення всіх розширень репозиторію</string>\n    <string name=\"all_languages_preference\">Усі мови</string>\n    <string name=\"previous\">Назад</string>\n    <string name=\"app_layout_subtext\">Змініть вигляд застосунку відповідно до вашого пристрою</string>\n    <string name=\"plugin_deleted\">Розширення видалено</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"audio_tracks\">Аудіодоріжки</string>\n    <string name=\"download_all_plugins_from_repo\">Увага: CloudStream не несе жодної відповідальності за використання сторонніх розширень і не надає жодної підтримки для них!</string>\n    <string name=\"player_pref\">Бажаний відеопрогравач</string>\n    <string name=\"safe_mode_title\">Увімкнено безпечний режим</string>\n    <string name=\"extension_authors\">Автори</string>\n    <string name=\"update_notification_downloading\">Завантаження оновлення застосунку…</string>\n    <string name=\"safe_mode_description\">Усі розширення було вимкнено через збій, щоби допомогти вам знайти те, яке спричиняє проблеми.</string>\n    <string name=\"app_not_found_error\">Застосунок не знайдено</string>\n    <string name=\"skip_type_mixed_op\">Змішаний опенінґ</string>\n    <string name=\"action_remove_from_watched\">Вилучити з переглянутого</string>\n    <string name=\"sort_updated_old\">Оновленням (від старого до нового)</string>\n    <string name=\"sort_updated_new\">Оновленням (від нового до старого)</string>\n    <string name=\"library\">Бібліотека</string>\n    <string name=\"sort\">Сортувати</string>\n    <string name=\"sort_rating_desc\">Рейтингом (від високого до низького)</string>\n    <string name=\"sort_by\">Сортувати за</string>\n    <string name=\"sort_alphabetical_a\">Алфавітом (від А до Я)</string>\n    <string name=\"sort_rating_asc\">Рейтингом (від низького до високого)</string>\n    <string name=\"empty_library_no_accounts_message\">Ваша бібліотека порожня :(\\nУвійдіть в обліковий запис бібліотеки або додайте щось до вашої локальної бібліотеки.</string>\n    <string name=\"sort_alphabetical_z\">Алфавітом (від Я до А)</string>\n    <string name=\"select_library\">Оберіть бібліотеку</string>\n    <string name=\"open_with\">Відкрити</string>\n    <string name=\"browser\">Браузер</string>\n    <string name=\"empty_library_logged_in_message\">Цей список порожній. Спробуйте перейти до іншого.</string>\n    <string name=\"safe_mode_file\">Файл безпечного режиму знайдено!\\nРозширення не завантажуватимуться під час запуску, доки файл не буде видалено.</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Прогрвач приховано – крок перемотування</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Програвач показано – крок перемотування</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Крок перемотування, який використовується, коли програвач видимий</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Крок перемотування, який використовується, коли плеєр прихований</string>\n    <string name=\"test_failed\">Провалено</string>\n    <string name=\"test_passed\">Пройдено</string>\n    <string name=\"restart\">Перезапустити</string>\n    <string name=\"test_log\">Журнал</string>\n    <string name=\"start\">Відновити</string>\n    <string name=\"stop\">Зупинити</string>\n    <string name=\"category_provider_test\">Перевірка постачальників</string>\n    <string name=\"subscription_in_progress_notification\">Оновлення підписок</string>\n    <string name=\"subscription_list_name\">Підписано</string>\n    <string name=\"subscription_new\">Ви підписалися на %s</string>\n    <string name=\"subscription_deleted\">Ви відписалися від %s</string>\n    <string name=\"subscription_episode_released\">Епізод %d випущено!</string>\n    <string name=\"revert\">Повернути</string>\n    <string name=\"jsdelivr_proxy\">GitHub проксі</string>\n    <string name=\"jsdelivr_enabled\">Не вдалось отримати доступ до GitHub. Увімкнення проксі-сервера jsDelivr…</string>\n    <string name=\"pref_category_bypass\">Обходи ISP</string>\n    <string name=\"jsdelivr_proxy_summary\">Обхід блокування GitHub за допомогою jsDelivr. Можлива затримка оновлень на кілька днів.</string>\n    <string name=\"watch_quality_pref_data\">Бажана якість перегляду (мобільні дані)</string>\n    <string name=\"set_default\">Змінити на типові</string>\n    <string name=\"profiles\">Профілі</string>\n    <string name=\"help\">Довідка</string>\n    <string name=\"quality_profile_help\">Тут можна змінити порядок джерел. Відео з вищим пріоритетом з’являтиметься вище в списку джерел. Сума пріоритету джерела та пріоритету якості утворює пріоритет відео.\\n\\nДжерело А: 3\\nЯкість Б: 7\\nЗагальний пріоритет відео дорівнюватиме 10.\\n\\nПРИМІТКА: Якщо сума пріоритетів дорівнюватиме 10 або більше, програвач автоматично пропустить завантаження цього покликання!</string>\n    <string name=\"profile_number\">Профіль %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Мобільні дані</string>\n    <string name=\"use\">Використовувати</string>\n    <string name=\"edit\">Редагувати</string>\n    <string name=\"qualities\">Якості</string>\n    <string name=\"profile_background_des\">Тло профілю</string>\n    <string name=\"unable_to_inflate\">Не вдалося коректно створити інтерфейс користувача. Це ВЕЛИКИЙ ЗБІЙ, про який варто негайно повідомити %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Оберіть режим фільтрування розширень для завантаження</string>\n    <string name=\"disable\">Вимкнути</string>\n    <string name=\"no_repository_found_error\">Репозиторій не знайдено, перевірте URL-адресу та спробуйте VPN</string>\n    <string name=\"no_plugins_found_error\">Не знайдено жодного розширення в репозиторії</string>\n    <string name=\"already_voted\">Ви вже проголосували</string>\n    <string name=\"backup_frequency\">Частота резервного копіювання</string>\n    <string name=\"favorite_removed\">%s вилучено з обраного</string>\n    <string name=\"favorites_list_name\">Обране</string>\n    <string name=\"favorite_added\">%s додано до обраного</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">У вашій бібліотеці виявлено можливі дублікати:\\n\\n%s\\n\\nУсе одно хочете додати цей елемент, замінити наявні чи скасувати дію?</string>\n    <string name=\"duplicate_title\">Знайдено можливий дублікат</string>\n    <string name=\"lock_profile\">Заблокувати профіль</string>\n    <string name=\"action_add_to_favorites\">Додати до обраного</string>\n    <string name=\"duplicate_replace_all\">Замінити все</string>\n    <string name=\"pin_error_incorrect\">Неправильний PIN-код. Спробуйте ще раз.</string>\n    <string name=\"action_unsubscribe\">Відписатися</string>\n    <string name=\"pin_error_length\">PIN-код має складатися із 4 символів</string>\n    <string name=\"duplicate_replace\">Замінити</string>\n    <string name=\"duplicate_add\">Додати</string>\n    <string name=\"action_subscribe\">Підписатися</string>\n    <string name=\"action_remove_from_favorites\">Вилучити з обраного</string>\n    <string name=\"select_an_account\">Оберіть обліковий запис</string>\n    <string name=\"duplicate_message_single\">Схоже, що у вашій бібліотеці вже є можливий дублікат: «%s.»\\n\\nУсе одно хочете додати цей елемент, замінити наявний чи скасувати дію?</string>\n    <string name=\"enter_pin\">Уведіть PIN-код</string>\n    <string name=\"pin\">PIN-код</string>\n    <string name=\"enter_current_pin\">Уведіть поточний PIN-код</string>\n    <string name=\"logged_account\" formatted=\"true\">Увійшли як %s</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Уведіть PIN-код для %s</string>\n    <string name=\"use_default_account\">Використовувати типовий обліковий запис</string>\n    <string name=\"skip_startup_account_select_pref\">Пропускати вибір облікового запису під час запуску</string>\n    <string name=\"manage_accounts\">Керувати обліковими записами</string>\n    <string name=\"edit_account\">Редагувати обліковий запис</string>\n    <string name=\"rotate_video_desc\">Показувати кнопку перемикання орієнтації екрана</string>\n    <string name=\"rotate_video\">Обернути</string>\n    <string name=\"links_reloaded_toast\">Посилання Перезавантажені</string>\n    <string name=\"auto_rotate_video\">Автообертання</string>\n    <string name=\"auto_rotate_video_desc\">Увімкнути автоматичну зміну орієнтації екрана відповідно до відео</string>\n    <string name=\"speed_setting_summary\">Додати налаштування швидкості до програвача</string>\n    <string name=\"test_extensions\">Перевірити всі розширення</string>\n    <string name=\"result_search_tooltip\">Пошук в інших розширеннях</string>\n    <string name=\"recommendations_tooltip\">Показати рекомендації</string>\n    <string name=\"test_extensions_summary\">Ця перевірка лише для розробників і не підтверджує або заперечує роботу жодного розширення.</string>\n    <string name=\"subscribe_tooltip\">Сповіщення про новий епізод</string>\n    <string name=\"password_pin_authentication_title\">Автентифікація за паролем/PIN-кодом</string>\n    <string name=\"biometric_authentication_title\">Розблокуйте CloudStream</string>\n    <string name=\"biometric_setting\">Біометричне блокування</string>\n    <string name=\"biometric_setting_summary\">Розблоковуйте застосунок за допомогою відбитка пальця, Face ID, PIN-коду, графічного ключа або пароля.</string>\n    <string name=\"biometric_warning\">Щойно було виконано резервне копіювання даних CloudStream. Хоча ймовірність цього вкрай мала, усі пристрої можуть поводитися по-різному. У рідкісних випадках, якщо ви втратите доступ до застосунку, повністю очистіть дані застосунку та відновіть їх із резервної копії. Просимо вибачення за будь-які незручності, що можуть виникнути.</string>\n    <string name=\"biometric_unsupported\">Біометрична автентифікація не підтримується на цьому пристрої</string>\n    <string name=\"biometric_prompt_description\">Після кількох невдалих спроб вікно запиту зникне. Перезапустіть застосунок, щоби спробувати ще раз.</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\nзалишилося</string>\n    <string name=\"unfavorite\">Вилучити з обраного</string>\n    <string name=\"favorite\">Додати до обраного</string>\n    <string name=\"toast_copied\">скопійовано!</string>\n    <string name=\"repo_copy_label\">Назва репозиторію та URL</string>\n    <string name=\"clipboard_unknown_error\">Помилка копіювання, скопіюйте logcat та зверніться до служби підтримки застосунку.</string>\n    <string name=\"clipboard_permission_error\">Помилка доступу до буфера обміну, спробуйте ще раз.</string>\n    <string name=\"ok\">Гаразд</string>\n    <string name=\"battery_dialog_title\">Вимкнути оптимізацію батареї</string>\n    <string name=\"battery_dialog_message\">Щоби забезпечити безперервне завантаження та сповіщення про підписані телепередачі, CloudStream потребує дозволу на роботу у фоновому режимі. Натиснувши «Гаразд», ви побачите діалогове вікно запиту. Натисніть «Дозволити».\\n\\nЗверніть увагу, що цей дозвіл не означає, що CS3 розряджатиме ваш акумулятор. Він працюватиме у фоновому режимі лише за необхідності, наприклад, під час отримання сповіщень або завантаження відео з офіційних розширень.</string>\n    <string name=\"app_unrestricted_toast\">Споживання батареї застосунком уже змінено на необмежене</string>\n    <string name=\"app_info_intent_error\">Не вдається відкрити подробиці про застосунок CloudStream.</string>\n    <string name=\"audio_book_singular\">Аудіокнига</string>\n    <string name=\"music_singlar\">Музика</string>\n    <string name=\"custom_media_singluar\">Медіа</string>\n    <string name=\"reset_btn\">Скинути</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Наступний через %s</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Сезон %1$d Епізод %2$d вийде через</string>\n    <string name=\"player_settings_select_cast_device\">Оберіть пристрій для трансляції</string>\n    <string name=\"episode_action_cast_mirror\">Трансляція через дзеркало</string>\n    <string name=\"cs3wiki\">Довідник CloudStream</string>\n    <string name=\"pref_category_security\">Безпека</string>\n    <string name=\"pref_category_accounts\">Облікові записи</string>\n    <string name=\"qr_image\">Зображення QR-коду</string>\n    <string name=\"open_downloaded_repo\">Відкрити репозиторій</string>\n    <string name=\"device_pin_url_message\">Відвідайте <b>%s</b> на своєму смартфоні або комп\\'ютері та введіть вищевказаний код</string>\n    <string name=\"device_pin_error_message\">Не вдається отримати PIN-код пристрою, спробуйте локальну автентифікацію</string>\n    <string name=\"device_pin_expired_message\">PIN-код застарів!</string>\n    <string name=\"device_pin_counter_text\">Термін дії коду закінчується через %1$dхв %2$dс</string>\n    <string name=\"auth_locally\">Локальна автентифікація</string>\n    <string name=\"dismiss\">Відхилити</string>\n    <string name=\"play_from_beginning_img_des\">Відтворити з Початку</string>\n    <string name=\"test_warning\">Попередження</string>\n    <string name=\"delete_plugin\">Видалити розширення</string>\n    <string name=\"downloads_empty\">Наразі завантажень немає.</string>\n    <string name=\"hide_player_control_names\">Приховати назви елементів керування в програвачі</string>\n    <string name=\"open_local_video\">Відкрити локальне відео</string>\n    <string name=\"sort_release_date_new\">Датою випуску (від нових до старих)</string>\n    <string name=\"sort_release_date_old\">Датою випуску (від старих до нових)</string>\n    <string name=\"downloads_delete_select\">Оберіть Елементи для Видалення</string>\n    <string name=\"select_all\">Обрати Все</string>\n    <string name=\"deselect_all\">Зняти Вибір Всіх</string>\n    <string name=\"delete_format\" formatted=\"true\">Видалити (%1$d | %2$s)</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Ви впевнені, що хочете назавжди видалити такі епізоди «%1$s»?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Ви також назавжди видалите всі епізоди в такому серіалі:\\n\\n%s</string>\n    <string name=\"offline_file\">Доступно для перегляду в оффлайн режимі</string>\n    <string name=\"delete_files\">Видалити файли</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Ви впевнені, що хочете назавжди видалити такі елементи?\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Ви впевнені, що хочете назавжди видалити всі епізоди в такому серіалі?\\n\\n%s</string>\n    <string name=\"preview_seekbar\">Попередній перегляд на шкалі перегляду</string>\n    <string name=\"preview_seekbar_desc\">Увімкнути мініатюру попереднього перегляду на шкалі перегляду</string>\n    <string name=\"no_subtitles_loaded\">Субтитри ще не завантажено</string>\n    <string name=\"confirm_before_exiting_title\">Підтвердіть перед виходом</string>\n    <string name=\"show\">Показувати</string>\n    <string name=\"confirm_before_exiting_desc\">Показувати діалог перед виходом із застосунку</string>\n    <string name=\"dont_show\">Не показувати</string>\n    <string name=\"backup_path_title\">Розташування теки для резервних копій</string>\n    <string name=\"custom\">Власний</string>\n    <string name=\"torrent_info\">Це відео – Торрент, це означає, що ваша відео діяльність може відстежуватися.\\nПереконайтеся, що розумієте, що таке Торрент, перед тим як продовжити.</string>\n    <string name=\"subs_edge_size\">Розмір обведення</string>\n    <string name=\"audio_singluar\">Аудіо</string>\n    <string name=\"podcast_singluar\">Подкаст</string>\n    <string name=\"unsupported_error\">Непідтримувана помилка</string>\n    <string name=\"encoding_error\">Помилка кодування</string>\n    <string name=\"player_load_one_subtitle_online\">Завантажити перші доступні</string>\n    <string name=\"torrent_preferred_media\">Увімкніть торент у Налаштування/Постачальники/Бажані медіа</string>\n    <string name=\"torrent_not_accepted\">Перезапустіть застосунок та прийміть спливне вікно Stream Torrent, щоби продовжити.</string>\n    <string name=\"software_decoding\">Програмне декодування</string>\n    <string name=\"software_decoding_desc\">Програмне декодування дозволяє плеєру відтворювати відеофайли, які не підтримуються вашим пристроєм, але може спричинити затримки або нестабільне відтворення у високій роздільній здатності.</string>\n    <string name=\"sort_episodes_date_newest\">Датою виходу (найновіша)</string>\n    <string name=\"sort_episodes_number_asc\">Епізодом (за зростанням)</string>\n    <string name=\"sort_episodes_rating_low_high\">Рейтингом (найнижчий)</string>\n    <string name=\"sort_button_rating\">Рейтинг %s</string>\n    <string name=\"sort_episodes_number_desc\">Епізодом (за спаданням)</string>\n    <string name=\"sort_episodes_rating_high_low\">Рейтингом (найвищий)</string>\n    <string name=\"sort_episodes_date_oldest\">Датою виходу (найстаріша)</string>\n    <string name=\"sort_button_episode\">Еп. %s</string>\n    <string name=\"sort_button_date\">Дата %s</string>\n    <string name=\"update_plugins\">Оновити розширення</string>\n    <string name=\"plugins_updated_manually\">Успішно оновлено %d розширення(-ь)!</string>\n    <string name=\"update_plugins_manually\">Оновити розширення вручну</string>\n    <string name=\"starting_plugin_update_manually\">Починається оновлення розширень!</string>\n    <string name=\"no_plugins_updated_manually\">Не оновлено жодного розширення.</string>\n    <string name=\"player_notification_channel_description\">Сповіщення програвача для керування відтворенням у фоновому режимі</string>\n    <string name=\"player_notification_channel_name\">Сповіщення програвача</string>\n    <string name=\"speech_recognition_unavailable\">Розпізнавання мовлення недоступне</string>\n    <string name=\"begin_speaking\">Почніть Говорити…</string>\n    <string name=\"subtitles_from_embedded\">Вбудовані</string>\n    <string name=\"subtitles_from_online\">Мережеві</string>\n    <string name=\"background_radius\">Радіус тла</string>\n    <string name=\"all_subtitles_bold\">Зробити всі субтитри жирним</string>\n    <string name=\"all_subtitles_italic\">Зробити всі субтитри курсивом</string>\n    <string name=\"volume_exceeded_100\">Гучність перевищила 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Ще раз проведіть угору, щоби перевищити 100%</string>\n    <string name=\"concurrent_connections\">Одночасних з’єднань</string>\n    <string name=\"overscan_settings_des\">Змінює межі екрана</string>\n    <string name=\"overscan_settings\">Обрізання зображення</string>\n    <string name=\"go_to_downloads\">Перейти до завантажень</string>\n    <string name=\"no_internet_connection\">Немає підключення до Інтернету.\\n\\nБудь ласка, підключіться до Інтернету та спробуйте ще раз або перегляньте завантажені відео офлайн.</string>\n    <string name=\"download_parallel_settings_des\">Скільки різних елементів можна завантажити паралельно</string>\n    <string name=\"parallel_downloads\">Паралельних завантажень</string>\n    <string name=\"concurrent_connections_settings_des\">Скільки одночасних з’єднань може використовувати кожне завантаження</string>\n    <string name=\"poster_size_settings_des\">Зміна розміру плакатів</string>\n    <string name=\"poster_size_settings\">Розмір постера</string>\n    <string name=\"player_settings_always_ask\">Завжди запитуйте</string>\n    <string name=\"speedup_title\">Змінювати швидкість при утриманні</string>\n    <string name=\"speedup_summary\">Утримуйте, щоб отримати 2-кратну швидкість</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dгод %2$dхв %3$dс</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dхв %2$dс</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$dс</string>\n    <string name=\"show_rating\">Мітка рейтингу</string>\n    <string name=\"no_account\">Немає облікового запису</string>\n    <string name=\"edit_profile_image_title\">Редагувати зображення профілю</string>\n    <string name=\"edit_profile_image_hint\">Введіть URL-адресу зображення профілю</string>\n    <string name=\"edit_profile_image_error_empty\">URL-адресу не знайдено</string>\n    <string name=\"edit_profile_image_error_invalid\">Недійсна URL-адреса або зображення</string>\n    <string name=\"edit_profile_image_success\">Зображення успішно оновлено</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Позначити як переглянуте до цього епізоду</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Вилучити переглянуті до цього епізоду</string>\n    <string name=\"action_reload\">Перезавантажено</string>\n    <string name=\"reload_provider\">Постачальник послуг поповнення рахунку</string>\n    <string name=\"episode_action_play_mirror\">Грати в дзеркало</string>\"\n    <string name=\"name\">Ім\\'я</string>\n    <string name=\"resolution_and_name\">Роздільна здатність та назва</string>\n    <string name=\"subs_subtitle_alignment\">Вирівнювання субтитрів</string>\n    <string name=\"bottom_left\">Внизу ліворуч</string>\n    <string name=\"bottom_center\">Внизу по центру</string>\n    <string name=\"bottom_right\">Внизу праворуч</string>\n    <string name=\"middle_left\">Середній лівий</string>\n    <string name=\"middle_center\">Середній центр</string>\n    <string name=\"middle_right\">Середній правий</string>\n    <string name=\"top_left\">Угорі ліворуч</string>\n    <string name=\"top_center\">Верхній центр</string>\n    <string name=\"top_right\">Угорі праворуч</string>\n    <string name=\"play_full_series_button\">Відтворити Повні Серії</string>\n    <string name=\"install_prerelease\">Встановити передрелізну версію</string>\n    <string name=\"prerelease_already_installed\">Попередня версія вже встановлена.</string>\n    <string name=\"prerelease_install_failed\">Не вдалося встановити попередню версію.</string>\n    <string name=\"show_episode_text\">Текст епізоду</string>\n    <string name=\"search_suggestions\">Пропозиції пошуку</string>\n    <string name=\"search_suggestions_des\">Показувати підказки пошуку під час введення тексту</string>\n    <string name=\"clear_suggestions\">Очистити пропозиції</string>\n    <string name=\"extra_brightness_settings\">Додаткова яскравість</string>\n    <string name=\"extra_brightness_settings_des\">Увімкнути фільтр яскравості при перевищенні 100% яскравості дисплея</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"show_cast_in_details\">Показати панель трансляції</string>\n    <string name=\"video_info\">Інформація про медіа</string>\n    <string name=\"source_name\">Назва джерела</string>\n    <string name=\"download_queue\">Черга завантаження</string>\n    <string name=\"queue_empty_message\">Наразі немає завантажень у черзі.</string>\n    <string name=\"download_all\">Завантажити все</string>\n    <string name=\"cancel_all\">Скасувати все</string>\n    <string name=\"download_episode_range\">Бажаєте завантажити %s епізод?</string>\n    <string name=\"cancel_queue_message\">Бажаєте скасувати всі завантаження в черзі?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d активне завантаження</item>\n        <item quantity=\"few\">%d активні завантаження</item>\n        <item quantity=\"many\">%d активних завантажень</item>\n        <item quantity=\"other\">%d активних завантажень</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d завантаження в черзі</item>\n        <item quantity=\"few\">%d завантаження в черзі</item>\n        <item quantity=\"many\">%d завантажень у черзі</item>\n        <item quantity=\"other\">%d завантажень у черзі</item>\n    </plurals>\n    <string name=\"source_priority\">Пріоритетне джерело</string>\n    <string name=\"source_priority_help\">Виберіть спосіб сортування джерел відео у програвачі</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+ur/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"cast_format\" formatted=\"true\">کاسٹ: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">قسط %d جاری کیا جائے گا</string>\n    <string name=\"search_poster_img_des\">پروموشنل تصویر</string>\n    <string name=\"episode_poster_img_des\">قسط کا پوسٹر</string>\n    <string name=\"home_main_poster_img_des\">مرکزی پوسٹر</string>\n    <string name=\"home_next_random_img_des\">اگلا بے ترتیب</string>\n    <string name=\"go_back_img_des\">رجوع</string>\n    <string name=\"home_change_provider_img_des\">ذریعہ تبدیل کریں</string>\n    <string name=\"preview_background_img_des\">پس منظر کا دیکھنا</string>\n    <string name=\"rated_format\" formatted=\"true\">درجہ بندی: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">نیا update آگیا ہے!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">بھرنے والا</string>\n    <string name=\"duration_format\" formatted=\"true\">%d منٹ</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d دن %2$d گھنٹے %3$d منٹ</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$d گھنٹے %2$d منٹ</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d منٹ</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">CloudStream کے ساتھ چلائیں</string>\n    <string name=\"title_home\">ہوم</string>\n    <string name=\"title_search\">تلاش کریں</string>\n    <string name=\"title_downloads\">ڈاؤن لوڈ</string>\n    <string name=\"title_settings\">ترتیبات</string>\n    <string name=\"search_hint\">تلاش کریں…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">فراہم کنندہ میں تلاش کریں%s…</string>\n    <string name=\"episode_more_options_des\">مزید آپشنز</string>\n    <string name=\"next_episode\">اگلا قسط</string>\n    <string name=\"result_open_in_browser\">براؤزر میں کھولیں</string>\n    <string name=\"skip_loading\">لوڈنگ چھوڑیں</string>\n    <string name=\"loading\">لوڈ ہو رہا ہے…</string>\n    <string name=\"type_watching\">دیکھ رہے ہیں</string>\n    <string name=\"type_on_hold\">معطل</string>\n    <string name=\"type_dropped\">چھوڑ دیا گیا</string>\n    <string name=\"type_plan_to_watch\">دیکھنے کا منصوبہ</string>\n    <string name=\"type_re_watching\">دوبارہ دیکھنا</string>\n    <string name=\"play_movie_button\">مووی لگائے</string>\n    <string name=\"play_trailer_button\">ٹریلر چلائیں</string>\n    <string name=\"play_livestream_button\">لائیو اسٹریم چلائیں</string>\n    <string name=\"play_torrent_button\">سٹریم ٹورینٹ</string>\n    <string name=\"pick_source\">ذرائع</string>\n    <string name=\"reload_error\">کنکشن کی دوبارہ کوشش کی جارہی ہے…</string>\n    <string name=\"go_back\">واپس جاو</string>\n    <string name=\"play_episode\">قسط چلائیں</string>\n    <string name=\"downloaded\">ڈاؤن لوڈ کردہ ویڈیوز</string>\n    <string name=\"downloading\">ڈاؤن لوڈ ہو رہا ہے</string>\n    <string name=\"download_paused\">ڈاؤن لوڈ موقوف</string>\n    <string name=\"download_started\">ڈاؤن لوڈ شروع ہو گیا</string>\n    <string name=\"download_failed\">ڈاؤن لوڈ نہیں ہو پا رہا</string>\n    <string name=\"download_canceled\">ڈاؤن لوڈ منسوخ ہو گیا</string>\n    <string name=\"stream\">نیٹ ورک سٹریم</string>\n    <string name=\"error_loading_links_toast\">لنک میں مسئلہ</string>\n    <string name=\"app_dubbed_text\">ڈب</string>\n    <string name=\"app_subbed_text\">سبد</string>\n    <string name=\"popup_delete_file\">فائل کو ڈیلیٹ کریں</string>\n    <string name=\"no_data\">کوئی مواد نہیں</string>\n    <string name=\"popup_play_file\">فائل چلائیں</string>\n    <string name=\"popup_resume_download\">ڈاؤن لوڈ دوبارہ شروع کریں</string>\n    <string name=\"home_more_info\">مزید معلومات</string>\n    <string name=\"home_expanded_hide\">چھپائیں</string>\n    <string name=\"home_play\">چلائیں</string>\n    <string name=\"home_info\">معلومات</string>\n    <string name=\"filter_bookmarks\">بک مارکس کو فلٹر کریں</string>\n    <string name=\"error_bookmarks_text\">بک مارکس</string>\n    <string name=\"action_remove_from_bookmarks\">ریمو</string>\n    <string name=\"action_add_to_bookmarks\">واچ اسٹیٹس کو سیٹ کریں</string>\n    <string name=\"sort_apply\">لاگو کریں</string>\n    <string name=\"sort_copy\">کاپی</string>\n    <string name=\"sort_close\">بند کریں</string>\n    <string name=\"sort_clear\">صاف کریں</string>\n    <string name=\"sort_save\">محفوظ کریں</string>\n    <string name=\"player_speed\">چلانے کی رفتار</string>\n    <string name=\"subtitles_settings\">Subtitles کی رفتار</string>\n    <string name=\"subs_text_color\">لکھائی کا رنگ</string>\n    <string name=\"subs_outline_color\">آؤٹ لائن کا رنگ</string>\n    <string name=\"subs_background_color\">پس منظر کا رنگ</string>\n    <string name=\"subs_window_color\">کھڑکی کا رنگ</string>\n    <string name=\"subs_edge_type\">کنارے کی قسم</string>\n    <string name=\"subs_subtitle_elevation\">ترجمہ کی اونچائی</string>\n    <string name=\"subs_font\">لکھائی</string>\n    <string name=\"subs_font_size\">حرف کا سائز</string>\n    <string name=\"search_provider_text_types\">انواع کا استعمال کرتے ہوئے تلاش کریں</string>\n    <string name=\"benene_count_text\">%d ایپ بنانے والے کیلئے 🍌</string>\n    <string name=\"benene_count_text_none\">کیلے نہیں</string>\n    <string name=\"subs_auto_select_language\">زبان خود بخود منتخب کریں</string>\n    <string name=\"subs_download_languages\">زبانیں ڈاؤن لوڈ کریں</string>\n    <string name=\"subs_subtitle_languages\">ترجمہ کی زبان</string>\n    <string name=\"subs_import_text\" formatted=\"true\">لکھائی کو یہاں رکھ کر درآمد کریں %s</string>\n    <string name=\"continue_watching\">دیکھنا جاری رکھیں</string>\n    <string name=\"action_remove_watching\">حذف کریں</string>\n    <string name=\"action_open_watching\">مزید معلومات</string>\n    <string name=\"action_open_play\">کھلا (آن)</string>\n    <string name=\"vpn_torrent\">یہ سورس Torrent ہے، ضرورت پڑنے پر VPN کا استعمال کریں</string>\n    <string name=\"torrent_plot\">تفصیل</string>\n    <string name=\"normal_no_plot\">کوئی کہانی نہیں ملی</string>\n    <string name=\"torrent_no_plot\">کوئی تفصیل نہیں ملی</string>\n    <string name=\"show_log_cat\">غلطی کا لاگ دیکھیں 🐈</string>\n    <string name=\"picture_in_picture\">PIP</string>\n    <string name=\"picture_in_picture_des\">دوسری ایپس کے اوپر ایک منی لانچر میں چلتا رہنا</string>\n    <string name=\"player_size_settings\">پلیئر کا سائز تبدیل کرنے کا بٹن</string>\n    <string name=\"player_size_settings_des\">سیاہ سرحد کو ہٹا دیں</string>\n    <string name=\"player_subtitles_settings\">سنٹیٹلز</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast ترجمہ</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast ترجمہ کی ترتیبات</string>\n    <string name=\"eigengraumode_settings\">پلے بیک کی رفتار</string>\n    <string name=\"swipe_to_seek_settings\">ویڈیو کو آگے سوائپ کریں</string>\n    <string name=\"swipe_to_change_settings\">ترتیبات کو تبدیل کرنے کے لیے سوائپ کریں</string>\n    <string name=\"autoplay_next_settings\">اگلا ایپی سوڈ خود بخود چلائیں</string>\n    <string name=\"autoplay_next_settings_des\">موجودہ قسط ختم ہونے پر اگلی قسط شروع کریں</string>\n    <string name=\"double_tap_to_seek_settings\">آگے یا پیچھے جانے کے لیے سکرین پر دو بار تھپتھپائیں</string>\n    <string name=\"double_tap_to_pause_settings\">روکنے کے لیے دو بار تھپتھپائیں</string>\n    <string name=\"double_tap_to_seek_settings_des\">آگے یا پیچھے کی طرف جانے کے لیے دائیں یا بائیں جانب دو بار تھپتھپائیں</string>\n    <string name=\"use_system_brightness_settings\">سسٹم کی Brightness کا استعمال کریں</string>\n    <string name=\"use_system_brightness_settings_des\">ڈارک overlay کے بجائے ایپ پلیئر میں سسٹم کی Brightness کا استعمال کریں</string>\n    <string name=\"restore_settings\">بیک اپ سے ڈیٹا کو بحال کریں</string>\n    <string name=\"backup_settings\">ڈیٹا کا بیک اپ لیں</string>\n    <string name=\"restore_success\">بیک اپ فائل اپ لوڈ کر دی گئی ہے</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">فائل سے ڈیٹا درآمد کرنا ناکام %s</string>\n    <string name=\"backup_success\">ذخیرہ شدہ ڈیٹا</string>\n    <string name=\"backup_failed_error_format\">بیک اپ بنانا ناکام ہوگیا %s</string>\n    <string name=\"episode_sync_settings\">دیکھنے کی پیشرفت کو اپ ڈیٹ کریں</string>\n    <string name=\"search\">تلاش کریں</string>\n    <string name=\"category_account\">اکاؤنٹس اور سیکیورٹی</string>\n    <string name=\"settings_info\">معلومات</string>\n    <string name=\"advanced_search_des\">آپ کو فراہم کنندہ کے ذریعہ علیحدہ کردہ تلاش کے نتائج فراہم کرتا ہے</string>\n    <string name=\"pref_filter_search_quality\">تلاش کے نتائج میں منتخب ویڈیو کوالٹی چھپائیں</string>\n    <string name=\"automatic_plugin_updates\">خودکار پلگ ان اپ ڈیٹس</string>\n    <string name=\"updates_settings\">ایپ کی تازہ کاریاں نمایش کریں</string>\n    <string name=\"redo_setup_process\">سیٹ اپ کا عمل دوبارہ کریں</string>\n    <string name=\"apk_installer_settings\">APK انسٹالر</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">یہ لائٹ ناول ایپ وہی ڈویلپرز نے تیار کی ہے جو اس ایپ کو ڈویلپ کیا ہے</string>\n    <string name=\"anim\">یہ اینمی ایپ وہی ڈویلپرز نے تیار کی ہے جو اس ایپ کو ڈویلپ کیا ہے</string>\n    <string name=\"discord\">ڈسکارڈ میں شامل ہوں</string>\n    <string name=\"benene\">شکریہ ڈویلپرز کو! آپ کا کام شاندار ہے</string>\n    <string name=\"benene_des\">تعریفیں</string>\n    <string name=\"app_language\">ایپ کی زبان</string>\n    <string name=\"no_chromecast_support_toast\">اس فراہم کنندہ کے پاس کروم کاسٹ سپورٹ نہیں ہے</string>\n    <string name=\"no_links_found_toast\">کوئی لنکس نہیں ملے</string>\n    <string name=\"copy_link_toast\">کلپ بورڈ میں نقل ہوا</string>\n    <string name=\"play_episode_toast\">قسط چلائیں</string>\n    <string name=\"subs_default_reset_toast\">طے شدہ قدر پر ری سیٹ کریں</string>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s قسط %2$d</string>\n    <string name=\"result_poster_img_des\">پوسٹر</string>\n    <string name=\"result_share\">شئیر کریں</string>\n    <string name=\"result_tags\">انواع</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">رفتار (%.2fx)</string>\n    <string name=\"type_completed\">مکمل</string>\n    <string name=\"pick_subtitle\">سب ٹائٹلز</string>\n    <string name=\"download\">ڈاؤنلوڈ</string>\n    <string name=\"download_done\">ڈاؤن لوڈ ہو گیا</string>\n    <string name=\"download_storage_text\">انٹرنل سٹوریج</string>\n    <string name=\"popup_pause_download\">ڈاؤن لوڈ کو روکیں</string>\n    <string name=\"search_provider_text_providers\">ذرائع کا استعمال کرتے ہوئے تلاش کریں</string>\n    <string name=\"vpn_might_be_needed\">اس فراہم کنندہ کو مناسب طریقے سے کام کرنے کے لیے VPN کی ضرورت پڑ سکتی ہے</string>\n    <string name=\"subs_hold_to_reset_to_default\">ڈیفالٹ سیٹنگز پر ری سیٹ کرنے کے لیے دبائیں اور تھامیں</string>\n    <string name=\"provider_info_meta\">سائٹ کی طرف سے میٹا ڈیٹا فراہم نہیں کیا گیا ہے، اور اگر ویڈیو سائٹ میں موجود نہیں ہے تو وہ لوڈ ہونے میں ناکام ہو جائے گا.</string>\n    <string name=\"player_subtitles_settings_des\">پلیئر کے ترجمہ کی ترتیبات</string>\n    <string name=\"swipe_to_seek_settings_des\">ویڈیو میں اپنی پوزیشن کو کنٹرول کرنے کے لیے ایک طرف سے دوسری طرف سوائپ کریں</string>\n    <string name=\"swipe_to_change_settings_des\">سکرین کی روشنی یا والیوم تبدیل کرنے کے لیے بائیں یا دائیں سوائپ کریں</string>\n    <string name=\"double_tap_to_seek_amount_settings\">کنٹرول کریں کہ پلیئر کتنا آگے ہے(سیکنڈوں میں)</string>\n    <string name=\"double_tap_to_pause_settings_des\">توقف کرنے کے لیے درمیان میں دبائیں</string>\n    <string name=\"backup_failed\">سٹوریج کی اجازتیں غائب ہیں، براہ کرم دوبارہ کوشش کریں۔</string>\n    <string name=\"kitsu_settings\">کٹسو سے پوسٹر نمایش کریں</string>\n    <string name=\"episode_sync_settings_des\">آپ کی حالیہ قسط کی پیش رفت خود بخود مطابقت پذیر کریں</string>\n    <string name=\"category_updates\">اپ ڈیٹس اور بیک اپ</string>\n    <string name=\"advanced_search\">اعلی درجے کی تلاش</string>\n    <string name=\"show_trailers_settings\">ٹریلر نمایش کریں</string>\n    <string name=\"show_fillers_settings\">anime کے لیے فلر ایپیسوڈ دکھائیں</string>\n    <string name=\"automatic_plugin_download\">پلگ ان خود بخود ڈاؤن لوڈ کریں</string>\n    <string name=\"automatic_plugin_download_summary\">شامل کردہ ذخیروں سے خود بخود تمام ابھی تک انسٹال نہیں ہوئے پلگ ان انسٹال کریں۔</string>\n    <string name=\"updates_settings_des\">اپلیکیشن کو شروع کرنے کے بعد خود بخود نئی اپ ڈیٹس کی تلاش کریں۔</string>\n    <string name=\"apk_installer_settings_des\">کچھ فون نئے پیکیج انسٹالر کو سپورٹ نہیں کرتے ہیں. اگر اپ ڈیٹس انسٹال نہیں ہوتے ہیں تو لیگیسی آپشن کو آزمائیں.</string>\n    <string name=\"season\">سیزن</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">کوئی سیزن نہیں</string>\n    <string name=\"episode\">قسط</string>\n    <string name=\"episodes\">اقساط</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">کوئی اقساط نہیں ملی</string>\n    <string name=\"delete_file\">فائل کو ڈیلیٹ کریں</string>\n    <string name=\"delete\">مٹا دیں</string>\n    <string name=\"cancel\">منسوخ کریں</string>\n    <string name=\"pause\">توقف</string>\n    <string name=\"resume\">از سر نو شروع کریں</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">یہ مستقل طور پر حذف ہوجائے گا %s\n\\nتمھيں يقين ہے?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\nباقی</string>\n    <string name=\"status_ongoing\">احوال</string>\n    <string name=\"status_completed\">مکمل</string>\n    <string name=\"status\">حالت</string>\n    <string name=\"year\">سال</string>\n    <string name=\"rating\">درجہ بندی</string>\n    <string name=\"duration\">دورانیہ</string>\n    <string name=\"site\">سائٹ</string>\n    <string name=\"synopsis\">خلاصہ</string>\n    <string name=\"queued\">قطار میں</string>\n    <string name=\"no_subtitles\">کوئی سب ٹائٹلز نہیں</string>\n    <string name=\"action_default\">ڈیفالٹ</string>\n    <string name=\"free_storage\">مفت</string>\n    <string name=\"used_storage\">استعمال شُدہ</string>\n    <string name=\"cartoons\">کارٹون</string>\n    <string name=\"app_storage\">App</string>\n    <string name=\"movies\">فلمیں</string>\n    <string name=\"tv_series\">ٹی وی سیریز</string>\n    <string name=\"torrent\">ٹورینٹ</string>\n    <string name=\"anime\">anime</string>\n    <string name=\"documentaries\">دستاویزی فلمیں</string>\n    <string name=\"ova\">او وی اے</string>\n    <string name=\"asian_drama\">ایشیائی ڈرامے</string>\n    <string name=\"livestreams\">لائیو اسٹریمز</string>\n    <string name=\"nsfw\">این ایس ایف ڈبلیو</string>\n    <string name=\"others\">دوسرے</string>\n    <string name=\"movies_singular\">فلم</string>\n    <string name=\"tv_series_singular\">سلسلہ</string>\n    <string name=\"cartoons_singular\">کارٹون</string>\n    <string name=\"anime_singular\">انیمی</string>\n    <string name=\"ova_singular\">اووا</string>\n    <string name=\"torrent_singular\">ٹورینٹ</string>\n    <string name=\"documentaries_singular\">دستاویزی فلم</string>\n    <string name=\"asian_drama_singular\">ایشین ڈرامہ</string>\n    <string name=\"live_singular\">لائیو اسٹریمز</string>\n    <string name=\"other_singular\">ویڈیو</string>\n    <string name=\"source_error\">Source error</string>\n    <string name=\"remote_error\">Remote error</string>\n    <string name=\"render_error\">Renderer error</string>\n    <string name=\"unexpected_error\">Unexpected player error</string>\n    <string name=\"storage_error\">ڈاؤن لوڈ error، اپپ کی storage permissions چیک کریں</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast قسط</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast mirror</string>\n    <string name=\"episode_action_play_in_app\">ایپ میں چلائیں</string>\n    <string name=\"episode_action_play_in_format\">%s میں چلائیں</string>\n    <string name=\"episode_action_download_mirror\">ڈاؤنلوڈ mirror</string>\n    <string name=\"episode_action_reload_links\">لنکس کو دوبارہ لوڈ کریں</string>\n    <string name=\"episode_action_download_subtitle\">سب ٹائٹلز ڈاؤن لوڈ</string>\n    <string name=\"show_hd\">کوالٹی لیبل</string>\n    <string name=\"show_dub\">Dub لیبل</string>\n    <string name=\"show_sub\">Sub لیبل</string>\n    <string name=\"show_title\">عنوان</string>\n    <string name=\"poster_ui_settings\">پوسٹر پر UI elements کو ٹوگل کریں</string>\n    <string name=\"no_update_found\">کوئی اپ ڈیٹ نہیں ملا</string>\n    <string name=\"check_for_update\">اپ ڈیٹ کے لیے چیک کریں</string>\n    <string name=\"video_lock\">لاک کریں</string>\n    <string name=\"video_aspect_ratio_resize\">سائز تبدیل کریں</string>\n    <string name=\"video_source\">Source</string>\n    <string name=\"video_skip_op\">Opening چھوڑیں</string>\n    <string name=\"dont_show_again\">دوبارہ نہ دکھائیں</string>\n    <string name=\"skip_update\">اس اپ ڈیٹ کو چھوڑ دیں</string>\n    <string name=\"update\">اپ ڈیٹ</string>\n    <string name=\"watch_quality_pref\">ترجیحی ویڈیو کوالٹی (Wifi)</string>\n    <string name=\"limit_title\">ویڈیو پلیئر کے عنوان کے زیادہ سے زیادہ حروف</string>\n    <string name=\"limit_title_rez\">ویڈیو پلیئر resolution</string>\n    <string name=\"video_buffer_size_settings\">ویڈیو buffer سائز</string>\n    <string name=\"video_buffer_length_settings\">ویڈیو buffer لمبائی</string>\n    <string name=\"video_buffer_disk_settings\">ڈسک پر ویڈیو cache</string>\n    <string name=\"video_buffer_clear_settings\">ویڈیو اور تصویری cache صاف کریں</string>\n    <string name=\"video_disk_description\">کم اسٹوریج اسپیس والی ڈیوائس (جیسے کہ Android TV) پر بہت زیادہ سیٹ کرنے پر مسائل کا سبب بنتا ہے.</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"dns_pref_summary\">ISP blocks کو bypass کرنے کے لئے مفید</string>\n    <string name=\"add_site_pref\">Clone site</string>\n    <string name=\"download_path_pref\">ڈاؤنلوڈ کی جگہ</string>\n    <string name=\"nginx_url_pref\">NGINX server URL</string>\n    <string name=\"display_subbed_dubbed_settings\">ڈسپلے Dubbed/Subbed Anime</string>\n    <string name=\"resize_zoom\">Zoom</string>\n    <string name=\"legal_notice\">دستبرداری</string>\n    <string name=\"pref_category_links\">لنکس</string>\n    <string name=\"pref_category_app_updates\">ایپ کی تازہ کاریاں</string>\n    <string name=\"pref_category_backup\">بیک اپ</string>\n    <string name=\"pref_category_cache\">کیسہ</string>\n    <string name=\"pref_category_gestures\">اشارے</string>\n    <string name=\"pref_category_extensions\">توسیعات</string>\n    <string name=\"pref_category_actions\">اعمال</string>\n    <string name=\"pref_category_player_features\">پلیئر کی خصوصیات</string>\n    <string name=\"pref_category_subtitles\">سب ٹائٹلز</string>\n    <string name=\"pref_category_player_layout\">لے آؤٹ</string>\n    <string name=\"pref_category_defaults\">طے شدہ</string>\n    <string name=\"pref_category_looks\">لگتا ہے</string>\n    <string name=\"pref_category_ui_features\">خصوصیات</string>\n    <string name=\"category_general\">عمومی</string>\n    <string name=\"random_button_settings\">بے ترتیب بٹن</string>\n    <string name=\"random_button_settings_desc\">ہوم پیج پر بے ترتیب بٹن نمایاں کریں</string>\n    <string name=\"provider_lang_settings\">ایکسٹینشن کی زبانیں</string>\n    <string name=\"app_layout\">ایپ لے آؤٹ</string>\n    <string name=\"preferred_media_settings\">ترجیحی میڈیا</string>\n    <string name=\"enable_nsfw_on_providers\">سپورٹڈ ایکسٹینشن پر NSFW فعال کریں</string>\n    <string name=\"subtitles_encoding\">سب ٹائٹل انکوڈنگ</string>\n    <string name=\"category_providers\">فراہم کنندگان</string>\n    <string name=\"category_ui\">لے آؤٹ</string>\n    <string name=\"automatic\">خودکار</string>\n    <string name=\"tv_layout\">ٹی وی لے آؤٹ</string>\n    <string name=\"phone_layout\">فون لے آؤٹ</string>\n    <string name=\"emulator_layout\">ایمولیٹر لے آؤٹ</string>\n    <string name=\"primary_color_settings\">بنیادی رنگ</string>\n    <string name=\"app_theme_settings\">ایپ تھیم</string>\n    <string name=\"bottom_title_settings\">پوسٹر کا عنوان محل وقوع</string>\n    <string name=\"bottom_title_settings_des\">عنوان کو پوسٹر کے نیچے رکھیں</string>\n    <string name=\"example_password\">password123</string>\n    <string name=\"example_username\">Username</string>\n    <string name=\"example_email\">hello@world.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">نیا سائٹ کا نام</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">زبان کا کوڈ (en)</string>\n    <string name=\"account\">اكاؤنٹ</string>\n    <string name=\"logout\">لاگ آوٹ</string>\n    <string name=\"login\">لاگ ان کریں</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s تصدیق شدہ</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">%s پر لاگ ان نہیں ہو سکا</string>\n    <string name=\"none\">کچھ نہیں</string>\n    <string name=\"normal\">عام</string>\n    <string name=\"all\">سب</string>\n    <string name=\"max\">زیادہ سے زیادہ</string>\n    <string name=\"min\">کم از کم</string>\n    <string name=\"subtitles_outline\">خاکہ</string>\n    <string name=\"subtitles_shadow\">سایہ</string>\n    <string name=\"subtitle_offset\">ذیلی ہم وقت سازی کریں</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">زیرنویس میں دیری</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">اگر سب ٹائٹلز %d ms بہت جلد دکھائے جائیں تو اسے استعمال کریں</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">کوئی زیرنویس میں دیری نہیں</string>\n    <string name=\"nsfw_singular\">این ایس ایف ڈبلیو</string>\n    <string name=\"episode_action_auto_download\">آٹو ڈاؤن لوڈ</string>\n    <string name=\"video_ram_description\">بہت زیادہ سیٹ ہونے پر کم میموری والی ڈیوائس(جیسے کہ Android TV) پر کریشوں کا سبب بنتا ہے.</string>\n    <string name=\"remove_site_pref\">Remove site</string>\n    <string name=\"add_site_summary\">Add a clone of an existing site, with a different URL</string>\n    <string name=\"resize_fit\">اسکرین پر فٹ کریں</string>\n    <string name=\"resize_fill\">اسکرین پر کھینچ کر دکھائیں</string>\n    <string name=\"create_account\">اکاؤنٹ بنائیں</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"switch_account\">اکاؤنٹ سوئچ کریں</string>\n    <string name=\"add_sync\">ٹریکنگ شامل کریں</string>\n    <string name=\"upload_sync\">تواقت</string>\n    <string name=\"subtitles_depressed\">دپرسڈ</string>\n    <string name=\"add_account\">اکاؤنٹ شامل کریں</string>\n    <string name=\"added_sync_format\" formatted=\"true\">شامل کیا گیا %s</string>\n    <string name=\"sync_score\">ریٹیڈ</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"subtitles_raised\">اٹھایا</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">اگر سب ٹائٹلز %d ms بہت جلد دکھائے جائیں تو اسے استعمال کریں</string>\n    <string name=\"skip_type_creddits\">کریڈٹس</string>\n    <string name=\"extras\">اضافی</string>\n    <string name=\"actor_main\">مرکزی</string>\n    <string name=\"sort\">ترتیب</string>\n    <string name=\"resolution_and_title\">قرارداد اور عنوان</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"subscription_deleted\">%s سے ان سبسکرائب کیا گیا</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"test_log\">لاگ</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"pref_category_android_tv\">اینڈرائیڈ ٹی وی</string>\n    <string name=\"previous\">پچھلا</string>\n    <string name=\"trailer\">ٹریلر</string>\n    <string name=\"safe_mode_crash_info\">حادثے کی معلومات دیکھیں</string>\n    <string name=\"delayed_update_notice\">باہر نکلنے پر ایپ کو اپ ڈیٹ کر دیا جائے گا</string>\n    <string name=\"download_all_plugins_from_repo\">اس ذخیرہ سے تمام پلگ ان ڈاؤن لوڈ کریں؟</string>\n    <string name=\"subscription_episode_released\">قسط %d ریلیز ہو گئی!</string>\n    <string name=\"update_notification_failed\">ایپ کا نیا ورژن انسٹال نہیں ہو سکا</string>\n    <string name=\"recommended\">تجویز کردہ</string>\n    <string name=\"restart\">دوبارہ شروع کریں</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">لوڈ %s</string>\n    <string name=\"player_load_subtitles_online\">انٹرنیٹ سے لوڈ کریں</string>\n    <string name=\"downloaded_file\">ڈاؤن لوڈڈ فائل</string>\n    <string name=\"actor_background\">پس منظر</string>\n    <string name=\"home_source\">ذریعہ</string>\n    <string name=\"quality_cam\">کیم</string>\n    <string name=\"quality_cam_rip\">کیم</string>\n    <string name=\"quality_cam_hd\">کیم</string>\n    <string name=\"quality_hd\">ایچ ڈی</string>\n    <string name=\"quality_ts\">ٹی ایس</string>\n    <string name=\"quality_tc\">ٹی سی</string>\n    <string name=\"quality_workprint\">ڈبلیو پی</string>\n    <string name=\"quality_4k\">4کے</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"category_player\">پلیئر</string>\n    <string name=\"title\">عنوان</string>\n    <string name=\"resolution\">قرارداد</string>\n    <string name=\"error_invalid_data\">غلط ڈیٹا</string>\n    <string name=\"error\">خرابی</string>\n    <string name=\"subtitles_remove_bloat\">سب ٹائٹلز سے بلوٹ کو ہٹا دیں</string>\n    <string name=\"subtitles_filter_lang\">ترجیحی میڈیا زبان کے لحاظ سے فلٹر کریں</string>\n    <string name=\"referer\">حوالہ دینے والا (مرضی پر)</string>\n    <string name=\"provider_languages_tip\">ان زبانوں میں ویڈیوز دیکھیں</string>\n    <string name=\"skip_setup\">سیٹ اپ کو چھوڑ دیں</string>\n    <string name=\"setup_done\">ہو گیا</string>\n    <string name=\"extensions\">ایکسٹینشنز</string>\n    <string name=\"repository_url_hint\">ذخیرہ URL</string>\n    <string name=\"plugin_loaded\">پلگ ان لوڈ ہو گیا</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">%s کو لوڈ نہیں کیا جا سکا</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">ڈاؤن لوڈ ہونا شروع ہو گیا %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">ڈاؤن لوڈ کیا گیا %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">سبھی %s پہلے ہی ڈاؤن لوڈ ہو چکے ہیں</string>\n    <string name=\"plugin_singular\">رابطہ بحال کرو</string>\n    <string name=\"plugin\">پلگ ان</string>\n    <string name=\"delete_repository\">ذخیرہ کو حذف کریں</string>\n    <string name=\"setup_extensions_subtext\">ان سائٹس کی فہرست ڈاؤن لوڈ کریں جنہیں آپ استعمال کرنا چاہتے ہیں</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">ڈاؤن لوڈڈ: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">غیر فعال: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">اپ ڈیٹ کردہ %d پلگ ان</string>\n    <string name=\"uppercase_all_subtitles\">تمام سب ٹائٹلز کو بڑے کریں</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (غیر فعال)</string>\n    <string name=\"tracks\">ٹریکس</string>\n    <string name=\"audio_tracks\">آڈیو ٹریکس</string>\n    <string name=\"apply_on_restart\">تبدیلیاں دیکھنے کے لیے ایپ کو دوبارہ اسٹارٹ کریں۔</string>\n    <string name=\"safe_mode_title\">سیف موڈ آن</string>\n    <string name=\"extension_rating\" formatted=\"true\">درجہ بندی: %s</string>\n    <string name=\"extension_description\">تفصیل</string>\n    <string name=\"extension_version\">ورژن</string>\n    <string name=\"extension_status\">حالت</string>\n    <string name=\"extension_size\">سائز</string>\n    <string name=\"extension_language\">زبان</string>\n    <string name=\"player_pref\">ترجیحی ویڈیو پلیئر</string>\n    <string name=\"player_settings_play_in_app\">اندرونی پلیئر</string>\n    <string name=\"app_not_found_error\">ایپ نہیں ملی</string>\n    <string name=\"skip_type_recap\">Recap</string>\n    <string name=\"skip_type_mixed_ed\">مخلوط اختتام</string>\n    <string name=\"skip_type_mixed_op\">مخلوط افتتاحی</string>\n    <string name=\"enable_skip_op_from_database_des\">کھولنے/ختم کرنے کے لیے سکپ پاپ اپ دکھائیں</string>\n    <string name=\"action_mark_as_watched\">دیکھا گیا کے طور پر نشان زد کریں</string>\n    <string name=\"no\">نہیں</string>\n    <string name=\"update_notification_downloading\">ایپ اپ ڈیٹ ڈاؤن لوڈ ہو رہا ہے…</string>\n    <string name=\"apk_installer_legacy\">میراث</string>\n    <string name=\"update_started\">اپ ڈیٹ شروع ہو گیا</string>\n    <string name=\"plugin_downloaded\">پلگ ان ڈاؤن لوڈ ہو گیا</string>\n    <string name=\"action_remove_from_watched\">دیکھے گئے سے ہٹا دیں</string>\n    <string name=\"apk_installer_package_installer\">پیکیج انسٹالر</string>\n    <string name=\"sort_rating_desc\">درجہ بندی (اعلی سے کم)</string>\n    <string name=\"sort_rating_asc\">درجہ بندی (کم سے زیادہ)</string>\n    <string name=\"sort_updated_old\">اپ ڈیٹ کیا گیا (پرانا سے نیا)</string>\n    <string name=\"sort_alphabetical_a\">حروف تہجی (A سے Z)</string>\n    <string name=\"sort_alphabetical_z\">حروف تہجی (Z سے A)</string>\n    <string name=\"select_library\">لائبریری کو منتخب کریں</string>\n    <string name=\"android_tv_interface_on_seek_settings\">پلیئردکھایا گیا - Seek Amount</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">پلیئر کے نظر آنے پر استعمال کی جانے والی Seek Amount</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">پلیئر کے چھپنے پر استعمال ہونے والی seek amount</string>\n    <string name=\"safe_mode_file\">سیف موڈ فائل مل گئی!\n\\nفائل کو ہٹانے تک اسٹارٹ اپ پر کوئی ایکسٹینشن لوڈ نہیں کرنا۔</string>\n    <string name=\"start\">شروع کریں</string>\n    <string name=\"test_failed\">ناکام</string>\n    <string name=\"test_passed\">کامیاب ہو گیا</string>\n    <string name=\"category_provider_test\">فراہم کنندہ ٹیسٹ</string>\n    <string name=\"stop\">رک جاؤ</string>\n    <string name=\"subscription_in_progress_notification\">سبسکرائب شدہ شوز کو اپ ڈیٹ کرنا</string>\n    <string name=\"watch_quality_pref_data\">ترجیحی ویڈیو کوالٹی (موبائل ڈیٹا)</string>\n    <string name=\"jsdelivr_proxy\">GitHub Proxy</string>\n    <string name=\"pref_category_bypass\">آئی ایس پی بائی پاسز</string>\n    <string name=\"subscription_new\">%s کو سبسکرائب کیا</string>\n    <string name=\"jsdelivr_proxy_summary\">Bypass blocking of raw github URLs using jsDelivr. اپ ڈیٹس میں کچھ دنوں کی تاخیر ہو سکتی ہے</string>\n    <string name=\"empty_library_no_accounts_message\">آپ کی لائبریری خالی ہے:(\n\\nلائبریری اکاؤنٹ میں لاگ ان کریں یا اپنی مقامی لائبریری میں شوز شامل کریں۔</string>\n    <string name=\"error_invalid_url\">غلط URL</string>\n    <string name=\"browser\">براؤزر</string>\n    <string name=\"quality_webrip\">ویب</string>\n    <string name=\"actor_supporting\">مددگار</string>\n    <string name=\"quality_hq\">ایچ کیو</string>\n    <string name=\"extension_types\">حمایت کی</string>\n    <string name=\"yes\">ہاں</string>\n    <string name=\"subscription_list_name\">سبسکرائب کیا ہوا</string>\n    <string name=\"sort_updated_new\">اپ ڈیٹ کیا گیا (نئے سے پرانے)</string>\n    <string name=\"quality_dvd\">ڈی وی ڈی</string>\n    <string name=\"clear_history\">ماضی مٹا دو</string>\n    <string name=\"skip_type_intro\">تعارف</string>\n    <string name=\"history\">تاریخ</string>\n    <string name=\"open_with\">کے ساتھ کھولیں</string>\n    <string name=\"error_invalid_id\">غلط ID</string>\n    <string name=\"repository_name_hint\">ذخیرہ کا نام (اختیاری)</string>\n    <string name=\"skip_type_ed\">ختم ہونے والا</string>\n    <string name=\"skip_type_op\">کھل رہا ہے</string>\n    <string name=\"confirm_exit_dialog\">کیا آپ کو یقین ہے کہ آپ ہیاں سے نکلنا چاہتے ہیں؟</string>\n    <string name=\"quality_sd\">ایس ڈی</string>\n    <string name=\"all_languages_preference\">تمام زبانیں</string>\n    <string name=\"android_tv_interface_off_seek_settings\">پلیئر چھپا ہوا - Seek Amount</string>\n    <string name=\"library\">لائبریری</string>\n    <string name=\"quality_blueray\">بلو رے</string>\n    <string name=\"revert\">واپس لوٹنا</string>\n    <string name=\"add_repository\">ذخیرہ شامل کریں</string>\n    <string name=\"preferred_media_subtext\">آپ کیا دیکھنا چاہتے ہیں</string>\n    <string name=\"view_public_repositories_button\">‪کمیونٹی ریپوزٹریز دیکھیں</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">ڈاؤن لوڈ نہیں ہوا: %d</string>\n    <string name=\"view_public_repositories_button_short\">عوامی فہرست</string>\n    <string name=\"player_load_subtitles\">فائل سے لوڈ کریں</string>\n    <string name=\"video_tracks\">ویڈیو ٹریکس</string>\n    <string name=\"hls_playlist\">HLS پلے لسٹ</string>\n    <string name=\"poster_image\">پوسٹر کی تصویر</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"skip_type_format\" formatted=\"true\">%s کو چھوڑ دیں</string>\n    <string name=\"home_random\">بے ترتیب</string>\n    <string name=\"sort_by\">ترتیب دیں</string>\n    <string name=\"extension_authors\">مصنفین</string>\n    <string name=\"delete_repository_plugins\">اس سے تمام ریپوزٹری پلگ ان بھی حذف ہو جائیں گے</string>\n    <string name=\"plugin_deleted\">پلگ ان کو حذف کر دیا گیا</string>\n    <string name=\"batch_download\">بیچ ڈاؤن لوڈ</string>\n    <string name=\"jsdelivr_enabled\">Could not reach GitHub. Turning on jsDelivr proxy…</string>\n    <string name=\"subtitles_example_text\">تیز بھوری لومڑی سست کتے پر چھلانگ لگاتی ہے</string>\n    <string name=\"coming_soon\">جلد آرہا ہے…</string>\n    <string name=\"subtitles_remove_captions\">سب ٹائٹلز سے بند کیپشنز کو ہٹا دیں</string>\n    <string name=\"app_layout_subtext\">اپنے آلے کے مطابق ایپ کی شکل تبدیل کریں</string>\n    <string name=\"next\">اگلے</string>\n    <string name=\"blank_repo_message\">CloudStream میں بذریعہ ڈیفالٹ کوئی سائٹ انسٹال نہیں ہے۔ آپ کو ریپوزٹری سے سائٹس انسٹال کرنے کی ضرورت ہے۔\n\\n\n\\nہمارے Discord میں شامل ہوں یا آن لائن تلاش کریں۔</string>\n    <string name=\"safe_mode_description\">تمام ایکسٹینشنز کریش کی وجہ سے آف کر دی گئیں تاکہ آپ کو پریشانی کا باعث تلاش کرنے میں مدد مل سکے۔</string>\n    <string name=\"extension_install_first\">پہلے ایکسٹینشن انسٹال کریں</string>\n    <string name=\"clipboard_too_large\">بہت زیادہ متن۔ کلپ بورڈ میں محفوظ کرنے سے قاصر۔</string>\n    <string name=\"update_notification_installing\">ایپ اپ ڈیٹ انسٹال ہو رہا ہے…</string>\n    <string name=\"empty_library_logged_in_message\">یہ فہرست خالی ہے۔ کسی اور پر سوئچ کرنے کی کوشش کریں۔</string>\n    <string name=\"mobile_data\">موبائل ڈیٹا</string>\n    <string name=\"profiles\">پروفائلز</string>\n    <string name=\"unable_to_inflate\">یو آئی درست طریقے سے تخلیق نہیں کی جاسکتی تھی، یہ ایک بڑا بگ ہے اور فوراً رپورٹ کیا جانا چاہئے%s</string>\n    <string name=\"edit\">ترتیب دیں</string>\n    <string name=\"wifi\">وائی فائی</string>\n    <string name=\"profile_background_des\">پروفائل پس منظر</string>\n    <string name=\"help\">مدد</string>\n    <string name=\"profile_number\">پروفائل %d</string>\n    <string name=\"automatic_plugin_download_mode_title\">پلگ انز کو ڈاؤن لوڈ کرنے کے لئے موڈ منتخب کریں</string>\n    <string name=\"qualities\">کوالٹیز</string>\n    <string name=\"use\">استعمال کریں</string>\n    <string name=\"disable\">غیرفعال کریں</string>\n    <string name=\"no_repository_found_error\">مخزن نہیں ملا، URL کو چیک کریں اور VPN استعمال کریں</string>\n    <string name=\"already_voted\">آپ نے پہلے ہی ووٹ دیا ہے</string>\n    <string name=\"no_plugins_found_error\">مخزن میں کوئی پلگ انز نہیں ملا</string>\n    <string name=\"set_default\">ترجیحی تعین کریں</string>\n    <string name=\"quality_profile_help\">یہاں آپ تبدیلی کرسکتے ہیں کہ سورسز کو کس طرح کی ترتیب دی جائے۔ اگر ایک ویڈیو کی زیادہ پرائیورٹی ہوتی ہے تو یہ سورس کی انتخاب میں زیادہ اوپر آئے گی۔ سورس کی پرائیورٹی اور کوالٹی کی پرائیورٹی کا مجموعہ ویڈیو کی پرائیورٹی ہوتی ہے۔\n\\n\n\\nسورس A: 3\n\\nکوالٹی B: 7\n\\nاس کا مجموعی ویڈیو پرائیورٹی 10 ہوتی ہے۔\n\\n\n\\nنوٹ: اگر مجموعہ 10 یا اس سے زیادہ ہو تو پلیر وہ لنک لوڈ کرنے کو خود بخود چھوڑ دے گا!</string>\n    <string name=\"favorites_list_name\">پسندیدہ</string>\n    <string name=\"favorite_added\">%s کو پسندیدہ میں شامل کیا گیا</string>\n    <string name=\"favorite_removed\">%s کو پسندیدہ سے ختم کیا گیا</string>\n    <string name=\"action_remove_from_favorites\">پسندیدہ سے ختم کریں</string>\n    <string name=\"enter_pin\">پن ڈالیں</string>\n    <string name=\"action_add_to_favorites\">پسندیدہ میں شامل کریں</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">%s کے لیے PIN درج کریں</string>\n    <string name=\"select_an_account\">ایک اکاؤنٹ منتخب کریں</string>\n    <string name=\"manage_accounts\">اکاؤنٹس کا نظم کریں</string>\n    <string name=\"edit_account\">اکاؤنٹ میں ترمیم کریں</string>\n    <string name=\"rotate_video\">گھمائیں</string>\n    <string name=\"rotate_video_desc\">اسکرین کی سمت بندی کے لیے ٹوگل بٹن دکھائیں</string>\n    <string name=\"backup_frequency\">بیک اپ فریکوئنسی</string>\n    <string name=\"pin\">پن</string>\n    <string name=\"pin_error_incorrect\">غلط پن۔ دوبارہ کوشش کریں۔</string>\n    <string name=\"pin_error_length\">پن چار حروف کا ہونا چاہیے</string>\n    <string name=\"enter_current_pin\">موجودہ پن درج کریں</string>\n    <string name=\"use_default_account\">ڈیفالٹ اکاؤنٹ استعمال کریں</string>\n    <string name=\"logged_account\" formatted=\"true\">%s کے بطور لاگ ان ہوا</string>\n    <string name=\"links_reloaded_toast\">لنکس دوبارہ لوڈ ہو گئے</string>\n    <string name=\"action_subscribe\">سبسکرائب</string>\n    <string name=\"action_unsubscribe\">ان سبسکرائب</string>\n    <string name=\"duplicate_title\">ممکنہ ڈپلیکیٹ ملا</string>\n    <string name=\"duplicate_add\">جمع کریں</string>\n    <string name=\"duplicate_replace_all\">سب کو بدل دیں</string>\n    <string name=\"duplicate_replace\">بدل دیں</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">آپ کی لائبریری میں ممکنہ ڈپلیکیٹ آئٹمز مل گئے ہیں:\n\\n\n\\n%s\n\\n\n\\nکیا آپ بہرحال اس آئٹم کو شامل کرنا چاہیں گے، موجودہ کو تبدیل کرنا چاہیں گے، یا کارروائی کو منسوخ کریں گے؟</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">ایسا معلوم ہوتا ہے کہ آپ کی لائبریری میں ممکنہ طور پر ڈپلیکیٹ آئٹم پہلے سے موجود ہے: \\'%s۔\\'\n\\n\n\\nکیا آپ بہرحال اس آئٹم کو شامل کرنا چاہیں گے، موجودہ کو تبدیل کرنا چاہیں گے، یا کارروائی کو منسوخ کریں گے؟</string>\n    <string name=\"lock_profile\">پروفائل لاک کریں</string>\n    <string name=\"skip_startup_account_select_pref\">آغاز پر اکاؤنٹ کا انتخاب چھوڑ دیں</string>\n    <string name=\"auto_rotate_video_desc\">ویڈیو واقفیت کی بنیاد پر اسکرین کی سمت بندی کی خودکار سوئچنگ کو فعال کریں</string>\n    <string name=\"auto_rotate_video\">خود بخود گھومنا</string>\n    <string name=\"toast_copied\">کاپی کر لیا!</string>\n    <string name=\"repo_copy_label\">ذخیرہ کا نام اور URL</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">%s میں آنے والا ہے</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\nباقی</string>\n    <string name=\"clipboard_permission_error\">کلپ بورڈ تک رسائی میں خرابی، براہ کرم دوبارہ کوشش کریں۔</string>\n    <string name=\"clipboard_unknown_error\">کاپی کرنے میں خرابی، براہ کرم logcat کاپی کریں اور ایپ سپورٹ سے رابطہ کریں۔</string>\n    <string name=\"battery_dialog_message\">سبسکرائب شدہ ٹی وی شوز کے لیے بلاتعطل ڈاؤن لوڈز اور اطلاعات کو یقینی بنانے کے لیے، CloudStream کو پس منظر میں چلنے کی اجازت درکار ہے۔ OK دبانے سے، آپ کو App info پر بھیج دیا جائے گا۔ وہاں اسکرول کریں 𝘼𝙥𝙥 𝙗𝙖𝙩𝙩𝙚𝙧𝙮 𝙪𝙨𝙖𝙜𝙚 اور battery usage کو 𝙐𝙣𝙧𝙚𝙨𝙩𝙧𝙞𝙘𝙩𝙚𝙙 کردیں، اس اجازت کا مطلب یہ نہیں ہے کہ CS3 آپ کی بیٹری ختم کردے گا۔ یہ صرف ضرورت پڑنے پر پس منظر میں کام کرے گا، جیسے کہ جب اطلاعات موصول ہوں یا آفیشل ایکسٹینشنز سے ویڈیوز ڈاؤن لوڈ کریں۔ اگر آپ منسوخ کرنے کا انتخاب کرتے ہیں، تو آپ اس ترتیب کو بعد میں 𝙂𝙚𝙣𝙚𝙧𝙖𝙡 𝙎𝙚𝙩𝙩𝙞𝙣𝙜𝙨 میں ایڈجسٹ کر سکتے ہیں۔</string>\n    <string name=\"biometric_setting_summary\">فنگر پرنٹ، فیس آئی ڈی، PIN، پیٹرن یا پاس ورڈ سے اپپ کو انلاک کریں.</string>\n    <string name=\"biometric_prompt_description\">یہ اسکرین متعدد ناکام کوششوں کی وجہ سے بند کر دی گئی تھی۔ براہ کرم ایپ کو ریسٹارٹ کریں۔</string>\n    <string name=\"subscribe_tooltip\">نئی قسط کی اطلاع</string>\n    <string name=\"speed_setting_summary\">پلیئر میں اسپیڈ آپشن شامل کرتا ہے</string>\n    <string name=\"test_extensions\">تمام ایکسٹینشن ٹیسٹ کریں</string>\n    <string name=\"test_extensions_summary\">یہ ٹیسٹ صرف ڈویلپرز کے لیے ہے اور کسی بھی توسیع کے کام کرنے کی تصدیق یا تردید نہیں کرتا ہے۔</string>\n    <string name=\"ok\">ٹھیک ہے</string>\n    <string name=\"battery_dialog_title\">Battery Optimization کو غیر فعال کریں</string>\n    <string name=\"app_unrestricted_toast\">اپپ battery usage پہلے سے ہی unrestricted ہے</string>\n    <string name=\"favorite\">پسندیدہ کریں</string>\n    <string name=\"music_singlar\">موسیقی</string>\n    <string name=\"audio_book_singular\">آڈیو بک</string>\n    <string name=\"custom_media_singluar\">میڈیا</string>\n    <string name=\"biometric_authentication_title\">انلاک CloudStream</string>\n    <string name=\"biometric_setting\">بایومیٹرکس کے ساتھ لاک کریں</string>\n    <string name=\"biometric_unsupported\">بایومیٹرک تصدیق اس ڈیوائس پر سپپورٹڈ نہیں ہے</string>\n    <string name=\"password_pin_authentication_title\">پاس ورڈ/PIN سے تصدیق</string>\n    <string name=\"app_info_intent_error\">CloudStream\\'s App info کھولنے میں مشکلات.</string>\n    <string name=\"unfavorite\">ناپسندیدہ کریں</string>\n    <string name=\"reset_btn\">ری سیٹ کریں</string>\n    <string name=\"result_search_tooltip\">دیگر ایکسٹینشنز میں تلاش کریں</string>\n    <string name=\"recommendations_tooltip\">سفارشات دکھائیں</string>\n    <string name=\"biometric_warning\">آپ کے CloudStream ڈیٹا کا اب بیک اپ لیا گیا ہے۔ اگرچہ اس کا امکان بہت کم ہے، لیکن مختلف ڈیوائس مختلف طریقے سے کام کر سکتے ہیں۔ اگر آپ ایپ تک رسائی حاصل کرنے سے قاصر ہیں تو، ایپ کا ڈیٹا مکمل طور پر صاف کریں اور بیک اپ سے بحال کریں۔ اس سے ہونے والی کسی بھی تکلیف کے لیے ہم بہت معذرت خواہ ہیں۔</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">سیزن %1$d کی قسط %2$d جاری ہوگی</string>\n    <string name=\"play_from_beginning_img_des\">شروع سےپلے کریں</string>\n    <string name=\"speech_recognition_unavailable\">کلام شناسی دستیاب نہیں</string>\n    <string name=\"begin_speaking\">بولنا شروع کریں…</string>\n    <string name=\"torrent_info\">یہ ویڈیو ایک ٹورنٹ ہے،یعنی آپ کی ویڈیو سرگرمی کا سراغ آپ تک لگایا جاسکتا ہے۔\\nآگے بڑھنے سے پہلے یہ بات یقینی بنائیں کہ آپ ٹورنٹنگ کو صحیح سے جانتے ہیں</string>\n    <string name=\"downloads_delete_select\">ڈیلیٹ کرنے کے لئے چیزیں چنیں</string>\n    <string name=\"downloads_empty\">فی الحال کوئی ڈاونلوڈ نہیں۔</string>\n    <string name=\"offline_file\">آف لائن دیکھنے کے لئے دستیاب ہے</string>\n    <string name=\"select_all\">سب چُنیں</string>\n    <string name=\"deselect_all\">سب غیر منتخب کریں</string>\n    <string name=\"open_local_video\">لوکل ویڈیو کھولیں</string>\n    <string name=\"delete_files\">فائلز حذف کریں</string>\n    <string name=\"test_warning\">انتباہ</string>\n    <string name=\"audio_singluar\">آواز</string>\n    <string name=\"sort_button_date\">تاریخ %s</string>\n    <string name=\"device_pin_url_message\">اپنے اسمارٹ فون یا کمپیوٹر پر یہ <b>%s</b> وزٹ کریں اور مندرجہ بالا کوڈ ڈالیں</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+vi/array.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n    <array name=\"cast_mini_controller_control_buttons\">\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_play_pause_toggle</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n    <array name=\"cast_expanded_controller_control_buttons\">\n        <!-- Fake sources button -->\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_rewind_30_seconds</item>\n        <item>@id/cast_button_type_forward_30_seconds</item>\n        <!-- Actually fake to make the skip op button the same style -->\n        <item>@id/cast_button_type_forward_30_seconds</item>\n    </array>\n\n\n    <array name=\"title_info_pref_names\">\n        <item>@string/source_name</item>\n        <item>@string/resolution</item>\n        <item>@string/video_info</item>\n    </array>\n\n    <array name=\"title_info_pref_values\">\n        <item>@string/show_name_key</item>\n        <item>@string/show_resolution_key</item>\n        <item>@string/show_media_info_key</item>\n    </array>\n\n\n    <array name=\"limit_title_pref_names\">\n        <item>@string/none</item>\n        <item>16 ký tự</item>\n        <item>32 ký tự</item>\n        <item>64 ký tự</item>\n        <item>128 ký tự</item>\n        <item>Ẩn Tiêu đề</item>\n    </array>\n    <array name=\"limit_title_pref_values\">\n        <item>0</item>\n        <item>16</item>\n        <item>32</item>\n        <item>64</item>\n        <item>128</item>\n        <item>-1</item>\n    </array>\n\n    <array name=\"skip_sec_values\">\n        <item>5</item>\n        <item>10</item>\n        <item>15</item>\n        <item>20</item>\n        <item>25</item>\n        <item>30</item>\n    </array>\n\n    <array name=\"video_buffer_length_names\">\n        <item>@string/automatic</item>\n        <item>1 phút</item>\n        <item>1 phút 30 giây</item>\n        <item>2 phút</item>\n        <item>2 phút 30 giây</item>\n        <item>3 phút</item>\n        <item>3 phút 30 giây</item>\n        <item>4 phút</item>\n        <item>5 phút</item>\n        <item>6 phút</item>\n        <item>7 phút</item>\n        <item>8 phút</item>\n        <item>9 phút</item>\n        <item>10 phút</item>\n        <item>15 phút</item>\n        <item>20 phút</item>\n        <item>30 phút</item>\n    </array>\n\n    <array name=\"video_buffer_length_values\">\n        <item>0</item>\n        <item>60</item>\n        <item>90</item>\n        <item>120</item>\n        <item>150</item>\n        <item>180</item>\n        <item>210</item>\n        <item>240</item>\n        <item>300</item>\n        <item>360</item>\n        <item>420</item>\n        <item>480</item>\n        <item>540</item>\n        <item>600</item>\n        <item>900</item>\n        <item>1200</item>\n        <item>1800</item>\n    </array>\n\n    <array name=\"video_buffer_size_names\">\n        <item>@string/automatic</item>\n        <item>10MB</item>\n        <item>20MB</item>\n        <item>30MB</item>\n        <item>40MB</item>\n        <item>50MB</item>\n        <item>60MB</item>\n        <item>70MB</item>\n        <item>80MB</item>\n        <item>90MB</item>\n        <item>100MB</item>\n        <item>150MB</item>\n        <item>200MB</item>\n        <item>250MB</item>\n        <item>300MB</item>\n        <item>350MB</item>\n        <item>400MB</item>\n        <item>450MB</item>\n        <item>500MB</item>\n    </array>\n\n    <array name=\"video_buffer_size_values\">\n        <item>0</item>\n        <item>10</item>\n        <item>20</item>\n        <item>30</item>\n        <item>40</item>\n        <item>50</item>\n        <item>60</item>\n        <item>70</item>\n        <item>80</item>\n        <item>90</item>\n        <item>100</item>\n        <item>150</item>\n        <item>200</item>\n        <item>250</item>\n        <item>300</item>\n        <item>350</item>\n        <item>400</item>\n        <item>450</item>\n        <item>500</item>\n    </array>\n\n    <array name=\"poster_ui_options\">\n        <item>@string/show_hd</item>\n        <item>@string/show_dub</item>\n        <item>@string/show_sub</item>\n        <item>@string/show_rating</item>\n        <item>@string/show_title</item>\n        <item>@string/show_episode_text</item>\n    </array>\n\n    <array name=\"poster_ui_options_values\">\n        <item>@string/show_hd_key</item>\n        <item>@string/show_dub_key</item>\n        <item>@string/show_sub_key</item>\n        <item>@string/show_rating_key</item>\n        <item>@string/show_title_key</item>\n        <item>@string/show_episode_text_key</item>\n    </array>\n\n    <array name=\"app_layout\">\n        <item>@string/automatic</item>\n        <item>@string/phone_layout</item>\n        <item>@string/tv_layout</item>\n        <item>@string/emulator_layout</item>\n    </array>\n\n    <array name=\"app_layout_values\">\n        <item>-1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>2</item>\n    </array>\n\n    <string-array name=\"themes_overlay_names\">\n        <item>Mặc định</item>\n        <item>bồ công anh màu vàng</item>\n        <item>Hồng nhạt</item>\n        <item>Quả cam</item>\n        <item>Xanh lam đậm</item>\n        <item>Nâu sẫm</item>\n        <item>Xanh lục</item>\n        <item>Xám</item>\n        <item>Trắng</item>\n        <item>Màu xanh mát</item>\n        <item>Nâu</item>\n        <item>Xanh lục nhạt</item>\n        <item>Đỏ</item>\n        <item>Tím</item>\n        <item>Xanh lam</item>\n        <item>Xanh lam nhạt</item>\n        <item>Vàng</item>\n        <item>Hồng</item>\n        <item>Hồng đậm</item>\n        <item>Hoa oải hương</item>\n        <item>Material You</item>\n        <item>Material You (Secondary)</item>\n    </string-array>\n    <string-array name=\"themes_overlay_names_values\">\n        <item>Normal</item>\n        <item>DandelionYellow</item>\n        <item>CarnationPink</item>\n        <item>Orange</item>\n        <item>DarkGreen</item>\n        <item>Maroon</item>\n        <item>NavyBlue</item>\n        <item>Grey</item>\n        <item>White</item>\n        <item>CoolBlue</item>\n        <item>Brown</item>\n        <item>Blue</item>\n        <item>Red</item>\n        <item>Purple</item>\n        <item>Green</item>\n        <item>GreenApple</item>\n        <item>Banana</item>\n        <item>Party</item>\n        <item>Pink</item>\n        <item>Lavender</item>\n        <item>Monet</item>\n        <item>Monet2</item>\n    </string-array>\n\n\n    <string-array name=\"themes_names\">\n        <item>Tối</item>\n        <item>Xám</item>\n        <item>Amoled</item>\n        <item>Sáng</item>\n        <item>Hệ thống</item>\n        <item>Material You</item>\n        <item>Dracula</item>\n        <item>Giấc Mơ Oải Hương</item>\n        <item>Xanh Lam Tĩnh Lặng</item>\n    </string-array>\n    <string-array name=\"themes_names_values\">\n        <item>AmoledLight</item>\n        <item>Black</item>\n        <item>Amoled</item>\n        <item>Light</item>\n        <item>System</item>\n        <item>Monet</item>\n        <item>Dracula</item>\n        <item>Lavender</item>\n        <item>SilentBlue</item>\n    </string-array>\n\n    <!--https://github.com/videolan/vlc-android/blob/72ccfb93db027b49855760001d1a930fa657c5a8/application/resources/src/main/res/values/arrays.xml#L266-->\n    <string-array name=\"subtitles_encoding_list\" tools:ignore=\"TypographyDashes\">\n        <item>@string/automatic</item>\n        <item>Universal (UTF-8)</item>\n        <item>Universal (UTF-16)</item>\n        <item>Universal (big endian UTF-16)</item>\n        <item>Universal (little endian UTF-16)</item>\n        <item>Universal, Chinese (GB18030)</item>\n        <item>Western European (Latin-9)</item>\n        <item>Western European (Windows-1252)</item>\n        <item>Western European (IBM 00850)</item>\n        <item>Eastern European (Latin-2)</item>\n        <item>Eastern European (Windows-1250)</item>\n        <item>Esperanto (Latin-3)</item>\n        <item>Nordic (Latin-6)</item>\n        <item>Cyrillic (Windows-1251)</item>\n        <item>Russian (KOI8-R)</item>\n        <item>Ukrainian (KOI8-U)</item>\n        <item>Arabic (ISO 8859-6)</item>\n        <item>Arabic (Windows-1256)</item>\n        <item>Greek (ISO 8859-7)</item>\n        <item>Greek (Windows-1253)</item>\n        <item>Hebrew (ISO 8859-8)</item>\n        <item>Hebrew (Windows-1255)</item>\n        <item>Turkish (ISO 8859-9)</item>\n        <item>Turkish (Windows-1254)</item>\n        <item>Thai (TIS 620-2533/ISO 8859-11)</item>\n        <item>Thai (Windows-874)</item>\n        <item>Baltic (Latin-7)</item>\n        <item>Baltic (Windows-1257)</item>\n        <item>Celtic (Latin-8)</item>\n        <item>South-Eastern European (Latin-10)</item>\n        <item>Simplified Chinese (ISO-2022-CN-EXT)</item>\n        <item>Simplified Chinese Unix (EUC-CN)</item>\n        <item>Japanese (7-bits JIS/ISO-2022-JP-2)</item>\n        <item>Japanese Unix (EUC-JP)</item>\n        <item>Japanese (Shift JIS)</item>\n        <item>Korean (EUC-KR/CP949)</item>\n        <item>Korean (ISO-2022-KR)</item>\n        <item>Traditional Chinese (Big5)</item>\n        <item>Traditional Chinese Unix (EUC-TW)</item>\n        <item>Hong-Kong Supplementary (HKSCS)</item>\n        <item>Vietnamese (VISCII)</item>\n        <item>Vietnamese (Windows-1258)</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- KEYS DON'T TRANSLATE -->\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Tập %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Diễn viên: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Tập %d sẽ ra mắt sau</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dng %2$dg %3$dph</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dgi %2$dph</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">Poster</string>\n    <string name=\"search_poster_img_des\">Ảnh bìa</string>\n    <string name=\"episode_poster_img_des\">Episode Poster</string>\n    <string name=\"home_main_poster_img_des\">Main Poster</string>\n    <string name=\"home_next_random_img_des\">Next Random</string>\n    <string name=\"go_back_img_des\">Quay trở lại</string>\n    <string name=\"home_change_provider_img_des\">Change Provider</string>\n    <string name=\"preview_background_img_des\">Preview Background</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">Tốc độ (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Đánh giá: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Đã tìm thấy bản cập nhật mới!\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Bộ lọc</string>\n    <string name=\"duration_format\" formatted=\"true\">%d phút</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Mở với CloudStream</string>\n    <string name=\"title_home\">Trang Chủ</string>\n    <string name=\"title_search\">Tìm Kiếm</string>\n    <string name=\"title_downloads\">Tải Về</string>\n    <string name=\"title_settings\">Cài Đặt</string>\n    <string name=\"search_hint\">Tìm kiếm…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Tìm kiếm %s…</string>\n    <string name=\"no_data\">Không có dữ liệu</string>\n    <string name=\"episode_more_options_des\">Thêm tuỳ chọn</string>\n    <string name=\"next_episode\">Tập tiếp theo</string>\n    <string name=\"result_tags\">Thể loại</string>\n    <string name=\"result_share\">Chia sẻ</string>\n    <string name=\"result_open_in_browser\">Mở bằng trình duyệt</string>\n    <string name=\"skip_loading\">Bỏ qua</string>\n    <string name=\"loading\">Đang tải…</string>\n    <string name=\"type_watching\">Đang xem</string>\n    <string name=\"type_on_hold\">Đang chờ</string>\n    <string name=\"type_completed\">Đã xem</string>\n    <string name=\"type_dropped\">Bỏ qua</string>\n    <string name=\"type_plan_to_watch\">Xem sau</string>\n    <string name=\"type_re_watching\">Xem lại</string>\n    <string name=\"play_movie_button\">Xem Ngay</string>\n    <string name=\"play_livestream_button\">Phát trực tiếp</string>\n    <string name=\"play_torrent_button\">Xem Torrent</string>\n    <string name=\"pick_source\">Nguồn Phim</string>\n    <string name=\"pick_subtitle\">Phụ đề</string>\n    <string name=\"reload_error\">Thử kết nối lại…</string>\n    <string name=\"go_back\">Quay lại</string>\n    <string name=\"play_episode\">Xem Tập Phim</string>\n    <!--<string name=\"need_storage\">Allow to download episodes</string>-->\n    <string name=\"download\">Tải xuống</string>\n    <string name=\"downloaded\">Đã tải</string>\n    <string name=\"downloading\">Đang tải</string>\n    <string name=\"download_paused\">Tạm dừng</string>\n    <string name=\"download_started\">Đã bắt đầu tải</string>\n    <string name=\"download_failed\">Tải lỗi</string>\n    <string name=\"download_canceled\">Đã hủy</string>\n    <string name=\"download_done\">Tải thành công</string>\n    <string name=\"stream\">Luồng mạng</string>\n    <string name=\"error_loading_links_toast\">Lỗi khi tải liên kết</string>\n    <string name=\"download_storage_text\">Bộ nhớ trong</string>\n    <string name=\"app_dubbed_text\">Lồng tiếng</string>\n    <string name=\"app_subbed_text\">Phụ đề</string>\n    <string name=\"popup_delete_file\">Xóa Tệp</string>\n    <string name=\"popup_play_file\">Xem Tệp</string>\n    <string name=\"popup_resume_download\">Tiếp tục tải</string>\n    <string name=\"popup_pause_download\">Tạm dừng tải</string>\n    <string name=\"home_more_info\">Thông tin thêm</string>\n    <string name=\"home_expanded_hide\">Ẩn</string>\n    <string name=\"home_play\">Xem ngay</string>\n    <string name=\"home_info\">Thông tin</string>\n    <string name=\"filter_bookmarks\">Lọc theo danh sách đã lưu</string>\n    <string name=\"error_bookmarks_text\">Danh sách đã lưu</string>\n    <string name=\"action_remove_from_bookmarks\">Xóa</string>\n    <string name=\"action_add_to_bookmarks\">Đặt trạng thái xem</string>\n    <string name=\"sort_apply\">Áp dụng</string>\n    <string name=\"sort_copy\">Sao chép</string>\n    <string name=\"sort_close\">Đóng</string>\n    <string name=\"sort_clear\">Huỷ bỏ</string>\n    <string name=\"sort_save\">Lưu</string>\n    <string name=\"player_speed\">Tốc độ phát</string>\n    <string name=\"subtitles_settings\">Cài đặt hiển thị phụ đề</string>\n    <string name=\"subs_text_color\">Màu chữ</string>\n    <string name=\"subs_outline_color\">Màu viền chữ</string>\n    <string name=\"subs_background_color\">Màu nền</string>\n    <string name=\"subs_window_color\">Màu cửa sổ</string>\n    <string name=\"subs_edge_type\">Kiểu viền</string>\n    <string name=\"subs_subtitle_elevation\">Độ nâng</string>\n    <string name=\"subs_font\">Kiểu chữ</string>\n    <string name=\"subs_font_size\">Kích thước chữ</string>\n    <string name=\"search_provider_text_providers\">Tìm kiếm theo nguồn phim</string>\n    <string name=\"search_provider_text_types\">Tìm kiếm theo thể loại</string>\n    <string name=\"benene_count_text\">%d lời cảm ơn đã được gửi tặng nhà phát triển</string>\n    <string name=\"benene_count_text_none\">Hãy tặng cho nhà phát triển một lời cảm ơn</string>\n    <string name=\"subs_auto_select_language\">Tự động chọn ngôn ngữ</string>\n    <string name=\"subs_download_languages\">Ngôn ngữ khi tải xuống</string>\n    <string name=\"subs_subtitle_languages\">Ngôn ngữ phụ đề</string>\n    <string name=\"subs_hold_to_reset_to_default\">Giữ để làm mới toàn bộ</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Thêm phông chữ tại %s</string>\n    <string name=\"continue_watching\">Tiếp tục xem</string>\n    <string name=\"action_remove_watching\">Loại bỏ</string>\n    <string name=\"action_open_watching\">Thông tin thêm</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Bạn có thể sẽ cần sử dụng VPN để xem phim này</string>\n    <string name=\"vpn_torrent\">Phim này được chiếu dưới dạng Torrent. Hãy sử dụng VPN để xem</string>\n    <string name=\"torrent_plot\">Thông tin phim</string>\n    <string name=\"normal_no_plot\">Đang cập nhật</string>\n    <string name=\"torrent_no_plot\">Không tìm thấy thông tin</string>\n    <string name=\"show_log_cat\">Hiển thị Logcat 🐈</string>\n    <string name=\"picture_in_picture\">Chế độ cửa sổ nhỏ</string>\n    <string name=\"picture_in_picture_des\">Tiếp tục xem phim khi thoát ứng dụng hoặc khi tìm kiếm</string>\n    <string name=\"player_size_settings\">Bật nút thu phóng khi xem</string>\n    <string name=\"player_size_settings_des\">Xóa khoảng đen của phim</string>\n    <string name=\"player_subtitles_settings\">Phụ đề</string>\n    <string name=\"player_subtitles_settings_des\">Cài đặt phụ đề</string>\n    <string name=\"chromecast_subtitles_settings\">Phụ đề Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Cài đặt phụ đề Chromecast</string>\n    <string name=\"eigengraumode_settings\">Tốc độ phát</string>\n    <string name=\"swipe_to_seek_settings\">Vuốt để tua nhanh</string>\n    <string name=\"swipe_to_seek_settings_des\">Vuốt sang trái hoặc phải để tua video</string>\n    <string name=\"swipe_to_change_settings\">Vuốt để chỉnh độ sáng và âm lượng</string>\n    <string name=\"swipe_to_change_settings_des\">Vuốt lên hoặc vuốt xuống ở hai bên để điều chỉnh độ sáng và âm lượng</string>\n    <string name=\"autoplay_next_settings\">Tự động phát tập tiếp theo</string>\n    <string name=\"autoplay_next_settings_des\">Phát tập tiếp theo sau khi hết tập hiện tại</string>\n    <string name=\"double_tap_to_seek_settings\">Nhấn 2 lần để tua</string>\n    <string name=\"double_tap_to_pause_settings\">Nhấn 2 lần để tạm dừng</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Thời lượng tua (Giây)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Nhấn 2 lần vào bên trái hoặc bên phải màn hình để tua trước hoặc sau</string>\n    <string name=\"double_tap_to_pause_settings_des\">Nhấn vào giữa hai lần để tạm dừng</string>\n    <string name=\"use_system_brightness_settings\">Sử dụng độ sáng hệ thống</string>\n    <string name=\"use_system_brightness_settings_des\">Sử dụng độ sáng hệ thống trong trình phát ứng dụng</string>\n    <string name=\"episode_sync_settings\">Cập nhật tiến trình xem</string>\n    <string name=\"episode_sync_settings_des\">Tự động đồng bộ tiến trình hiện tại của bạn</string>\n    <string name=\"restore_settings\">Khôi phục dữ liệu từ bản sao lưu</string>\n    <string name=\"backup_settings\">Sao lưu dữ liệu</string>\n    <string name=\"restore_success\">Đã tải dữ liệu sao lưu</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Không thể khôi phục dữ liệu từ %s</string>\n    <string name=\"backup_success\">Sao lưu dữ liệu thành công</string>\n    <string name=\"backup_failed\">Thiếu quyền truy cập bộ nhớ, hãy thử lại.</string>\n    <string name=\"backup_failed_error_format\">Lỗi khi sao lưu %s</string>\n    <string name=\"search\">Tìm kiếm</string>\n    <string name=\"category_account\">Tài khoản và Bảo mật</string>\n    <string name=\"category_updates\">Cập nhật và Sao lưu</string>\n    <string name=\"settings_info\">Thông tin</string>\n    <string name=\"advanced_search\">Tìm kiếm nâng cao</string>\n    <string name=\"advanced_search_des\">Cho phép tìm kiếm theo bộ lọc từng nhà cung cấp</string>\n    <string name=\"show_fillers_settings\">Hiển thị tập phụ cho anime</string>\n    <string name=\"show_trailers_settings\">Hiển thị trailer</string>\n    <string name=\"kitsu_settings\">Hiển thị poster từ Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Ẩn chất lượng video trong kết quả tìm kiếm</string>\n    <string name=\"automatic_plugin_updates\">Tự động cập nhật plugin</string>\n    <string name=\"updates_settings\">Hiển thị thông báo cập nhật ứng dụng</string>\n    <string name=\"updates_settings_des\">Tự động tìm kiếm bản cập nhật mới sau khi khởi động ứng dụng.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">Ứng dụng đọc tiểu thuyết của cùng nhà phát triển</string>\n    <string name=\"anim\">Ứng dụng xem Anime của cùng nhà phát triển</string>\n    <string name=\"discord\">Tham gia cộng đồng trên Discord</string>\n    <string name=\"benene\">Gửi lời cảm ơn tới nhà phát triển</string>\n    <string name=\"benene_des\">Gửi lời cảm ơn</string>\n    <string name=\"app_language\">Ngôn ngữ ứng dụng</string>\n    <string name=\"no_chromecast_support_toast\">Nguồn phim này chưa hỗ trợ Chromecast</string>\n    <string name=\"no_links_found_toast\">Không tìm thấy liên kết</string>\n    <string name=\"copy_link_toast\">Đã sao chép liên kết vào bộ nhớ tạm</string>\n    <string name=\"play_episode_toast\">Xem Phim</string>\n    <string name=\"subs_default_reset_toast\">Thiết lập lại giá trị mặc định</string>\n    <string name=\"season\">Mùa</string>\n    <string name=\"no_season\">Không có mùa nào</string>\n    <string name=\"episode\">Tập</string>\n    <string name=\"episodes\">Tập</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">M</string>\n    <string name=\"episode_short\">T</string>\n    <string name=\"no_episodes_found\">Không có tập nào</string>\n    <string name=\"delete_file\">Xóa Tệp</string>\n    <string name=\"delete\">Xóa</string>\n    <string name=\"cancel\">Hủy bỏ</string>\n    <string name=\"pause\">Tạm Dừng</string>\n    <string name=\"resume\">Tiếp Tục</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\">%s sẽ bị xoá vĩnh viễn\n\\nBạn có chắc chắn muốn xóa?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dm\n\\ncòn lại</string>\n    <string name=\"status_ongoing\">Đang chiếu</string>\n    <string name=\"status_completed\">Hoàn Thành</string>\n    <string name=\"status\">Trạng Thái</string>\n    <string name=\"year\">Năm</string>\n    <string name=\"rating\">Đánh Giá</string>\n    <string name=\"duration\">Thời Lượng</string>\n    <string name=\"site\">Nguồn</string>\n    <string name=\"synopsis\">Thông tin</string>\n    <string name=\"queued\">Hàng chờ</string>\n    <string name=\"no_subtitles\">Không có phụ đề</string>\n    <string name=\"action_default\">Mặc Định</string>\n    <string name=\"free_storage\">Còn trống</string>\n    <string name=\"used_storage\">Đã sử dụng</string>\n    <string name=\"app_storage\">App</string>\n    <!--plural-->\n    <string name=\"movies\">Phim Lẻ</string>\n    <string name=\"tv_series\">Phim Bộ</string>\n    <string name=\"cartoons\">Hoạt Hình</string>\n    <string name=\"anime\">Anime</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"torrent\">Torrent</string>\n    <string name=\"documentaries\">Phim Tài Liệu</string>\n    <string name=\"asian_drama\">Truyền Hình Châu Á</string>\n    <string name=\"livestreams\">Trực tiếp</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Khác</string>\n    <!--singular-->\n    <string name=\"movies_singular\">Phim Lẻ</string>\n    <string name=\"tv_series_singular\">Phim Bộ</string>\n    <string name=\"cartoons_singular\">Hoạt Hình</string>\n    <string name=\"anime_singular\">Anime</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Phim Tài Liệu</string>\n    <string name=\"asian_drama_singular\">Truyền Hình Châu Á</string>\n    <string name=\"live_singular\">Trực tiếp</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Video</string>\n    <string name=\"source_error\">Lỗi nguồn phim</string>\n    <string name=\"remote_error\">Lỗi kết nối tới máy chủ</string>\n    <string name=\"render_error\">Không thể render</string>\n    <string name=\"unexpected_error\">Đã có lỗi xảy ra. Vui lòng thử lại sau</string>\n    <string name=\"storage_error\">Lỗi tải xuống. Hãy kiểm tra quyền truy cập bộ nhớ của ứng dụng</string>\n    <string name=\"episode_action_chromecast_episode\">Tập Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Chiếu Chromecast</string>\n    <string name=\"episode_action_play_in_app\">Xem với trình phát mặc định</string>\n    <string name=\"episode_action_play_in_format\">Xem với trình phát %s</string>\n    <string name=\"episode_action_auto_download\">Tự động tải xuống</string>\n    <string name=\"episode_action_download_mirror\">Nguồn tải xuống</string>\n    <string name=\"episode_action_reload_links\">Lấy link mới nhất</string>\n    <string name=\"episode_action_download_subtitle\">Tải phụ đề</string>\n    <string name=\"show_hd\">Nhãn chất lượng phim</string>\n    <string name=\"show_dub\">Nhãn lồng tiếng</string>\n    <string name=\"show_sub\">Nhãn phụ đề</string>\n    <string name=\"show_title\">Tiêu đề</string>\n    <string name=\"poster_ui_settings\">Thay đổi giao diện trên poster</string>\n    <string name=\"no_update_found\">Bạn đang dùng phiên bản mới nhất</string>\n    <string name=\"check_for_update\">Kiểm tra cập nhật</string>\n    <string name=\"video_lock\">Khóa</string>\n    <string name=\"video_aspect_ratio_resize\">Thu Phóng</string>\n    <string name=\"video_source\">Nguồn &amp; Phụ đề</string>\n    <string name=\"video_skip_op\">Bỏ qua OP</string>\n    <string name=\"dont_show_again\">Không hiện lại</string>\n    <string name=\"skip_update\">Bỏ qua bản cập nhật này</string>\n    <string name=\"update\">Cập nhật</string>\n    <string name=\"watch_quality_pref\">Chất lượng xem ưu tiên (WiFi)</string>\n    <string name=\"limit_title\">Kí tự tối đa trên tiêu đề</string>\n    <string name=\"limit_title_rez\">Hiện thông tin trình phát</string>\n    <string name=\"video_buffer_size_settings\">Kích thước bộ nhớ đệm video</string>\n    <string name=\"video_buffer_length_settings\">Thời lượng bộ nhớ đệm</string>\n    <string name=\"video_buffer_disk_settings\">Lưu bộ nhớ đệm video trên ổ cứng</string>\n    <string name=\"video_buffer_clear_settings\">Xoá bộ nhớ đệm hình ảnh và video</string>\n    <string name=\"video_ram_description\">Sẽ gây lỗi nếu đặt quá cao trên máy có dung lượng ram thấp như Android TV.</string>\n    <string name=\"video_disk_description\">Sẽ gây lỗi nếu đặt quá cao trên máy có dung lượng lưu trữ thấp như Android TV.</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"dns_pref_summary\">Rất hữu ích để bỏ chặn ISP</string>\n    <string name=\"add_site_pref\">Sao chép trang web</string>\n    <string name=\"remove_site_pref\">Xoá trang web</string>\n    <string name=\"add_site_summary\">Thêm bản sao của một trang web, với một địa chỉ khác</string>\n    <string name=\"download_path_pref\">Đường dẫn tải xuống</string>\n    <string name=\"nginx_url_pref\">Địa chỉ máy chủ Nginx</string>\n    <string name=\"display_subbed_dubbed_settings\">Hiển thị nhãn Phụ đề hoặc Thuyết minh</string>\n    <string name=\"resize_fit\">Vừa màn hình</string>\n    <string name=\"resize_fill\">Kéo dãn</string>\n    <string name=\"resize_zoom\">Phóng to</string>\n    <string name=\"legal_notice\">Disclaimer</string>\n    <string name=\"category_general\">Tổng quan</string>\n    <string name=\"random_button_settings\">Nút ngẫu nhiên</string>\n    <string name=\"random_button_settings_desc\">Hiện nút ngẫu nhiên trên Trang chủ và Thư viện</string>\n    <string name=\"provider_lang_settings\">Ngôn ngữ mở rộng</string>\n    <string name=\"app_layout\">Giao diện App</string>\n    <string name=\"preferred_media_settings\">Thể loại ưu tiên</string>\n    <string name=\"enable_nsfw_on_providers\">Kích hoạt NSFW trên các tiện ích mở rộng được hỗ trợ</string>\n    <string name=\"subtitles_encoding\">Mã hoá phụ đề</string>\n    <string name=\"category_providers\">Nguồn phim</string>\n    <string name=\"category_ui\">Giao diện</string>\n    <string name=\"automatic\">Tự động</string>\n    <string name=\"tv_layout\">Giao diện TV</string>\n    <string name=\"phone_layout\">Giao diện điện thoại</string>\n    <string name=\"emulator_layout\">Giao diện giả lập</string>\n    <string name=\"primary_color_settings\">Màu chính</string>\n    <string name=\"app_theme_settings\">Chủ đề App</string>\n    <string name=\"bottom_title_settings\">Vị trí tiêu đề</string>\n    <string name=\"bottom_title_settings_des\">Đặt tiêu đề dưới poster</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">Mật khẩu</string>\n    <string name=\"example_username\">Tài khoản</string>\n    <string name=\"example_email\">Email</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">Tên mới</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">Mã ngôn ngữ (vi)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">tài khoản</string>\n    <string name=\"logout\">Đăng xuất</string>\n    <string name=\"login\">Đăng nhập</string>\n    <string name=\"switch_account\">Đổi tài khoản</string>\n    <string name=\"add_account\">Thêm tài khoản</string>\n    <string name=\"create_account\">Tạo tài khoản</string>\n    <string name=\"add_sync\">Thêm theo dõi</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Đã thêm %s</string>\n    <string name=\"upload_sync\">Đồng bộ</string>\n    <string name=\"sync_score\">Đánh giá</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">Đã xác thực %s</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Không thể xác thực %s</string>\n    <!-- ============ -->\n    <string name=\"none\">Mặc định</string>\n    <string name=\"normal\">Bình thường</string>\n    <string name=\"all\">Tất cả</string>\n    <string name=\"max\">Tối đa</string>\n    <string name=\"min\">Tối thiểu</string>\n    <string name=\"subtitles_outline\">Viền</string>\n    <string name=\"subtitles_depressed\">Chìm</string>\n    <string name=\"subtitles_shadow\">Đổ bóng</string>\n    <string name=\"subtitles_raised\">Nâng</string>\n    <string name=\"subtitle_offset\">Chỉnh phụ đề</string>\n    <string name=\"subtitle_offset_hint\">1000ms</string>\n    <string name=\"subtitle_offset_title\">Độ trễ phụ đề</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Dùng nếu phụ đề bị nhanh %dms</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Dùng nếu phụ đề bị trễ %dms</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Không chỉnh</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">Xem trước mẫu phụ đề</string>\n    <string name=\"recommended\">Được đề xuất</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Đã tải %s</string>\n    <string name=\"player_load_subtitles\">Chọn từ máy</string>\n    <string name=\"player_load_subtitles_online\">Chọn từ Internet</string>\n    <string name=\"downloaded_file\">Tệp đã tải</string>\n    <string name=\"actor_main\">Vai chính</string>\n    <string name=\"actor_supporting\">Vai phụ</string>\n    <string name=\"actor_background\">Lý lịch</string>\n    <string name=\"home_source\">Nguồn</string>\n    <string name=\"home_random\">Ngẫu nhiên</string>\n    <string name=\"coming_soon\">Sắp có…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Ảnh áp phích</string>\n    <string name=\"category_player\">Trình phát</string>\n    <string name=\"resolution_and_title\">Độ phân giải và Tên nguồn</string>\n    <string name=\"title\">Tên nguồn</string>\n    <string name=\"resolution\">Độ phân giải</string>\n    <string name=\"error_invalid_id\">Id không hợp lệ</string>\n    <string name=\"error_invalid_data\">Lỗi dữ liệu</string>\n    <string name=\"error_invalid_url\">Lỗi đường dẫn</string>\n    <string name=\"error\">Lỗi</string>\n    <string name=\"subtitles_remove_captions\">Xoá phụ đề đã dùng</string>\n    <string name=\"subtitles_remove_bloat\">Loại bỏ mã hoá phụ đề</string>\n    <string name=\"subtitles_filter_lang\">Lọc theo ngôn ngữ media được chuộng hơn</string>\n    <string name=\"extras\">Thêm</string>\n    <string name=\"trailer\">Trailer</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"referer\">Đề xuất (tuỳ chọn)</string>\n    <string name=\"next\">Tiếp theo</string>\n    <string name=\"provider_languages_tip\">Xem video bằng các ngôn ngữ này</string>\n    <string name=\"previous\">Trước đó</string>\n    <string name=\"skip_setup\">Bỏ qua cài đặt setup</string>\n    <string name=\"app_layout_subtext\">Chọn giao diện phù hợp với thiết bị của bạn</string>\n    <string name=\"preferred_media_subtext\">Bạn muốn xem gì</string>\n    <string name=\"setup_done\">Hoàn tất</string>\n    <string name=\"extensions\">Tiện ích mở rộng</string>\n    <string name=\"add_repository\">Thêm kho lưu trữ</string>\n    <string name=\"repository_name_hint\">Tên kho lưu trữ (Tùy chọn)</string>\n    <string name=\"repository_url_hint\">Đường dẫn kho lưu trữ hoặc Mã ngắn</string>\n    <string name=\"plugin_loaded\">Đã tải plugin</string>\n    <string name=\"plugin_deleted\">Plugin đã xoá</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Không tải được %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Đã bắt đầu tải xuống %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">Đã tải xuống %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Toàn bộ %s đã được tải xuống</string>\n    <string name=\"batch_download\">Tải hàng loạt</string>\n    <string name=\"plugin_singular\">plugin</string>\n    <string name=\"plugin\">plugin</string>\n    <string name=\"delete_repository_plugins\">Tất cả plugin của kho lưu trữ sẽ bị xoá</string>\n    <string name=\"delete_repository\">Xoá kho lưu trữ</string>\n    <string name=\"setup_extensions_subtext\">Tải nguồn phim bạn muốn dùng</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Đã tải: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Đã vô hiệu: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Không tải: %d</string>\n    <string name=\"blank_repo_message\">CloudStream không có sẵn trang web nào. Bạn cần cài đặt các trang web từ kho lưu trữ.\n\\n\n\\nHãy tham gia Discord của chúng tôi hoặc tìm kiếm trực tuyến.</string>\n    <string name=\"view_public_repositories_button\">Xem kho lưu trữ của cộng đồng</string>\n    <string name=\"view_public_repositories_button_short\">Danh sách công khai</string>\n    <string name=\"uppercase_all_subtitles\">In hoa toàn bộ phụ đề</string>\n    <string name=\"download_all_plugins_from_repo\">Cảnh báo: CloudStream không chịu trách nhiệm về các tiện ích bên thứ ba và không cung cấp bất kỳ sự hỗ trợ nào!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (Đã vô hiệu hoá)</string>\n    <string name=\"tracks\">Âm thanh &amp; Chất lượng</string>\n    <string name=\"audio_tracks\">Âm thanh</string>\n    <string name=\"video_tracks\">Chất lượng Video</string>\n    <string name=\"apply_on_restart\">Áp dụng khi khởi động lại ứng dụng.</string>\n    <string name=\"safe_mode_title\">Chế độ an toàn được bật</string>\n    <string name=\"safe_mode_description\">Đã xảy ra sự cố và chúng tôi đã tự động tắt tất cả các tiện ích mở rộng, hãy tìm và xóa tiện ích mở rộng đang gây ra sự cố.</string>\n    <string name=\"safe_mode_crash_info\">Xem thông tin sự cố</string>\n    <string name=\"history\">Lịch sử</string>\n    <string name=\"action_mark_as_watched\">Đánh dấu là đã xem</string>\n    <string name=\"automatic_plugin_download\">Tự động tải xuống plugin</string>\n    <string name=\"redo_setup_process\">Làm lại tiến trình cài đặt</string>\n    <string name=\"apk_installer_settings\">Bộ cài APK</string>\n    <string name=\"apk_installer_settings_des\">Một số thiết bị không hỗ trợ trình cài đặt gói mới. Hãy thử tùy chọn cũ nếu các bản cập nhật không cài đặt.</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"play_trailer_button\">Xem Trailer</string>\n    <string name=\"automatic_plugin_download_summary\">Tự động cài đặt tất cả plugin chưa được cài đặt từ những kho lưu trữ đã thêm vào.</string>\n    <string name=\"update_started\">Bắt đầu cập nhật</string>\n    <string name=\"pref_category_links\">Liên kết</string>\n    <string name=\"hls_playlist\">Danh sách HLS</string>\n    <string name=\"player_pref\">Trình phát ưu tiên</string>\n    <string name=\"player_settings_play_in_app\">Trình phát mặc định</string>\n    <string name=\"extension_rating\" formatted=\"true\">Đánh giá: %s</string>\n    <string name=\"no\">Không</string>\n    <string name=\"extension_version\">Phiên bản</string>\n    <string name=\"extension_authors\">Tác giả</string>\n    <string name=\"pref_category_app_updates\">Cập nhật ứng dụng</string>\n    <string name=\"pref_category_backup\">Sao lưu</string>\n    <string name=\"pref_category_extensions\">Tiện ích</string>\n    <string name=\"pref_category_actions\">Hành động</string>\n    <string name=\"pref_category_cache\">Cache</string>\n    <string name=\"pref_category_gestures\">Cử chỉ</string>\n    <string name=\"pref_category_player_features\">Tính năng trình phát</string>\n    <string name=\"pref_category_subtitles\">Phụ đề</string>\n    <string name=\"pref_category_player_layout\">Bố cục</string>\n    <string name=\"pref_category_defaults\">Mặc định</string>\n    <string name=\"pref_category_looks\">Giao diện</string>\n    <string name=\"pref_category_ui_features\">Tính năng</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Đã cập nhật %d plugin</string>\n    <string name=\"extension_description\">Mô tả</string>\n    <string name=\"extension_status\">Trạng thái</string>\n    <string name=\"extension_size\">Kích thước</string>\n    <string name=\"extension_types\">Hỗ trợ</string>\n    <string name=\"extension_language\">Ngôn ngữ</string>\n    <string name=\"extension_install_first\">Cài đặt tiện ích trước</string>\n    <string name=\"app_not_found_error\">Không thấy ứng dụng</string>\n    <string name=\"all_languages_preference\">Tất cả ngôn ngữ</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Tua %s</string>\n    <string name=\"skip_type_op\">Mở đầu</string>\n    <string name=\"skip_type_ed\">Kết thúc</string>\n    <string name=\"skip_type_recap\">Tóm tắt</string>\n    <string name=\"skip_type_mixed_ed\">Các kết thúc hỗn hợp</string>\n    <string name=\"skip_type_mixed_op\">Các mở đầu hỗn hợp</string>\n    <string name=\"skip_type_creddits\">Danh đề</string>\n    <string name=\"skip_type_intro\">Giới thiệu</string>\n    <string name=\"clear_history\">Xoá lịch sử</string>\n    <string name=\"enable_skip_op_from_database_des\">Hiển thị nút tua nhanh cho mở đầu/kết thúc</string>\n    <string name=\"clipboard_too_large\">Văn bản quá dài. Không thể lưu vào khay nhớ tạm.</string>\n    <string name=\"action_remove_from_watched\">Xoá khỏi đã xem</string>\n    <string name=\"confirm_exit_dialog\">Bạn có chắc muốn thoát?</string>\n    <string name=\"yes\">Có</string>\n    <string name=\"update_notification_downloading\">Đang tải bản cập nhật…</string>\n    <string name=\"update_notification_installing\">Đang cài bản cập nhật…</string>\n    <string name=\"update_notification_failed\">Không thể cài đặt phiên bản mới</string>\n    <string name=\"delayed_update_notice\">Ứng dụng sẽ được cập nhật khi thoát</string>\n    <string name=\"library\">Thư viện</string>\n    <string name=\"browser\">Trình duyệt</string>\n    <string name=\"plugin_downloaded\">Plugin đã tải</string>\n    <string name=\"apk_installer_legacy\">Legacy</string>\n    <string name=\"sort_updated_new\">Đã cập nhật (Mới đến Cũ)</string>\n    <string name=\"sort_updated_old\">Đã cập nhật (Cũ đến Mới)</string>\n    <string name=\"empty_library_no_accounts_message\">Thư viện của bạn đang trống :(\n\\nĐăng nhập vào tài khoản thư viện hoặc thêm phim vào thư viện cục bộ.</string>\n    <string name=\"open_with\">Mở với</string>\n    <string name=\"provider_info_meta\">Thông tin dữ liệu không được cung cấp bởi trang web, video sẽ không tìm thấy link nếu nó không tồn tại trên trang web.</string>\n    <string name=\"apk_installer_package_installer\">PackageInstaller</string>\n    <string name=\"sort\">Sắp xếp</string>\n    <string name=\"sort_rating_desc\">Xếp hạng (Cao đến Thấp)</string>\n    <string name=\"sort_rating_asc\">Xếp hạng (Thấp đến Cao)</string>\n    <string name=\"sort_alphabetical_z\">Chữ cái (Z đến A)</string>\n    <string name=\"sort_by\">Sắp xếp theo</string>\n    <string name=\"empty_library_logged_in_message\">Danh sách này trống, hãy thử chuyển sang danh sách khác.</string>\n    <string name=\"sort_alphabetical_a\">Chữ cái (A đến Z)</string>\n    <string name=\"select_library\">Chọn Thư viện</string>\n    <string name=\"test_log\">Nhật ký</string>\n    <string name=\"watch_quality_pref_data\">Chất lượng xem ưu tiên (Dữ liệu di động)</string>\n    <string name=\"test_failed\">Thất bại</string>\n    <string name=\"test_passed\">Thành công</string>\n    <string name=\"start\">Bắt đầu</string>\n    <string name=\"category_provider_test\">Kiểm tra nguồn phim</string>\n    <string name=\"jsdelivr_proxy\">GitHub Proxy</string>\n    <string name=\"jsdelivr_enabled\">Không thể kết nối được tới GitHub. Đang bật jsDelivr proxy…</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"restart\">Khởi động lại</string>\n    <string name=\"subscription_new\">Đã đăng kí %s</string>\n    <string name=\"subscription_episode_released\">Tập %d đã ra mắt!</string>\n    <string name=\"subscription_list_name\">Đã đăng kí</string>\n    <string name=\"stop\">Dừng lại</string>\n    <string name=\"pref_category_bypass\">Bỏ qua ISP</string>\n    <string name=\"subscription_deleted\">Đã bỏ đăng ký %s</string>\n    <string name=\"safe_mode_file\">Tìm thấy tệp Safe mode!\n\\nKhông tải bất cứ tiện ích mở rộng nào khi khởi động cho đến khi loại bỏ tệp.</string>\n    <string name=\"revert\">Đảo ngược lại</string>\n    <string name=\"subscription_in_progress_notification\">Đang cập nhật các phim đã đăng kí</string>\n    <string name=\"jsdelivr_proxy_summary\">Bỏ qua chặn đường link GitHub bằng cách dùng jsDelivr. Có thể gây ra việc cập nhật bị chậm vài ngày.</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Lượng tua thêm được sử dụng khi trình phát ẩn</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Lượng tua thêm</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Lượng tua thêm được sử dụng khi trình phát hiện lên</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Lượng tua thêm</string>\n    <string name=\"profile_number\">Hồ sơ %d</string>\n    <string name=\"mobile_data\">Dữ liệu di động</string>\n    <string name=\"set_default\">Đặt mặc định</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"use\">Sử dụng</string>\n    <string name=\"edit\">Điều chỉnh</string>\n    <string name=\"profiles\">Hồ sơ</string>\n    <string name=\"help\">Trợ giúp</string>\n    <string name=\"profile_background_des\">Nền hồ sơ</string>\n    <string name=\"quality_profile_help\">Tại đây bạn có thể thay đổi cách sắp xếp các nguồn. Nếu video có mức độ ưu tiên cao hơn thì video đó sẽ xuất hiện cao hơn trong lựa chọn nguồn. Tổng ưu tiên nguồn và ưu tiên chất lượng là ưu tiên video.\n\\n\n\\nNguồn A: 3\n\\nChất lượng B: 7\n\\nSẽ có mức độ ưu tiên video kết hợp là 10.\n\\n\n\\nLƯU Ý: Nếu tổng là 10 hoặc nhiều hơn, trình phát sẽ tự động bỏ tải khi liên kết đó được tải!</string>\n    <string name=\"qualities\">Các chất lượng</string>\n    <string name=\"already_voted\">Bạn đã bình chọn</string>\n    <string name=\"disable\">Vô hiệu hoá</string>\n    <string name=\"no_repository_found_error\">Không tìm thấy tiện ích, hãy kiểm tra URL và thử lại với VPN</string>\n    <string name=\"no_plugins_found_error\">Không tìm thấy plugin</string>\n    <string name=\"unable_to_inflate\">Không thể khởi tạo UI, đây là một LỖI LỚN và cần được báo cáo ngay lập tức tới %s</string>\n    <string name=\"automatic_plugin_download_mode_title\">Chọn chế độ để lọc plugin tải xuống</string>\n    <string name=\"favorite_removed\">%s đã loại bỏ khỏi mục yêu thích</string>\n    <string name=\"favorites_list_name\">Yêu thích</string>\n    <string name=\"favorite_added\">%s đã thêm vào mục yêu thích</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Các mục có thể trùng lặp đã được tìm thấy trong thư viện của bạn:\n\\n\n\\n%s\n\\n\n\\nBạn vẫn muốn thêm mục này, thay thế những mục hiện có hay hủy hành động?</string>\n    <string name=\"backup_frequency\">Tần suất sao lưu</string>\n    <string name=\"duplicate_title\">Đã tìm thấy bản sao tiềm năng</string>\n    <string name=\"lock_profile\">Khóa hồ sơ</string>\n    <string name=\"action_add_to_favorites\">Thêm vào mục yêu thích</string>\n    <string name=\"duplicate_replace_all\">Thay thế tất cả</string>\n    <string name=\"pin_error_incorrect\">Mã PIN không chính xác. Vui lòng thử lại.</string>\n    <string name=\"action_unsubscribe\">Hủy đăng ký</string>\n    <string name=\"pin_error_length\">Mã PIN phải có 4 ký tự</string>\n    <string name=\"duplicate_replace\">Thay thế</string>\n    <string name=\"duplicate_add\">Thêm vào</string>\n    <string name=\"action_subscribe\">Đăng ký</string>\n    <string name=\"action_remove_from_favorites\">Loại bỏ khỏi mục yêu thích</string>\n    <string name=\"select_an_account\">Chọn một tài khoản</string>\n    <string name=\"duplicate_message_single\">Có vẻ như một mục có khả năng trùng lặp đã tồn tại trong thư viện của bạn: \\'%s.\\'\n\\n\n\\nBạn vẫn muốn thêm mục này, thay thế mục hiện có hay hủy hành động?</string>\n    <string name=\"enter_pin\">Nhập PIN</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"enter_current_pin\">Nhập mã PIN hiện tại</string>\n    <string name=\"logged_account\" formatted=\"true\">Đã đăng nhập với tư cách %s</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Nhập mã PIN cho %s</string>\n    <string name=\"use_default_account\">Sử dụng tài khoản mặc định</string>\n    <string name=\"skip_startup_account_select_pref\">Bỏ qua lựa chọn tài khoản khi khởi động</string>\n    <string name=\"manage_accounts\">Quản lý tài khoản</string>\n    <string name=\"edit_account\">Chỉnh sửa tài khoản</string>\n    <string name=\"links_reloaded_toast\">Tải lại liên kết</string>\n    <string name=\"result_search_tooltip\">Tìm kiếm tiện ích khác</string>\n    <string name=\"recommendations_tooltip\">Hiển thị đề xuất</string>\n    <string name=\"test_extensions\">Kiểm tra nguồn phim</string>\n    <string name=\"rotate_video\">Xoay</string>\n    <string name=\"subscribe_tooltip\">Thông báo tập mới</string>\n    <string name=\"speed_setting_summary\">Chỉnh tốc độ trong trình phát</string>\n    <string name=\"rotate_video_desc\">Hiển thị nút xoay màn hình</string>\n    <string name=\"auto_rotate_video_desc\">Kích hoạt chế độ xoay màn hình tự động</string>\n    <string name=\"auto_rotate_video\">Tự động xoay</string>\n    <string name=\"toast_copied\">đã sao chép!</string>\n    <string name=\"clipboard_permission_error\">Vấn đề truy cập Bảng ghi tạm, Hãy thử lại.</string>\n    <string name=\"clipboard_unknown_error\">Lỗi sao chép, Hãy sao chép logcat và liên hệ hỗ trợ ứng dụng.</string>\n    <string name=\"favorite\">Yêu thích</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"battery_dialog_title\">Vô hiệu Tối ưu pin</string>\n    <string name=\"app_info_intent_error\">Không thể mở thông tin ứng dụng của CloudStream.</string>\n    <string name=\"unfavorite\">Không thích</string>\n    <string name=\"biometric_authentication_title\">Mở khóa Cloudstream</string>\n    <string name=\"music_singlar\">Nhạc</string>\n    <string name=\"audio_book_singular\">Sách nói</string>\n    <string name=\"biometric_setting\">Khóa với sinh trắc học</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\ncòn lại</string>\n    <string name=\"biometric_unsupported\">Xác thực bằng sinh trắc học không được hỗ trợ trên thiết bị này</string>\n    <string name=\"password_pin_authentication_title\">Mật khẩu/PIN Xác thực</string>\n    <string name=\"biometric_warning\">Dữ liệu CloudStream của bạn hiện đã được sao lưu. Mặc dù khả năng xảy ra điều này là rất thấp nhưng tất cả các thiết bị đều có thể hoạt động khác nhau. Trong trường hợp hiếm gặp là bạn bị khóa truy cập ứng dụng, hãy xóa hoàn toàn dữ liệu ứng dụng và khôi phục từ bản sao lưu. Chúng tôi rất xin lỗi vì bất kỳ sự bất tiện nào phát sinh từ việc này.</string>\n    <string name=\"biometric_setting_summary\">Mở khóa ứng dụng bằng Vân tay, Khuôn mặt, PIN, Hình vẽ và Mật khẩu.</string>\n    <string name=\"biometric_prompt_description\">Màn hình bị đóng sau nhiều lần thử thất bại. Hãy khởi động lại ứng dụng.</string>\n    <string name=\"test_extensions_summary\">Bài kiểm tra này chỉ dành cho các nhà phát triển và không xác nhận hay phủ nhận việc hoạt động của bất kỳ nguồn phim nào.</string>\n    <string name=\"app_unrestricted_toast\">Chế độ tiêu thụ pin của ứng dụng đã được đặt ở mức không giới hạn</string>\n    <string name=\"custom_media_singluar\">Phương tiện</string>\n    <string name=\"repo_copy_label\">Tên và URL kho lưu trữ</string>\n    <string name=\"reset_btn\">Đặt lại</string>\n    <string name=\"battery_dialog_message\">Để đảm bảo quá trình tải xuống và thông báo cho các chương trình truyền hình đã đăng ký không bị gián đoạn, CloudStream cần có quyền chạy ở chế độ nền. Bằng cách nhấn OK, một hộp thoại yêu cầu sẽ hiển thị. Hãy nhấn \\\"Cho phép\\\".\\n\\nXin lưu ý, quyền này không có nghĩa là CS3 sẽ làm hao pin của bạn. Nó sẽ chỉ hoạt động ở chế độ nền khi cần thiết, chẳng hạn như khi nhận được thông báo hoặc tải xuống video từ các tiện ích mở rộng chính thức.</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Mùa %1$d Tập %2$d sẽ được phát hành vào</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Sắp tới sau %s</string>\n    <string name=\"player_settings_select_cast_device\">Chọn thiết bị truyền</string>\n    <string name=\"pref_category_security\">Bảo mật</string>\n    <string name=\"pref_category_accounts\">Tài khoản</string>\n    <string name=\"qr_image\">Mã QR</string>\n    <string name=\"dismiss\">Bỏ qua</string>\n    <string name=\"open_downloaded_repo\">Mở tiện ích mở rộng</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"device_pin_url_message\">Truy cập <b>%s</b> trên điện thoại hoặc máy tính và nhập mã bên trên</string>\n    <string name=\"device_pin_expired_message\">Mã PIN đã hết hạn!</string>\n    <string name=\"device_pin_counter_text\">Mã sẽ hết hạn trong %1$dm %2$ds</string>\n    <string name=\"device_pin_error_message\">Không lấy được mã PIN, hãy thử xác thực cục bộ</string>\n    <string name=\"downloads_empty\">Hiện không có bản tải xuống nào.</string>\n    <string name=\"auth_locally\">Xác thực cục bộ</string>\n    <string name=\"episode_action_cast_mirror\">Phản chiếu màn hình</string>\n    <string name=\"play_from_beginning_img_des\">Xem từ đầu</string>\n    <string name=\"open_local_video\">Mở video có sẵn</string>\n    <string name=\"test_warning\">Cảnh báo</string>\n    <string name=\"sort_release_date_new\">Ngày phát hành (Mới đến Cũ)</string>\n    <string name=\"downloads_delete_select\">Chọn mục để xoá</string>\n    <string name=\"offline_file\">Có thể xem ngoại tuyến</string>\n    <string name=\"select_all\">Chọn tất cả</string>\n    <string name=\"deselect_all\">Bỏ chọn tất cả</string>\n    <string name=\"delete_files\">Xoá các tệp</string>\n    <string name=\"delete_format\" formatted=\"true\">Xoá (%1$d | %2$s)</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Bạn có chắc chắn muốn xóa vĩnh viễn các mục sau không?\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Bạn có chắc chắn muốn xóa vĩnh viễn các tập trong %1$s?\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Bạn cũng sẽ xóa vĩnh viễn tất cả các tập trong loạt phim sau:\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Bạn có chắc chắn muốn xóa vĩnh viễn tất cả các tập trong loạt phim này không?\n\\n\n\\n%s</string>\n    <string name=\"delete_plugin\">Xóa plugin</string>\n    <string name=\"sort_release_date_old\">Ngày phát hành (Cũ đến mới)</string>\n    <string name=\"hide_player_control_names\">Ẩn tên các nút điều khiển</string>\n    <string name=\"preview_seekbar_desc\">Bật chế độ xem trước hình thu nhỏ trên seekbar</string>\n    <string name=\"preview_seekbar\">Xem trước Seekbar</string>\n    <string name=\"no_subtitles_loaded\">Chưa tải phụ đề</string>\n    <string name=\"confirm_before_exiting_title\">Xác nhận trước khi thoát</string>\n    <string name=\"confirm_before_exiting_desc\">Hiện hộp thoại xác nhận thoát ứng dụng</string>\n    <string name=\"dont_show\">Không hiển thị</string>\n    <string name=\"show\">Hiển thị</string>\n    <string name=\"backup_path_title\">Vị trí thư mục sao lưu</string>\n    <string name=\"custom\">Tuỳ chỉnh</string>\n    <string name=\"subs_edge_size\">Kích thước cạnh</string>\n    <string name=\"torrent_info\">Video này là Torrent, điều này có nghĩa là hoạt động video của bạn có thể được theo dõi.\\nHãy đảm bảo rằng bạn hiểu về Torrent trước khi tiếp tục.</string>\n    <string name=\"encoding_error\">Lỗi mã hóa</string>\n    <string name=\"software_decoding_desc\">Giải mã phần mềm cho phép phát các tệp video không được thiết bị của bạn hỗ trợ, nhưng có thể gây ra phản hồi chậm hoặc phát lại không ổn định ở độ phân giải cao.</string>\n    <string name=\"software_decoding\">Bộ giải mã ứng dụng</string>\n    <string name=\"torrent_not_accepted\">Khởi động lại ứng dụng và chấp nhận cửa sổ Stream Torrent để tiếp tục.</string>\n    <string name=\"torrent_preferred_media\">Kích hoạt torrent trong Cài đặt/Nguồn phim/Thể loại ưu tiên</string>\n    <string name=\"player_load_one_subtitle_online\">Tải phụ đề đầu tiên có sẵn</string>\n    <string name=\"audio_singluar\">Âm thanh</string>\n    <string name=\"podcast_singluar\">Podcast</string>\n    <string name=\"unsupported_error\">Lỗi không được hỗ trợ</string>\n    <string name=\"sort_episodes_rating_low_high\">Xếp hạng (Thấp nhất)</string>\n    <string name=\"sort_episodes_number_asc\">Tập (Tăng dần)</string>\n    <string name=\"sort_episodes_date_newest\">Ngày phát sóng (Mới nhất)</string>\n    <string name=\"sort_button_rating\">Xếp hạng %s</string>\n    <string name=\"sort_button_date\">Ngày %s</string>\n    <string name=\"sort_button_episode\">Tập %s</string>\n    <string name=\"update_plugins\">Cập nhật plugin</string>\n    <string name=\"no_plugins_updated_manually\">Không có plugin nào được cập nhật.</string>\n    <string name=\"sort_episodes_date_oldest\">Ngày phát hành (Cũ nhất)</string>\n    <string name=\"plugins_updated_manually\">Đã cập nhật thành công %d plugin!</string>\n    <string name=\"sort_episodes_rating_high_low\">Xếp hạng (Cao nhất)</string>\n    <string name=\"update_plugins_manually\">Cập nhật plugin thủ công</string>\n    <string name=\"sort_episodes_number_desc\">Tập (Giảm dần)</string>\n    <string name=\"starting_plugin_update_manually\">Bắt đầu quá trình cập nhật plugin!</string>\n    <string name=\"player_notification_channel_name\">Thông báo trình phát</string>\n    <string name=\"player_notification_channel_description\">Thông báo trình phát để điều khiển phát lại từ nền</string>\n    <string name=\"begin_speaking\">Bắt đầu nói…</string>\n    <string name=\"speech_recognition_unavailable\">Tìm kiếm giọng nói không khả dụng</string>\n    <string name=\"subtitles_from_online\">Trực tuyến</string>\n    <string name=\"background_radius\">Bo tròn nền</string>\n    <string name=\"volume_exceeded_100\">Âm lượng đã vượt quá 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Vuốt lên lần nữa để vượt quá 100%</string>\n    <string name=\"subtitles_from_embedded\">Được nhúng</string>\n    <string name=\"all_subtitles_bold\">Làm tất cả phụ đề in đậm</string>\n    <string name=\"all_subtitles_italic\">Làm tất cả phụ đề in nghiêng</string>\n    <string name=\"player_settings_always_ask\">Luôn hỏi</string>\n    <string name=\"show_rating\">Nhãn đánh giá</string>\n    <string name=\"download_parallel_settings_des\">Số lượng mục khác nhau có thể tải xuống cùng lúc</string>\n    <string name=\"parallel_downloads\">Tải xuống song song</string>\n    <string name=\"concurrent_connections\">Kết nối đồng thời</string>\n    <string name=\"concurrent_connections_settings_des\">Số lượng kết nối đồng thời có thể sử dụng cho mỗi lượt tải</string>\n    <string name=\"go_to_downloads\">Đến mục tải xuống</string>\n    <string name=\"no_internet_connection\">Không có kết nối Internet. \\n\\nVui lòng kết nối Internet rồi thử lại, hoặc xem các nội dung đã tải xuống khi đang ngoại tuyến.</string>\n    <string name=\"overscan_settings_des\">Thay đổi khung hiển thị màn hình</string>\n    <string name=\"overscan_settings\">Vượt khung</string>\n    <string name=\"poster_size_settings_des\">Thay đổi kích thước của hình poster</string>\n    <string name=\"poster_size_settings\">Kích thước poster</string>\n    <string name=\"speedup_title\">Tăng tốc độ phát khi nhấn giữ</string>\n    <string name=\"speedup_summary\">Nhấn giữ để tăng tốc độ phát 2x</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh %2$dm %3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm %2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"no_account\">Không có tài khoản</string>\n    <string name=\"edit_profile_image_title\">Đổi hình đại điện</string>\n    <string name=\"edit_profile_image_hint\">Nhập url hình đại diện</string>\n    <string name=\"edit_profile_image_error_empty\">Không tìm thấy url</string>\n    <string name=\"edit_profile_image_error_invalid\">URL hoặc hình không hợp lệ</string>\n    <string name=\"edit_profile_image_success\">Tải hình lên thành công</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Đánh dấu là đã xem đến tập này</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Xóa những tập đã xem đến tập này</string>\n    <string name=\"action_reload\">Đã tải lại</string>\n    <string name=\"reload_provider\">Tải lại nguồn phát</string>\n    <string name=\"name\">Tên</string>\n    <string name=\"resolution_and_name\">Độ phân giải và tên</string>\n    <string name=\"episode_action_play_mirror\">Xem phản chiếu</string>\"\n    <string name=\"subs_subtitle_alignment\">Căn chỉnh phụ đề</string>\n    <string name=\"bottom_left\">Dưới trái</string>\n    <string name=\"bottom_center\">Dưới giữa</string>\n    <string name=\"bottom_right\">Dưới phải</string>\n    <string name=\"top_left\">Trên trái</string>\n    <string name=\"top_right\">Trên phải</string>\n    <string name=\"top_center\">Trên giữa</string>\n    <string name=\"middle_center\">Trung tâm</string>\n    <string name=\"middle_left\">Giữa trái</string>\n    <string name=\"middle_right\">Giữa phải</string>\n    <string name=\"play_full_series_button\">Phát trọn bộ loạt phim</string>\n    <string name=\"search_suggestions\">Gợi ý tìm kiếm</string>\n    <string name=\"search_suggestions_des\">Hiển thị gợi ý tìm kiếm khi đang nhập</string>\n    <string name=\"clear_suggestions\">Xóa gợi ý</string>\n    <string name=\"install_prerelease\">Cài đặt phiên bản phát hành trước</string>\n    <string name=\"prerelease_already_installed\">Bản phát hành trước đã được cài đặt.</string>\n    <string name=\"prerelease_install_failed\">Cài đặt bản phát hành trước thất bại.</string>\n    <string name=\"show_episode_text\">Chữ của tập</string>\n    <string name=\"extra_brightness_settings_des\">Kích hoạt bộ lọc độ sáng khi độ sáng màn hình vượt quá 100%</string>\n    <string name=\"show_cast_in_details\">Hiển thị bảng điều khiển</string>\n    <string name=\"video_info\">Thông tin âm thanh</string>\n    <string name=\"extra_brightness_settings\">Độ sáng bổ sung</string>\n    <string name=\"source_name\">Tên nguồn</string>\n    <string name=\"download_queue\">Hàng đợi tải xuống</string>\n    <string name=\"queue_empty_message\">Hiện tại không có tệp nào đang chờ tải xuống.</string>\n    <string name=\"source_priority_help\">Hãy quyết định cách sắp xếp các nguồn video trong trình phát.</string>\n    <string name=\"source_priority\">Ưu tiên nguồn</string>\n    <string name=\"download_all\">Tải xuống tất cả</string>\n    <string name=\"cancel_all\">Hủy tất cả</string>\n    <string name=\"download_episode_range\">Bạn có muốn tải xuống tập %s không?</string>\n    <string name=\"cancel_queue_message\">Bạn có muốn hủy tất cả các lượt tải xuống đang chờ xử lý không?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"other\">%d đang tải xuống</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"other\">%d lượt tải xuống đang chờ xử lý</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+zh/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s Ep %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">演员：%s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">第 %d 集将发布于</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">封面</string>\n    <string name=\"search_poster_img_des\">封面</string>\n    <string name=\"episode_poster_img_des\">剧集封面</string>\n    <string name=\"home_main_poster_img_des\">主封面</string>\n    <string name=\"home_next_random_img_des\">随机下一个</string>\n    <string name=\"go_back_img_des\">返回</string>\n    <string name=\"home_change_provider_img_des\">更改片源</string>\n    <string name=\"preview_background_img_des\">预览背景</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">速度（%.2fx）</string>\n    <string name=\"rated_format\" formatted=\"true\">评分：%.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">发现新版本！\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">填充</string>\n    <string name=\"duration_format\" formatted=\"true\">%d 分钟</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">使用 CloudStream 播放</string>\n    <string name=\"title_home\">主页</string>\n    <string name=\"title_search\">搜索</string>\n    <string name=\"title_downloads\">下载</string>\n    <string name=\"title_settings\">设置</string>\n    <string name=\"search_hint\">搜索…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">搜索 %s…</string>\n    <string name=\"no_data\">无数据</string>\n    <string name=\"episode_more_options_des\">更多选项</string>\n    <string name=\"next_episode\">下一集</string>\n    <string name=\"result_tags\">类型</string>\n    <string name=\"result_share\">分享</string>\n    <string name=\"result_open_in_browser\">在浏览器中打开</string>\n    <string name=\"skip_loading\">跳过加载</string>\n    <string name=\"loading\">加载中…</string>\n    <string name=\"type_watching\">正在观看</string>\n    <string name=\"type_on_hold\">暂时搁置</string>\n    <string name=\"type_completed\">观看完毕</string>\n    <string name=\"type_dropped\">放弃观看</string>\n    <string name=\"type_plan_to_watch\">计划观看</string>\n    <string name=\"type_re_watching\">重新观看</string>\n    <string name=\"play_movie_button\">播放电影</string>\n    <string name=\"play_livestream_button\">播放直播</string>\n    <string name=\"play_torrent_button\">播放种子</string>\n    <string name=\"pick_source\">来源</string>\n    <string name=\"pick_subtitle\">字幕</string>\n    <string name=\"reload_error\">重试连接…</string>\n    <string name=\"go_back\">返回</string>\n    <string name=\"play_episode\">播放剧集</string>\n    <!--<string name=\"need_storage\">允许下载剧集</string>-->\n    <string name=\"download\">下载</string>\n    <string name=\"downloaded\">已下载</string>\n    <string name=\"downloading\">下载中</string>\n    <string name=\"download_paused\">下载暂停</string>\n    <string name=\"download_started\">下载开始</string>\n    <string name=\"download_failed\">下载失败</string>\n    <string name=\"download_canceled\">下载取消</string>\n    <string name=\"download_done\">下载完毕</string>\n    <string name=\"stream\">播放</string>\n    <string name=\"error_loading_links_toast\">加载链接错误</string>\n    <string name=\"download_storage_text\">内部存储</string>\n    <string name=\"app_dubbed_text\">配音</string>\n    <string name=\"app_subbed_text\">字幕</string>\n    <string name=\"popup_delete_file\">删除文件</string>\n    <string name=\"popup_play_file\">播放文件</string>\n    <string name=\"popup_resume_download\">继续下载</string>\n    <string name=\"popup_pause_download\">暂停下载</string>\n    <string name=\"home_more_info\">更多信息</string>\n    <string name=\"home_expanded_hide\">隐藏</string>\n    <string name=\"home_play\">播放</string>\n    <string name=\"home_info\">信息</string>\n    <string name=\"filter_bookmarks\">筛选书签</string>\n    <string name=\"error_bookmarks_text\">书签</string>\n    <string name=\"action_remove_from_bookmarks\">移除</string>\n    <string name=\"action_add_to_bookmarks\">设置观看状态</string>\n    <string name=\"sort_apply\">应用</string>\n    <string name=\"sort_copy\">复制</string>\n    <string name=\"sort_close\">关闭</string>\n    <string name=\"sort_clear\">清除</string>\n    <string name=\"sort_save\">保存</string>\n    <string name=\"player_speed\">播放速度</string>\n    <string name=\"subtitles_settings\">字幕设置</string>\n    <string name=\"subs_text_color\">文本颜色</string>\n    <string name=\"subs_outline_color\">轮廓颜色</string>\n    <string name=\"subs_background_color\">背景颜色</string>\n    <string name=\"subs_window_color\">窗口颜色</string>\n    <string name=\"subs_edge_type\">边缘类型</string>\n    <string name=\"subs_subtitle_elevation\">字幕高度</string>\n    <string name=\"subs_font\">字体</string>\n    <string name=\"subs_font_size\">字体大小</string>\n    <string name=\"search_provider_text_providers\">按片源搜索</string>\n    <string name=\"search_provider_text_types\">按类型搜索</string>\n    <string name=\"benene_count_text\">给开发者送 %d 根香蕉</string>\n    <string name=\"benene_count_text_none\">不送香蕉</string>\n    <string name=\"subs_auto_select_language\">自动选择语言</string>\n    <string name=\"subs_download_languages\">下载语言</string>\n    <string name=\"subs_subtitle_languages\">字幕语言</string>\n    <string name=\"subs_hold_to_reset_to_default\">按住重置为默认值</string>\n    <string name=\"subs_import_text\" formatted=\"true\">将字体导入到 %s</string>\n    <string name=\"continue_watching\">继续观看</string>\n    <string name=\"action_remove_watching\">移除</string>\n    <string name=\"action_open_watching\">更多信息</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">此片源可能需要 VPN 才能正常使用</string>\n    <string name=\"vpn_torrent\">此片源为种子文件，建议使用 VPN</string>\n    <string name=\"provider_info_meta\">站点不提供元数据，如果站点上不存在元数据，视频加载将失败。</string>\n    <string name=\"torrent_plot\">简介</string>\n    <string name=\"normal_no_plot\">未找到简介</string>\n    <string name=\"torrent_no_plot\">未找到简介</string>\n    <string name=\"show_log_cat\">显示 Logcat 🐈</string>\n    <string name=\"picture_in_picture\">画中画</string>\n    <string name=\"picture_in_picture_des\">在其他应用上层的迷你播放器中继续播放</string>\n    <string name=\"player_size_settings\">播放器画面调整按钮</string>\n    <string name=\"player_size_settings_des\">移除黑色边框</string>\n    <string name=\"player_subtitles_settings\">字幕</string>\n    <string name=\"player_subtitles_settings_des\">播放器字幕设置</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast 字幕</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast 字幕设置</string>\n    <string name=\"eigengraumode_settings\">播放速度</string>\n    <string name=\"swipe_to_seek_settings\">滑动控制进度</string>\n    <string name=\"swipe_to_seek_settings_des\">左右滑动以控制视频中的位置</string>\n    <string name=\"swipe_to_change_settings\">滑动更改设置</string>\n    <string name=\"swipe_to_change_settings_des\">上下滑动修改亮度或音量</string>\n    <string name=\"autoplay_next_settings\">自动播放下一集</string>\n    <string name=\"autoplay_next_settings_des\">播放完毕后播放下一集</string>\n    <string name=\"double_tap_to_seek_settings\">双击控制进度</string>\n    <string name=\"double_tap_to_pause_settings\">双击暂停</string>\n    <string name=\"double_tap_to_seek_amount_settings\">双击控制进度时间 （秒）</string>\n    <string name=\"double_tap_to_seek_settings_des\">在左右侧双击快进或快退</string>\n    <string name=\"double_tap_to_pause_settings_des\">双击中间暂停</string>\n    <string name=\"use_system_brightness_settings\">使用系统亮度</string>\n    <string name=\"use_system_brightness_settings_des\">在应用播放器中使用系统亮度替代黑色遮罩</string>\n    <string name=\"episode_sync_settings\">更新观看进度</string>\n    <string name=\"episode_sync_settings_des\">自动同步当前剧集进度</string>\n    <string name=\"restore_settings\">从备份中恢复数据</string>\n    <string name=\"backup_settings\">备份数据</string>\n    <string name=\"restore_success\">已加载备份文件</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">无法从 %s 文件中还原数据</string>\n    <string name=\"backup_success\">数据已储存</string>\n    <string name=\"backup_failed\">缺少存储权限，请重试。</string>\n    <string name=\"backup_failed_error_format\">备份 %s 出错</string>\n    <string name=\"search\">搜索</string>\n    <string name=\"category_account\">账户和安全</string>\n    <string name=\"category_updates\">更新与备份</string>\n    <string name=\"settings_info\">信息</string>\n    <string name=\"advanced_search\">高级搜索</string>\n    <string name=\"advanced_search_des\">按片源分割搜索结果</string>\n    <string name=\"show_fillers_settings\">显示动画外传</string>\n    <string name=\"show_trailers_settings\">显示预告片</string>\n    <string name=\"kitsu_settings\">显示来自 Kitsu 的封面</string>\n    <string name=\"pref_filter_search_quality\">在搜索结果中隐藏选中视频画质</string>\n    <string name=\"automatic_plugin_updates\">自动更新插件</string>\n    <string name=\"automatic_plugin_download\">自动下载插件</string>\n    <string name=\"updates_settings\">显示应用更新</string>\n    <string name=\"updates_settings_des\">启动应用后自动搜索更新。</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">由相同开发者开发的轻小说应用</string>\n    <string name=\"anim\">由相同开发者开发的动漫应用</string>\n    <string name=\"discord\">加入 Discord</string>\n    <string name=\"benene\">给开发者送一根香蕉</string>\n    <string name=\"benene_des\">送香蕉</string>\n    <string name=\"app_language\">应用语言</string>\n    <string name=\"no_chromecast_support_toast\">此片源不支持 Chromecast</string>\n    <string name=\"no_links_found_toast\">未找到链接</string>\n    <string name=\"copy_link_toast\">链接已复制到剪贴板</string>\n    <string name=\"play_episode_toast\">播放剧集</string>\n    <string name=\"subs_default_reset_toast\">重置为默认值</string>\n    <string name=\"season\">季</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">无季</string>\n    <string name=\"episode\">集</string>\n    <string name=\"episodes\">集</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">未找到剧集</string>\n    <string name=\"delete_file\">删除文件</string>\n    <string name=\"delete\">删除</string>\n    <string name=\"cancel\">取消</string>\n    <string name=\"pause\">暂停</string>\n    <string name=\"resume\">继续</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">这将永久删除 %s\n\\n您确定吗?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%d 分钟\n\\n剩余</string>\n    <string name=\"status_ongoing\">连载中</string>\n    <string name=\"status_completed\">已完结</string>\n    <string name=\"status\">状态</string>\n    <string name=\"year\">年份</string>\n    <string name=\"rating\">评分</string>\n    <string name=\"duration\">时间</string>\n    <string name=\"site\">网站</string>\n    <string name=\"synopsis\">简介</string>\n    <string name=\"queued\">已加入队列</string>\n    <string name=\"no_subtitles\">无字幕</string>\n    <string name=\"action_default\">默认</string>\n    <string name=\"free_storage\">空闲</string>\n    <string name=\"used_storage\">已使用</string>\n    <string name=\"app_storage\">应用</string>\n    <!--plural-->\n    <string name=\"movies\">电影</string>\n    <string name=\"tv_series\">电视剧</string>\n    <string name=\"cartoons\">卡通</string>\n    <string name=\"anime\">动漫</string>\n    <string name=\"torrent\">种子</string>\n    <string name=\"documentaries\">纪录片</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">亚洲剧</string>\n    <string name=\"livestreams\">直播</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">其他</string>\n    <!--singular-->\n    <string name=\"movies_singular\">电影</string>\n    <string name=\"tv_series_singular\">电视剧</string>\n    <string name=\"cartoons_singular\">卡通</string>\n    <string name=\"anime_singular\">动漫</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">种子</string>\n    <string name=\"documentaries_singular\">纪录片</string>\n    <string name=\"asian_drama_singular\">亚洲剧</string>\n    <string name=\"live_singular\">直播</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">其他</string>\n    <string name=\"source_error\">来源错误</string>\n    <string name=\"remote_error\">远程错误</string>\n    <string name=\"render_error\">渲染器错误</string>\n    <string name=\"unexpected_error\">意外的播放器错误</string>\n    <string name=\"storage_error\">下载错误，请检查存储权限</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast 剧集</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast 镜像</string>\n    <string name=\"episode_action_play_in_app\">在应用中播放</string>\n    <string name=\"episode_action_play_in_format\">在 %s 中播放</string>\n    <string name=\"episode_action_auto_download\">自动下载</string>\n    <string name=\"episode_action_download_mirror\">下载镜像</string>\n    <string name=\"episode_action_reload_links\">重新加载链接</string>\n    <string name=\"episode_action_download_subtitle\">下载字幕</string>\n    <string name=\"show_hd\">画质标签</string>\n    <string name=\"show_dub\">配音标签</string>\n    <string name=\"show_sub\">字幕标签</string>\n    <string name=\"show_title\">标题</string>\n    <string name=\"poster_ui_settings\">封面内容</string>\n    <string name=\"no_update_found\">未找到更新</string>\n    <string name=\"check_for_update\">检查更新</string>\n    <string name=\"video_lock\">锁定</string>\n    <string name=\"video_aspect_ratio_resize\">调整画面</string>\n    <string name=\"video_source\">来源</string>\n    <string name=\"video_skip_op\">跳过片头</string>\n    <string name=\"dont_show_again\">不再显示</string>\n    <string name=\"skip_update\">跳过此更新</string>\n    <string name=\"update\">更新</string>\n    <string name=\"watch_quality_pref\">首选播放画质（WiFi）</string>\n    <string name=\"limit_title\">视频播放器标题最多字符</string>\n    <string name=\"limit_title_rez\">显示播放器信息</string>\n    <string name=\"video_buffer_size_settings\">视频缓冲大小</string>\n    <string name=\"video_buffer_length_settings\">视频缓冲长度</string>\n    <string name=\"video_buffer_disk_settings\">视频缓存存储</string>\n    <string name=\"video_buffer_clear_settings\">清除视频与图像缓存</string>\n    <string name=\"video_ram_description\">如果在内存较少的设备（例如 Android TV）上设置得太高会导致崩溃。</string>\n    <string name=\"video_disk_description\">如果在存储空间较小的设备（例如 Android TV）上设置过高会导致问题。</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"dns_pref_summary\">用于绕过 ISP 的封锁</string>\n    <string name=\"add_site_pref\">复制片源</string>\n    <string name=\"remove_site_pref\">移除片源</string>\n    <string name=\"add_site_summary\">添加不同链接的已有片源复制</string>\n    <string name=\"download_path_pref\">下载路径</string>\n    <string name=\"nginx_url_pref\">NGINX 服务器链接</string>\n    <string name=\"display_subbed_dubbed_settings\">显示带配音/字幕的动漫</string>\n    <string name=\"resize_fit\">适应</string>\n    <string name=\"resize_fill\">拉伸</string>\n    <string name=\"resize_zoom\">缩放</string>\n    <string name=\"legal_notice\">免责声明</string>\n    <string name=\"category_general\">通用</string>\n    <string name=\"random_button_settings\">随机按钮</string>\n    <string name=\"random_button_settings_desc\">在主页和库中显示随机按钮</string>\n    <string name=\"provider_lang_settings\">扩展语言</string>\n    <string name=\"app_layout\">应用布局</string>\n    <string name=\"preferred_media_settings\">首选类型</string>\n    <string name=\"enable_nsfw_on_providers\">在支持的扩展程序中启用 NSFW 内容</string>\n    <string name=\"subtitles_encoding\">字幕编码</string>\n    <string name=\"category_providers\">片源</string>\n    <string name=\"category_ui\">布局</string>\n    <string name=\"automatic\">自动</string>\n    <string name=\"tv_layout\">电视布局</string>\n    <string name=\"phone_layout\">手机布局</string>\n    <string name=\"emulator_layout\">模拟器布局</string>\n    <string name=\"primary_color_settings\">主题色</string>\n    <string name=\"app_theme_settings\">应用主题</string>\n    <string name=\"bottom_title_settings\">封面标题位置</string>\n    <string name=\"bottom_title_settings_des\">将标题移至封面下方</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">密码</string>\n    <string name=\"example_username\">用户名</string>\n    <string name=\"example_email\">邮箱</string>\n    <string name=\"example_ip\">IP</string>\n    <string name=\"example_site_name\">网站名称</string>\n    <string name=\"example_site_url\">网站链接</string>\n    <string name=\"example_lang_name\">语言代码 (zh)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">账户</string>\n    <string name=\"logout\">注销</string>\n    <string name=\"login\">登录</string>\n    <string name=\"switch_account\">切换账户</string>\n    <string name=\"add_account\">添加账户</string>\n    <string name=\"create_account\">创建账户</string>\n    <string name=\"add_sync\">添加同步</string>\n    <string name=\"added_sync_format\" formatted=\"true\">已添加 %s</string>\n    <string name=\"upload_sync\">同步</string>\n    <string name=\"sync_score\">评分</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">已验证 %s</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">无法登录到 %s</string>\n    <!-- ============ -->\n    <string name=\"none\">无</string>\n    <string name=\"normal\">普通</string>\n    <string name=\"all\">全部</string>\n    <string name=\"max\">最大</string>\n    <string name=\"min\">最小</string>\n    <string name=\"subtitles_outline\">轮廓</string>\n    <string name=\"subtitles_depressed\">凹陷</string>\n    <string name=\"subtitles_shadow\">阴影</string>\n    <string name=\"subtitles_raised\">凸出</string>\n    <string name=\"subtitle_offset\">同步字幕</string>\n    <string name=\"subtitle_offset_hint\">1000 ms</string>\n    <string name=\"subtitle_offset_title\">字幕延迟</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">如果字幕过早显示 %d ms，请使用此选项</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">如果字幕过晚显示 %d ms，请使用此选项</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">无字幕延迟</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">The quick brown fox jumps over the lazy dog</string>\n    <string name=\"recommended\">推荐</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">已加载 %s</string>\n    <string name=\"player_load_subtitles\">从文件加载</string>\n    <string name=\"player_load_subtitles_online\">从互联网加载</string>\n    <string name=\"downloaded_file\">下载的文件</string>\n    <string name=\"actor_main\">主演</string>\n    <string name=\"actor_supporting\">配演</string>\n    <string name=\"actor_background\">群演</string>\n    <string name=\"home_source\">来源</string>\n    <string name=\"home_random\">随机</string>\n    <string name=\"coming_soon\">即将到来…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">封面图像</string>\n    <string name=\"category_player\">播放器</string>\n    <string name=\"resolution_and_title\">分辨率与标题</string>\n    <string name=\"title\">标题</string>\n    <string name=\"resolution\">分辨率</string>\n    <string name=\"error_invalid_id\">无效 ID</string>\n    <string name=\"error_invalid_data\">无效数据</string>\n    <string name=\"error_invalid_url\">无效链接</string>\n    <string name=\"error\">错误</string>\n    <string name=\"subtitles_remove_captions\">移除隐藏式字幕</string>\n    <string name=\"subtitles_remove_bloat\">移除字幕广告</string>\n    <string name=\"subtitles_filter_lang\">按首选片源语言过滤</string>\n    <string name=\"extras\">附加</string>\n    <string name=\"trailer\">预告片</string>\n    <string name=\"network_adress_example\">播放链接</string>\n    <string name=\"referer\">参考者（可选项）</string>\n    <string name=\"next\">下一个</string>\n    <string name=\"provider_languages_tip\">观看这些语言的视频</string>\n    <string name=\"previous\">上一个</string>\n    <string name=\"skip_setup\">跳过设置向导</string>\n    <string name=\"app_layout_subtext\">更改为适应您的设备的应用布局</string>\n    <string name=\"preferred_media_subtext\">您想要看什么</string>\n    <string name=\"setup_done\">完成</string>\n    <string name=\"extensions\">扩展</string>\n    <string name=\"add_repository\">添加仓库</string>\n    <string name=\"repository_name_hint\">仓库名称（可选）</string>\n    <string name=\"repository_url_hint\">仓库链接或短代码</string>\n    <string name=\"plugin_loaded\">插件已加载</string>\n    <string name=\"plugin_deleted\">插件已删除</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">无法加载 %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">开始下载 %1$d %2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">已下载 %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">全部 %s 已经下载</string>\n    <string name=\"batch_download\">批量下载</string>\n    <string name=\"plugin_singular\">插件</string>\n    <string name=\"plugin\">插件</string>\n    <string name=\"delete_repository_plugins\">这也将删除所有仓库插件</string>\n    <string name=\"delete_repository\">删除仓库</string>\n    <string name=\"setup_extensions_subtext\">下载您所需的片源</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">已下载：%d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">已禁用：%d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">未下载：%d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">已更新 %d 插件</string>\n    <string name=\"blank_repo_message\">CloudStream 默认不安装片源。您需要从仓库中安装片源。\n\\n\n\\n加入我们的 Discord 或在网上搜索。</string>\n    <string name=\"view_public_repositories_button\">查看社区仓库</string>\n    <string name=\"view_public_repositories_button_short\">公开列表</string>\n    <string name=\"uppercase_all_subtitles\">字幕全大写</string>\n    <string name=\"download_all_plugins_from_repo\">警告： CloudStream 对使用第三方插件不承担任何责任，不提供任何支持！</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s（禁用）</string>\n    <string name=\"tracks\">轨道</string>\n    <string name=\"audio_tracks\">音频轨道</string>\n    <string name=\"video_tracks\">视频轨道</string>\n    <string name=\"apply_on_restart\">重启生效。</string>\n    <string name=\"safe_mode_title\">安全模式已启用</string>\n    <string name=\"safe_mode_description\">由于崩溃，所有扩展都已关闭，以帮助您找到导致问题的扩展。</string>\n    <string name=\"safe_mode_crash_info\">查看崩溃信息</string>\n    <string name=\"extension_rating\" formatted=\"true\">评分：%s</string>\n    <string name=\"extension_description\">简介</string>\n    <string name=\"extension_version\">版本</string>\n    <string name=\"extension_status\">状态</string>\n    <string name=\"extension_size\">大小</string>\n    <string name=\"extension_authors\">作者</string>\n    <string name=\"extension_types\">类型</string>\n    <string name=\"extension_language\">语言</string>\n    <string name=\"extension_install_first\">请先安装扩展</string>\n    <string name=\"hls_playlist\">HLS 播放列表</string>\n    <string name=\"player_pref\">首选视频播放器</string>\n    <string name=\"player_settings_play_in_app\">内部播放器</string>\n    <string name=\"app_not_found_error\">未找到应用</string>\n    <string name=\"all_languages_preference\">所有语言</string>\n    <string name=\"skip_type_format\" formatted=\"true\">跳过 %s</string>\n    <string name=\"skip_type_op\">片头</string>\n    <string name=\"skip_type_ed\">片尾</string>\n    <string name=\"skip_type_recap\">前情回顾</string>\n    <string name=\"skip_type_mixed_ed\">混合片尾</string>\n    <string name=\"skip_type_mixed_op\">混合片头</string>\n    <string name=\"skip_type_creddits\">致谢名单</string>\n    <string name=\"skip_type_intro\">介绍</string>\n    <string name=\"clear_history\">清除历史记录</string>\n    <string name=\"history\">历史记录</string>\n    <string name=\"enable_skip_op_from_database_des\">显示跳过片头/片尾弹窗</string>\n    <string name=\"clipboard_too_large\">文本过多，无法保存到剪贴板。</string>\n    <string name=\"action_mark_as_watched\">标记为已观看</string>\n    <string name=\"confirm_exit_dialog\">您确定要离开吗？</string>\n    <string name=\"yes\">是</string>\n    <string name=\"no\">否</string>\n    <string name=\"update_notification_downloading\">正在下载应用更新…</string>\n    <string name=\"update_notification_installing\">正在安装应用更新…</string>\n    <string name=\"update_notification_failed\">无法安装新版的应用</string>\n    <string name=\"automatic_plugin_download_summary\">自动安装已添加的仓库内所有未安装的插件。</string>\n    <string name=\"apk_installer_settings\">APK 安装器</string>\n    <string name=\"apk_installer_settings_des\">部分设备不支持新的软件包安装程序。如果未安装更新，请尝试使用传统选项。</string>\n    <string name=\"apk_installer_legacy\">传统</string>\n    <string name=\"apk_installer_package_installer\">软件包安装程序</string>\n    <string name=\"play_trailer_button\">播放预告片</string>\n    <string name=\"pref_category_ui_features\">功能</string>\n    <string name=\"pref_category_defaults\">默认</string>\n    <string name=\"redo_setup_process\">重置设置向导</string>\n    <string name=\"pref_category_player_layout\">布局</string>\n    <string name=\"pref_category_links\">链接</string>\n    <string name=\"pref_category_extensions\">扩展</string>\n    <string name=\"pref_category_subtitles\">字幕</string>\n    <string name=\"pref_category_app_updates\">应用更新</string>\n    <string name=\"pref_category_backup\">备份</string>\n    <string name=\"pref_category_cache\">缓存</string>\n    <string name=\"pref_category_gestures\">手势</string>\n    <string name=\"pref_category_player_features\">播放器功能</string>\n    <string name=\"pref_category_actions\">行为</string>\n    <string name=\"pref_category_looks\">外观</string>\n    <string name=\"update_started\">更新开始</string>\n    <string name=\"delayed_update_notice\">应用退出后将会更新</string>\n    <string name=\"plugin_downloaded\">插件已下载</string>\n    <string name=\"action_remove_from_watched\">从已观看中移除</string>\n    <string name=\"safe_mode_file\">发现安全模式文件！\n\\n启动时不加载任何扩展，直到文件被删除。</string>\n    <string name=\"browser\">浏览器</string>\n    <string name=\"library\">库</string>\n    <string name=\"sort_by\">排序方式</string>\n    <string name=\"sort\">排序</string>\n    <string name=\"sort_rating_desc\">评分（从高到低）</string>\n    <string name=\"sort_rating_asc\">评分（从低到高）</string>\n    <string name=\"sort_updated_new\">更新（从新到旧）</string>\n    <string name=\"sort_updated_old\">更新（从旧到新）</string>\n    <string name=\"sort_alphabetical_a\">字母排序（从 A 到 Z）</string>\n    <string name=\"sort_alphabetical_z\">字母排序（从 Z 到 A）</string>\n    <string name=\"select_library\">选择库</string>\n    <string name=\"open_with\">打开方式</string>\n    <string name=\"empty_library_no_accounts_message\">您的库是空的 :(\n\\n登录库账户或添加节目到您的本地库。</string>\n    <string name=\"empty_library_logged_in_message\">此列表是空的，请尝试切换到另一个。</string>\n    <string name=\"android_tv_interface_on_seek_settings\">播放器显示 - 快进快退秒数</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">播放器可见时使用的快进快退秒数</string>\n    <string name=\"android_tv_interface_off_seek_settings\">播放器隐藏 - 快进快退秒数</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">播放器隐藏时使用的快进快退秒数</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"test_failed\">失败</string>\n    <string name=\"category_provider_test\">片源测试</string>\n    <string name=\"restart\">重启</string>\n    <string name=\"stop\">停止</string>\n    <string name=\"subscription_in_progress_notification\">正在更新订阅节目</string>\n    <string name=\"subscription_list_name\">已订阅</string>\n    <string name=\"subscription_new\">已订阅 %s</string>\n    <string name=\"subscription_deleted\">已取消订阅 %s</string>\n    <string name=\"start\">开始</string>\n    <string name=\"subscription_episode_released\">第 %d 集已发布！</string>\n    <string name=\"test_passed\">成功</string>\n    <string name=\"test_log\">日志</string>\n    <string name=\"jsdelivr_proxy\">GitHub 代理</string>\n    <string name=\"jsdelivr_enabled\">无法访问 GitHub。正在开启 jsDelivr 代理…</string>\n    <string name=\"jsdelivr_proxy_summary\">使用 jsDelivr 绕过 raw github URL 的封锁。可能会延迟几天的更新。</string>\n    <string name=\"pref_category_bypass\">ISP 绕过</string>\n    <string name=\"revert\">还原</string>\n    <string name=\"watch_quality_pref_data\">首选播放画质（移动数据）</string>\n    <string name=\"profile_number\">简介 %d</string>\n    <string name=\"wifi\">无线网络</string>\n    <string name=\"set_default\">设为默认</string>\n    <string name=\"use\">使用</string>\n    <string name=\"edit\">编辑</string>\n    <string name=\"profiles\">配置文件</string>\n    <string name=\"help\">帮助</string>\n    <string name=\"mobile_data\">移动流量</string>\n    <string name=\"quality_profile_help\">在这里，您可以更改源的排序方式。如果视频具有更高的优先级，它将在源选择中显示得更高。源优先级和质量优先级的总和就是视频优先级。\n\\n\n\\n来源 A：3\n\\n质量 B： 7\n\\n组合视频优先级为 10。\n\\n\n\\n注意：如果总和为 10 或更多，则加载该链接时播放器将自动跳过加载！</string>\n    <string name=\"qualities\">质量</string>\n    <string name=\"profile_background_des\">个人资料背景</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"links_reloaded_toast\">链接已重新加载</string>\n    <string name=\"disable\">禁用</string>\n    <string name=\"pin_error_incorrect\">PIN码不正确，请再试一次。</string>\n    <string name=\"pin_error_length\">PIN码必须为4个字符</string>\n    <string name=\"select_an_account\">选择一个账户</string>\n    <string name=\"manage_accounts\">账户管理</string>\n    <string name=\"action_subscribe\">订阅</string>\n    <string name=\"action_unsubscribe\">取消订阅</string>\n    <string name=\"duplicate_add\">添加</string>\n    <string name=\"duplicate_replace\">替换</string>\n    <string name=\"duplicate_replace_all\">替换全部</string>\n    <string name=\"no_plugins_found_error\">仓库中未找到任何插件</string>\n    <string name=\"rotate_video\">旋转</string>\n    <string name=\"auto_rotate_video\">自动旋转</string>\n    <string name=\"logged_account\" formatted=\"true\">以%s的身份登录</string>\n    <string name=\"use_default_account\">使用默认账户</string>\n    <string name=\"automatic_plugin_download_mode_title\">选择过滤插件的下载模式</string>\n    <string name=\"favorites_list_name\">收藏夹</string>\n    <string name=\"action_remove_from_favorites\">从收藏夹删除</string>\n    <string name=\"enter_current_pin\">输入当前 PIN</string>\n    <string name=\"backup_frequency\">自动备份频率</string>\n    <string name=\"no_repository_found_error\">仓库未找到，请检查你的URL或尝试使用VPN</string>\n    <string name=\"unable_to_inflate\">无法正确的创建用户界面，这是一个重大BUG，应立即报告%s</string>\n    <string name=\"already_voted\">您已投票</string>\n    <string name=\"favorite_added\">%s已添加到收藏夹</string>\n    <string name=\"favorite_removed\">%s已从收藏夹中删除</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">您的资料库中似乎已经存在一个可能相同的项目：\\'%s.\\'\n\\n\n\\n您想添加该项目、替换现有项目还是取消操作？</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">在您的资料库中发现了潜在的重复项目：\n\\n\n\\n%s\n\\n\n\\n您想添加此项目、替换现有项目还是取消操作？</string>\n    <string name=\"enter_pin\">确认PIN</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">输入来自 %s 的 PIN 码</string>\n    <string name=\"lock_profile\">锁定个人资料</string>\n    <string name=\"rotate_video_desc\">显示屏幕方向切换按钮</string>\n    <string name=\"edit_account\">编辑账户</string>\n    <string name=\"duplicate_title\">发现潜在重复</string>\n    <string name=\"action_add_to_favorites\">添加到收藏夹</string>\n    <string name=\"skip_startup_account_select_pref\">启动时跳过账户选择</string>\n    <string name=\"auto_rotate_video_desc\">根据视频方向自动切换屏幕方向</string>\n    <string name=\"subscribe_tooltip\">新剧集通知</string>\n    <string name=\"result_search_tooltip\">在其他扩展中搜索</string>\n    <string name=\"recommendations_tooltip\">显示推荐</string>\n    <string name=\"speed_setting_summary\">在播放器中添加速度选项</string>\n    <string name=\"biometric_unsupported\">这台设备不支持生物验证</string>\n    <string name=\"unfavorite\">不喜欢</string>\n    <string name=\"favorite\">喜欢</string>\n    <string name=\"biometric_authentication_title\">解锁 CloudStream</string>\n    <string name=\"biometric_setting\">使用生物识别技术锁定</string>\n    <string name=\"password_pin_authentication_title\">密码或 PIN 验证</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\n剩余</string>\n    <string name=\"test_extensions\">测试所有扩展</string>\n    <string name=\"toast_copied\">已复制！</string>\n    <string name=\"clipboard_permission_error\">访问剪贴板出错，请重试。</string>\n    <string name=\"app_unrestricted_toast\">应用程序电池使用量已设置为不受限制</string>\n    <string name=\"audio_book_singular\">有声书</string>\n    <string name=\"custom_media_singluar\">媒体</string>\n    <string name=\"battery_dialog_title\">禁用电池最佳化</string>\n    <string name=\"music_singlar\">音乐</string>\n    <string name=\"app_info_intent_error\">无法打开 CloudStream 的应用程序信息。</string>\n    <string name=\"biometric_setting_summary\">使用指纹、面部 ID、PIN 码、图案和密码解锁应用程序。</string>\n    <string name=\"test_extensions_summary\">此测试仅适用于开发人员，不会验证或否认任何扩展的工作。</string>\n    <string name=\"battery_dialog_message\">为了确保已订阅电视节目的不间断下载和通知，CloudStream 需要获得在后台运行的权限。 点击“确定”将显示请求对话框。请按下“允许”。\\n\\n请注意，此权限并不意味着 Cloudstream 3 会耗尽您的电池。 它只会在必要时在后台运行，例如接收通知或从官方扩展下载视频时。</string>\n    <string name=\"biometric_warning\">您的CloudStream数据现已备份。 尽管发生这种情况的可能性非常低，但不同设备的行为都会有所不同。 在极少数情况下，您可能会被锁定而无法访问该应用程序，请完全清除应用程序数据并从备份中恢复。 对于由此造成的任何不便，我们深表歉意。</string>\n    <string name=\"repo_copy_label\">存储库名称和 URL</string>\n    <string name=\"clipboard_unknown_error\">复制错误，请复制 logcat 并联系应用程序支持。</string>\n    <string name=\"ok\">好的</string>\n    <string name=\"reset_btn\">重置</string>\n    <string name=\"biometric_prompt_description\">在多次尝试失败后，提示将关闭。只需重启应用程序再试。</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">即将在 %s</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"player_settings_select_cast_device\">选择投射设备</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">%1$d季%2$d集将在</string>\n    <string name=\"episode_action_cast_mirror\">投射镜像</string>\n    <string name=\"downloads_empty\">目前尚无下载。</string>\n    <string name=\"open_local_video\">打开本地视频</string>\n    <string name=\"pref_category_security\">安全</string>\n    <string name=\"device_pin_url_message\">访问智能手机或电脑上的 <b>%s</b> 并输入上述代码</string>\n    <string name=\"preview_seekbar\">进度条预览</string>\n    <string name=\"preview_seekbar_desc\">启用进度条预览缩略图</string>\n    <string name=\"delete_plugin\">删除插件</string>\n    <string name=\"auth_locally\">本地授权</string>\n    <string name=\"play_from_beginning_img_des\">从头播放</string>\n    <string name=\"qr_image\">二维码图像</string>\n    <string name=\"test_warning\">警告</string>\n    <string name=\"pref_category_accounts\">账户</string>\n    <string name=\"dismiss\">取消</string>\n    <string name=\"open_downloaded_repo\">开源仓库</string>\n    <string name=\"sort_release_date_old\">发布日期（由旧到新）</string>\n    <string name=\"hide_player_control_names\">隐藏播放器控件名称</string>\n    <string name=\"downloads_delete_select\">选择要删除的项</string>\n    <string name=\"offline_file\">可脱机观看</string>\n    <string name=\"select_all\">全选</string>\n    <string name=\"deselect_all\">全不选</string>\n    <string name=\"delete_files\">删除文件</string>\n    <string name=\"delete_format\" formatted=\"true\">删除 (%1$d | %2$s)</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">您确定要永久删除以下项目吗？\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">您确定要永久删除 %1$s中的下述剧集吗？\n\\n\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">您还将永久删除下述系列中的所有剧集：\n\\n\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">您确定要永久删除下述系列的所有剧集吗？\n\\n\n\\n%s</string>\n    <string name=\"sort_release_date_new\">发布日期（从新至旧）</string>\n    <string name=\"device_pin_error_message\">无法获取设备 PIN 码，尝试本地身份验证</string>\n    <string name=\"device_pin_expired_message\">PIN 码现已过期！</string>\n    <string name=\"device_pin_counter_text\">验证码 %1$dm %2$ds 后过期</string>\n    <string name=\"no_subtitles_loaded\">字幕尚未载入</string>\n    <string name=\"custom\">自定义</string>\n    <string name=\"confirm_before_exiting_title\">退出前确认</string>\n    <string name=\"confirm_before_exiting_desc\">退出 App 前弹窗确认</string>\n    <string name=\"show\">显示</string>\n    <string name=\"dont_show\">不显示</string>\n    <string name=\"torrent_info\">这是个 Torrent 的视频，这意味着您的视频活动可以被追踪。\\n请确认您了解 Torrenting 后，再继续。</string>\n    <string name=\"backup_path_title\">备份文件夹位置</string>\n    <string name=\"subs_edge_size\">边缘大小</string>\n    <string name=\"audio_singluar\">音频</string>\n    <string name=\"podcast_singluar\">播客</string>\n    <string name=\"encoding_error\">编码错误</string>\n    <string name=\"unsupported_error\">不受支持的错误</string>\n    <string name=\"player_load_one_subtitle_online\">加载第一个可用的字幕</string>\n    <string name=\"torrent_preferred_media\">在设置/提供者/首选媒体处开启 torrent</string>\n    <string name=\"torrent_not_accepted\">重启应用并接受在线播放 Torrent 弹窗以继续。</string>\n    <string name=\"software_decoding\">软件解码</string>\n    <string name=\"software_decoding_desc\">软件解码让播放器能够播放你的设备所不支持的视频文件，但可能导致播放高分辨率视频时的延迟或不稳定。</string>\n    <string name=\"sort_episodes_number_desc\">集数（降序）</string>\n    <string name=\"sort_episodes_date_oldest\">播放日期（最旧）</string>\n    <string name=\"sort_button_rating\">得分 %s</string>\n    <string name=\"sort_button_date\">日期 %s</string>\n    <string name=\"update_plugins\">更新插件</string>\n    <string name=\"plugins_updated_manually\">成功更新了 %d 个插件！</string>\n    <string name=\"no_plugins_updated_manually\">没有插件被更新。</string>\n    <string name=\"update_plugins_manually\">手动更新插件</string>\n    <string name=\"sort_episodes_number_asc\">集数（升序）</string>\n    <string name=\"sort_episodes_date_newest\">播出日期（最新）</string>\n    <string name=\"sort_episodes_rating_high_low\">评分（最高）</string>\n    <string name=\"sort_episodes_rating_low_high\">评分（最低）</string>\n    <string name=\"sort_button_episode\">第 %s 集</string>\n    <string name=\"starting_plugin_update_manually\">正在开始插件更新过程！</string>\n    <string name=\"player_notification_channel_description\">控制后台播放的播放器通知</string>\n    <string name=\"player_notification_channel_name\">播放器通知</string>\n    <string name=\"begin_speaking\">开始说话…</string>\n    <string name=\"speech_recognition_unavailable\">语音识别不可用</string>\n    <string name=\"subtitles_from_embedded\">内嵌</string>\n    <string name=\"subtitles_from_online\">在线</string>\n    <string name=\"all_subtitles_italic\">让所有字幕变为斜体</string>\n    <string name=\"background_radius\">背景半径</string>\n    <string name=\"all_subtitles_bold\">加粗所有字幕</string>\n    <string name=\"volume_exceeded_100\">音量已经超过 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">再次上滑让音量超过 100%</string>\n    <string name=\"parallel_downloads\">并行下载</string>\n    <string name=\"concurrent_connections\">并发连接</string>\n    <string name=\"overscan_settings_des\">更改屏幕边界</string>\n    <string name=\"overscan_settings\">过扫描</string>\n    <string name=\"go_to_downloads\">转到下载</string>\n    <string name=\"download_parallel_settings_des\">可同时下载多少项目</string>\n    <string name=\"concurrent_connections_settings_des\">每个下载项目下载期间可同时使用多少个连接</string>\n    <string name=\"no_internet_connection\">无互联网连接。\\n\\n请连接到互联网并重试，或者在离线时观看已下载项目。</string>\n    <string name=\"poster_size_settings_des\">更改海报尺寸</string>\n    <string name=\"poster_size_settings\">海报尺寸</string>\n    <string name=\"player_settings_always_ask\">始终询问</string>\n    <string name=\"speedup_title\">长按速度开关</string>\n    <string name=\"speedup_summary\">按住获得 2 倍速</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$d小时 %2$d分钟 %3$d秒</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$d分钟 %2$d秒</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d秒</string>\n    <string name=\"show_rating\">评分标签</string>\n    <string name=\"no_account\">无账户</string>\n    <string name=\"edit_profile_image_title\">编辑个人资料图片</string>\n    <string name=\"edit_profile_image_hint\">输入个人资料图片 URL</string>\n    <string name=\"edit_profile_image_error_empty\">未找到 URL</string>\n    <string name=\"edit_profile_image_error_invalid\">无效 URL 或图片</string>\n    <string name=\"edit_profile_image_success\">成功更新了图片</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">将这一集和之前的标为已观看</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">去除这一集和之前集数的已观看状态</string>\n    <string name=\"action_reload\">已重新加载</string>\n    <string name=\"reload_provider\">重新加载视频源</string>\n    <string name=\"episode_action_play_mirror\">播放镜像</string>\"\n    <string name=\"name\">名称</string>\n    <string name=\"resolution_and_name\">分辨率和名称</string>\n    <string name=\"subs_subtitle_alignment\">字幕对齐</string>\n    <string name=\"bottom_left\">左下</string>\n    <string name=\"bottom_center\">底部居中</string>\n    <string name=\"bottom_right\">右下</string>\n    <string name=\"middle_left\">中左</string>\n    <string name=\"middle_center\">正中</string>\n    <string name=\"middle_right\">中右</string>\n    <string name=\"top_left\">左上</string>\n    <string name=\"top_center\">顶部居中</string>\n    <string name=\"top_right\">右上</string>\n    <string name=\"play_full_series_button\">播放全剧</string>\n    <string name=\"install_prerelease\">安装预发行版</string>\n    <string name=\"prerelease_already_installed\">已安装预发行版。</string>\n    <string name=\"prerelease_install_failed\">安装预发行版失败。</string>\n    <string name=\"show_episode_text\">剧集文本</string>\n    <string name=\"search_suggestions\">搜索建议</string>\n    <string name=\"search_suggestions_des\">输入时显示搜索建议</string>\n    <string name=\"clear_suggestions\">清除建议</string>\n    <string name=\"show_cast_in_details\">显示投屏面板</string>\n    <string name=\"video_info\">媒体信息</string>\n    <string name=\"source_name\">源名称</string>\n    <string name=\"extra_brightness_settings\">额外亮度</string>\n    <string name=\"extra_brightness_settings_des\">超过 100% 亮度时启用亮度过滤器</string>\n    <string name=\"download_queue\">下载队列</string>\n    <string name=\"queue_empty_message\">队列中当前无下载。</string>\n    <string name=\"download_all\">全部下载</string>\n    <string name=\"cancel_all\">全部取消</string>\n    <string name=\"download_episode_range\">要下载第 %s 集吗？</string>\n    <string name=\"cancel_queue_message\">要取消队列中的所有下载吗？</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"other\">%d 个活跃下载</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"other\">队列中有 %d 个下载</item>\n    </plurals>\n    <string name=\"source_priority\">源优先级</string>\n    <string name=\"source_priority_help\">确定在播放器中如何排列视频源的顺序</string>\n    <string name=\"extra_brightness_key\">已启用额外亮度</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-b+zh+TW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s 共 %2$d 集</string>\n    <string name=\"cast_format\" formatted=\"true\">演員：%s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">第 %d 集即將發佈於</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd %2$dh %3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh %2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->\n    <string name=\"result_poster_img_des\">封面</string>\n    <string name=\"search_poster_img_des\">封面</string>\n    <string name=\"episode_poster_img_des\">劇集封面</string>\n    <string name=\"home_main_poster_img_des\">主封面</string>\n    <string name=\"home_next_random_img_des\">隨機下一個</string>\n    <string name=\"go_back_img_des\">返回</string>\n    <string name=\"home_change_provider_img_des\">更改片源</string>\n    <string name=\"preview_background_img_des\">預覽背景</string>\n    <!-- TRANSLATE, BUT DON'T FORGET FORMAT -->\n    <string name=\"player_speed_text_format\" formatted=\"true\">速度（%.2fx）</string>\n    <string name=\"rated_format\" formatted=\"true\">評分：%.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">發現新版本！\n\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">填充</string>\n    <string name=\"duration_format\" formatted=\"true\">%d 分鐘</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">使用 CloudStream 播放</string>\n    <string name=\"title_home\">主畫面</string>\n    <string name=\"title_search\">搜尋</string>\n    <string name=\"title_downloads\">下載</string>\n    <string name=\"title_settings\">設定</string>\n    <string name=\"search_hint\">搜尋…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">搜尋 %s…</string>\n    <string name=\"no_data\">無資料</string>\n    <string name=\"episode_more_options_des\">更多選項</string>\n    <string name=\"next_episode\">下一集</string>\n    <string name=\"result_tags\">類型</string>\n    <string name=\"result_share\">分享</string>\n    <string name=\"result_open_in_browser\">在瀏覽器中打開</string>\n    <string name=\"skip_loading\">跳過載入</string>\n    <string name=\"loading\">載入中…</string>\n    <string name=\"type_watching\">正在觀看</string>\n    <string name=\"type_on_hold\">暫時擱置</string>\n    <string name=\"type_completed\">觀看完畢</string>\n    <string name=\"type_dropped\">放棄觀看</string>\n    <string name=\"type_plan_to_watch\">計畫觀看</string>\n    <string name=\"type_re_watching\">重新觀看</string>\n    <string name=\"play_movie_button\">播放電影</string>\n    <string name=\"play_livestream_button\">播放直播</string>\n    <string name=\"play_torrent_button\">播放種子</string>\n    <string name=\"pick_source\">來源</string>\n    <string name=\"pick_subtitle\">字幕</string>\n    <string name=\"reload_error\">重試連接…</string>\n    <string name=\"go_back\">返回</string>\n    <string name=\"play_episode\">播放劇集</string>\n    <!--<string name=\"need_storage\">允許下載劇集</string>-->\n    <string name=\"download\">下載</string>\n    <string name=\"downloaded\">已下載</string>\n    <string name=\"downloading\">下載中</string>\n    <string name=\"download_paused\">下載暫停</string>\n    <string name=\"download_started\">下載開始</string>\n    <string name=\"download_failed\">下載失敗</string>\n    <string name=\"download_canceled\">下載取消</string>\n    <string name=\"download_done\">下載完畢</string>\n    <string name=\"stream\">網路串流</string>\n    <string name=\"error_loading_links_toast\">載入連結錯誤</string>\n    <string name=\"download_storage_text\">內部儲存空間</string>\n    <string name=\"app_dubbed_text\">配音</string>\n    <string name=\"app_subbed_text\">字幕</string>\n    <string name=\"popup_delete_file\">刪除檔案</string>\n    <string name=\"popup_play_file\">播放檔案</string>\n    <string name=\"popup_resume_download\">繼續下載</string>\n    <string name=\"popup_pause_download\">暫停下載</string>\n    <string name=\"home_more_info\">更多資訊</string>\n    <string name=\"home_expanded_hide\">隱藏</string>\n    <string name=\"home_play\">播放</string>\n    <string name=\"home_info\">資訊</string>\n    <string name=\"filter_bookmarks\">篩選書籤</string>\n    <string name=\"error_bookmarks_text\">書籤</string>\n    <string name=\"action_remove_from_bookmarks\">移除</string>\n    <string name=\"action_add_to_bookmarks\">設定觀看狀態</string>\n    <string name=\"sort_apply\">套用</string>\n    <string name=\"sort_copy\">複製</string>\n    <string name=\"sort_close\">關閉</string>\n    <string name=\"sort_clear\">清除</string>\n    <string name=\"sort_save\">儲存</string>\n    <string name=\"player_speed\">播放速度</string>\n    <string name=\"subtitles_settings\">字幕設定</string>\n    <string name=\"subs_text_color\">字體顏色</string>\n    <string name=\"subs_outline_color\">輪廓顏色</string>\n    <string name=\"subs_background_color\">背景顏色</string>\n    <string name=\"subs_window_color\">視窗顏色</string>\n    <string name=\"subs_edge_type\">邊緣類型</string>\n    <string name=\"subs_subtitle_elevation\">字幕高度</string>\n    <string name=\"subs_font\">字體</string>\n    <string name=\"subs_font_size\">字體大小</string>\n    <string name=\"search_provider_text_providers\">按片源搜尋</string>\n    <string name=\"search_provider_text_types\">按類型搜尋</string>\n    <string name=\"benene_count_text\">送開發者 %d 根香蕉</string>\n    <string name=\"benene_count_text_none\">不送香蕉</string>\n    <string name=\"subs_auto_select_language\">自動選擇語言</string>\n    <string name=\"subs_download_languages\">下載語言</string>\n    <string name=\"subs_subtitle_languages\">字幕語言</string>\n    <string name=\"subs_hold_to_reset_to_default\">按住重設為預設值</string>\n    <string name=\"subs_import_text\" formatted=\"true\">將字體匯入到 %s</string>\n    <string name=\"continue_watching\">繼續觀看</string>\n    <string name=\"action_remove_watching\">移除</string>\n    <string name=\"action_open_watching\">更多資訊</string>\n    <string name=\"action_open_play\">@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">此片源可能需要 VPN 才能正常使用</string>\n    <string name=\"vpn_torrent\">此片源是種子，建議使用 VPN</string>\n    <string name=\"provider_info_meta\">站點不提供元數據，如果站點上不存在元數據，影片載入將失敗。</string>\n    <string name=\"torrent_plot\">簡介</string>\n    <string name=\"normal_no_plot\">未找到簡介</string>\n    <string name=\"torrent_no_plot\">未找到簡介</string>\n    <string name=\"show_log_cat\">顯示 Logcat 🐈</string>\n    <string name=\"picture_in_picture\">字母畫面</string>\n    <string name=\"picture_in_picture_des\">在其他應用程式上的子母畫面中繼續播放</string>\n    <string name=\"player_size_settings\">播放器調整大小按鈕</string>\n    <string name=\"player_size_settings_des\">移除黑色邊框</string>\n    <string name=\"player_subtitles_settings\">字幕</string>\n    <string name=\"player_subtitles_settings_des\">播放器字幕設定</string>\n    <string name=\"chromecast_subtitles_settings\">Chromecast 字幕</string>\n    <string name=\"chromecast_subtitles_settings_des\">Chromecast 字幕設定</string>\n    <string name=\"eigengraumode_settings\">播放速度</string>\n    <string name=\"swipe_to_seek_settings\">活動控制進度</string>\n    <string name=\"swipe_to_seek_settings_des\">從一側滑動到另一側以控制影片中的位置</string>\n    <string name=\"swipe_to_change_settings\">滑動更改設定</string>\n    <string name=\"swipe_to_change_settings_des\">上下滑動更改亮度或音量</string>\n    <string name=\"autoplay_next_settings\">自動播放下一集</string>\n    <string name=\"autoplay_next_settings_des\">播放完畢後播放下一集</string>\n    <string name=\"double_tap_to_seek_settings\">輕按兩下以控制進度</string>\n    <string name=\"double_tap_to_pause_settings\">輕按兩下以暫停</string>\n    <string name=\"double_tap_to_seek_amount_settings\">輕按兩下以控制進度時間（秒）</string>\n    <string name=\"double_tap_to_seek_settings_des\">在右側或左側輕按兩次以向前或向後快轉</string>\n    <string name=\"double_tap_to_pause_settings_des\">輕按兩下中間以暫停</string>\n    <string name=\"use_system_brightness_settings\">使用系統亮度</string>\n    <string name=\"use_system_brightness_settings_des\">在應用程序播放器中使用系統亮度替代黑色遮罩</string>\n    <string name=\"episode_sync_settings\">更新觀看進度</string>\n    <string name=\"episode_sync_settings_des\">自動同步當前劇集進度</string>\n    <string name=\"restore_settings\">從備份中恢復資料</string>\n    <string name=\"backup_settings\">備份資料</string>\n    <string name=\"restore_success\">已載入備份資料</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">無法從 %s 檔案中還原資料</string>\n    <string name=\"backup_success\">已儲存資料</string>\n    <string name=\"backup_failed\">缺少儲存權限，請再試一次。</string>\n    <string name=\"backup_failed_error_format\">備份 %s 錯誤</string>\n    <string name=\"search\">搜尋</string>\n    <string name=\"category_account\">帳戶和安全</string>\n    <string name=\"category_updates\">更新和備份</string>\n    <string name=\"settings_info\">資訊</string>\n    <string name=\"advanced_search\">進階搜尋</string>\n    <string name=\"advanced_search_des\">為您提供按片源分開的搜尋結果</string>\n    <string name=\"show_fillers_settings\">顯示動畫外傳</string>\n    <string name=\"show_trailers_settings\">顯示預告片</string>\n    <string name=\"kitsu_settings\">顯示來自 Kitsu 的封面</string>\n    <string name=\"pref_filter_search_quality\">在搜尋結果中隱藏所選的影片畫質</string>\n    <string name=\"automatic_plugin_updates\">自動更新外掛程式</string>\n    <string name=\"updates_settings\">顯示應用程式更新</string>\n    <string name=\"updates_settings_des\">啟動應用程式後自動搜尋更新。</string>\n    <string name=\"github\">Github</string>\n    <string name=\"lightnovel\">由相同開發者開發的輕小說應用程式</string>\n    <string name=\"anim\">由相同開發者開發的動漫應用程式</string>\n    <string name=\"discord\">加入 Discord</string>\n    <string name=\"benene\">送開發者一根香蕉</string>\n    <string name=\"benene_des\">送香蕉</string>\n    <string name=\"app_language\">應用程式語言</string>\n    <string name=\"no_chromecast_support_toast\">此片源不支援 Chromecast</string>\n    <string name=\"no_links_found_toast\">未找到連結</string>\n    <string name=\"copy_link_toast\">連結已複製到剪貼簿</string>\n    <string name=\"play_episode_toast\">播放劇集</string>\n    <string name=\"subs_default_reset_toast\">重設為預設值</string>\n    <string name=\"season\">季</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">無季</string>\n    <string name=\"episode\">集</string>\n    <string name=\"episodes\">集</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"season_short\">S</string>\n    <string name=\"episode_short\">E</string>\n    <string name=\"no_episodes_found\">未找到劇集</string>\n    <string name=\"delete_file\">刪除檔案</string>\n    <string name=\"delete\">刪除</string>\n    <string name=\"cancel\">取消</string>\n    <string name=\"pause\">暫停</string>\n    <string name=\"resume\">繼續</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">這將永遠刪除 %s\n\\n你確定嗎?</string>\n    <string name=\"resume_time_left\" formatted=\"true\">剩下\n\\n%d 分鐘</string>\n    <string name=\"status_ongoing\">連載中</string>\n    <string name=\"status_completed\">已完結</string>\n    <string name=\"status\">狀態</string>\n    <string name=\"year\">年份</string>\n    <string name=\"rating\">評分</string>\n    <string name=\"duration\">時間</string>\n    <string name=\"site\">網站</string>\n    <string name=\"synopsis\">簡介</string>\n    <string name=\"queued\">已加入佇列</string>\n    <string name=\"no_subtitles\">無字幕</string>\n    <string name=\"action_default\">預設</string>\n    <string name=\"free_storage\">空閒</string>\n    <string name=\"used_storage\">已使用</string>\n    <string name=\"app_storage\">應用程式</string>\n    <!--plural-->\n    <string name=\"movies\">電影</string>\n    <string name=\"tv_series\">電視劇</string>\n    <string name=\"cartoons\">卡通</string>\n    <string name=\"anime\">動漫</string>\n    <string name=\"torrent\">種子</string>\n    <string name=\"documentaries\">紀錄片</string>\n    <string name=\"ova\">原創動畫錄影帶</string>\n    <string name=\"asian_drama\">亞洲劇</string>\n    <string name=\"livestreams\">直播</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">其他</string>\n    <!--singular-->\n    <string name=\"movies_singular\">電影</string>\n    <string name=\"tv_series_singular\">電視劇</string>\n    <string name=\"cartoons_singular\">卡通</string>\n    <string name=\"anime_singular\">動畫</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">種子</string>\n    <string name=\"documentaries_singular\">紀錄片</string>\n    <string name=\"asian_drama_singular\">亞洲劇</string>\n    <string name=\"live_singular\">直播</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">其他</string>\n    <string name=\"source_error\">來源錯誤</string>\n    <string name=\"remote_error\">遠端錯誤</string>\n    <string name=\"render_error\">算繪器錯誤</string>\n    <string name=\"unexpected_error\">意料之外的播放器錯誤</string>\n    <string name=\"storage_error\">下載錯誤，請檢查儲存權限</string>\n    <string name=\"episode_action_chromecast_episode\">Chromecast 劇集</string>\n    <string name=\"episode_action_chromecast_mirror\">Chromecast 鏡像</string>\n    <string name=\"episode_action_play_in_app\">在應用程式中播放</string>\n    <string name=\"episode_action_play_in_format\">在 %s 中播放</string>\n    <string name=\"episode_action_auto_download\">自動下載</string>\n    <string name=\"episode_action_download_mirror\">下載鏡像</string>\n    <string name=\"episode_action_reload_links\">重新載入連結</string>\n    <string name=\"episode_action_download_subtitle\">下載字幕</string>\n    <string name=\"show_hd\">畫質標籤</string>\n    <string name=\"show_dub\">配音標籤</string>\n    <string name=\"show_sub\">字幕標籤</string>\n    <string name=\"show_title\">標題</string>\n    <string name=\"poster_ui_settings\">封面內容</string>\n    <string name=\"no_update_found\">未找到更新</string>\n    <string name=\"check_for_update\">檢查更新</string>\n    <string name=\"video_lock\">鎖定</string>\n    <string name=\"video_aspect_ratio_resize\">調整大小</string>\n    <string name=\"video_source\">來源</string>\n    <string name=\"video_skip_op\">跳過片頭</string>\n    <string name=\"dont_show_again\">不再顯示</string>\n    <string name=\"skip_update\">跳過此更新</string>\n    <string name=\"update\">更新</string>\n    <string name=\"watch_quality_pref\">偏好播放畫質 (WiFi)</string>\n    <string name=\"limit_title\">影片播放器標題最大字數</string>\n    <string name=\"limit_title_rez\">影片播放器標題</string>\n    <string name=\"video_buffer_size_settings\">影片緩衝大小</string>\n    <string name=\"video_buffer_length_settings\">影片緩衝長度</string>\n    <string name=\"video_buffer_disk_settings\">磁碟上的影片快取</string>\n    <string name=\"video_buffer_clear_settings\">清除影片和圖片快取</string>\n    <string name=\"video_ram_description\">如果在記憶體不足的裝置（例如 Android TV）上設定得太高會導致程式崩潰。</string>\n    <string name=\"video_disk_description\">如果在儲存空間較小的裝置（例如 Android TV）上設定過高會導致問題。</string>\n    <string name=\"dns_pref\">DNS over HTTPS</string>\n    <string name=\"dns_pref_summary\">用於繞過網路服務供應商的封鎖</string>\n    <string name=\"add_site_pref\">複製片源</string>\n    <string name=\"remove_site_pref\">移除片源</string>\n    <string name=\"add_site_summary\">使用不同的 URL 新增現有站點的複製</string>\n    <string name=\"download_path_pref\">下載路徑</string>\n    <string name=\"nginx_url_pref\">NGINX 伺服器 URL</string>\n    <string name=\"display_subbed_dubbed_settings\">顯示有配音/字幕的動漫</string>\n    <string name=\"resize_fit\">適應螢幕</string>\n    <string name=\"resize_fill\">拉伸</string>\n    <string name=\"resize_zoom\">縮放</string>\n    <string name=\"legal_notice\">免責聲明</string>\n    <string name=\"category_general\">通用</string>\n    <string name=\"random_button_settings\">隨機按鈕</string>\n    <string name=\"random_button_settings_desc\">在主畫面與媒體庫中顯示隨機按鈕</string>\n    <string name=\"provider_lang_settings\">擴充功能語言</string>\n    <string name=\"app_layout\">應用程式版面配置</string>\n    <string name=\"preferred_media_settings\">偏好類型</string>\n    <string name=\"enable_nsfw_on_providers\">在支援的擴充功能上啟用 NSFW</string>\n    <string name=\"subtitles_encoding\">字幕編碼</string>\n    <string name=\"category_providers\">片源</string>\n    <string name=\"category_ui\">佈局</string>\n    <string name=\"automatic\">自動</string>\n    <string name=\"tv_layout\">電視版面配置</string>\n    <string name=\"phone_layout\">手機版面配置</string>\n    <string name=\"emulator_layout\">模擬器版面配置</string>\n    <string name=\"primary_color_settings\">主題色</string>\n    <string name=\"app_theme_settings\">應用程式主題</string>\n    <string name=\"bottom_title_settings\">封面標題位置</string>\n    <string name=\"bottom_title_settings_des\">將標題移到封面下方</string>\n    <!-- account stuff -->\n    <string name=\"example_password\">密碼</string>\n    <string name=\"example_username\">使用者名稱</string>\n    <string name=\"example_email\">電子郵件</string>\n    <string name=\"example_ip\">IP</string>\n    <string name=\"example_site_name\">新網站名稱</string>\n    <string name=\"example_site_url\">https://example.com</string>\n    <string name=\"example_lang_name\">語言代號 (zh_TW)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s %2$s</string>\n    <string name=\"account\">帳號</string>\n    <string name=\"logout\">登出</string>\n    <string name=\"login\">登入</string>\n    <string name=\"switch_account\">切換帳號</string>\n    <string name=\"add_account\">新增帳號</string>\n    <string name=\"create_account\">建立帳號</string>\n    <string name=\"add_sync\">加入同步</string>\n    <string name=\"added_sync_format\" formatted=\"true\">已新增 %s</string>\n    <string name=\"upload_sync\">同步</string>\n    <string name=\"sync_score\">評分</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s 已驗證</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">無法在 %s 登入</string>\n    <!-- ============ -->\n    <string name=\"none\">無</string>\n    <string name=\"normal\">普通</string>\n    <string name=\"all\">全部</string>\n    <string name=\"max\">最大</string>\n    <string name=\"min\">最小</string>\n    <string name=\"subtitles_outline\">輪廓</string>\n    <string name=\"subtitles_depressed\">凹陷</string>\n    <string name=\"subtitles_shadow\">陰影</string>\n    <string name=\"subtitles_raised\">凸出</string>\n    <string name=\"subtitle_offset\">同步字幕</string>\n    <string name=\"subtitle_offset_hint\">1000 毫秒</string>\n    <string name=\"subtitle_offset_title\">字幕延遲</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">如果字幕提早 %d 毫秒顯示，請使用此選項</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">如果字幕延遲 %d 毫秒顯示，請使用此選項</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">無字幕延遲</string>\n    <!--\n    Example text (pangram) can optionally be translated; if you do, include all the letters in the alphabet,\n    see: \n\thttps://en.wikipedia.org/w/index.php?title=Pangram&oldid=225849300\n\thttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog\n    -->\n    <string name=\"subtitles_example_text\">The quick brown fox jumps over the lazy dog</string>\n    <string name=\"recommended\">推薦</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">已載入 %s</string>\n    <string name=\"player_load_subtitles\">從檔案載入</string>\n    <string name=\"player_load_subtitles_online\">從網路載入</string>\n    <string name=\"downloaded_file\">下載的檔案</string>\n    <string name=\"actor_main\">主角</string>\n    <string name=\"actor_supporting\">配角</string>\n    <string name=\"actor_background\">群演</string>\n    <string name=\"home_source\">來源</string>\n    <string name=\"home_random\">隨機</string>\n    <string name=\"coming_soon\">即將到來…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">封面圖片</string>\n    <string name=\"category_player\">播放器</string>\n    <string name=\"resolution_and_title\">解析度與標題</string>\n    <string name=\"title\">標題</string>\n    <string name=\"resolution\">解析度</string>\n    <string name=\"error_invalid_id\">無效 ID</string>\n    <string name=\"error_invalid_data\">無效資料</string>\n    <string name=\"error_invalid_url\">無效 URL</string>\n    <string name=\"error\">錯誤</string>\n    <string name=\"subtitles_remove_captions\">移除隱藏式字幕</string>\n    <string name=\"subtitles_remove_bloat\">移除字幕廣告</string>\n    <string name=\"subtitles_filter_lang\">按偏好的片源語言篩選</string>\n    <string name=\"extras\">附加</string>\n    <string name=\"trailer\">預告片</string>\n    <string name=\"network_adress_example\">https://example.com/example.mp4</string>\n    <string name=\"referer\">推薦人（選填）</string>\n    <string name=\"next\">下一個</string>\n    <string name=\"provider_languages_tip\">觀看這些語言的影片</string>\n    <string name=\"previous\">上一個</string>\n    <string name=\"skip_setup\">跳過設定</string>\n    <string name=\"app_layout_subtext\">更改應用程式的外觀以適應你的設備</string>\n    <string name=\"preferred_media_subtext\">你想要看什麼</string>\n    <string name=\"setup_done\">完成</string>\n    <string name=\"extensions\">擴充功能</string>\n    <string name=\"add_repository\">新增資源庫</string>\n    <string name=\"repository_name_hint\">資源庫名稱（選填）</string>\n    <string name=\"repository_url_hint\">資源庫 URL 或簡碼</string>\n    <string name=\"plugin_loaded\">外掛程式已載入</string>\n    <string name=\"plugin_deleted\">外掛程式已刪除</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">無法載入 %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">開始下載 %1$d %2$s …</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">已下載 %1$d %2$s</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">全部 %s 已經下載</string>\n    <string name=\"batch_download\">批次下載</string>\n    <string name=\"plugin_singular\">外掛程式</string>\n    <string name=\"plugin\">外掛程式</string>\n    <string name=\"delete_repository_plugins\">這也將刪除所有在資源庫中的外掛程式</string>\n    <string name=\"delete_repository\">刪除資源庫</string>\n    <string name=\"setup_extensions_subtext\">下載你所需的片源</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">已下載：%d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">已停用：%d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">未下載：%d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">已更新 %d 外掛程式</string>\n    <string name=\"blank_repo_message\">CloudStream 預設沒有安裝網站。你需要從儲存庫安裝網站。\n\\n\n\\n加入我們的 Discord 或在網路上搜尋。</string>\n    <string name=\"view_public_repositories_button\">查看</string>\n    <string name=\"view_public_repositories_button_short\">公開清單</string>\n    <string name=\"uppercase_all_subtitles\">字幕全大寫</string>\n    <string name=\"download_all_plugins_from_repo\">警告：CloudStream 3 不對使用第三方擴充功能承擔任何責任，也不提供任何支援！</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s （停用）</string>\n    <string name=\"tracks\">軌道</string>\n    <string name=\"audio_tracks\">音頻軌道</string>\n    <string name=\"video_tracks\">影片軌道</string>\n    <string name=\"apply_on_restart\">重新啟動應用程式以查看變更。</string>\n    <string name=\"safe_mode_title\">安全模式已啟用</string>\n    <string name=\"safe_mode_description\">由於程式崩潰，所有外掛程式皆已關閉，以協助您找到導致問題的程式。</string>\n    <string name=\"safe_mode_crash_info\">查看程式崩潰資訊</string>\n    <string name=\"extension_rating\" formatted=\"true\">評分：%s</string>\n    <string name=\"extension_description\">簡介</string>\n    <string name=\"extension_version\">版本</string>\n    <string name=\"extension_status\">狀態</string>\n    <string name=\"extension_size\">大小</string>\n    <string name=\"extension_authors\">作者</string>\n    <string name=\"extension_types\">類型</string>\n    <string name=\"extension_language\">語言</string>\n    <string name=\"extension_install_first\">請先安裝外掛程式</string>\n    <string name=\"hls_playlist\">HLS 播放清單</string>\n    <string name=\"player_pref\">偏好影片播放器</string>\n    <string name=\"player_settings_play_in_app\">內部播放器</string>\n    <string name=\"app_not_found_error\">未找到應用程式</string>\n    <string name=\"all_languages_preference\">所有語言</string>\n    <string name=\"skip_type_format\" formatted=\"true\">跳過 %s</string>\n    <string name=\"skip_type_op\">片頭</string>\n    <string name=\"skip_type_ed\">片尾</string>\n    <string name=\"skip_type_recap\">前情回顧</string>\n    <string name=\"skip_type_mixed_ed\">混合片尾</string>\n    <string name=\"skip_type_mixed_op\">混合片頭</string>\n    <string name=\"skip_type_creddits\">致謝名單</string>\n    <string name=\"skip_type_intro\">介紹</string>\n    <string name=\"clear_history\">清除歷史紀錄</string>\n    <string name=\"history\">歷史紀錄</string>\n    <string name=\"automatic_plugin_download\">自動下載外掛程式</string>\n    <string name=\"confirm_exit_dialog\">你確定要離開？</string>\n    <string name=\"automatic_plugin_download_summary\">從新增的資源庫自動安裝所有尚未安裝的外掛程式。</string>\n    <string name=\"enable_skip_op_from_database_des\">在開始/結束顯示跳過彈出視窗</string>\n    <string name=\"update_notification_failed\">無法安裝新版本的應用程式</string>\n    <string name=\"apk_installer_settings\">APK 安裝器</string>\n    <string name=\"apk_installer_settings_des\">有些手機不支援新的軟體包安裝程式。 如果未安裝更新，請嘗試使用舊版選項。</string>\n    <string name=\"clipboard_too_large\">文字太多。 無法儲存到剪貼簿。</string>\n    <string name=\"yes\">是</string>\n    <string name=\"update_notification_downloading\">正在下載應用程式更新…</string>\n    <string name=\"update_notification_installing\">正在安裝應用程式更新…</string>\n    <string name=\"apk_installer_package_installer\">套件安裝程式</string>\n    <string name=\"action_mark_as_watched\">標記為已觀看</string>\n    <string name=\"no\">否</string>\n    <string name=\"apk_installer_legacy\">傳統</string>\n    <string name=\"pref_category_player_features\">播放器功能</string>\n    <string name=\"pref_category_subtitles\">字幕</string>\n    <string name=\"play_trailer_button\">播放預告片</string>\n    <string name=\"redo_setup_process\">重設設定過程</string>\n    <string name=\"pref_category_links\">連結</string>\n    <string name=\"pref_category_app_updates\">應用程式更新</string>\n    <string name=\"pref_category_backup\">備份</string>\n    <string name=\"pref_category_extensions\">擴充功能</string>\n    <string name=\"pref_category_actions\">動作</string>\n    <string name=\"pref_category_cache\">快取</string>\n    <string name=\"pref_category_gestures\">手勢</string>\n    <string name=\"pref_category_player_layout\">版面</string>\n    <string name=\"pref_category_defaults\">預設</string>\n    <string name=\"pref_category_looks\">外觀</string>\n    <string name=\"pref_category_ui_features\">功能</string>\n    <string name=\"browser\">瀏覽器</string>\n    <string name=\"subscription_episode_released\">第 %d 集已發行！</string>\n    <string name=\"library\">媒體庫</string>\n    <string name=\"start\">開始</string>\n    <string name=\"android_tv_interface_on_seek_settings\">播放器顯示 - 快轉快退秒數</string>\n    <string name=\"open_with\">開啟方式</string>\n    <string name=\"delayed_update_notice\">應用程式將在關閉時更新</string>\n    <string name=\"sort_rating_asc\">評分（從低到高）</string>\n    <string name=\"update_started\">更新開始</string>\n    <string name=\"plugin_downloaded\">外掛程式已下載</string>\n    <string name=\"action_remove_from_watched\">從已觀看清單中刪除</string>\n    <string name=\"sort_by\">排序方式</string>\n    <string name=\"sort\">排序</string>\n    <string name=\"sort_rating_desc\">評分（從高到低）</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">播放器可見時使用的快轉快退秒數</string>\n    <string name=\"android_tv_interface_off_seek_settings\">播放器隱藏 - 快轉快退秒數</string>\n    <string name=\"sort_updated_new\">更新（從新到舊）</string>\n    <string name=\"sort_updated_old\">更新（從舊到新）</string>\n    <string name=\"sort_alphabetical_a\">按字母順序（A 到 Z）</string>\n    <string name=\"sort_alphabetical_z\">按字母順序（Z 到 A）</string>\n    <string name=\"select_library\">選擇媒體庫</string>\n    <string name=\"safe_mode_file\">找到安全模式檔案！\n\\n在刪除此檔案之前，將不會在啟動時載入任何擴充功能。</string>\n    <string name=\"test_log\">日誌</string>\n    <string name=\"test_failed\">失敗</string>\n    <string name=\"test_passed\">通過</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">播放器隱藏時使用的快轉快退秒數</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"category_provider_test\">片源測試</string>\n    <string name=\"restart\">重新啟動</string>\n    <string name=\"stop\">停止</string>\n    <string name=\"subscription_list_name\">訂閱</string>\n    <string name=\"subscription_new\">已訂閱 %s</string>\n    <string name=\"subscription_deleted\">已取消訂閱 %s</string>\n    <string name=\"watch_quality_pref_data\">偏好播放畫質 (行動數據)</string>\n    <string name=\"jsdelivr_proxy\">GitHub 代理</string>\n    <string name=\"pref_category_bypass\">繞過 ISP</string>\n    <string name=\"revert\">還原</string>\n    <string name=\"jsdelivr_enabled\">無法存取 GitHub。 正在開啟 jsDelivr proxy…</string>\n    <string name=\"jsdelivr_proxy_summary\">使用 jsDelivr 繞過直接使用 GitHub 網址時的存取封鎖。 可能導致更新延遲數天。</string>\n    <string name=\"empty_library_no_accounts_message\">您的媒體庫是空的 :(\n\\n登入媒體庫帳號或將節目新增到您本機的媒體庫。</string>\n    <string name=\"empty_library_logged_in_message\">您的媒體庫是空的。可嘗試以不同的帳號登入。</string>\n    <string name=\"subscription_in_progress_notification\">正在更新訂閱節目</string>\n    <string name=\"backup_frequency\">備份頻率</string>\n    <string name=\"favorite_removed\">%s 已由我的最愛移除</string>\n    <string name=\"favorites_list_name\">我的最愛</string>\n    <string name=\"favorite_added\">%s 已加入我的最愛</string>\n    <string name=\"logged_account\" formatted=\"true\">以 %s 的身分登入</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">您的媒體庫中似乎有多個重覆的項目：\n\\n\n\\n%s\n\\n\n\\n您要強制加入、取代已有項目、還是取消操作？</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">輸入 %s 的 PIN 碼</string>\n    <string name=\"mobile_data\">行動數據</string>\n    <string name=\"duplicate_title\">找到可能重覆的項目</string>\n    <string name=\"lock_profile\">鎖定設定檔</string>\n    <string name=\"use_default_account\">使用預設帳號</string>\n    <string name=\"skip_startup_account_select_pref\">啟動時略過選擇帳號</string>\n    <string name=\"action_add_to_favorites\">加入我的最愛</string>\n    <string name=\"manage_accounts\">管理帳號</string>\n    <string name=\"profiles\">設定檔</string>\n    <string name=\"unable_to_inflate\">無法正確建立使用者介面，這是重大的程式錯誤，請立即回報 %s</string>\n    <string name=\"edit\">編輯</string>\n    <string name=\"duplicate_replace_all\">全部取代</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"profile_background_des\">設定檔背景</string>\n    <string name=\"help\">說明</string>\n    <string name=\"edit_account\">編輯帳號</string>\n    <string name=\"pin_error_incorrect\">PIN 碼不符，請再試一次。</string>\n    <string name=\"profile_number\">設定檔 %d</string>\n    <string name=\"action_unsubscribe\">取消訂閱</string>\n    <string name=\"pin_error_length\">PIN 碼需為 4 個字元</string>\n    <string name=\"duplicate_replace\">取代</string>\n    <string name=\"duplicate_add\">加入</string>\n    <string name=\"action_subscribe\">訂閱</string>\n    <string name=\"qualities\">品質</string>\n    <string name=\"use\">使用</string>\n    <string name=\"action_remove_from_favorites\">由我的最愛移除</string>\n    <string name=\"select_an_account\">選擇帳號</string>\n    <string name=\"disable\">停用</string>\n    <string name=\"no_repository_found_error\">找不到資源庫，請檢查網址與 VPN 設定</string>\n    <string name=\"already_voted\">您已完成投票</string>\n    <string name=\"no_plugins_found_error\">在資源庫中找不到外掛程式</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">您的媒體庫中似乎有重覆的項目：「%s」。\n\\n\n\\n您要強制加入、取代已有項目、還是取消操作？</string>\n    <string name=\"set_default\">設回預設</string>\n    <string name=\"enter_pin\">輸入 PIN 碼</string>\n    <string name=\"pin\">PIN 碼</string>\n    <string name=\"quality_profile_help\">您可在此調整來源的排序方式。具有愈小的優先值的影片，在來源選擇中顯示得愈前面。來源優先值與品質優先值的加總就是影片優先值。\n\\n例如：\n\\n來源 A：3\n\\n品質 B： 7\n\\n則該來源的影片優先值為 10。\n\\n\n\\n注意：如果加總達到 10 或更高，則載入該連結時播放器將自動跳過載入！</string>\n    <string name=\"enter_current_pin\">輸入目前的 PIN 碼</string>\n    <string name=\"rotate_video_desc\">顯示切換畫面方向的按鈕</string>\n    <string name=\"automatic_plugin_download_mode_title\">選擇篩選外掛程式下載的模式</string>\n    <string name=\"auto_rotate_video\">自動旋轉</string>\n    <string name=\"rotate_video\">旋轉</string>\n    <string name=\"auto_rotate_video_desc\">根據影片方向自動切換畫面方向</string>\n    <string name=\"links_reloaded_toast\">連結已重新載入</string>\n    <string name=\"repo_copy_label\">儲存庫名稱和網址</string>\n    <string name=\"toast_copied\">已複製！</string>\n    <string name=\"favorite\">喜歡</string>\n    <string name=\"unfavorite\">不喜歡</string>\n    <string name=\"biometric_setting\">使用生物辨識技術鎖定</string>\n    <string name=\"app_unrestricted_toast\">應用程式電池使用已設定為無限制</string>\n    <string name=\"biometric_authentication_title\">解除鎖定 CloudStream</string>\n    <string name=\"custom_media_singluar\">媒體</string>\n    <string name=\"reset_btn\">重置</string>\n    <string name=\"recommendations_tooltip\">顯示推薦</string>\n    <string name=\"speed_setting_summary\">在播放器中新增速度選項</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">即將在 %s 推出</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\n\\n剩餘</string>\n    <string name=\"test_extensions\">測試所有擴充功能</string>\n    <string name=\"battery_dialog_title\">停用電池優化</string>\n    <string name=\"audio_book_singular\">有聲書</string>\n    <string name=\"music_singlar\">音樂</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">第 %1$d 季第 %2$d 集即將發佈於</string>\n    <string name=\"result_search_tooltip\">在其他擴充功能中搜尋</string>\n    <string name=\"subscribe_tooltip\">新集數通知</string>\n    <string name=\"episode_action_cast_mirror\">投放鏡像</string>\n    <string name=\"player_settings_select_cast_device\">選擇投放裝置</string>\n    <string name=\"ok\">好的</string>\n    <string name=\"password_pin_authentication_title\">密碼／PIN 驗證</string>\n    <string name=\"biometric_setting_summary\">使用指紋、面容 ID、PIN、圖案和密碼解除鎖定應用程式。</string>\n    <string name=\"biometric_prompt_description\">多次嘗試失敗後，此提示將會關閉。只需重新啟動應用程式即可再次嘗試。</string>\n    <string name=\"clipboard_permission_error\">剪貼簿存取失敗，請再試一次。</string>\n    <string name=\"clipboard_unknown_error\">複製失敗，請複製 logcat 內容並聯繫應用程式支援者。</string>\n    <string name=\"app_info_intent_error\">無法開啟 CloudStream 的應用程式資訊頁面。</string>\n    <string name=\"biometric_warning\">您的 CloudStream 資料已完成備份。儘管可能性非常低，但因不同裝置的行為都有所不同，在極少數情況下，您可能會無法存取本應用程式。此時請完全清除本應用程式的資料，再使用已有的備份進行還原。若因此造成任何不便，我們深感抱歉。</string>\n    <string name=\"test_extensions_summary\">此測試是供開發人員參考，而不是用以驗證任何擴充功能的正常運作與否。</string>\n    <string name=\"battery_dialog_message\">為了確保下載與通知已訂閱的電視節目的不間斷，CloudStream 需要取得在背景執行的權限。若點選「確定」，將移至「應用程式資訊」，請找到「應用程式電池使用」並將電池用量設置為「無限制」。請注意，取得此權限並不表示 CS3 會明顯增加電池用量，而是只在必要時在背景執行，例如取得通知或使用官方擴充功能下載影片時。若選擇「取消」，您可以稍後在「一般設定」中調整此設定。</string>\n    <string name=\"cs3wiki\">CloudStream Wiki</string>\n    <string name=\"biometric_unsupported\">此裝置不支援生物特徵認證</string>\n    <string name=\"device_pin_error_message\">無法取得裝置 PIN 碼，請嘗試本機驗證</string>\n    <string name=\"delete_plugin\">刪除外掛程式</string>\n    <string name=\"open_downloaded_repo\">開啟資源庫</string>\n    <string name=\"device_pin_expired_message\">PIN 碼已過期！</string>\n    <string name=\"device_pin_counter_text\">驗證碼將在 %1$d 分 %2$d 秒後過期</string>\n    <string name=\"sort_release_date_new\">發行日期（由新到舊）</string>\n    <string name=\"sort_release_date_old\">發行日期（由舊到新）</string>\n    <string name=\"hide_player_control_names\">隱藏播放器控制項名稱</string>\n    <string name=\"preview_seekbar\">進度條預覽</string>\n    <string name=\"preview_seekbar_desc\">啟用進度條上的預覽縮圖</string>\n    <string name=\"downloads_empty\">目前沒有任何下載。</string>\n    <string name=\"auth_locally\">本機驗證</string>\n    <string name=\"dismiss\">關閉</string>\n    <string name=\"backup_path_title\">備份資料夾位置</string>\n    <string name=\"custom\">自訂</string>\n    <string name=\"confirm_before_exiting_desc\">退出應用程式前顯示對話框</string>\n    <string name=\"show\">顯示</string>\n    <string name=\"dont_show\">不顯示</string>\n    <string name=\"qr_image\">QR Code 圖片</string>\n    <string name=\"device_pin_url_message\">請在您的智慧型手機或電腦上造訪 <b>%s</b> 並輸入上方的驗證碼</string>\n    <string name=\"test_warning\">警告</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">您也將永久刪除以下系列中的所有集數：\\n\\n%s</string>\n    <string name=\"confirm_before_exiting_title\">退出前確認</string>\n    <string name=\"pref_category_accounts\">帳號</string>\n    <string name=\"open_local_video\">開啟本機影片</string>\n    <string name=\"play_from_beginning_img_des\">從頭開始播放</string>\n    <string name=\"downloads_delete_select\">選擇要刪除的項目</string>\n    <string name=\"offline_file\">可離線觀看</string>\n    <string name=\"select_all\">全選</string>\n    <string name=\"deselect_all\">取消全選</string>\n    <string name=\"delete_files\">刪除檔案</string>\n    <string name=\"delete_format\" formatted=\"true\">刪除（%1$d | %2$s）</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">您確定要永久刪除以下項目嗎？\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">您確定要永久刪除 %1$s 中的以下集數嗎？\\n\\n%2$s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">您確定要永久刪除以下系列中的所有集數嗎？\\n\\n%s</string>\n    <string name=\"pref_category_security\">安全</string>\n    <string name=\"no_subtitles_loaded\">尚未載入字幕</string>\n    <string name=\"torrent_info\">此影片是 Torrent，這意味著你的影片活動可以被追蹤。\\n在繼續之前，請確保你瞭解 Torrenting。</string>\n    <string name=\"subs_edge_size\">subs_edge_size</string>\n    <string name=\"audio_singluar\">音樂</string>\n    <string name=\"encoding_error\">編碼錯誤</string>\n    <string name=\"unsupported_error\">因為不支持造成的錯誤</string>\n    <string name=\"podcast_singluar\">播客</string>\n    <string name=\"software_decoding\">軟體解碼</string>\n    <string name=\"torrent_not_accepted\">不接受的種子</string>\n    <string name=\"player_load_one_subtitle_online\">載入第一個可用的</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$s серыя %2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Склад: %s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">Серыя %d будзе выпушчана праз</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">Серыя %2$d сезона %1$d будзе выпушчана праз</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$d д %2$d гадз %3$d хв</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$d гадз %2$d хв</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%d м</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$d гадз %2$d хв %3$d с</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$d хв %2$d с</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$d с</string>\n    <string name=\"result_poster_img_des\">Плакат</string>\n    <string name=\"search_poster_img_des\">Плакат</string>\n    <string name=\"episode_poster_img_des\">Плакат серыі</string>\n    <string name=\"home_main_poster_img_des\">Асноўны плакат</string>\n    <string name=\"home_next_random_img_des\">Наступны выпадковы</string>\n    <string name=\"go_back_img_des\">Назад</string>\n    <string name=\"play_from_beginning_img_des\">Прайграць з пачатку</string>\n    <string name=\"home_change_provider_img_des\">Змяніць пастаўшчыка</string>\n    <string name=\"preview_background_img_des\">Перадпрагляд фону</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Хуткасць (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Ацэнка: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">Знойдзена новае абнаўленне!\\n%1$s -&gt; %2$s</string>\n    <string name=\"filler\" formatted=\"true\">Запаўняльнік</string>\n    <string name=\"duration_format\" formatted=\"true\">%d хвіл</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Прайграць праз CloudStream</string>\n    <string name=\"title_home\">Дамашняя</string>\n    <string name=\"title_search\">Пошук</string>\n    <string name=\"title_downloads\">Спампоўкі</string>\n    <string name=\"title_settings\">Налады</string>\n    <string name=\"search_hint\">Шукаць…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Шукаць па %s…</string>\n    <string name=\"speech_recognition_unavailable\">Распазнаванне маўлення недаступна</string>\n    <string name=\"begin_speaking\">Пачніце размаўляць…</string>\n    <string name=\"no_data\">Няма даных</string>\n    <string name=\"episode_more_options_des\">Больш параметраў</string>\n    <string name=\"next_episode\">Наступная серыя</string>\n    <string name=\"result_tags\">Жанры</string>\n    <string name=\"result_share\">Абагуліць</string>\n    <string name=\"result_open_in_browser\">Адкрыць у браўзеры</string>\n    <string name=\"browser\">Браўзер</string>\n    <string name=\"skip_loading\">Прапусціць загрузку</string>\n    <string name=\"loading\">Загрузка…</string>\n    <string name=\"type_watching\">Гляджу</string>\n    <string name=\"type_on_hold\">На ўтрыманні</string>\n    <string name=\"type_completed\">Завершана</string>\n    <string name=\"type_dropped\">Пакінута</string>\n    <string name=\"type_plan_to_watch\">Планірую глядзець</string>\n    <string name=\"type_re_watching\">Пераглядваю</string>\n    <string name=\"play_movie_button\">Прайграць фільм</string>\n    <string name=\"play_trailer_button\">Прайграць трэйлер</string>\n    <string name=\"play_livestream_button\">Прайграць трансляцыю</string>\n    <string name=\"play_torrent_button\">Трансліраваць Torrent</string>\n    <string name=\"play_full_series_button\">Прайграць серыял поўнасцю</string>\n    <string name=\"torrent_info\">Гэта відэа — Torrent, гэта значыць, што ваша актыўнасць можа быць адсочана.\\nУпэўніцеся, што вы ведаеце, як працуюць Torrent-файлы, перад працягам.</string>\n    <string name=\"pick_source\">Крыніцы</string>\n    <string name=\"pick_subtitle\">Субцітры</string>\n    <string name=\"reload_error\">Паспрабаваць перападлучыцца…</string>\n    <string name=\"go_back\">Назад</string>\n    <string name=\"play_episode\">Прайграць серыю</string>\n    <string name=\"download\">Спампаваць</string>\n    <string name=\"downloaded\">Спампавана</string>\n    <string name=\"downloading\">Ідзе спампоўванне</string>\n    <string name=\"download_paused\">Спампоўванне прыпынена</string>\n    <string name=\"download_started\">Спампоўванне пачалося</string>\n    <string name=\"download_failed\">Не ўдалося спампаваць</string>\n    <string name=\"download_canceled\">Спампоўванне скасавана</string>\n    <string name=\"download_done\">Спампоўванне завершана</string>\n    <string name=\"downloads_delete_select\">Выберыце элементы для выдалення</string>\n    <string name=\"downloads_empty\">Спамповак пакуль што няма.</string>\n    <string name=\"offline_file\">Даступна для прагляду па-за сеткай</string>\n    <string name=\"select_all\">Выбраць ўсё</string>\n    <string name=\"deselect_all\">Зняць выбар</string>\n    <string name=\"update_started\">Пачалося абнаўленне</string>\n    <string name=\"stream\">Сеткавая трансляцыя</string>\n    <string name=\"open_local_video\">Адкрыць лакальнае відэа</string>\n    <string name=\"error_loading_links_toast\">Памылка пры загрузцы спасылак</string>\n    <string name=\"links_reloaded_toast\">Спасылкі перазагружаны</string>\n    <string name=\"download_storage_text\">Унутранае сховішча</string>\n    <string name=\"app_dubbed_text\">Дуб</string>\n    <string name=\"app_subbed_text\">Суб</string>\n    <string name=\"popup_delete_file\">Выдаліць файл</string>\n    <string name=\"popup_play_file\">Прайграць файл</string>\n    <string name=\"popup_resume_download\">Узнавіць спампоўванне</string>\n    <string name=\"popup_pause_download\">Прыпыніць спампоўванне</string>\n    <string name=\"home_more_info\">Дадатковыя звесткі</string>\n    <string name=\"home_expanded_hide\">Схаваць</string>\n    <string name=\"home_play\">Прайграць</string>\n    <string name=\"home_info\">Звесткі</string>\n    <string name=\"filter_bookmarks\">Фільтр закладак</string>\n    <string name=\"error_bookmarks_text\">Закладкі</string>\n    <string name=\"action_remove_from_bookmarks\">Выдаліць</string>\n    <string name=\"action_add_to_bookmarks\">Задаць статус прагляду</string>\n    <string name=\"sort_apply\">Прымяніць</string>\n    <string name=\"sort_copy\">Скапіраваць</string>\n    <string name=\"sort_close\">Закрыць</string>\n    <string name=\"sort_clear\">Ачысціць</string>\n    <string name=\"sort_save\">Захаваць</string>\n    <string name=\"repo_copy_label\">Назва рэпазіторыя і спасылка</string>\n    <string name=\"toast_copied\">скапіравана!</string>\n    <string name=\"subscribe_tooltip\">Паведамленне аб новай серыі</string>\n    <string name=\"result_search_tooltip\">Пошук у іншых пашырэннях</string>\n    <string name=\"recommendations_tooltip\">Паказваць рэкамендацыі</string>\n    <string name=\"player_speed\">Хуткасць прайгравальніка</string>\n    <string name=\"subtitles_settings\">Налады субцітраў</string>\n    <string name=\"subs_text_color\">Колер тэксту</string>\n    <string name=\"subs_outline_color\">Колер контуру</string>\n    <string name=\"subs_background_color\">Колер фону</string>\n    <string name=\"subs_window_color\">Колер акна</string>\n    <string name=\"subs_edge_type\">Тып контуру</string>\n    <string name=\"subs_subtitle_elevation\">Уздым субцітраў</string>\n    <string name=\"subs_font\">Шрыфт</string>\n    <string name=\"subs_font_size\">Памер шрыфту</string>\n    <string name=\"search_provider_text_providers\">Пошук праз пастаўшчыкоў</string>\n    <string name=\"search_provider_text_types\">Пошук праз тыпы</string>\n    <string name=\"benene_count_text\">%d бенена(ў) дадзена распрацоўшчыкам</string>\n    <string name=\"benene_count_text_none\">Бененаў не дадзена</string>\n    <string name=\"subs_auto_select_language\">Выбраць мову аўтаматычна</string>\n    <string name=\"subs_download_languages\">Спампаваць мовы</string>\n    <string name=\"subs_subtitle_languages\">Мова субцітраў</string>\n    <string name=\"subs_hold_to_reset_to_default\">Утрымайце, каб скінуць</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Усталёўвайце шрыфты, перацягваючы іх да %s</string>\n    <string name=\"continue_watching\">Працягнуць прагляд</string>\n    <string name=\"action_remove_watching\">Выдаліць</string>\n    <string name=\"action_open_watching\">Больш інфармацыі</string>\n    <string name=\"action_open_play\">\\@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Для карэктнай працы гэтага пастаўшчыка можа спатрэбіцца VPN</string>\n    <string name=\"vpn_torrent\">Гэты пастаўшчык — Torrent, рэкамендуецца VPN</string>\n    <string name=\"provider_info_meta\">Вэб-сайт не пастаўляе метаданых, загрузіць відэа не ўдасца, калі на сайце яго няма.</string>\n    <string name=\"torrent_plot\">Апісанне</string>\n    <string name=\"normal_no_plot\">Сюжэту не знойдзена</string>\n    <string name=\"torrent_no_plot\">Апісання не знойдзена</string>\n    <string name=\"show_log_cat\">Паказаць Logcat 🐈</string>\n    <string name=\"test_log\">Журнал</string>\n    <string name=\"picture_in_picture\">Відарыс у відарысе</string>\n    <string name=\"picture_in_picture_des\">Працягвае прайграванне ў мініяцюры зверху іншых праграм</string>\n    <string name=\"player_size_settings\">Кнопка змены памеру прайгравальніка</string>\n    <string name=\"player_size_settings_des\">Прыбраць чорныя межы</string>\n    <string name=\"player_subtitles_settings\">Субцітры</string>\n    <string name=\"player_subtitles_settings_des\">Налады субцітраў прайгравальніка</string>\n    <string name=\"chromecast_subtitles_settings\">Субцітры Chromecast</string>\n    <string name=\"chromecast_subtitles_settings_des\">Налады субцітраў Chromecast</string>\n    <string name=\"eigengraumode_settings\">Хуткасць прайгравання</string>\n    <string name=\"speed_setting_summary\">Дадаць параметр хуткасці да прайгравальніка</string>\n    <string name=\"swipe_to_seek_settings\">Чырканне для перамоткі</string>\n    <string name=\"swipe_to_seek_settings_des\">Правядзіце пальцам з боку ў бок, каб кіраваць пазіцыяй у відэа</string>\n    <string name=\"swipe_to_change_settings\">Чырканне для змены налад</string>\n    <string name=\"swipe_to_change_settings_des\">Правядзіце пальцам уверх або ўніз злева ці справа, каб змяніць яркасць або гучнасць</string>\n    <string name=\"autoplay_next_settings\">Аўтаматычнае прайграванне наступнай серыі</string>\n    <string name=\"autoplay_next_settings_des\">Прайграць наступную серыю пасля сканчэння бягучай</string>\n    <string name=\"double_tap_to_seek_settings\">Падвойнае націсканне для перамоткі</string>\n    <string name=\"double_tap_to_pause_settings\">Падвойнае націсканне для прыпынення</string>\n    <string name=\"double_tap_to_seek_amount_settings\">Крок перамоткі (у секундах)</string>\n    <string name=\"double_tap_to_seek_settings_des\">Двойчы націсніце справа ці злева, каб перайсці наперад ці назад</string>\n    <string name=\"double_tap_to_pause_settings_des\">Двойчы націсніце пасярэдзіне, каб прыпыніць прайграванне</string>\n    <string name=\"use_system_brightness_settings\">Выкарыстоўваць сістэмную яркасць</string>\n    <string name=\"use_system_brightness_settings_des\">Выкарыстоўваць сістэмную яркасць у прайгравальніку замест цёмнага накладання</string>\n    <string name=\"episode_sync_settings\">Абнаўляць працэс прагляду</string>\n    <string name=\"episode_sync_settings_des\">Аўтаматычна сінхранізаваць прагрэс бягучай серыі</string>\n    <string name=\"restore_settings\">Аднавіць даныя з рэзервовай копіі</string>\n    <string name=\"backup_settings\">Рэзервовае капіраванне даных</string>\n    <string name=\"backup_frequency\">Частата рэзервовага капіравання</string>\n    <string name=\"restore_success\">Загружаны файл рэзервовай копіі</string>\n    <string name=\"restore_failed_format\" formatted=\"true\">Не ўдалося аднавіць даныя з файла %s</string>\n    <string name=\"backup_success\">Даныя захаваны</string>\n    <string name=\"backup_failed\">Няма дазволу да сховішча. Паспрабуйце ізноў.</string>\n    <string name=\"backup_failed_error_format\">Памылка пры рэзервовым капіраванні %s</string>\n    <string name=\"search\">Пошук</string>\n    <string name=\"library\">Бібліятэка</string>\n    <string name=\"category_account\">Уліковыя запісы і бяспека</string>\n    <string name=\"category_updates\">Абнаўленні і рэзервовае капіраванне</string>\n    <string name=\"settings_info\">Звесткі</string>\n    <string name=\"advanced_search\">Пашыраны пошук</string>\n    <string name=\"advanced_search_des\">Паказвае пошукавыя вынікі, падзеленыя па пастаўшчыкам</string>\n    <string name=\"show_fillers_settings\">Паказваць серыі-запаўнялнікі для анімэ</string>\n    <string name=\"show_trailers_settings\">Паказваць трэйлеры</string>\n    <string name=\"kitsu_settings\">Паказваць плакаты з Kitsu</string>\n    <string name=\"pref_filter_search_quality\">Схаваць выбраную якасць відэа з вынікаў пошуку</string>\n    <string name=\"automatic_plugin_updates\">Аўтаматычнае абнаўленне пашырэнняў</string>\n    <string name=\"automatic_plugin_download\">Аўтаматычная спампоўка ўбудоў</string>\n    <string name=\"apk_installer_settings_des\">Некаторыя прылады не падтрымліваюць новы ўсталёўшчык пакетаў. Калі абнаўленні не ўсталёўваюцца, паспрабуйце ранейшую версію.</string>\n    <string name=\"github\">Github</string>\n    <string name=\"automatic_plugin_download_mode_title\">Выберыце рэжым фільтравання спампоўвання убудоў</string>\n    <string name=\"search_suggestions\">Прапановы пошуку</string>\n    <string name=\"search_suggestions_des\">Паказваць прапановы пошуку падчас уводу тэксту</string>\n    <string name=\"clear_suggestions\">Ачысціць прапановы</string>\n    <string name=\"show_cast_in_details\">Паказваць склад акцёраў</string>\n    <string name=\"automatic_plugin_download_summary\">Аўтаматычна ўсталёўваць усе яшчэ не ўсталяваныя ўбудовы з даданых рэпазіторыяў.</string>\n    <string name=\"updates_settings\">Паказваць абнаўленні праграмы</string>\n    <string name=\"updates_settings_des\">Аўтаматычна правяраць на новыя абнаўленні пасля адкрыцця праграмы.</string>\n    <string name=\"redo_setup_process\">Паўтарыць наладжванне</string>\n    <string name=\"install_prerelease\">Усталяваць перадфінальную версію</string>\n    <string name=\"prerelease_already_installed\">Перадфінальная версія ўжо ўсталявана.</string>\n    <string name=\"prerelease_install_failed\">Не ўдалося ўсталяваць перадфінальную версію.</string>\n    <string name=\"apk_installer_settings\">Усталёўшчык APK</string>\n    <string name=\"lightnovel\">Лёгкая праграма для раманаў ад тых жа распрацоўшчыкаў</string>\n    <string name=\"anim\">Праграма для анімэ ад тых жа распрацоўшчыкаў</string>\n    <string name=\"discord\">Далучайцеся да Discord</string>\n    <string name=\"benene\">Даць распрацоўшчыкам бенен</string>\n    <string name=\"benene_des\">Дадзена бененаў</string>\n    <string name=\"app_language\">Мова праграмы</string>\n    <string name=\"no_chromecast_support_toast\">У гэтага пастаўшчыка няма падтрымкі Chromecast</string>\n    <string name=\"no_links_found_toast\">Спасылак не знойдзена</string>\n    <string name=\"copy_link_toast\">Спасылка скапіравана да буфера абмену</string>\n    <string name=\"play_episode_toast\">Прайграць серыю</string>\n    <string name=\"subs_default_reset_toast\">Скінуць да пачатковага значэння</string>\n    <string name=\"season\">Сезон</string>\n    <string name=\"season_format\">%1$s %2$d%3$s</string>\n    <string name=\"no_season\">Сезона няма</string>\n    <string name=\"episode\">Серыя</string>\n    <string name=\"episodes\">Серый</string>\n    <string name=\"episodes_range\">%1$d-%2$d</string>\n    <string name=\"episode_format\" formatted=\"true\">%1$d %2$s</string>\n    <string name=\"episode_upcoming_format\" formatted=\"true\">Наступны праз %s</string>\n    <string name=\"season_short\">Сез</string>\n    <string name=\"episode_short\">Сер</string>\n    <string name=\"no_episodes_found\">Серый не знойдзена</string>\n    <string name=\"delete\">Выдаліць</string>\n    <string name=\"delete_file\">Выдаліць файл</string>\n    <string name=\"delete_files\">Выдаліць файлы</string>\n    <string name=\"delete_format\" formatted=\"true\">Выдаліць (%1$d | %2$s)</string>\n    <string name=\"cancel\">Скасаваць</string>\n    <string name=\"pause\">Прыпыніць</string>\n    <string name=\"start\">Пачаць</string>\n    <string name=\"test_failed\">Няўдала</string>\n    <string name=\"test_passed\">Пройдзена</string>\n    <string name=\"test_warning\">Увага</string>\n    <string name=\"resume\">Узнавіць</string>\n    <string name=\"go_back_30\">-30</string>\n    <string name=\"go_forward_30\">+30</string>\n    <string name=\"delete_message\" formatted=\"true\">Гэта выдаліць %s назаўсёды\\nВы ўпэўнены?</string>\n    <string name=\"delete_message_multiple\" formatted=\"true\">Вы ўпэўнены, што хочаце назаўсёды выдаліць наступныя элементы?\\n\\n%s</string>\n    <string name=\"delete_message_series_episodes\" formatted=\"true\">Вы ўпэўнены, што хочаце назаўсёды выдаліць наступныя серыі «%1$s»?\\n\\n%2$s</string>\n    <string name=\"delete_message_series_section\" formatted=\"true\">Вы таксама назаўсёды выдаліце ўсе серыі гэтага серыяла:\\n\\n%s</string>\n    <string name=\"delete_message_series_only\" formatted=\"true\">Вы ўпэўнены, што хочаце назаўсёды выдаліце ўсе серыі гэтага серыяла:\\n\\n%s</string>\n    <string name=\"resume_time_left\" formatted=\"true\">%dхв\\nзасталося</string>\n    <string name=\"resume_remaining\" formatted=\"true\">%s\\nзасталося</string>\n    <string name=\"status_ongoing\">Бягучы</string>\n    <string name=\"status_completed\">Завершана</string>\n    <string name=\"status\">Стан</string>\n    <string name=\"year\">Год</string>\n    <string name=\"rating\">Рэйтынг</string>\n    <string name=\"duration\">Працягласць</string>\n    <string name=\"site\">Вэб-сайт</string>\n    <string name=\"synopsis\">Сціслы агляд</string>\n    <string name=\"queued\">у чарзе</string>\n    <string name=\"no_subtitles\">Субцітраў няма</string>\n    <string name=\"action_default\">Прадвызначанае</string>\n    <string name=\"free_storage\">Свабодна</string>\n    <string name=\"used_storage\">Ужыта</string>\n    <string name=\"app_storage\">Праграма</string>\n    <string name=\"movies\">Фільмы</string>\n    <string name=\"tv_series\">Тэлесерыялы</string>\n    <string name=\"cartoons\">Мультфільмы</string>\n    <string name=\"anime\">Анімэ</string>\n    <string name=\"torrent\">Torrents</string>\n    <string name=\"documentaries\">Дакументальныя фільмы</string>\n    <string name=\"ova\">OVA</string>\n    <string name=\"asian_drama\">Азіяцкія драмы</string>\n    <string name=\"livestreams\">Прамыя трансляцыі</string>\n    <string name=\"nsfw\">NSFW</string>\n    <string name=\"others\">Іншыя</string>\n    <string name=\"movies_singular\">Фільм</string>\n    <string name=\"tv_series_singular\">Серыял</string>\n    <string name=\"cartoons_singular\">Мультфільм</string>\n    <string name=\"anime_singular\">Анімэ</string>\n    <string name=\"ova_singular\">OVA</string>\n    <string name=\"torrent_singular\">Torrent</string>\n    <string name=\"documentaries_singular\">Дакументальны фільм</string>\n    <string name=\"asian_drama_singular\">Азіяцкая драма</string>\n    <string name=\"live_singular\">Прамая трансляцыя</string>\n    <string name=\"nsfw_singular\">NSFW</string>\n    <string name=\"other_singular\">Відэа</string>\n    <string name=\"music_singlar\">Музыка</string>\n    <string name=\"audio_book_singular\">Аўдыякніга</string>\n    <string name=\"custom_media_singluar\">Медыя</string>\n    <string name=\"audio_singluar\">Аўдыя</string>\n    <string name=\"podcast_singluar\">Падкаст</string>\n    <string name=\"source_error\">Памылка крыніцы</string>\n    <string name=\"remote_error\">Памылка аддаленага элемента</string>\n    <string name=\"render_error\">Памылка паказу</string>\n    <string name=\"encoding_error\">Памылка кадзіравання</string>\n    <string name=\"unsupported_error\">Непадтрыманая памылка</string>\n    <string name=\"unexpected_error\">Нечаканая памылка прайгравальніка</string>\n    <string name=\"storage_error\">Памылка спампоўвання, праверце дазвол на сховішча</string>\n    <string name=\"episode_action_chromecast_episode\">Глядзець праз Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Люстэрка Chromecast</string>\n    <string name=\"extra_brightness_settings\">Дадатковая яркасць</string>\n    <string name=\"extra_brightness_settings_des\">Уключыць фільтр яркасці калі яркасць дысплэя больш за 100%</string>\n    <string name=\"extra_brightness_key\">extra_brightness_enabled</string>\n    <string name=\"episode_action_cast_mirror\">Трансляцыя праз люстэрку</string>\n    <string name=\"episode_action_play_in_app\">Глядзець у праграме</string>\n    <string name=\"episode_action_play_mirror\">Глядзець праз люстэрку</string>\"\n    <string name=\"episode_action_play_in_format\">Глядзець у %s</string>\n    <string name=\"episode_action_auto_download\">Аўтаспампоўка</string>\n    <string name=\"episode_action_download_mirror\">Спампаваць люстэрку</string>\n    <string name=\"episode_action_reload_links\">Абнавіць спасылкі</string>\n    <string name=\"episode_action_download_subtitle\">Спампаваць субцітры</string>\n    <string name=\"show_hd\">Метка якасці</string>\n    <string name=\"show_dub\">Метка дубляжу</string>\n    <string name=\"show_sub\">Метка субцітраў</string>\n    <string name=\"show_rating\">Метка рэйтынгу</string>\n    <string name=\"show_title\">Загаловак</string>\n    <string name=\"show_episode_text\">Тэкст серыі</string>\n    <string name=\"poster_ui_settings\">Пераключэнне элементаў інтэрфейсу на плакаце</string>\n    <string name=\"no_update_found\">Абнаўленняў не знойдзена</string>\n    <string name=\"check_for_update\">Праверыць на абнаўленні</string>\n    <string name=\"video_lock\">Блакіроўка</string>\n    <string name=\"video_aspect_ratio_resize\">Змена памеру</string>\n    <string name=\"video_source\">Крыніца</string>\n    <string name=\"video_skip_op\">Прапусціць ОП</string>\n    <string name=\"dont_show_again\">Не паказваць зноў</string>\n    <string name=\"skip_update\">Прапусціць гэта абнаўленне</string>\n    <string name=\"update\">Абнавіць</string>\n    <string name=\"watch_quality_pref\">Прыярытэтная якасць прагляду (WiFi)</string>\n    <string name=\"watch_quality_pref_data\">Прыярытэтная якасць прагляду (Мабільная перадача даных)</string>\n    <string name=\"limit_title\">Максімальная колькасць сімвалаў у загалоўку праглядальніка</string>\n    <string name=\"limit_title_rez\">Паказваць інфармацыю ў прайгравальніку</string>\n    <string name=\"video_buffer_size_settings\">Памер буфера відэа</string>\n    <string name=\"video_buffer_length_settings\">Даўжыня буфера відэа</string>\n    <string name=\"video_buffer_disk_settings\">Кэш відэа на дыску</string>\n    <string name=\"video_buffer_clear_settings\">Ачысціць кэш відэа і відарысаў</string>\n    <string name=\"android_tv_interface_on_seek_settings\">Прайгравальнік паказаны — крок перамоткі</string>\n    <string name=\"android_tv_interface_on_seek_settings_summary\">Крок перамоткі калі прайгравальнік бачны</string>\n    <string name=\"android_tv_interface_off_seek_settings\">Прайгравальнік схаваны — крок перамоткі</string>\n    <string name=\"android_tv_interface_off_seek_settings_summary\">Крок перамоткі калі прайгравальнік схаваны</string>\n    <string name=\"video_ram_description\">Выклікае збоі пры высокіх значэннях на прыладах з маленькім аб\\'ёмам памяці, такіх як Android TV.</string>\n    <string name=\"video_disk_description\">Выклікае праблемы пры высокіх значэннях на прыладах з маленькім аб\\'ёмам сховішча, такіх як Android TV.</string>\n    <string name=\"dns_pref\">DNS праз HTTPS</string>\n    <string name=\"dns_pref_summary\">Карысна для абходу блакіровак</string>\n    <string name=\"jsdelivr_proxy\">Проксі GitHub</string>\n    <string name=\"jsdelivr_enabled\">Не ўдалося дасягнуць GitHub. Уключэнне проксі jsDelivr…</string>\n    <string name=\"jsdelivr_proxy_summary\">Абыходзьце блакіроўкі спасылак GitHub з дапамогай jsDelivr. Можа затрымаць абнаўленні на некалькі дзён.</string>\n    <string name=\"add_site_pref\">Кланіраваць вэб-сайт</string>\n    <string name=\"remove_site_pref\">Выдаліць вэб-сайт</string>\n    <string name=\"add_site_summary\">Дадайце копію існуючага вэб-сайта з іншым URL-адрасам</string>\n    <string name=\"download_path_pref\">Шлях спампоўкі</string>\n    <string name=\"nginx_url_pref\">URL-адрас сервера NGINX</string>\n    <string name=\"display_subbed_dubbed_settings\">Паказваць метку «Дубляж»/«Субцітры» для анімэ</string>\n    <string name=\"resize_fit\">Умясціць у экран</string>\n    <string name=\"resize_fill\">Запоўніць</string>\n    <string name=\"resize_zoom\">Маштабаваць</string>\n    <string name=\"legal_notice\">Адмова ад адказнасці</string>\n    <string name=\"pref_category_bypass\">Абходы ISP</string>\n    <string name=\"pref_category_links\">Спасылкі</string>\n    <string name=\"pref_category_app_updates\">Абнаўленні праграмы</string>\n    <string name=\"pref_category_backup\">Рэзервовае капіраванне</string>\n    <string name=\"pref_category_extensions\">Пашырэнні</string>\n    <string name=\"pref_category_actions\">Дзеянні</string>\n    <string name=\"pref_category_cache\">Кэш</string>\n    <string name=\"pref_category_android_tv\">Android TV</string>\n    <string name=\"pref_category_gestures\">Жэсты</string>\n    <string name=\"pref_category_security\">Бяспека</string>\n    <string name=\"pref_category_accounts\">Уліковыя запісы</string>\n    <string name=\"pref_category_player_features\">Функцыі прайгравальніка</string>\n    <string name=\"pref_category_subtitles\">Субцітры</string>\n    <string name=\"pref_category_player_layout\">Макет</string>\n    <string name=\"pref_category_defaults\">Прадвызначэнні</string>\n    <string name=\"pref_category_looks\">Выгляд</string>\n    <string name=\"pref_category_ui_features\">Функцыі</string>\n    <string name=\"category_general\">Агульныя</string>\n    <string name=\"random_button_settings\">Кнопка «Выпадковае»</string>\n    <string name=\"random_button_settings_desc\">Паказваць кнопку «Выпадковае» на дамашняй старонцы і ў бібліятэцы</string>\n    <string name=\"provider_lang_settings\">Мовы пашырэнняў</string>\n    <string name=\"app_layout\">Макет праграмы</string>\n    <string name=\"preferred_media_settings\">Прыярытэтнае медыя</string>\n    <string name=\"enable_nsfw_on_providers\">Уключыць NSFW на пашырэннях, дзе гэта падтрымліваецца</string>\n    <string name=\"subtitles_encoding\">Кадзіраванне субцітраў</string>\n    <string name=\"category_providers\">Пастаўшчыкі</string>\n    <string name=\"category_provider_test\">Праверка пастаўшчыкоў</string>\n    <string name=\"test_extensions\">Праверыць усе пашырэнні</string>\n    <string name=\"test_extensions_summary\">Гэта праверка прызначана толькі для распрацоўшчыкаў і не вызначае работу абы-якога пашырэння.</string>\n    <string name=\"category_ui\">Макет</string>\n    <string name=\"automatic\">Аўтаматычны</string>\n    <string name=\"tv_layout\">Макет тэлевізара</string>\n    <string name=\"phone_layout\">Макет тэлефона</string>\n    <string name=\"emulator_layout\">Макет эмулятара</string>\n    <string name=\"primary_color_settings\">Асноўны колер</string>\n    <string name=\"app_theme_settings\">Тэма праграмы</string>\n    <string name=\"bottom_title_settings\">Размяшчэнне загалоўка плаката</string>\n    <string name=\"bottom_title_settings_des\">Размяшчаць назву пад плакатам</string>\n    <string name=\"example_password\">parol123</string>\n    <string name=\"example_username\">Імя карыстальніка</string>\n    <string name=\"example_email\">vitaju@sviet.com</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">НоваяНазваСайта</string>\n    <string name=\"example_site_url\">https://pryklad.by</string>\n    <string name=\"example_lang_name\">Код мовы (be)</string>\n    <string name=\"login_format\" formatted=\"true\">%2$s%1$s</string>\n    <string name=\"account\">уліковы запіс</string>\n    <string name=\"logout\">Выйсці</string>\n    <string name=\"login\">Увайсці</string>\n    <string name=\"auth_locally\">Лакальная праверка сапраўднасці</string>\n    <string name=\"switch_account\">Змяніць ўліковы запіс</string>\n    <string name=\"add_account\">Дадаць уліковы запіс</string>\n    <string name=\"create_account\">Стварыць уліковы запіс</string>\n    <string name=\"add_sync\">Дадаць адсочванне</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Дададзена %s</string>\n    <string name=\"upload_sync\">Сінхранізаваць</string>\n    <string name=\"sync_score\">Ацэнка</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/%d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s праверана на сапраўднасць</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">Не ўдалося ўвайсці ў %s</string>\n    <string name=\"disable\">Выключыць</string>\n    <string name=\"none\">Нічога</string>\n    <string name=\"normal\">Звычайны</string>\n    <string name=\"all\">Усё</string>\n    <string name=\"max\">Макс.</string>\n    <string name=\"min\">Мін.</string>\n    <string name=\"subtitles_outline\">Контур</string>\n    <string name=\"subtitles_depressed\">Заніжаныя</string>\n    <string name=\"subtitles_shadow\">Цень</string>\n    <string name=\"subtitles_raised\">Паднятыя</string>\n    <string name=\"subtitle_offset\">Сінхранізаваць субцітры</string>\n    <string name=\"subtitle_offset_hint\">1000 мс</string>\n    <string name=\"subtitle_offset_title\">Затрымка субцітраў</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Выкарыстоўвайце, калі субцітры паяўляюцца на %d мс раней</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Выкарыстоўвайце, калі субцітры паяўляюцца на %d мс пазней</string>\n    <string name=\"subtitle_offset_extra_hint_none_format\">Без затрымкі субцітраў</string>\n    <string name=\"subtitles_example_text\">У цэху з’яўляецца чорт, кроўю і пугай фарбуе свежы шампіньён</string>\n    <string name=\"recommended\">Рэкамендавана</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">Загружана %s</string>\n    <string name=\"player_load_subtitles\">Загрузіць з файла</string>\n    <string name=\"player_load_subtitles_online\">Спампаваць з інтэрнэту</string>\n    <string name=\"player_load_one_subtitle_online\">Спампаваць першыя даступныя</string>\n    <string name=\"downloaded_file\">Спампаваны файл</string>\n    <string name=\"actor_main\">Галоўны</string>\n    <string name=\"actor_supporting\">Другасны</string>\n    <string name=\"actor_background\">Фонавы</string>\n    <string name=\"home_source\">Крыніца</string>\n    <string name=\"home_random\">Выпадковае</string>\n    <string name=\"coming_soon\">Скора…</string>\n    <string name=\"quality_cam\">Cam</string>\n    <string name=\"quality_cam_rip\">Cam</string>\n    <string name=\"quality_cam_hd\">Cam</string>\n    <string name=\"quality_hq\">HQ</string>\n    <string name=\"quality_hd\">HD</string>\n    <string name=\"quality_ts\">TS</string>\n    <string name=\"quality_tc\">TC</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">WP</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">SD</string>\n    <string name=\"quality_uhd\">UHD</string>\n    <string name=\"quality_hdr\">HDR</string>\n    <string name=\"quality_sdr\">SDR</string>\n    <string name=\"quality_webrip\">Web</string>\n    <string name=\"poster_image\">Відарыс плаката</string>\n    <string name=\"qr_image\">Відарыс QR-кода</string>\n    <string name=\"category_player\">Прайгравальнік</string>\n    <string name=\"resolution_and_title\">Раздзяляльнасць і загаловак</string>\n    <string name=\"title\">Загаловак</string>\n    <string name=\"resolution\">Раздзяляльнасць</string>\n    <string name=\"video_info\">Звесткі пра медыя</string>\n    <string name=\"error_invalid_id\">Памылковы ID</string>\n    <string name=\"error_invalid_data\">Памылковыя даныя</string>\n    <string name=\"error_invalid_url\">Памылковы URL-адрэс</string>\n    <string name=\"error\">Памылка</string>\n    <string name=\"subtitles_remove_captions\">Прыбраць схаваныя цітры з субцітраў</string>\n    <string name=\"subtitles_remove_bloat\">Прыбраць раздуванне з субцітраў</string>\n    <string name=\"subtitles_filter_lang\">Фільтраваць па прыярытэтнай мове медыя</string>\n    <string name=\"extras\">Дадатковае</string>\n    <string name=\"trailer\">Трэйлер</string>\n    <string name=\"network_adress_example\">https://pryklad.by/pryklad.mp4</string>\n    <string name=\"referer\">Referer (неабавязкова)</string>\n    <string name=\"next\">Далей</string>\n    <string name=\"provider_languages_tip\">Праглядвайце відэа на гэтых мовах</string>\n    <string name=\"previous\">Назад</string>\n    <string name=\"skip_setup\">Прапусціць наладжванне</string>\n    <string name=\"app_layout_subtext\">Змяніце выгляд праграмы пад вашу прыладу</string>\n    <string name=\"preferred_media_subtext\">Што хочаце ўбачыць</string>\n    <string name=\"setup_done\">Гатова</string>\n    <string name=\"extensions\">Пашырэнні</string>\n    <string name=\"add_repository\">Дадаць рэпазіторый</string>\n    <string name=\"repository_name_hint\">Назва рэпазіторыя (неабавязкова)</string>\n    <string name=\"repository_url_hint\">URL-адрас рэпазіторыя або кароткі код</string>\n    <string name=\"plugin_loaded\">Убудова загружана</string>\n    <string name=\"plugin_downloaded\">Убудава спампавана</string>\n    <string name=\"plugin_deleted\">Убудова выдалена</string>\n    <string name=\"plugin_load_fail\" formatted=\"true\">Не ўдалося загрузіць %s</string>\n    <string name=\"is_adult\">18+</string>\n    <string name=\"batch_download_start_format\" formatted=\"true\">Пачатак спампоўвання %1$d%2$s…</string>\n    <string name=\"batch_download_finish_format\" formatted=\"true\">%1$d%2$s спампавана</string>\n    <string name=\"batch_download_nothing_to_download_format\" formatted=\"true\">Усе %s ужо спампаваныя</string>\n    <string name=\"no_plugins_found_error\">У рэпазіторыі не знойдзена ўбудоў</string>\n    <string name=\"no_repository_found_error\">Рэпазіторый не знойдзены, праверце URL-адрас і паспрабуйце VPN</string>\n    <string name=\"batch_download\">Пакетная спампоўка</string>\n    <string name=\"plugin_singular\">убудова</string>\n    <string name=\"plugin\">убудовы</string>\n    <string name=\"delete_repository_plugins\">Гэта таксама прывядзе да выдалення ўсіх убудоў рэпазіторыя</string>\n    <string name=\"delete_repository\">Выдаліць рэпазіторый</string>\n    <string name=\"delete_plugin\">Выдаліць убудову</string>\n    <string name=\"setup_extensions_subtext\">Спампуйце спіс вэб-сайтаў, якімі вы хочаце карыстацца</string>\n    <string name=\"plugins_downloaded\" formatted=\"true\">Спампавана: %d</string>\n    <string name=\"plugins_disabled\" formatted=\"true\">Выключана: %d</string>\n    <string name=\"plugins_not_downloaded\" formatted=\"true\">Не спампавана: %d</string>\n    <string name=\"plugins_updated\" formatted=\"true\">Абноўлена %d плагіна(ў)</string>\n    <string name=\"blank_repo_message\">Прадвызначана на CloudStream няма ўсталяваных вэб-сайтаў. Вам трэба ўсталяваць вэб-сайты з рэпазіторыяў. \\n \\nДалучыцеся да нашага сервера Discord або пашукайце ў сетцы.</string>\n    <string name=\"view_public_repositories_button\">Праглядзець рэпазіторыі ад супольнасці</string>\n    <string name=\"view_public_repositories_button_short\">Публічны спіс</string>\n    <string name=\"uppercase_all_subtitles\">Усе субцітры верхнім рэгістрам</string>\n    <string name=\"download_all_plugins_from_repo\">Увага: CloudStream не нясе адказнасці за выкарыстанне старонніх пашырэнняў і не пастаўляе для іх ніякай падтрымцы!</string>\n    <string name=\"single_plugin_disabled\" formatted=\"true\">%s (выключана)</string>\n    <string name=\"tracks\">Трэкі</string>\n    <string name=\"audio_tracks\">Аўдыятрэкі</string>\n    <string name=\"video_tracks\">Відэатрэкі</string>\n    <string name=\"apply_on_restart\">Перазапусціце праграму, каб убачыць змены.</string>\n    <string name=\"restart\">Перазапусціць</string>\n    <string name=\"stop\">Спыніць</string>\n    <string name=\"safe_mode_title\">Бяспечны рэжым уключаны</string>\n    <string name=\"safe_mode_description\">Усе пашырэнні былі выключаны праз збой, каб вы змаглі знайсці, якое з іх выклікае праблемы.</string>\n    <string name=\"safe_mode_crash_info\">Праглядзець звесткі пра збой</string>\n    <string name=\"extension_rating\" formatted=\"true\">Рэйтынг: %s</string>\n    <string name=\"extension_description\">Апісанне</string>\n    <string name=\"extension_version\">Версія</string>\n    <string name=\"extension_status\">Стан</string>\n    <string name=\"extension_size\">Памер</string>\n    <string name=\"extension_authors\">Аўтары</string>\n    <string name=\"extension_types\">Падтрымлівае</string>\n    <string name=\"extension_language\">Мова</string>\n    <string name=\"extension_install_first\">Спачатку ўсталюйце пашырэнне</string>\n    <string name=\"hls_playlist\">Плэй-ліст HLS</string>\n    <string name=\"player_pref\">Прыярытэтны прайгравальнік</string>\n    <string name=\"player_settings_play_in_app\">Убудаваны прайгравальнік</string>\n    <string name=\"player_settings_always_ask\">Заўсёды пытацца</string>\n    <string name=\"player_settings_select_cast_device\">Выбраць прыладу для трансляцыі</string>\n    <string name=\"app_not_found_error\">Праграмы не знойдзена</string>\n    <string name=\"all_languages_preference\">Усе мовы</string>\n    <string name=\"skip_type_format\" formatted=\"true\">Прапусціць %s</string>\n    <string name=\"skip_type_op\">Опенінг</string>\n    <string name=\"skip_type_ed\">Заканчэнне</string>\n    <string name=\"skip_type_recap\">Зводка</string>\n    <string name=\"skip_type_mixed_ed\">Змешанае заканчэнне</string>\n    <string name=\"skip_type_mixed_op\">Змешаны опенінг</string>\n    <string name=\"skip_type_creddits\">Удзельнікі</string>\n    <string name=\"skip_type_intro\">Застаўка</string>\n    <string name=\"clear_history\">Ачысціць гісторыю</string>\n    <string name=\"history\">Гісторыя</string>\n    <string name=\"enable_skip_op_from_database_des\">Паказваць усплывальнае акно для пропуску опенінга/заканчэння</string>\n    <string name=\"clipboard_too_large\">Надта шмат тэксту. Не ўдалося захаваць да буфера абмену.</string>\n    <string name=\"clipboard_permission_error\">Памылка доступу да буфера абмену, паспрабуйце яшчэ раз.</string>\n    <string name=\"clipboard_unknown_error\">Памылка пры капіраванні, скапіруйце logcat і звярніцеся ў падтрымку.</string>\n    <string name=\"action_mark_as_watched\">Пазначыць як прагледжанае</string>\n    <string name=\"action_remove_from_watched\">Прыбраць з прагледжанага</string>\n    <string name=\"confirm_exit_dialog\">Вы ўпэўнены, што хочаце выйсці?</string>\n    <string name=\"yes\">Так</string>\n    <string name=\"no\">Не</string>\n    <string name=\"ok\">ОК</string>\n    <string name=\"dismiss\">Адхіліць</string>\n    <string name=\"open_downloaded_repo\">Адкрыць рэпазіторый</string>\n    <string name=\"battery_dialog_title\">Выключыць аптымізацыю батарэі</string>\n    <string name=\"battery_dialog_message\">Каб забяспечыць бесперапынныя спампоўкі і апавяшчэнні аб тэлеперадачах, на якія вы падпісаны, CloudStream патрэбны дазвол на выкананне ў фонавым рэжыме. Па націсканні «ОК», вам пакажацца дыялогавае акно. Націсніце «Дазволіць».\\n\\nЗвярніце ўвагу — гэта не значыць, што CS3 будзе садзіць вашу батарэю. Праграма будзе працаваць у фоне толькі калі патрэбна, напрыклад пры атрыманні апавяшчэнняў або спампоўванні відэа з афіцыйных пашырэнняў.</string>\n    <string name=\"app_unrestricted_toast\">Выкарыстанне батарэі ўжо выстаўлена як неабмежаванае</string>\n    <string name=\"app_info_intent_error\">Не ўдалося адкрыць звесткі пра праграму CloudStream.</string>\n    <string name=\"update_notification_downloading\">Спампоўванне абнаўлення праграмы…</string>\n    <string name=\"update_notification_installing\">Усталяванне абнаўлення праграмы…</string>\n    <string name=\"update_notification_failed\">Не ўдалося ўсталяваць новую версію праграмы</string>\n    <string name=\"apk_installer_legacy\">Састарэлая версія</string>\n    <string name=\"apk_installer_package_installer\">Усталёўшчык пакетаў</string>\n    <string name=\"delayed_update_notice\">Праграма будзе абноўлена пасля выхаду</string>\n    <string name=\"sort_by\">Сартаваць па</string>\n    <string name=\"sort\">Сартаваць</string>\n    <string name=\"sort_rating_desc\">Рэйтынгу (ад высокага да нізкага)</string>\n    <string name=\"sort_rating_asc\">Рэйтынгу (ад нізкага да высокага)</string>\n    <string name=\"sort_updated_new\">Абнаўленню (ад новага да старога)</string>\n    <string name=\"sort_updated_old\">Абнаўленню (ад старога да новага)</string>\n    <string name=\"sort_alphabetical_a\">Алфавіту (ад А да Я)</string>\n    <string name=\"sort_alphabetical_z\">Алфавіту (ад Я да А)</string>\n    <string name=\"sort_episodes_number_asc\">Серыі (па ўзрастанні)</string>\n    <string name=\"sort_episodes_number_desc\">Серыі (па ўбыванні)</string>\n    <string name=\"sort_episodes_rating_high_low\">Рэйтынгу (найвышэйшы)</string>\n    <string name=\"sort_episodes_rating_low_high\">Рэйтынгу (найніжэйшы)</string>\n    <string name=\"sort_episodes_date_newest\">Даце паказу (найноўшыя)</string>\n    <string name=\"sort_episodes_date_oldest\">Даце паказу (найстарэйшыя)</string>\n    <string name=\"sort_button_episode\">Сер. %s</string>\n    <string name=\"sort_button_rating\">Рэйтынг %s</string>\n    <string name=\"sort_button_date\">Дата %s</string>\n    <string name=\"select_library\">Выбраць бібліятэку</string>\n    <string name=\"open_with\">Адкрыць праз</string>\n    <string name=\"empty_library_no_accounts_message\">Ваша бібліятэка пустая :( \\nУвайдзіце ва ўліковы запіс з бібліятэкай або дадайце праграмы да вашай лакальнай бібліятэкі.</string>\n    <string name=\"empty_library_logged_in_message\">Гэты спіс пусты. Паспрабуйце пераключыцца на іншы.</string>\n    <string name=\"safe_mode_file\">Знойдзены файл бяспечнага рэжыму! \\nПашырэнні не будуць загружацца на запуску, пакуль файл не будзе выдалены.</string>\n    <string name=\"revert\">Вярнуць</string>\n    <string name=\"subscription_in_progress_notification\">Ідзе абнаўленне падпісак</string>\n    <string name=\"subscription_list_name\">Вы падпісаны</string>\n    <string name=\"subscription_new\">Вы падпісаліся на %s</string>\n    <string name=\"subscription_deleted\">Вы адпісаліся ад %s</string>\n    <string name=\"subscription_episode_released\">Выпушчана серыя %d!</string>\n    <string name=\"action_subscribe\">Падпісацца</string>\n    <string name=\"action_unsubscribe\">Адпісацца</string>\n    <string name=\"profile_number\">Профіль %d</string>\n    <string name=\"wifi\">Wi-Fi</string>\n    <string name=\"mobile_data\">Мабільная перадача даных</string>\n    <string name=\"set_default\">Выбраць як прадвызначаны</string>\n    <string name=\"use\">Выкарыстоўваць</string>\n    <string name=\"edit\">Рэдагаваць</string>\n    <string name=\"profiles\">Профілі</string>\n    <string name=\"help\">Даведка</string>\n    <string name=\"quality_profile_help\">Тут можна змяніць парадак крыніц. Калі ў відэа большы прыярытэт, яно будзе паказвацца вышэй пры выбары крыніцы. Прыярытэтам відэа з\\'яўляецца сума прыярытэту крыніцы і прыярытэту якасці.\\n\\nКрыніца А: 3\\nЯкасць Б: 7\\nПрыярытэт відэа будзе 10.\\n\\nЗАЎВАГА: Калі сума раўняецца 10 ці болей прайгравальнік аўтаматычна прапусціць загрузку для гэтай спасылцы!</string>\n    <string name=\"qualities\">Якасці</string>\n    <string name=\"profile_background_des\">Фон профілю</string>\n    <string name=\"unable_to_inflate\">Не ўдалося карэктна стварыць інтэрфейс, гэта СУР\\'ЁЗНАЯ ХІБА, пра якую варта неадкладна паведаміць %s</string>\n    <string name=\"already_voted\">Вы ўжо прагаласавалі</string>\n    <string name=\"favorites_list_name\">Абраныя</string>\n    <string name=\"favorite_added\">%s дададзена ў абранае</string>\n    <string name=\"favorite_removed\">%s прыбрана з абранага</string>\n    <string name=\"action_add_to_favorites\">Дадаць у абранае</string>\n    <string name=\"action_remove_from_favorites\">Прыбраць з абранага</string>\n    <string name=\"duplicate_title\">Знойдзены магчымы дублікат</string>\n    <string name=\"duplicate_add\">Дадаць</string>\n    <string name=\"duplicate_replace\">Замяніць</string>\n    <string name=\"duplicate_replace_all\">Замяніць усё</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Падобна на тое, што ў вашай бібліятэцы ёсць дублікат гэтага элемента: ‹%s.›\\n\\nЦі хочаце вы ўсё роўна яго дадаць, замяніць ужо існуючы, або скасаваць дзеянне?</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">У вашай бібліятэцы знойдзены магчымыя дублікаты: \\n\\n%s \\n\\nЦі хочаце вы ўсё роўна яго дадаць, замяніць ужо існуючыя, або скасаваць дзеянне?</string>\n    <string name=\"enter_pin\">Увядзіце PIN-код</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Увядзіце PIN-код для %s</string>\n    <string name=\"enter_current_pin\">Увядзіце бягучы PIN-код</string>\n    <string name=\"lock_profile\">Заблакіраваць профіль</string>\n    <string name=\"pin\">PIN-код</string>\n    <string name=\"pin_error_incorrect\">Няправільны PIN-код. Паспрабуйце яшчэ раз.</string>\n    <string name=\"pin_error_length\">PIN-код павінны быць з 4 сімвалаў</string>\n    <string name=\"select_an_account\">Выберыце ўліковы запіс</string>\n    <string name=\"no_account\">Без ўліковага запісу</string>\n    <string name=\"manage_accounts\">Кіраванне ўліковымі запісамі</string>\n    <string name=\"edit_account\">Рэдагаваць уліковы запіс</string>\n    <string name=\"logged_account\" formatted=\"true\">Вы ўвайшлі як %s</string>\n    <string name=\"skip_startup_account_select_pref\">Прапускаць выбар уліковага запісу пры запуске</string>\n    <string name=\"use_default_account\">Выкарыстоўваць прадвызначаны ўліковы запіс</string>\n    <string name=\"rotate_video\">Павярнуць</string>\n    <string name=\"rotate_video_desc\">Паказваць кнопку пераключэння арыентацыі экрана</string>\n    <string name=\"auto_rotate_video_desc\">Уключыць аўтаматычнае пераключэнне арыентацыі экрана ў залежнасці ад арыентацыі відэа</string>\n    <string name=\"auto_rotate_video\">Аўтапаварот</string>\n    <string name=\"favorite\">Дадаць у абраныя</string>\n    <string name=\"unfavorite\">Выдаліць з абранага</string>\n    <string name=\"biometric_authentication_title\">Разблакіруйце CloudStream</string>\n    <string name=\"biometric_setting\">Блакіроўка біяметрыяй</string>\n    <string name=\"password_pin_authentication_title\">Праверка сапраўднасці паролем/PIN-кодам</string>\n    <string name=\"biometric_unsupported\">Праверка сапраўднасці біяметрыяй не падтрымліваецца на гэтай прыладзе</string>\n    <string name=\"biometric_setting_summary\">Разблакіруйце праграму адбіткам пальца, Face ID, PIN-кодам, узорам разблакіроўкі або паролем.</string>\n    <string name=\"biometric_prompt_description\">Праз некалькі няўдалых спроб акно з запытам закрыецца. Проста перазапусціце праграму, каб паўтарыць спробу.</string>\n    <string name=\"biometric_warning\">Вашы даныя CloudStream былі зарэзерваваныя. Нягледзячы на тое, што магчымасць вельмі маленькая, усе прылады могуць паводзіць сябе па-рознаму. У рэдкасным выпадку, калі вы страціце доступ да праграмы, поўнасцю ачысціце даныя і аднавіце іх праз рэзервовую копію. Выбачайце за любую нязручнасць, якая можа з гэтага атрымацца.</string>\n    <string name=\"reset_btn\">Скінуць</string>\n    <string name=\"cs3wiki\">CloudStream-Вікі</string>\n    <string name=\"device_pin_url_message\">Наведайце <b>%s</b> на вашым смартфоне або камп\\'ютары і ўвядзіце код вышэй</string>\n    <string name=\"device_pin_error_message\">Не ўдалося атрымаць PIN-код прылады, паспрабуйце лакальную праверку сапраўднасці</string>\n    <string name=\"device_pin_expired_message\">PIN-код састарэў!</string>\n    <string name=\"device_pin_counter_text\">Код мінуе праз %1$dхв %2$dс</string>\n    <string name=\"sort_release_date_new\">Даце выпуску (ад новага да старога)</string>\n    <string name=\"sort_release_date_old\">Даце выпуску (ад старога да новага)</string>\n    <string name=\"hide_player_control_names\">Схаваць назвы элементаў кіравання прайгравальніка</string>\n    <string name=\"preview_seekbar\">Перадпрагляд на шкале часу</string>\n    <string name=\"preview_seekbar_desc\">Уключыць мініяцюру папярэдняга прагляду на шкале часу</string>\n    <string name=\"no_subtitles_loaded\">Субцітраў яшчэ не загружана</string>\n    <string name=\"backup_path_title\">Размяшчэнне папкі з рэзервовымі копіямі</string>\n    <string name=\"custom\">Уласнае</string>\n    <string name=\"confirm_before_exiting_title\">Пацвярджэнне перад выхадам</string>\n    <string name=\"confirm_before_exiting_desc\">Паказваць дыялог перад выхадам з праграмы</string>\n    <string name=\"show\">Паказваць</string>\n    <string name=\"dont_show\">Не паказваць</string>\n    <string name=\"subs_edge_size\">Памер краёў</string>\n    <string name=\"torrent_preferred_media\">Уключыце Torrent у Наладах/Пастаўшчыкі/Прыярытэтнае медыя</string>\n    <string name=\"torrent_not_accepted\">Перазапусціце праграму і прыміце ўсплывальнае акно «Трансліраваць Torrent», каб працягнуць.</string>\n    <string name=\"software_decoding\">Праграмная дэкадзіроўка</string>\n    <string name=\"software_decoding_desc\">Праграмная дэкадзіроўка дазваляе прайгравальніку паказваць відэафайлы, якія не падтрымліваюцца на вашай прыладзе, але можа выклікаць затрымкі або рабіць прайграванне нестабільным на высокіх раздзяляльнасцях.</string>\n    <string name=\"volume_exceeded_100\">Гучнасць перавысіла 100%</string>\n    <string name=\"slide_up_again_to_exceed_100\">Правядзіце пальцам уверх яшчэ раз, каб зрабіць гучнасць больш за 100%</string>\n    <string name=\"update_plugins\">Абнавіць убудовы</string>\n    <string name=\"update_plugins_manually\">Абнавіць убудовы ўручную</string>\n    <string name=\"starting_plugin_update_manually\">Пачынаецца абнаўленне ўбудоў!</string>\n    <string name=\"plugins_updated_manually\">Абноўлена %d убудова(ы/ў)!</string>\n    <string name=\"no_plugins_updated_manually\">Ніводнай убудовы не было абноўлена.</string>\n    <string name=\"player_notification_channel_name\">Апавяшчэнні прайгравальніка</string>\n    <string name=\"player_notification_channel_description\">Апавяшчэнне прайгравальніка для кіравання прайграваннем у фонавым рэжыме</string>\n    <string name=\"subtitles_from_embedded\">Убудаваны</string>\n    <string name=\"subtitles_from_online\">Сеткавы</string>\n    <string name=\"all_subtitles_bold\">Зрабіць усе субцітры тоўстымі</string>\n    <string name=\"all_subtitles_italic\">Зрабіць усе субцітры курсіўнымі</string>\n    <string name=\"background_radius\">Радыус фону</string>\n    <string name=\"download_parallel_settings_des\">Колькі разных элементаў можна спампоўваць паралельна</string>\n    <string name=\"parallel_downloads\">Паралельныя спампоўкі</string>\n    <string name=\"concurrent_connections\">Адначасовыя злучэнні</string>\n    <string name=\"concurrent_connections_settings_des\">Колькі адначасовых злучэнняў можа выкарыстоўваць кожнае спампоўванне</string>\n    <string name=\"go_to_downloads\">Перайсці ў спампоўкі</string>\n    <string name=\"no_internet_connection\">Інтэрнет-злучэнне адсутнічае.\\n\\nЗлучыцеся з інтэрнэтам і паспрабуйце яшчэ раз, або паглядзіце свае спампоўкі, пакуль вы па-за сеткай.</string>\n    <string name=\"overscan_settings_des\">Змяняе краі экрана</string>\n    <string name=\"overscan_settings\">Абрэзка відарыса</string>\n    <string name=\"poster_size_settings_des\">Змяняе памер плакатаў</string>\n    <string name=\"poster_size_settings\">Памер плаката</string>\n    <string name=\"speedup_title\">Пераключэнне хуткасці пры доўгім націсканні</string>\n    <string name=\"speedup_summary\">Утрымлівайце, каб пераключыцца на 2-кратную хуткасць</string>\n    <string name=\"edit_profile_image_title\">Рэдагаваць відарыс профілю</string>\n    <string name=\"edit_profile_image_hint\">Увядзіце URL-адрас відарыса профілю</string>\n    <string name=\"edit_profile_image_error_empty\">URL-адрас не знойдзены</string>\n    <string name=\"edit_profile_image_error_invalid\">Памылковы URL-адрас або відарыс</string>\n    <string name=\"edit_profile_image_success\">Відарыс абноўлены</string>\n    <string name=\"action_mark_watched_up_to_this_episode\">Пазначыць прагледжаным усё да гэтай серыі</string>\n    <string name=\"action_remove_mark_watched_up_to_this_episode\">Прыбраць пазнаку «Прагледжана» з усіх серый да гэтай</string>\n    <string name=\"action_reload\">Перазагружана</string>\n    <string name=\"reload_provider\">Перазагрузіць пастаўшчыка</string>\n    <string name=\"name\">Назва</string>\n    <string name=\"source_name\">Назва крыніцы</string>\n    <string name=\"resolution_and_name\">Раздзяляльнасць і назва</string>\n    <string name=\"subs_subtitle_alignment\">Выраўноўванне</string>\n    <string name=\"bottom_left\">Знізу злева</string>\n    <string name=\"bottom_center\">Знізу па цэнтру</string>\n    <string name=\"bottom_right\">Знізу справа</string>\n    <string name=\"middle_left\">У сярэдзіне злева</string>\n    <string name=\"middle_center\">У сярэдзіне па цэнтру</string>\n    <string name=\"middle_right\">У сярэдзіне справа</string>\n    <string name=\"top_left\">Зверху злева</string>\n    <string name=\"top_center\">Зверху па цэнтру</string>\n    <string name=\"top_right\">Зверху справа</string>\n    <string name=\"download_queue\">Чагра спампоўванняў</string>\n    <string name=\"queue_empty_message\">У чарзе пакуль што няма спампоўванняў.</string>\n    <string name=\"source_priority\">Прыярытэт крыніц</string>\n    <string name=\"source_priority_help\">Выберыце, як сартаваць крыніцы відэа ў прайгравальніку</string>\n    <string name=\"download_all\">Спампаваць усё</string>\n    <string name=\"cancel_all\">Скасаваць усё</string>\n    <string name=\"download_episode_range\">Спампаваць %s серыю?</string>\n    <string name=\"cancel_queue_message\">Скасаваць усе спампоўванні ў чарзе?</string>\n    <plurals name=\"downloads_active\">\n        <item quantity=\"one\">%d актыўнае спампоўванне</item>\n        <item quantity=\"few\">%d актыўных спампоўвання</item>\n        <item quantity=\"many\">%d актыўных спампоўванняў</item>\n        <item quantity=\"other\">%d актыўных спампоўванняў</item>\n    </plurals>\n    <plurals name=\"downloads_queued\">\n        <item quantity=\"one\">%d спампоўванне ў чарзе</item>\n        <item quantity=\"few\">%d спампоўвання ў чарзе</item>\n        <item quantity=\"many\">%d спампоўванняў у чарзе</item>\n        <item quantity=\"other\">%d спампоўванняў у чарзе</item>\n    </plurals>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-ca/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_dub_sub_episode_text_format\" formatted=\"true\">%1$sEp.%2$d</string>\n    <string name=\"cast_format\" formatted=\"true\">Repartiment:%s</string>\n    <string name=\"next_episode_format\" formatted=\"true\">L\\'episodi %d s\\'estrenarà en</string>\n    <string name=\"next_season_episode_format\" formatted=\"true\">La temporada %1$d, Episodi %2$d s\\'estrenarà en</string>\n    <string name=\"next_episode_time_day_format\" formatted=\"true\">%1$dd%2$dh%3$dm</string>\n    <string name=\"next_episode_time_hour_format\" formatted=\"true\">%1$dh%2$dm</string>\n    <string name=\"next_episode_time_min_format\" formatted=\"true\">%dm</string>\n    <string name=\"download_time_left_hour_min_sec_format\" formatted=\"true\">%1$dh%2$dm%3$ds</string>\n    <string name=\"download_time_left_min_sec_format\" formatted=\"true\">%1$dm%2$ds</string>\n    <string name=\"download_time_left_sec_format\" formatted=\"true\">%1$ds</string>\n    <string name=\"result_poster_img_des\">Cartell</string>\n    <string name=\"search_poster_img_des\">Cartell</string>\n    <string name=\"episode_poster_img_des\">Cartell de l\\'episodi</string>\n    <string name=\"home_main_poster_img_des\">Cartell principal</string>\n    <string name=\"home_next_random_img_des\">Proper aleatori</string>\n    <string name=\"go_back_img_des\">Tornar</string>\n    <string name=\"play_from_beginning_img_des\">Reproduïr des del començament</string>\n    <string name=\"home_change_provider_img_des\">Canvia el proveïdor</string>\n    <string name=\"preview_background_img_des\">Fons de la previsualització</string>\n    <string name=\"player_speed_text_format\" formatted=\"true\">Velocitat (%.2fx)</string>\n    <string name=\"rated_format\" formatted=\"true\">Valoració: %.1f</string>\n    <string name=\"new_update_format\" formatted=\"true\">S\\'ha trobat una nova actualització!\\n%1$s-&gt;%2$s</string>\n    <string name=\"filler\" formatted=\"true\">Episodi especial</string>\n    <string name=\"duration_format\" formatted=\"true\">%d min</string>\n    <string name=\"app_name\">CloudStream</string>\n    <string name=\"play_with_app_name\">Reprodueix amb CloudStream</string>\n    <string name=\"title_home\">Inici</string>\n    <string name=\"title_search\">Cercar</string>\n    <string name=\"title_downloads\">Descàrregues</string>\n    <string name=\"title_settings\">Configuració</string>\n    <string name=\"search_hint\">Cercar…</string>\n    <string name=\"search_hint_site\" formatted=\"true\">Cercar a %s…</string>\n    <string name=\"speech_recognition_unavailable\">Reconeixement de veu no disponible</string>\n    <string name=\"begin_speaking\">Comenci a parlar…</string>\n    <string name=\"no_data\">Sense dades</string>\n    <string name=\"episode_more_options_des\">Més opcions</string>\n    <string name=\"next_episode\">Proper episodi</string>\n    <string name=\"result_tags\">Gèneres</string>\n    <string name=\"result_share\">Comparteix</string>\n    <string name=\"result_open_in_browser\">Obre al navegador</string>\n    <string name=\"browser\">Navegador</string>\n    <string name=\"skip_loading\">Omet la càrrega</string>\n    <string name=\"loading\">Carregant…</string>\n    <string name=\"type_watching\">Mirant</string>\n    <string name=\"type_on_hold\">En espera</string>\n    <string name=\"type_completed\">Completat</string>\n    <string name=\"type_dropped\">Descartat</string>\n    <string name=\"type_plan_to_watch\">Planeja mirar</string>\n    <string name=\"type_re_watching\">Tornant a mirar</string>\n    <string name=\"play_movie_button\">Reprodueix pel·licula</string>\n    <string name=\"play_trailer_button\">Reprodueix tràiler</string>\n    <string name=\"play_livestream_button\">Reprodueix Livestream</string>\n    <string name=\"play_torrent_button\">Transmet Torrent</string>\n    <string name=\"torrent_info\">Aquest vídeo és un Torrent, i implica que la vostra activitat pot ésser rastrejada\\nAssegureu-vos d\\'entendre com funcionen els Torrents abans de continuar.</string>\n    <string name=\"pick_source\">Fonts</string>\n    <string name=\"pick_subtitle\">Subtítols</string>\n    <string name=\"reload_error\">Torna a intentar la connexió…</string>\n    <string name=\"go_back\">Torna</string>\n    <string name=\"play_episode\">Reprodueix l\\'episodi</string>\n    <string name=\"download\">Descarregar</string>\n    <string name=\"downloading\">Descarregant</string>\n    <string name=\"download_paused\">Descàrrega en espera</string>\n    <string name=\"download_started\">S\\'ha iniciat la descàrrega</string>\n    <string name=\"download_failed\">Descarrega fallida</string>\n    <string name=\"download_canceled\">Descàrrega cancel·lada</string>\n    <string name=\"download_done\">Descàrrega completada</string>\n    <string name=\"downloads_delete_select\">Selecciona els elements a eliminar</string>\n    <string name=\"downloads_empty\">No hi ha descàrregues en curs.</string>\n    <string name=\"offline_file\">Disponible fora de línia</string>\n    <string name=\"select_all\">Seleccionar tot</string>\n    <string name=\"deselect_all\">Deseleccionar tot</string>\n    <string name=\"update_started\">Actualització iniciada</string>\n    <string name=\"stream\">Transmissió</string>\n    <string name=\"open_local_video\">Obre vídeo local</string>\n    <string name=\"error_loading_links_toast\">Error carregant els enllaços</string>\n    <string name=\"links_reloaded_toast\">S\\'han tornat a carregar els enllaços</string>\n    <string name=\"download_storage_text\">emmagatzematge intern</string>\n    <string name=\"app_dubbed_text\">Doblat</string>\n    <string name=\"app_subbed_text\">Sub.</string>\n    <string name=\"popup_delete_file\">Esborra el fitxer</string>\n    <string name=\"popup_play_file\">Reprodueix el fitxer</string>\n    <string name=\"popup_resume_download\">Continua la descàrrega</string>\n    <string name=\"popup_pause_download\">Posa la descàrrega en espera</string>\n    <string name=\"home_more_info\">Més informació</string>\n    <string name=\"home_expanded_hide\">Amaga</string>\n    <string name=\"home_play\">Reprodueix</string>\n    <string name=\"home_info\">Informació</string>\n    <string name=\"filter_bookmarks\">Filtra els favorits</string>\n    <string name=\"error_bookmarks_text\">Favorits</string>\n    <string name=\"action_remove_from_bookmarks\">Elimina</string>\n    <string name=\"action_add_to_bookmarks\">Defineix l\\'estat de visualització</string>\n    <string name=\"sort_apply\">Aplica</string>\n    <string name=\"sort_copy\">Copia</string>\n    <string name=\"sort_close\">Tanca</string>\n    <string name=\"sort_clear\">Buida</string>\n    <string name=\"sort_save\">Desa</string>\n    <string name=\"repo_copy_label\">Nom i URL del repositori</string>\n    <string name=\"toast_copied\">Copiat!</string>\n    <string name=\"subscribe_tooltip\">Notificació d\\'episodi nou</string>\n    <string name=\"result_search_tooltip\">Cerca en altres extensions</string>\n    <string name=\"recommendations_tooltip\">Mostra les recomanacions</string>\n    <string name=\"player_speed\">Velocitat de reproducció</string>\n    <string name=\"subtitles_settings\">Configuració dels subtítols</string>\n    <string name=\"subs_text_color\">Color del text</string>\n    <string name=\"subs_outline_color\">Color de la vora</string>\n    <string name=\"subs_background_color\">Color del fons</string>\n    <string name=\"subs_window_color\">Color de la finestra</string>\n    <string name=\"subs_edge_type\">Tipus de vora</string>\n    <string name=\"subs_subtitle_elevation\">alçada del subtítol</string>\n    <string name=\"subs_font\">Lletra</string>\n    <string name=\"subs_font_size\">Tamany de la lletra</string>\n    <string name=\"search_provider_text_providers\">Cerca amb proveïdors</string>\n    <string name=\"search_provider_text_types\">Cerca per tipus</string>\n    <string name=\"benene_count_text\">%d bananes donades als desenvolupadors</string>\n    <string name=\"benene_count_text_none\">No s\\'han donat bananes</string>\n    <string name=\"subs_auto_select_language\">Selecciona l\\'idioma automàticament</string>\n    <string name=\"subs_download_languages\">Descarrega els idiomes</string>\n    <string name=\"subs_subtitle_languages\">Idioma dels subtítols</string>\n    <string name=\"subs_hold_to_reset_to_default\">Manteniu premut per restablir els valors per defecte</string>\n    <string name=\"subs_import_text\" formatted=\"true\">Importeu tipus de lletra desant-les a %s</string>\n    <string name=\"continue_watching\">Continua mirant</string>\n    <string name=\"action_remove_watching\">Eliminar</string>\n    <string name=\"action_open_watching\">Més info</string>\n    <string name=\"action_open_play\">\\@string/home_play</string>\n    <string name=\"vpn_might_be_needed\">Potser necessiteu una VPN per que aquest proveïdor funcioni correctament</string>\n    <string name=\"vpn_torrent\">Aquest proveïdor és un Torrent, es recomana fer servir una VPN</string>\n    <string name=\"provider_info_meta\">El lloc no proveeix metadades, la càrrega del video fallarà si no existeix al lloc.</string>\n    <string name=\"torrent_plot\">Descripció</string>\n    <string name=\"normal_no_plot\">No hi ha descripció de la trama</string>\n    <string name=\"torrent_no_plot\">No hi ha descripció</string>\n    <string name=\"show_log_cat\">Mostra el registre logcat 🐈</string>\n    <string name=\"test_log\">Registre</string>\n    <string name=\"picture_in_picture\">PIP (Imatge dins d\\'imatge)</string>\n    <string name=\"picture_in_picture_des\">Continua la reproducció en una finestra en miniatura per sobre de altres aplicacions</string>\n    <string name=\"player_size_settings\">Botó de canvi de mida del reproductor</string>\n    <string name=\"audio_book_singular\">Audiollibre</string>\n    <string name=\"custom_media_singluar\">Mitjà</string>\n    <string name=\"audio_singluar\">Àudio</string>\n    <string name=\"podcast_singluar\">Pòdcast</string>\n    <string name=\"source_error\">Error a l\\'origen</string>\n    <string name=\"remote_error\">Error remot</string>\n    <string name=\"render_error\">Error de renderitzat</string>\n    <string name=\"encoding_error\">Error de codificació</string>\n    <string name=\"unsupported_error\">Error no suportat</string>\n    <string name=\"unexpected_error\">Error inesperat del reproductor</string>\n    <string name=\"storage_error\">Error de descàrrega, verifiqueu els permisos de emmagatzematge</string>\n    <string name=\"episode_action_chromecast_episode\">Envia l\\'episodi al Chromecast</string>\n    <string name=\"episode_action_chromecast_mirror\">Duplica al Chromecast</string>\n    <string name=\"episode_action_cast_mirror\">Transmet la duplicació del vídeo</string>\n    <string name=\"episode_action_play_in_app\">Reprodueix a l\\'aplicació</string>\n    <string name=\"episode_action_play_mirror\">Reprodueix en duplicat</string>\"\n    <string name=\"episode_action_play_in_format\">Reprodueix en %s</string>\n    <string name=\"episode_action_auto_download\">Descàrrega automàtica</string>\n    <string name=\"episode_action_download_mirror\">Descarrega el duplicat</string>\n    <string name=\"episode_action_reload_links\">Torna a carregar els enllaços</string>\n    <string name=\"episode_action_download_subtitle\">Descarrega els subtítols</string>\n    <string name=\"show_hd\">Etiqueta de qualitat</string>\n    <string name=\"show_dub\">Etiqueta de doblatge</string>\n    <string name=\"show_sub\">Etiqueta de subtítol</string>\n    <string name=\"show_rating\">Etiqueta de valoració</string>\n    <string name=\"show_title\">Títol</string>\n    <string name=\"poster_ui_settings\">Activa o desactiva elements al cartell</string>\n    <string name=\"no_update_found\">No s\\'ha trobat cap actualització</string>\n    <string name=\"check_for_update\">Comprova si hi ha actualitzacions</string>\n    <string name=\"video_lock\">Bloqueja</string>\n    <string name=\"video_aspect_ratio_resize\">Canvia la mida</string>\n    <string name=\"video_source\">Font</string>\n    <string name=\"video_skip_op\">Omet la obertura</string>\n    <string name=\"dont_show_again\">No el tornis a mostrar</string>\n    <string name=\"skip_update\">Omet aquesta actualització</string>\n    <string name=\"update\">Actualitza</string>\n    <string name=\"watch_quality_pref\">Qualitat de vídeo preferida (WiFi)</string>\n    <string name=\"watch_quality_pref_data\">Qualitat de vídeo preferida (dades mòbils)</string>\n    <string name=\"limit_title\">Caràcters màxims al títol del reproductor</string>\n    <string name=\"limit_title_rez\">Resolució del reproductor de vídeo</string>\n    <string name=\"pref_category_defaults\">Valors per defecte</string>\n    <string name=\"pref_category_looks\">Aspecte</string>\n    <string name=\"pref_category_ui_features\">Funcions</string>\n    <string name=\"category_general\">General</string>\n    <string name=\"random_button_settings\">Botó aleatori</string>\n    <string name=\"random_button_settings_desc\">Mostra el botó \\'aleatori\\' a l\\'inici i a la llibreria</string>\n    <string name=\"provider_lang_settings\">Idiomes de la extensió</string>\n    <string name=\"app_layout\">Disseny de l\\'aplicació</string>\n    <string name=\"preferred_media_settings\">Mitjà preferit</string>\n    <string name=\"enable_nsfw_on_providers\">Permet contingut per adults (NSFW) a les extensions compatibles</string>\n    <string name=\"subtitles_encoding\">Codificació dels subtítols</string>\n    <string name=\"category_providers\">Proveïdors</string>\n    <string name=\"category_provider_test\">Comprova els proveïdors</string>\n    <string name=\"test_extensions\">Comprova totes les extensions</string>\n    <string name=\"test_extensions_summary\">Aquesta prova està destinada als desenvolupadors, i no valida el funcionament de cap extensió.</string>\n    <string name=\"category_ui\">Disseny</string>\n    <string name=\"automatic\">Automàtic</string>\n    <string name=\"tv_layout\">Disseny a la TV</string>\n    <string name=\"phone_layout\">Disseny al telèfon</string>\n    <string name=\"emulator_layout\">Disseny a l\\'emulador</string>\n    <string name=\"primary_color_settings\">Color principal</string>\n    <string name=\"app_theme_settings\">aspecte de l\\'aplicació</string>\n    <string name=\"bottom_title_settings\">Ubicació del títol al cartell</string>\n    <string name=\"bottom_title_settings_des\">Mostra el títol sota el cartell</string>\n    <string name=\"example_password\">contrassenya123</string>\n    <string name=\"example_username\">Nom d\\'usuari</string>\n    <string name=\"example_email\">hola@mon.cat</string>\n    <string name=\"example_ip\">127.0.0.1</string>\n    <string name=\"example_site_name\">NomDelLloc</string>\n    <string name=\"example_site_url\">https://exemple.cat</string>\n    <string name=\"example_lang_name\">Codi d\\'idioma (ca_ES)</string>\n    <string name=\"login_format\" formatted=\"true\">%1$s%2$s</string>\n    <string name=\"account\">compte</string>\n    <string name=\"logout\">Tanca la sessió</string>\n    <string name=\"login\">Inicia la sessió</string>\n    <string name=\"auth_locally\">Autenticació local</string>\n    <string name=\"switch_account\">Canvia el compte</string>\n    <string name=\"add_account\">Afegeix un compte</string>\n    <string name=\"create_account\">Crea un compte</string>\n    <string name=\"add_sync\">Afegeix seguiment</string>\n    <string name=\"added_sync_format\" formatted=\"true\">Afegit %s</string>\n    <string name=\"upload_sync\">Sincronitza</string>\n    <string name=\"sync_score\">Valorat</string>\n    <string name=\"sync_score_format\" formatted=\"true\">%d / 10</string>\n    <string name=\"sync_total_episodes_none\">/ ??</string>\n    <string name=\"sync_total_episodes_some\" formatted=\"true\">/ %d</string>\n    <string name=\"authenticated_user\" formatted=\"true\">%s autenticat</string>\n    <string name=\"authenticated_user_fail\" formatted=\"true\">No s\\'ha pogut iniciar sessió a %s</string>\n    <string name=\"disable\">Deshabilita</string>\n    <string name=\"none\">Cap</string>\n    <string name=\"normal\">Normal</string>\n    <string name=\"all\">Tot</string>\n    <string name=\"max\">Màx</string>\n    <string name=\"min\">Mín</string>\n    <string name=\"subtitles_outline\">Vora</string>\n    <string name=\"subtitles_depressed\">Enfonsat</string>\n    <string name=\"subtitles_shadow\">Ombra</string>\n    <string name=\"subtitles_raised\">Elevat</string>\n    <string name=\"subtitle_offset\">Sincronitza els subtítols</string>\n    <string name=\"subtitle_offset_hint\">1000 mil·lisegons</string>\n    <string name=\"subtitle_offset_title\">Retard dels subtítols</string>\n    <string name=\"subtitle_offset_extra_hint_later_format\">Fes servir això si els subtítols es mostren %d mil·lisegons massa aviat</string>\n    <string name=\"subtitle_offset_extra_hint_before_format\">Fes servir això si els subtítols es mostren %d mil·lisegons massa tard</string>\n    <string name=\"subtitles_example_text\">Jove xef, porti whisky amb quinze glaçons d\\'hidrogen, coi</string>\n    <string name=\"recommended\">Recomanat</string>\n    <string name=\"player_loaded_subtitles\" formatted=\"true\">%s carregat</string>\n    <string name=\"player_load_subtitles\">Carrega des del fitxer</string>\n    <string name=\"player_load_subtitles_online\">Carrega des d\\'internet</string>\n    <string name=\"player_load_one_subtitle_online\">Carrega el primer disponible</string>\n    <string name=\"downloaded_file\">Fitxer descarregat</string>\n    <string name=\"actor_main\">Principal</string>\n    <string name=\"actor_supporting\">actor secundari</string>\n    <string name=\"actor_background\">antecendents de l\\'actor</string>\n    <string name=\"home_source\">Font</string>\n    <string name=\"home_random\">Aleatori</string>\n    <string name=\"coming_soon\">Aviat…</string>\n    <string name=\"quality_cam\">Càmera</string>\n    <string name=\"quality_cam_rip\">Extret de càmera</string>\n    <string name=\"quality_cam_hd\">Càmera HD</string>\n    <string name=\"quality_hq\">Alta Qualitat (HQ)</string>\n    <string name=\"quality_hd\">Alta Definició (HD)</string>\n    <string name=\"quality_ts\">Telesync (TS)</string>\n    <string name=\"quality_tc\">Telecine (TC)</string>\n    <string name=\"quality_blueray\">Blu-ray</string>\n    <string name=\"quality_workprint\">Còpia de treball (WP)</string>\n    <string name=\"quality_dvd\">DVD</string>\n    <string name=\"quality_4k\">4K</string>\n    <string name=\"quality_sd\">Definició simple (SD)</string>\n    <string name=\"quality_uhd\">Definició ultra alta (UHD)</string>\n    <string name=\"quality_hdr\">Alt rang dinàmic (HDR)</string>\n    <string name=\"quality_sdr\">Rang dinamic simple (SDR)</string>\n    <string name=\"quality_webrip\">Web (webrip)</string>\n    <string name=\"poster_image\">Imatge del cartell</string>\n    <string name=\"qr_image\">imatge del codi QR</string>\n    <string name=\"category_player\">Reproductor</string>\n    <string name=\"resolution_and_title\">Resolució i títol</string>\n    <string name=\"title\">Títol</string>\n    <string name=\"resolution\">Resolució</string>\n    <string name=\"error_invalid_id\">Identificador no vàlid</string>\n    <string name=\"error_invalid_data\">Dades no vàlides</string>\n    <string name=\"error_invalid_url\">URL no vàlida</string>\n    <string name=\"error\">Error</string>\n    <string name=\"subtitles_remove_captions\">Elimina la transcripció de l\\'àudio (CC) dels subtítols</string>\n    <string name=\"subtitles_remove_bloat\">Eliminar contingut irrellevant dels subtítols</string>\n    <string name=\"subtitles_filter_lang\">Filtra per l\\'idioma preferit</string>\n    <string name=\"extras\">Extres</string>\n    <string name=\"trailer\">Tràiler</string>\n    <string name=\"network_adress_example\">https://exemple.cat/exemple.mp4</string>\n    <string name=\"referer\">Referit (opcional)</string>\n    <string name=\"next\">Següent</string>\n    <string name=\"provider_languages_tip\">Veure vídeos en aquests idiomes</string>\n    <string name=\"previous\">Anterior</string>\n    <string name=\"skip_setup\">Omet la configuració</string>\n    <string name=\"app_layout_subtext\">Canvia l\\'aspecte de la aplicació perquè s\\'adapti al vostre dispositiu</string>\n    <string name=\"preferred_media_subtext\">Què vols veure</string>\n    <string name=\"setup_done\">Fet</string>\n    <string name=\"extensions\">Extensions</string>\n    <string name=\"add_repository\">Afegir repositori</string>\n    <string name=\"set_default\">Estableix opció per defecte</string>\n    <string name=\"use\">Utilitza</string>\n    <string name=\"edit\">Edita</string>\n    <string name=\"profiles\">Perfils</string>\n    <string name=\"help\">Ajuda</string>\n    <string name=\"quality_profile_help\">Aqui pots modificar l\\'ordre de les fonts. Si un vídeo té una prioritat superior, apareixerà abans a la selecció de fonts. La suma de la prioritat de font i la prioritat de qualitat és la prioritat de vídeo.\\n\\nFont: 3\\nQualitat: 7\\nTindría una prioritat de vídeo total de 10.\\n\\nNOTA: Si la suma és 10 o més, el reproductor ometrà autimàticament la càrrega quan es carregui l\\'enllaç!</string>\n    <string name=\"qualities\">Qualitats</string>\n    <string name=\"profile_background_des\">Fons del perfil</string>\n    <string name=\"unable_to_inflate\">La interfície d\\'usuari no s\\'ha pogut crear correctament, es tracta d\\'un ERROR MAJOR que s\\'ha de reportar immediatament %s</string>\n    <string name=\"already_voted\">Ja heu votat</string>\n    <string name=\"favorites_list_name\">Preferits</string>\n    <string name=\"favorite_added\">%s afegit als favorits</string>\n    <string name=\"favorite_removed\">%s eliminat dels favorits</string>\n    <string name=\"action_add_to_favorites\">Afegir als favorits</string>\n    <string name=\"action_remove_from_favorites\">Eliminar dels favorits</string>\n    <string name=\"duplicate_title\">S\\'ha trobat un possible duplicat</string>\n    <string name=\"duplicate_add\">Afegir</string>\n    <string name=\"duplicate_replace\">Reemplaça</string>\n    <string name=\"duplicate_replace_all\">Reemplaça-ho tot</string>\n    <string name=\"duplicate_message_single\" formatted=\"true\">Un possible duplicat ja existeix a la vostra bibliotèca: \\'%s\\'.\\n\\nVol afegir aquest element de totes maneres, reemplaçar l\\'existent o cancel·lar aquesta acció?</string>\n    <string name=\"duplicate_message_multiple\" formatted=\"true\">Diversos possibles duplicats ja existeixen a la vostra bibliotèca:\\n\\n%s\\n\\nVol afegir aquest element de totes maneres, reemplaçar els existents o cancel·lar aquesta acció?</string>\n    <string name=\"enter_pin\">Introduïu el PIN</string>\n    <string name=\"enter_pin_with_name\" formatted=\"true\">Introduïu el PIN per %s</string>\n    <string name=\"enter_current_pin\">Introduïu el PIN actual</string>\n    <string name=\"lock_profile\">Bloqueja el perfil</string>\n    <string name=\"pin\">PIN</string>\n    <string name=\"pin_error_incorrect\">PIN incorrecte. Si us plau, torneu a intentar-ho.</string>\n    <string name=\"pin_error_length\">El PIN ha de tenir 4 caràcters</string>\n    <string name=\"select_an_account\">Seleccioneu un compte</string>\n    <string name=\"no_account\">Sense compte</string>\n    <string name=\"manage_accounts\">Gestiona els comptes</string>\n    <string name=\"edit_account\">Edita el compte</string>\n    <string name=\"logged_account\" formatted=\"true\">Connectat com %s</string>\n    <string name=\"skip_startup_account_select_pref\">Omet la selecció de comtpe a l\\'inici</string>\n    <string name=\"use_default_account\">Utilitza el compte per defecte</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/xml/backup_descriptor.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<full-backup-content>\n</full-backup-content>"
  },
  {
    "path": "app/src/main/res/xml/data_extraction_rules.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<data-extraction-rules>\n</data-extraction-rules>"
  },
  {
    "path": "app/src/main/res/xml/provider_paths.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<paths>\n    <external-path\n            name=\"external\"\n            path=\".\" />\n    <external-files-path\n            name=\"external_files\"\n            path=\".\" />\n    <cache-path\n            name=\"cache\"\n            path=\".\" />\n    <external-cache-path\n            name=\"external_cache\"\n            path=\".\" />\n    <files-path\n            name=\"files\"\n            path=\".\" />\n</paths>"
  },
  {
    "path": "app/src/main/res/xml/settings_account.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <PreferenceCategory\n        android:title=\"@string/pref_category_accounts\">\n\n        <Preference\n            android:icon=\"@drawable/mal_logo\"\n            android:key=\"@string/mal_key\" />\n\n        <Preference\n            android:icon=\"@drawable/kitsu_icon\"\n            android:key=\"@string/kitsu_key\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_anilist_icon\"\n            android:key=\"@string/anilist_key\" />\n\n        <Preference\n            android:icon=\"@drawable/simkl_logo\"\n            android:key=\"@string/simkl_key\" />\n\n        <Preference\n            android:icon=\"@drawable/open_subtitles_icon\"\n            android:key=\"@string/opensubtitles_key\" />\n\n        <Preference\n            android:icon=\"@drawable/subdl_logo_big\"\n            android:key=\"@string/subdl_key\" />\n\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:icon=\"@drawable/ic_outline_account_circle_24\"\n            android:key=\"@string/skip_startup_account_select_key\"\n            android:title=\"@string/skip_startup_account_select_pref\" />\n\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_category_security\"\n        app:key=\"@string/pref_category_security_key\">\n\n        <SwitchPreference\n            android:key=\"@string/biometric_key\"\n            android:defaultValue=\"false\"\n            android:summary=\"@string/biometric_setting_summary\"\n            android:icon=\"@drawable/ic_fingerprint\"\n            android:title=\"@string/biometric_setting\" />\n\n    </PreferenceCategory>\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/settings_general.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <Preference\n        android:icon=\"@drawable/ic_baseline_language_24\"\n        android:key=\"@string/locale_key\"\n        android:title=\"@string/app_language\" />\n\n    <Preference\n        android:icon=\"@drawable/ic_baseline_warning_24\"\n        android:key=\"@string/legal_notice_key\"\n        android:title=\"@string/legal_notice\" />\n\n    <Preference\n        android:icon=\"@drawable/benene\"\n        android:key=\"@string/benene_count\"\n        android:title=\"@string/benene\"\n        app:summary=\"@string/benene_des\" />\n\n    <PreferenceCategory android:title=\"@string/title_downloads\">\n\n        <Preference\n            android:icon=\"@drawable/netflix_download\"\n            android:key=\"@string/download_path_key\"\n            android:title=\"@string/download_path_pref\" />\n\n        <SeekBarPreference\n            android:defaultValue=\"3\"\n            android:icon=\"@drawable/arrow_or_edge_24px\"\n            android:key=\"@string/download_parallel_key\"\n            android:max=\"10\"\n            android:summary=\"@string/download_parallel_settings_des\"\n            android:title=\"@string/parallel_downloads\"\n            app:adjustable=\"true\"\n            app:min=\"1\"\n            app:seekBarIncrement=\"1\"\n            app:showSeekBarValue=\"true\" />\n\n        <SeekBarPreference\n            android:defaultValue=\"3\"\n            android:icon=\"@drawable/arrow_and_edge_24px\"\n            android:key=\"@string/download_concurrent_key\"\n            android:max=\"10\"\n            android:summary=\"@string/concurrent_connections_settings_des\"\n            android:title=\"@string/concurrent_connections\"\n            app:adjustable=\"true\"\n            app:min=\"1\"\n            app:seekBarIncrement=\"1\"\n            app:showSeekBarValue=\"true\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_battery\"\n            android:key=\"@string/battery_optimisation_key\"\n            android:title=\"@string/battery_dialog_title\" />\n\n    </PreferenceCategory>\n\n    <PreferenceCategory android:title=\"@string/pref_category_bypass\">\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_add_24\"\n            android:key=\"@string/override_site_key\"\n            android:summary=\"@string/add_site_summary\"\n            android:title=\"@string/add_site_pref\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_dns_24\"\n            android:key=\"@string/dns_key\"\n            android:summary=\"@string/dns_pref_summary\"\n            android:title=\"@string/dns_pref\" />\n\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:icon=\"@drawable/ic_github_logo\"\n            android:key=\"@string/jsdelivr_proxy_key\"\n            android:summary=\"@string/jsdelivr_proxy_summary\"\n            android:title=\"@string/jsdelivr_proxy\" />\n\n    </PreferenceCategory>\n\n    <PreferenceCategory android:title=\"@string/pref_category_links\">\n\n        <Preference\n            android:icon=\"@drawable/ic_github_logo\"\n            android:title=\"@string/github\"\n            app:summary=\"https://github.com/recloudstream/cloudstream\">\n            <intent\n                android:action=\"android.intent.action.VIEW\"\n                android:data=\"https://github.com/recloudstream/cloudstream\" />\n        </Preference>\n\n        <Preference\n            android:icon=\"@drawable/quick_novel_icon\"\n            android:title=\"@string/lightnovel\"\n            app:summary=\"https://github.com/LagradOst/QuickNovel\">\n            <intent\n                android:action=\"android.intent.action.VIEW\"\n                android:data=\"https://github.com/LagradOst/QuickNovel\" />\n        </Preference>\n        <Preference\n            android:icon=\"@drawable/ic_baseline_discord_24\"\n            android:title=\"@string/discord\"\n            app:summary=\"https://discord.gg/5Hus6fM\">\n            <intent\n                android:action=\"android.intent.action.VIEW\"\n                android:data=\"https://discord.gg/5Hus6fM\" />\n        </Preference>\n        <Preference\n            android:icon=\"@drawable/baseline_description_24\"\n            android:title=\"@string/cs3wiki\"\n            app:summary=\"https://cloudstream.miraheze.org/\">\n            <intent\n                android:action=\"android.intent.action.VIEW\"\n                android:data=\"https://cloudstream.miraheze.org/\" />\n        </Preference>\n\n    </PreferenceCategory>\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/settings_player.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <SwitchPreference\n        android:icon=\"@drawable/baseline_sync_24\"\n        android:summary=\"@string/episode_sync_settings_des\"\n        android:title=\"@string/episode_sync_settings\"\n        app:defaultValue=\"true\"\n        app:key=\"@string/episode_sync_enabled_key\" />\n\n    <PreferenceCategory android:title=\"@string/pref_category_defaults\">\n        <!--        <Preference-->\n        <!--            android:icon=\"@drawable/ic_baseline_hd_24\"-->\n        <!--            android:key=\"@string/quality_pref_key\"-->\n        <!--            android:title=\"@string/watch_quality_pref\" />-->\n        <!--        <Preference-->\n        <!--            android:icon=\"@drawable/ic_baseline_hd_24\"-->\n        <!--            android:key=\"@string/quality_pref_mobile_data_key\"-->\n        <!--            android:title=\"@string/watch_quality_pref_data\" />-->\n\n        <Preference\n            android:icon=\"@drawable/netflix_play\"\n            android:key=\"@string/player_default_key\"\n            android:title=\"@string/player_pref\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory android:title=\"@string/pref_category_player_layout\">\n        <Preference\n            android:icon=\"@drawable/ic_baseline_text_format_24\"\n            android:key=\"@string/prefer_limit_title_key\"\n            android:title=\"@string/limit_title\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_text_format_24\"\n            android:key=\"@string/prefer_limit_show_player_info\"\n            android:title=\"@string/limit_title_rez\" />\n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:icon=\"@drawable/ic_baseline_text_format_24\"\n            android:key=\"@string/hide_player_control_names_key\"\n            android:title=\"@string/hide_player_control_names\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory android:title=\"@string/pref_category_subtitles\">\n        <Preference\n            android:icon=\"@drawable/ic_outline_subtitles_24\"\n            android:key=\"@string/subtitle_settings_key\"\n            android:title=\"@string/player_subtitles_settings\"\n            app:summary=\"@string/player_subtitles_settings_des\" />\n        <Preference\n            android:icon=\"@drawable/ic_outline_subtitles_24\"\n            android:key=\"@string/subtitle_settings_chromecast_key\"\n            android:title=\"@string/chromecast_subtitles_settings\"\n            app:summary=\"@string/chromecast_subtitles_settings_des\" />\n    </PreferenceCategory>\n\n\n    <PreferenceCategory android:title=\"@string/pref_category_player_features\">\n        <Preference\n            android:icon=\"@drawable/ic_baseline_people_24\"\n            android:summary=\"@string/source_priority_help\"\n            android:title=\"@string/source_priority\"\n            app:key=\"@string/player_source_priority_key\"/>\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_picture_in_picture_alt_24\"\n            android:summary=\"@string/picture_in_picture_des\"\n            android:title=\"@string/picture_in_picture\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/pip_enabled_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_aspect_ratio_24\"\n            android:summary=\"@string/player_size_settings_des\"\n            android:title=\"@string/player_size_settings\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/player_resize_enabled_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_speed_24\"\n            android:summary=\"@string/speed_setting_summary\"\n            android:title=\"@string/eigengraumode_settings\"\n            app:defaultValue=\"false\"\n            app:key=\"@string/playback_speed_enabled_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/speedup\"\n            android:summary=\"@string/speedup_summary\"\n            android:title=\"@string/speedup_title\"\n            app:defaultValue=\"false\"\n            app:key=\"@string/speedup_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_skip_next_24\"\n            android:summary=\"@string/autoplay_next_settings_des\"\n            android:title=\"@string/autoplay_next_settings\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/autoplay_next_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_skip_next_24\"\n            android:summary=\"@string/enable_skip_op_from_database_des\"\n            android:title=\"@string/video_skip_op\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/enable_skip_op_from_database\" />\n        <SwitchPreference\n            android:icon=\"@drawable/screen_rotation\"\n            android:summary=\"@string/rotate_video_desc\"\n            android:title=\"@string/rotate_video\"\n            app:defaultValue=\"false\"\n            app:key=\"@string/rotate_video_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/screen_rotation\"\n            android:summary=\"@string/auto_rotate_video_desc\"\n            android:title=\"@string/auto_rotate_video\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/auto_rotate_video_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/preview_seekbar_24\"\n            android:summary=\"@string/preview_seekbar_desc\"\n            android:title=\"@string/preview_seekbar\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/preview_seekbar_key\" />\n        <Preference\n            android:icon=\"@drawable/ic_baseline_extension_24\"\n            android:summary=\"@string/software_decoding_desc\"\n            android:title=\"@string/software_decoding\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/software_decoding_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/sun_7_24\"\n            android:summary=\"@string/extra_brightness_settings_des\"\n            android:title=\"@string/extra_brightness_settings\"\n            app:defaultValue=\"false\"\n            app:key=\"@string/extra_brightness_key\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:title=\"@string/pref_category_gestures\"\n        app:key=\"@string/pref_category_gestures_key\">\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_ondemand_video_24\"\n            android:summary=\"@string/swipe_to_seek_settings_des\"\n            android:title=\"@string/swipe_to_seek_settings\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/swipe_enabled_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_ondemand_video_24\"\n            android:summary=\"@string/swipe_to_change_settings_des\"\n            android:title=\"@string/swipe_to_change_settings\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/swipe_vertical_enabled_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_touch_app_24\"\n            android:summary=\"@string/double_tap_to_seek_settings_des\"\n            android:title=\"@string/double_tap_to_seek_settings\"\n            app:defaultValue=\"false\"\n            app:key=\"@string/double_tap_enabled_key\" />\n        <SwitchPreference\n            android:icon=\"@drawable/netflix_pause\"\n            android:summary=\"@string/double_tap_to_pause_settings_des\"\n            android:title=\"@string/double_tap_to_pause_settings\"\n            app:defaultValue=\"false\"\n            app:key=\"@string/double_tap_pause_enabled_key\" />\n\n        <SeekBarPreference\n            android:defaultValue=\"10\"\n            android:max=\"60\"\n            android:title=\"@string/double_tap_to_seek_amount_settings\"\n            app:adjustable=\"true\"\n            app:defaultValue=\"10\"\n            app:icon=\"@drawable/go_forward_30\"\n            app:key=\"@string/double_tap_seek_time_key\"\n            app:min=\"5\"\n            app:seekBarIncrement=\"5\"\n            app:showSeekBarValue=\"true\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory android:title=\"@string/pref_category_cache\">\n        <Preference\n            android:icon=\"@drawable/ic_baseline_storage_24\"\n            android:key=\"@string/video_buffer_disk_key\"\n            android:summary=\"@string/video_disk_description\"\n            android:title=\"@string/video_buffer_disk_settings\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_storage_24\"\n            android:key=\"@string/video_buffer_size_key\"\n            android:summary=\"@string/video_ram_description\"\n            android:title=\"@string/video_buffer_size_settings\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_storage_24\"\n            android:key=\"@string/video_buffer_length_key\"\n            android:summary=\"@string/video_ram_description\"\n            android:title=\"@string/video_buffer_length_settings\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_delete_outline_24\"\n            android:key=\"@string/video_buffer_clear_key\"\n            android:title=\"@string/video_buffer_clear_settings\" />\n    </PreferenceCategory>\n    <PreferenceCategory\n        android:key=\"@string/pref_category_android_tv_key\"\n        android:title=\"@string/pref_category_android_tv\">\n        <SeekBarPreference\n            android:defaultValue=\"10\"\n            android:max=\"60\"\n            android:summary=\"@string/android_tv_interface_on_seek_settings_summary\"\n            android:title=\"@string/android_tv_interface_on_seek_settings\"\n            app:adjustable=\"true\"\n            app:defaultValue=\"30\"\n            app:icon=\"@drawable/go_forward_30\"\n            app:key=\"@string/android_tv_interface_on_seek_key\"\n            app:min=\"5\"\n            app:seekBarIncrement=\"5\"\n            app:showSeekBarValue=\"true\" />\n        <SeekBarPreference\n            android:defaultValue=\"10\"\n            android:max=\"60\"\n            android:summary=\"@string/android_tv_interface_off_seek_settings_summary\"\n            android:title=\"@string/android_tv_interface_off_seek_settings\"\n            app:adjustable=\"true\"\n            app:defaultValue=\"10\"\n            app:icon=\"@drawable/go_forward_30\"\n            app:key=\"@string/android_tv_interface_off_seek_key\"\n            app:min=\"5\"\n            app:seekBarIncrement=\"5\"\n            app:showSeekBarValue=\"true\" />\n    </PreferenceCategory>\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/settings_providers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <Preference\n        android:icon=\"@drawable/ic_baseline_language_24\"\n        android:key=\"@string/provider_lang_key\"\n        android:title=\"@string/provider_lang_settings\" />\n\n    <Preference\n        android:icon=\"@drawable/ic_baseline_play_arrow_24\"\n        android:key=\"@string/prefer_media_type_key\"\n        android:title=\"@string/preferred_media_settings\" />\n    <Preference\n        android:icon=\"@drawable/ic_outline_voice_over_off_24\"\n        android:key=\"@string/display_sub_key\"\n        android:title=\"@string/display_subbed_dubbed_settings\" />\n\n    <SwitchPreference\n        android:icon=\"@drawable/ic_baseline_extension_24\"\n        android:key=\"@string/enable_nsfw_on_providers_key\"\n        android:summary=\"@string/apply_on_restart\"\n        android:title=\"@string/enable_nsfw_on_providers\"\n        app:defaultValue=\"false\" />\n\n    <Preference\n        android:icon=\"@drawable/baseline_network_ping_24\"\n        android:key=\"@string/test_providers_key\"\n        android:title=\"@string/test_extensions\"\n        android:summary=\"@string/test_extensions_summary\"/>\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/settings_ui.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <PreferenceCategory android:title=\"@string/pref_category_looks\">\n        <Preference\n            android:icon=\"@drawable/ic_baseline_color_lens_24\"\n            android:key=\"@string/primary_color_key\"\n            android:title=\"@string/primary_color_settings\" />\n        <Preference\n            android:icon=\"@drawable/ic_baseline_color_lens_24\"\n            android:key=\"@string/app_theme_key\"\n            android:title=\"@string/app_theme_settings\" />\n        <Preference\n            android:icon=\"@drawable/ic_baseline_tv_24\"\n            android:key=\"@string/app_layout_key\"\n            android:title=\"@string/app_layout\" />\n        <SwitchPreference\n            android:defaultValue=\"true\"\n            android:icon=\"@drawable/title_24px\"\n            android:key=\"@string/bottom_title_key\"\n            android:summary=\"@string/bottom_title_settings_des\"\n            android:title=\"@string/bottom_title_settings\" />\n\n        <SeekBarPreference\n            android:defaultValue=\"0\"\n            android:icon=\"@drawable/arrows_input_24px\"\n            android:key=\"@string/overscan_key\"\n            android:max=\"100\"\n            android:summary=\"@string/overscan_settings_des\"\n            android:title=\"@string/overscan_settings\"\n            app:adjustable=\"true\"\n            app:min=\"0\"\n            app:seekBarIncrement=\"1\"\n            app:showSeekBarValue=\"true\" />\n\n        <SeekBarPreference\n            android:defaultValue=\"0\"\n            android:icon=\"@drawable/baseline_grid_view_24\"\n            android:key=\"@string/poster_size_key\"\n            android:max=\"15\"\n            android:summary=\"@string/poster_size_settings_des\"\n            android:title=\"@string/poster_size_settings\"\n            app:adjustable=\"true\"\n            app:min=\"0\"\n            app:seekBarIncrement=\"1\"\n            app:showSeekBarValue=\"true\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory android:title=\"@string/pref_category_ui_features\">\n        <Preference\n            android:icon=\"@drawable/ic_baseline_tv_24\"\n            android:key=\"@string/poster_ui_key\"\n            android:title=\"@string/poster_ui_settings\" />\n        <SwitchPreference\n            android:icon=\"@drawable/search_icon\"\n            android:summary=\"@string/advanced_search_des\"\n            android:title=\"@string/advanced_search\"\n            app:defaultValue=\"true\"\n            app:key=\"advanced_search\" />\n        <SwitchPreference\n            android:icon=\"@drawable/search_icon\"\n            android:summary=\"@string/search_suggestions_des\"\n            android:title=\"@string/search_suggestions\"\n            app:defaultValue=\"true\"\n            app:key=\"search_suggestions_enabled\" />\n        <SwitchPreference\n            android:defaultValue=\"true\"\n            android:icon=\"@drawable/baseline_theaters_24\"\n            android:key=\"@string/show_trailers_key\"\n            android:title=\"@string/show_trailers_settings\" />\n        <SwitchPreference\n            android:defaultValue=\"true\"\n            android:icon=\"@drawable/kitsu_icon\"\n            android:key=\"@string/show_kitsu_posters_key\"\n            android:title=\"@string/kitsu_settings\" />\n        <SwitchPreference\n            android:defaultValue=\"true\"\n            android:icon=\"@drawable/ic_baseline_people_24\"\n            android:key=\"@string/show_cast_in_details_key\"\n            android:title=\"@string/show_cast_in_details\" />    \n        <SwitchPreference\n            android:defaultValue=\"false\"\n            android:icon=\"@drawable/ic_baseline_skip_next_24\"\n            android:key=\"@string/show_fillers_key\"\n            android:title=\"@string/show_fillers_settings\" />\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_play_arrow_24\"\n            android:summary=\"@string/random_button_settings_desc\"\n            android:title=\"@string/random_button_settings\"\n            app:defaultValue=\"false\"\n            app:key=\"@string/random_button_key\" />\n        <Preference\n            android:icon=\"@drawable/ic_baseline_exit_24\"\n            android:key=\"@string/confirm_exit_key\"\n            android:summary=\"@string/confirm_before_exiting_desc\"\n            android:title=\"@string/confirm_before_exiting_title\" />\n        <Preference\n            android:icon=\"@drawable/ic_baseline_filter_list_24\"\n            android:key=\"@string/pref_filter_search_quality_key\"\n            android:title=\"@string/pref_filter_search_quality\" />\n    </PreferenceCategory>\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/settings_updates.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <PreferenceCategory\n        android:title=\"@string/pref_category_app_updates\">\n        <Preference\n            android:title=\"@string/check_for_update\"\n            app:icon=\"@drawable/ic_baseline_system_update_24\"\n            app:key=\"@string/manual_check_update_key\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_developer_mode_24\"\n            android:title=\"@string/install_prerelease\"\n            app:key=\"@string/install_prerelease_key\" />\n\n        <Preference\n            android:icon=\"@drawable/netflix_download\"\n            android:key=\"@string/apk_installer_key\"\n            android:title=\"@string/apk_installer_settings\"\n            android:summary=\"@string/apk_installer_settings_des\" />\n\n        <SwitchPreference\n            android:icon=\"@drawable/ic_baseline_notifications_active_24\"\n            android:summary=\"@string/updates_settings_des\"\n            android:title=\"@string/updates_settings\"\n            app:defaultValue=\"true\"\n            app:key=\"@string/auto_update_key\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_category_backup\">\n        <Preference\n            android:icon=\"@drawable/baseline_save_as_24\"\n            android:key=\"@string/backup_key\"\n            android:title=\"@string/backup_settings\" />\n\n        <Preference\n            android:icon=\"@drawable/baseline_save_as_24\"\n            android:key=\"@string/automatic_backup_key\"\n            android:title=\"@string/backup_frequency\" />\n\n        <Preference\n            android:icon=\"@drawable/baseline_restore_page_24\"\n            android:key=\"@string/restore_key\"\n            android:title=\"@string/restore_settings\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_folder_open_24\"\n            android:key=\"@string/backup_path_key\"\n            android:title=\"@string/backup_path_title\" />\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_category_extensions\">\n        <SwitchPreference\n            android:defaultValue=\"true\"\n            android:icon=\"@drawable/ic_baseline_extension_24\"\n            android:key=\"@string/auto_update_plugins_key\"\n            android:title=\"@string/automatic_plugin_updates\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_extension_24\"\n            android:key=\"@string/auto_download_plugins_key\"\n            android:title=\"@string/automatic_plugin_download\"\n            android:summary=\"@string/automatic_plugin_download_summary\" />\n\n        <Preference\n            android:icon=\"@drawable/ic_baseline_extension_24\"\n            android:key=\"@string/manual_update_plugins_key\"\n            android:title=\"@string/update_plugins\"\n            android:summary=\"@string/update_plugins_manually\"/>\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        android:title=\"@string/pref_category_actions\">\n        <Preference\n            android:icon=\"@drawable/baseline_description_24\"\n            android:key=\"@string/show_logcat_key\"\n            android:title=\"@string/show_log_cat\" />\n        <Preference\n            android:icon=\"@drawable/ic_baseline_construction_24\"\n            android:title=\"@string/redo_setup_process\"\n            app:key=\"@string/redo_setup_key\" />\n    </PreferenceCategory>\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/prerelease/res/drawable/ic_banner_foreground.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n        android:width=\"320dp\"\n        android:height=\"180dp\"\n        android:viewportWidth=\"320\"\n        android:viewportHeight=\"180\">\n    <group\n            android:scaleX=\"0.6666667\"\n            android:scaleY=\"0.6666667\"\n            android:translateX=\"53.333332\"\n            android:translateY=\"30\">\n        <group\n                android:scaleX=\"0\"\n                android:scaleY=\"0\"\n                android:translateX=\"160\"\n                android:translateY=\"90\">\n            <group android:translateY=\"155.39062\">\n                <path\n                        android:pathData=\"M81.84375,-4.53125Q70.671875,2,54,2Q32.484375,2,19.546875,-11.953125Q6.609375,-25.921875,6.609375,-48.59375Q6.609375,-72.953125,21.15625,-87.96875Q35.71875,-103,58.078125,-103Q72.421875,-103,81.84375,-98.59375L81.84375,-86Q71.015625,-92,57.9375,-92Q40.578125,-92,29.78125,-80.375Q18.984375,-68.765625,18.984375,-49.34375Q18.984375,-30.890625,29.078125,-19.9375Q39.171875,-9,55.546875,-9Q70.734375,-9,81.84375,-16L81.84375,-4.53125Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M112.203125,0L100.671875,0L100.671875,-107L112.203125,-107L112.203125,0Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M165.76562,2Q149.8125,2,140.28125,-8.171875Q130.75,-18.34375,130.75,-35.15625Q130.75,-53.4375,140.65625,-63.71875Q150.57812,-74,167.45312,-74Q183.5625,-74,192.59375,-64Q201.625,-54,201.625,-36.28125Q201.625,-18.921875,191.89062,-8.453125Q182.15625,2,165.76562,2ZM166.60938,-64Q155.5,-64,149.03125,-56.4375Q142.5625,-48.875,142.5625,-35.578125Q142.5625,-22.78125,149.09375,-15.390625Q155.64062,-8,166.60938,-8Q177.79688,-8,183.79688,-15.25Q189.8125,-22.5,189.8125,-35.859375Q189.8125,-49.359375,183.79688,-56.671875Q177.79688,-64,166.60938,-64Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M277.89062,0L266.35938,0L266.35938,-11.375L266.07812,-11.375Q258.90625,2,243.85938,2Q218.125,2,218.125,-28.78125L218.125,-72L229.59375,-72L229.59375,-30.78125Q229.59375,-8,247.03125,-8Q255.46875,-8,260.90625,-14.21875Q266.35938,-20.453125,266.35938,-30.5L266.35938,-72L277.89062,-72L277.89062,0Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M363.125,0L351.59375,0L351.59375,-12.21875L351.3125,-12.21875Q343.29688,2,326.5625,2Q313,2,304.875,-7.75Q296.75,-17.5,296.75,-34.296875Q296.75,-52.3125,305.75,-63.15625Q314.75,-74,329.73438,-74Q344.5625,-74,351.3125,-62.03125L351.59375,-62.03125L351.59375,-107L363.125,-107L363.125,0ZM351.59375,-32.546875L351.59375,-43.171875Q351.59375,-51.90625,345.82812,-57.953125Q340.0625,-64,331.20312,-64Q320.65625,-64,314.60938,-56.25Q308.5625,-48.515625,308.5625,-34.875Q308.5625,-22.421875,314.35938,-15.203125Q320.17188,-8,329.9375,-8Q339.57812,-8,345.57812,-14.953125Q351.59375,-21.921875,351.59375,-32.546875Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M383.51562,-4.078125L383.51562,-18Q385.90625,-15.90625,389.23438,-14.234375Q392.57812,-12.5625,396.26562,-11.40625Q399.96875,-10.25,403.6875,-9.625Q407.42188,-9,410.57812,-9Q421.48438,-9,426.85938,-13Q432.23438,-17,432.23438,-24.5Q432.23438,-28.609375,430.4375,-31.65625Q428.65625,-34.703125,425.48438,-37.21875Q422.32812,-39.734375,418,-42.03125Q413.67188,-44.328125,408.6875,-46.890625Q403.40625,-49.578125,398.82812,-52.34375Q394.26562,-55.109375,390.89062,-58.4375Q387.51562,-61.765625,385.57812,-65.96875Q383.65625,-70.1875,383.65625,-75.859375Q383.65625,-82.796875,386.67188,-87.9375Q389.70312,-93.078125,394.625,-96.40625Q399.54688,-99.734375,405.82812,-101.359375Q412.125,-103,418.67188,-103Q433.57812,-103,440.39062,-99.296875L440.39062,-86Q431.46875,-92,417.46875,-92Q413.60938,-92,409.73438,-91.1875Q405.875,-90.390625,402.84375,-88.578125Q399.82812,-86.765625,397.92188,-83.90625Q396.03125,-81.046875,396.03125,-76.921875Q396.03125,-73.03125,397.46875,-70.1875Q398.90625,-67.359375,401.71875,-65.015625Q404.53125,-62.6875,408.57812,-60.484375Q412.625,-58.28125,417.89062,-55.671875Q423.3125,-52.96875,428.15625,-50Q433.01562,-47.03125,436.67188,-43.40625Q440.32812,-39.796875,442.46875,-35.40625Q444.60938,-31.015625,444.60938,-25.34375Q444.60938,-17.828125,441.6875,-12.625Q438.78125,-7.421875,433.8125,-4.15625Q428.85938,-0.90625,422.39062,0.546875Q415.92188,2,408.75,2Q406.35938,2,402.84375,1.59375Q399.32812,1.1875,395.67188,0.40625Q392.01562,-0.375,388.75,-1.515625Q385.48438,-2.671875,383.51562,-4.078125Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M497.07812,-0.234375Q493,2,486.3125,2Q467.40625,2,467.40625,-19.1875L467.40625,-62L455.03125,-62L455.03125,-72L467.40625,-72L467.40625,-89.328125L478.9375,-93L478.9375,-72L497.07812,-72L497.07812,-62L478.9375,-62L478.9375,-21.4375Q478.9375,-14.1875,481.39062,-11.09375Q483.85938,-8,489.54688,-8Q493.90625,-8,497.07812,-10L497.07812,-0.234375Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M550.21875,-60Q547.2031,-62,541.5,-62Q534.125,-62,529.15625,-55.109375Q524.2031,-48.21875,524.2031,-36.328125L524.2031,0L512.6719,0L512.6719,-72L524.2031,-72L524.2031,-56.515625L524.4844,-56.515625Q526.9531,-64.296875,532.0156,-68.640625Q537.0781,-73,543.3281,-73Q547.8281,-73,550.21875,-72.015625L550.21875,-60Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M620.5469,-33L569.7031,-33Q569.9844,-21.03125,576.1719,-14.515625Q582.3594,-8,593.1875,-8Q605.3594,-8,615.5469,-16L615.5469,-5Q606.0625,2,590.4531,2Q575.1875,2,566.46875,-7.890625Q557.75,-17.78125,557.75,-35.71875Q557.75,-52.65625,567.28125,-63.328125Q576.8125,-74,590.9375,-74Q605.0781,-74,612.8125,-64.765625Q620.5469,-55.53125,620.5469,-39.109375L620.5469,-33ZM608.7344,-43Q608.65625,-52.9375,603.90625,-58.46875Q599.1719,-64,590.7344,-64Q582.5781,-64,576.875,-58.1875Q571.1875,-52.375,569.84375,-43L608.7344,-43Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M689.21875,0L677.6875,0L677.6875,-11.234375L677.40625,-11.234375Q669.875,2,655.25,2Q644.5,2,638.40625,-3.765625Q632.3281,-9.546875,632.3281,-19.109375Q632.3281,-39.578125,656.09375,-42.9375L677.6875,-46Q677.6875,-64,662.84375,-64Q649.84375,-64,639.3594,-55L639.3594,-67.09375Q649.9844,-74,663.8281,-74Q689.21875,-74,689.21875,-47.03125L689.21875,0ZM677.6875,-37L660.3125,-34.5625Q652.2969,-33.40625,648.21875,-30.5Q644.1406,-27.59375,644.1406,-20.203125Q644.1406,-14.8125,647.90625,-11.40625Q651.6719,-8,657.9219,-8Q666.5,-8,672.09375,-14.140625Q677.6875,-20.28125,677.6875,-29.671875L677.6875,-37Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M812.90625,0L801.375,0L801.375,-41.359375Q801.375,-53.3125,797.6875,-58.65625Q794,-64,785.28125,-64Q777.8906,-64,772.71875,-57.25Q767.5625,-50.5,767.5625,-41.078125L767.5625,0L756.03125,0L756.03125,-42.765625Q756.03125,-64,739.6406,-64Q732.0469,-64,727.125,-57.625Q722.2031,-51.265625,722.2031,-41.078125L722.2031,0L710.6719,0L710.6719,-72L722.2031,-72L722.2031,-60.625L722.4844,-60.625Q730.15625,-74,744.84375,-74Q752.2344,-74,757.71875,-69.796875Q763.2031,-65.609375,765.2344,-58.796875Q773.25,-74,789.1406,-74Q812.90625,-74,812.90625,-44.5625L812.90625,0Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M875.21875,0L875.21875,-101L903.0625,-101Q956.3594,-101,956.3594,-51.765625Q956.3594,-28.390625,941.5625,-14.1875Q926.7656,0,901.9375,0L875.21875,0ZM887.03125,-90L887.03125,-11L902.0781,-11Q921.90625,-11,932.9375,-21.546875Q943.9844,-32.109375,943.9844,-51.484375Q943.9844,-90,902.78125,-90L887.03125,-90Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M1032.5469,-33L981.7031,-33Q981.9844,-21.03125,988.1719,-14.515625Q994.3594,-8,1005.1875,-8Q1017.3594,-8,1027.5469,-16L1027.5469,-5Q1018.0625,2,1002.4531,2Q987.1875,2,978.46875,-7.890625Q969.75,-17.78125,969.75,-35.71875Q969.75,-52.65625,979.28125,-63.328125Q988.8125,-74,1002.9375,-74Q1017.0781,-74,1024.8125,-64.765625Q1032.5469,-55.53125,1032.5469,-39.109375L1032.5469,-33ZM1020.7344,-43Q1020.65625,-52.9375,1015.90625,-58.46875Q1011.1719,-64,1002.7344,-64Q994.5781,-64,988.875,-58.1875Q983.1875,-52.375,981.84375,-43L1020.7344,-43Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M1061.4844,-10.390625L1061.2031,-10.390625L1061.2031,0L1049.6719,0L1049.6719,-107L1061.2031,-107L1061.2031,-59.359375L1061.4844,-59.359375Q1070,-74,1086.375,-74Q1100.2344,-74,1108.0625,-64.25Q1115.9062,-54.5,1115.9062,-38.125Q1115.9062,-19.90625,1107.1094,-8.953125Q1098.3281,2,1083.0781,2Q1068.7969,2,1061.4844,-10.390625ZM1061.2031,-39.453125L1061.2031,-29.390625Q1061.2031,-20.453125,1067,-14.21875Q1072.8125,-8,1081.7344,-8Q1092.2188,-8,1098.1562,-16.015625Q1104.0938,-24.046875,1104.0938,-38.328125Q1104.0938,-50.359375,1098.5312,-57.171875Q1092.9844,-64,1083.5,-64Q1073.4375,-64,1067.3125,-57Q1061.2031,-50,1061.2031,-39.453125Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M1192.8906,0L1181.3594,0L1181.3594,-11.375L1181.0781,-11.375Q1173.9062,2,1158.8594,2Q1133.125,2,1133.125,-28.78125L1133.125,-72L1144.5938,-72L1144.5938,-30.78125Q1144.5938,-8,1162.0312,-8Q1170.4688,-8,1175.9062,-14.21875Q1181.3594,-20.453125,1181.3594,-30.5L1181.3594,-72L1192.8906,-72L1192.8906,0Z\"\n                        android:fillColor=\"#FFFFFF\" />\n                <path\n                        android:pathData=\"M1278.125,-5.703125Q1278.125,34,1240.1562,34Q1226.7969,34,1216.8125,28.8125L1216.8125,17Q1228.9844,24,1240.0156,24Q1266.5938,24,1266.5938,-4.21875L1266.5938,-12.078125L1266.3125,-12.078125Q1258.0938,2,1241.5625,2Q1228.1406,2,1219.9375,-7.671875Q1211.75,-17.359375,1211.75,-33.65625Q1211.75,-52.171875,1220.5781,-63.078125Q1229.4062,-74,1244.7344,-74Q1259.2812,-74,1266.3125,-62.03125L1266.5938,-62.03125L1266.5938,-72L1278.125,-72L1278.125,-5.703125ZM1266.5938,-32.546875L1266.5938,-43.171875Q1266.5938,-51.765625,1260.7969,-57.875Q1255,-64,1246.3438,-64Q1235.6562,-64,1229.6094,-56.21875Q1223.5625,-48.453125,1223.5625,-34.453125Q1223.5625,-22.421875,1229.3594,-15.203125Q1235.1719,-8,1244.7344,-8Q1254.4375,-8,1260.5156,-14.890625Q1266.5938,-21.78125,1266.5938,-32.546875Z\"\n                        android:fillColor=\"#FFFFFF\" />\n            </group>\n        </group>\n    </group>\n</vector>"
  },
  {
    "path": "app/src/prerelease/res/drawable-v24/ic_banner_background.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"320dp\"\n    android:height=\"180dp\"\n    android:viewportWidth=\"320\"\n    android:viewportHeight=\"180\">\n  <group android:scaleX=\"0.6666667\"\n      android:scaleY=\"0.6666667\"\n      android:translateX=\"53.333332\"\n      android:translateY=\"30\">\n    <group android:scaleX=\"0.35277516\"\n        android:scaleY=\"0.35277516\"\n        android:translateX=\"5.879586E-4\">\n        <path\n                android:strokeWidth=\"1\"\n                android:pathData=\"M-20.09,-10.91h949.79v534.26h-949.79z\"\n                android:fillColor=\"#121212\"\n                android:strokeColor=\"#fff\" />\n        <path android:pathData=\"M273.68,250.58a18.79,18.79 0,0 0,-5.64 0.86,26.56 26.56,0 0,0 -24.73,-21.51 40.83,40.83 0,0 0,-68.95 -13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H273.68a18.9,18.9 0,0 0,0 -37.8Z\">\n            <aapt:attr name=\"android:fillColor\">\n                <gradient\n                        android:startY=\"245.72\"\n                        android:startX=\"113.12\"\n                        android:endY=\"245.72\"\n                        android:endX=\"292.58\"\n                        android:type=\"linear\">\n                    <item\n                            android:offset=\"0\"\n                            android:color=\"#DB0909\" />\n                    <item\n                            android:offset=\"1\"\n                            android:color=\"#A10808\" />\n                </gradient>\n            </aapt:attr>\n        </path>\n        <path android:pathData=\"M248.76,234.41c0,-1.22 0,-2.42 -0.09,-3.63a27,27 0,0 0,-5.36 -0.85,40.83 40.83,0 0,0 -68.95,-13.08A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.9,18.9 0,0 0,0 37.8H228.5A81.75,81.75 0,0 0,248.76 234.41Z\">\n            <aapt:attr name=\"android:fillColor\">\n                <gradient\n                        android:startY=\"245.72\"\n                        android:startX=\"113.12\"\n                        android:endY=\"245.72\"\n                        android:endX=\"248.76\"\n                        android:type=\"linear\">\n                    <item\n                            android:offset=\"0\"\n                            android:color=\"#E23A3A\" />\n                    <item\n                            android:offset=\"1\"\n                            android:color=\"#DD1130\" />\n                </gradient>\n            </aapt:attr>\n        </path>\n        <path android:pathData=\"M174.36,216.85A32.07,32.07 0,0 0,132 247.24a30.92,30.92 0,0 0,0.18 3.35H132a18.89,18.89 0,0 0,-1.18 37.74A81.53,81.53 0,0 0,210 206.83c0,-1.15 0,-2.29 -0.09,-3.43a41.33,41.33 0,0 0,-5 -0.33A40.71,40.71 0,0 0,174.36 216.85Z\">\n            <aapt:attr name=\"android:fillColor\">\n                <gradient\n                        android:startY=\"245.69\"\n                        android:startX=\"113.12\"\n                        android:endY=\"245.69\"\n                        android:endX=\"210.03\"\n                        android:type=\"linear\">\n                    <item\n                            android:offset=\"0\"\n                            android:color=\"#E44D4D\" />\n                    <item\n                            android:offset=\"1\"\n                            android:color=\"#E76161\" />\n                </gradient>\n            </aapt:attr>\n        </path>\n\n        <path\n                android:pathData=\"M358.81,285q-13.53,0 -22.64,-9.1t-9,-22.72q0,-13.62 9,-22.64 9,-9.18 22.64,-9.19 13.79,0 22.38,10l-5.62,5.44a20.82,20.82 0,0 0,-16.76 -7.91,23 23,0 0,0 -16.94,6.81q-6.72,6.72 -6.72,17.53t6.72,17.53a23,23 0,0 0,16.94 6.81q10.63,0 18.46,-8.94l5.7,5.53a29.57,29.57 0,0 1,-10.63 8A32.44,32.44 0,0 1,358.81 285Z\"\n                android:fillColor=\"#E23A3A\" />\n        <path\n                android:pathData=\"M397.78,222.69v60.93H390V222.69Z\"\n                android:fillColor=\"#E23A3A\" />\n        <path\n                android:pathData=\"M404.5,262.77q0,-9.61 6,-15.91a20.6,20.6 0,0 1,15.41 -6.3,20.31 20.31,0 0,1 15.31,6.3 21.87,21.87 0,0 1,6.13 15.91q0,9.71 -6.13,15.92A20.3,20.3 0,0 1,426 285a20.6,20.6 0,0 1,-15.41 -6.29Q404.5,272.39 404.5,262.77ZM412.33,262.77a15.31,15.31 0,0 0,3.91 10.9,13.38 13.38,0 0,0 19.41,0 17,17 0,0 0,0 -21.7,13.18 13.18,0 0,0 -19.41,0A15.18,15.18 0,0 0,412.33 262.77Z\"\n                android:fillColor=\"#E23A3A\" />\n        <path\n                android:pathData=\"M490.7,283.62h-7.48v-5.78h-0.35a13.86,13.86 0,0 1,-5.48 5.1,15.77 15.77,0 0,1 -7.7,2q-7.67,0 -11.79,-4.38t-4.13,-12.47v-26.2h7.83v25.69q0.25,10.22 10.3,10.22a9.81,9.81 0,0 0,7.83 -3.79,13.7 13.7,0 0,0 3.14,-9.06V241.93h7.83Z\"\n                android:fillColor=\"#E23A3A\" />\n        <path\n                android:pathData=\"M517.25,285a18.34,18.34 0,0 1,-14 -6.46,24.34 24.34,0 0,1 0,-31.49 18.35,18.35 0,0 1,14 -6.47,18.07 18.07,0 0,1 8.39,2 14.84,14.84 0,0 1,5.83 5.19h0.34l-0.34,-5.78L531.47,222.69h7.82v60.93h-7.48v-5.78h-0.34a14.84,14.84 0,0 1,-5.83 5.19A18.07,18.07 0,0 1,517.25 285ZM518.53,277.86a12,12 0,0 0,9.45 -4.17q3.82,-4.17 3.83,-10.9A15.54,15.54 0,0 0,528 252a12.05,12.05 0,0 0,-9.45 -4.26,12.19 12.19,0 0,0 -9.44,4.26 15.5,15.5 0,0 0,-3.83 10.8,15.32 15.32,0 0,0 3.83,10.81A12.19,12.19 0,0 0,518.53 277.84Z\"\n                android:fillColor=\"#E23A3A\" />\n        <path\n                android:pathData=\"M587.8,267.33a15.91,15.91 0,0 1,-5.87 12.88A22.43,22.43 0,0 1,567.46 285a21.39,21.39 0,0 1,-13.36 -4.42,22.65 22.65,0 0,1 -8,-12.08l7.49,-3.07a19.3,19.3 0,0 0,2.13 4.94,15.72 15.72,0 0,0 3.19,3.78 14.25,14.25 0,0 0,4 2.47,12.26 12.26,0 0,0 4.68,0.9 13.47,13.47 0,0 0,8.76 -2.77,9 9,0 0,0 3.41,-7.36 8.8,8.8 0,0 0,-2.81 -6.55q-2.64,-2.64 -9.87,-5.11 -7.32,-2.64 -9.11,-3.57 -9.69,-4.94 -9.7,-14.55a14.84,14.84 0,0 1,5.37 -11.49A19.53,19.53 0,0 1,567 221.33a20.5,20.5 0,0 1,12.09 3.58,16.67 16.67,0 0,1 6.8,8.76l-7.31,3.06a10.84,10.84 0,0 0,-4 -5.65,13.1 13.1,0 0,0 -15.11,0.28 7.41,7.41 0,0 0,-3.15 6.19,7.14 7.14,0 0,0 2.47,5.42q2.73,2.29 11.83,5.42 9.27,3.17 13.23,7.72A16.53,16.53 0,0 1,587.8 267.33Z\"\n                android:fillColor=\"#E76161\" />\n        <path\n                android:pathData=\"M610.26,284.3a11.88,11.88 0,0 1,-8.46 -3.15c-2.25,-2.09 -3.4,-5 -3.45,-8.76V249.07H591v-7.14h7.32V229.16h7.83v12.77h10.21v7.14H606.18v20.77c0,2.78 0.54,4.66 1.61,5.66a5.27,5.27 0,0 0,3.66 1.48,7.9 7.9,0 0,0 1.83,-0.21 9,9 0,0 0,1.66 -0.55l2.47,7A21.23,21.23 0,0 1,610.26 284.3Z\"\n                android:fillColor=\"#E76161\" />\n        <path\n                android:pathData=\"M631.71,283.62h-7.83V241.93h7.48v6.8h0.35a11.31,11.31 0,0 1,4.89 -5.66,13.66 13.66,0 0,1 7.27,-2.34 14.7,14.7 0,0 1,5.79 1l-2.38,7.57a12.93,12.93 0,0 0,-4.6 -0.6,10.11 10.11,0 0,0 -7.7,3.58 12,12 0,0 0,-3.27 8.34Z\"\n                android:fillColor=\"#E76161\" />\n        <path\n                android:pathData=\"M670.93,285a19.93,19.93 0,0 1,-15.14 -6.29q-6,-6.3 -6,-15.92a22.65,22.65 0,0 1,5.79 -15.87,19.15 19.15,0 0,1 14.8,-6.34q9.29,0 14.77,6t5.49,16.81l-0.09,0.85L657.83,264.24a13.56,13.56 0,0 0,4.08 9.87,13.06 13.06,0 0,0 9.36,3.75q7.49,0 11.75,-7.49l7,3.4a20.69,20.69 0,0 1,-7.78 8.25A21.51,21.51 0,0 1,670.93 285ZM658.42,257.77h23.92a10.43,10.43 0,0 0,-3.53 -7.19,12.38 12.38,0 0,0 -8.56,-2.85 11.34,11.34 0,0 0,-7.61 2.72A13.09,13.09 0,0 0,658.42 257.75Z\"\n                android:fillColor=\"#E76161\" />\n        <path\n                android:pathData=\"M714.08,240.56q8.67,0 13.7,4.64c3.34,3.1 5,7.33 5,12.72v25.7h-7.49v-5.78H725Q720.11,285 712,285a16.83,16.83 0,0 1,-11.53 -4.08,13 13,0 0,1 -4.63,-10.21 12.38,12.38 0,0 1,4.89 -10.3q4.89,-3.83 13.06,-3.83a23.16,23.16 0,0 1,11.49 2.55v-1.78a8.9,8.9 0,0 0,-3.24 -6.94,11.08 11.08,0 0,0 -7.57,-2.85 12,12 0,0 0,-10.38 5.53l-6.89,-4.34Q702.93,240.57 714.08,240.56ZM704,270.86a6.24,6.24 0,0 0,2.59 5.1,9.57 9.57,0 0,0 6.09,2.05 12.5,12.5 0,0 0,8.81 -3.66,11.47 11.47,0 0,0 3.87,-8.6q-3.66,-2.88 -10.21,-2.89a13.22,13.22 0,0 0,-8 2.3A6.81,6.81 0,0 0,704 270.86Z\"\n                android:fillColor=\"#E76161\" />\n        <path\n                android:pathData=\"M749.47,283.62h-7.82V241.93h7.48v5.78h0.34a14,14 0,0 1,5.49 -5.1,15.06 15.06,0 0,1 7.36,-2.05 15.22,15.22 0,0 1,8.09 2.13,12.56 12.56,0 0,1 5.1,5.87q5.19,-8 14.39,-8 7.23,0 11.14,4.43T805,257.58v26h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.06,9v23.06h-7.83V258.77q0,-5.86 -2.13,-8.46t-7.15,-2.6a9.35,9.35 0,0 0,-7.57 3.83,14 14,0 0,0 -3.07,9Z\"\n                android:fillColor=\"#E76161\" />\n\n        <path android:pathData=\"M-13.76,555.76c10.3,-20.89 58.91,-113.94 157.31,-139.7C261.3,385.24 405.9,462.43 469.89,613.28\">\n            <aapt:attr name=\"android:fillColor\">\n                <gradient\n                        android:startY=\"252.3\"\n                        android:startX=\"194.11\"\n                        android:endY=\"252.3\"\n                        android:endX=\"373.57\"\n                        android:type=\"linear\">\n                    <item\n                            android:offset=\"0\"\n                            android:color=\"#E76161\" />\n                    <item\n                            android:offset=\"1\"\n                            android:color=\"#E23A3A\" />\n                </gradient>\n            </aapt:attr>\n        </path>\n        <path android:pathData=\"M318.2,592.15c52.89,-55.46 139,-131.3 263,-187.83 223.69,-102 495.29,-119.94 515.35,-62.21 13,37.39 -73.5,124.43 -496.69,339.65\">\n            <aapt:attr name=\"android:fillColor\">\n                <gradient\n                        android:startX=\"400.11\"\n                        android:endX=\"900\"\n                        android:type=\"linear\">\n                    <item\n                            android:offset=\"0\"\n                            android:color=\"#E76161\" />\n                    <item\n                            android:offset=\"1\"\n                            android:color=\"#E23A3A\" />\n                </gradient>\n            </aapt:attr>\n        </path>\n        <path android:pathData=\"M-57.58,195c206.91,86.6 494,-219.13 453.91,-347.48C353.52,-289.67 -103.15,-353.41 -203.15,-176 -265.5,-65.35 -189.57,139.73 -57.58,195Z\">\n            <aapt:attr name=\"android:fillColor\">\n                <gradient\n                        android:startY=\"252.3\"\n                        android:startX=\"-100\"\n                        android:endY=\"252.3\"\n                        android:endX=\"373.57\"\n                        android:type=\"linear\">\n                    <item\n                            android:offset=\"0\"\n                            android:color=\"#E76161\" />\n                    <item\n                            android:offset=\"1\"\n                            android:color=\"#E23A3A\" />\n                </gradient>\n            </aapt:attr>\n        </path>\n        <path android:pathData=\"M698.42,648.89C625.71,546 764,320.79 920.68,218.45c46.61,-30.44 110.17,-72 164.35,-50.08 102.25,41.28 158.19,303.22 28.17,446.08C996.65,742.52 762.64,739.78 698.42,648.89Z\">\n            <aapt:attr name=\"android:fillColor\">\n                <gradient\n                        android:startX=\"700.11\"\n                        android:endX=\"900.57\"\n                        android:type=\"linear\">\n                    <item\n                            android:offset=\"0\"\n                            android:color=\"#E76161\" />\n                    <item\n                            android:offset=\"1\"\n                            android:color=\"#E23A3A\" />\n                </gradient>\n            </aapt:attr>\n        </path>\n        <path android:pathData=\"M339.91,-42.46a246.52,141.46 0,1 0,493.04 0a246.52,141.46 0,1 0,-493.04 0z\">\n            <aapt:attr name=\"android:fillColor\">\n                <gradient\n                        android:startX=\"400.11\"\n                        android:endX=\"800.57\"\n                        android:type=\"linear\">\n                    <item\n                            android:offset=\"0\"\n                            android:color=\"#E76161\" />\n                    <item\n                            android:offset=\"1\"\n                            android:color=\"#E23A3A\" />\n                </gradient>\n            </aapt:attr>\n        </path>\n    </group>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/prerelease/res/drawable-v24/ic_launcher_foreground.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\"\n    android:name=\"vector\">\n  <group android:scaleX=\"0.1755477\"\n      android:scaleY=\"0.1755477\"\n      android:translateX=\"29.16\"\n      android:translateY=\"29.16\">\n      <path android:name=\"path\"\n            android:pathData=\"M 245.05 148.63 C 242.249 148.627 239.463 149.052 236.79 149.89 C 235.151 141.364 230.698 133.63 224.147 127.931 C 217.597 122.233 209.321 118.893 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 245.05 203.9 C 252.375 203.9 259.408 200.987 264.587 195.807 C 269.767 190.628 272.68 183.595 272.68 176.27 C 272.68 168.945 269.767 161.912 264.587 156.733 C 259.408 151.553 252.375 148.64 245.05 148.64 Z\"\n            android:strokeWidth=\"1\"\n            tools:ignore=\"VectorPath\">\n          <aapt:attr name=\"android:fillColor\">\n              <gradient\n                      android:startY=\"0\"\n                      android:startX=\"200\"\n                      android:endY=\"0\"\n                      android:endX=\"300\"\n                      android:type=\"linear\">\n                  <item android:offset=\"0\" android:color=\"#DB0909\"/>\n                  <item android:offset=\"1\" android:color=\"#A10808\"/>\n              </gradient>\n          </aapt:attr>\n      </path>\n\n      <path android:name=\"path_1\" android:pathData=\"M 208.61 125 C 208.61 123.22 208.55 121.45 208.48 119.69 C 205.919 119.01 203.296 118.595 200.65 118.45 C 195.913 105.431 186.788 94.458 174.851 87.427 C 162.914 80.396 148.893 77.735 135.21 79.905 C 121.527 82.074 109.017 88.941 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.615 148.64 23.582 151.553 18.403 156.733 C 13.223 161.912 10.31 168.945 10.31 176.27 C 10.31 183.595 13.223 190.628 18.403 195.807 C 23.582 200.987 30.615 203.9 37.94 203.9 L 179 203.9 C 198.116 182.073 208.646 154.015 208.61 125 Z\"\n            android:strokeWidth=\"1\">\n      <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"0\"\n                  android:startX=\"200\"\n                  android:endY=\"0\"\n                  android:endX=\"000\"\n                  android:type=\"linear\">\n              <item android:offset=\"0\" android:color=\"#E23A3A\"/>\n              <item android:offset=\"1\" android:color=\"#DD1130\"/>\n          </gradient>\n      </aapt:attr>\n      </path>\n\n      <path android:name=\"path_2\" android:pathData=\"M 99.84 99.32 C 89.871 95.945 79.051 96.024 69.133 99.545 C 59.215 103.065 50.765 109.826 45.155 118.73 C 39.545 127.634 37.094 138.174 38.2 148.64 L 37.94 148.64 C 30.783 148.665 23.909 151.471 18.779 156.461 C 13.648 161.452 10.653 168.246 10.43 175.399 C 10.207 182.553 12.773 189.52 17.583 194.82 C 22.392 200.121 29.079 203.349 36.22 203.82 C 67.216 202.93 96.673 189.98 118.284 167.742 C 139.895 145.504 151.997 115.689 152 84.68 C 152 83 151.94 81.33 151.87 79.68 C 149.443 79.361 146.998 79.194 144.55 79.18 C 136.095 79.171 127.735 80.962 120.026 84.434 C 112.317 87.907 105.435 92.982 99.84 99.32 Z\"\n             android:strokeWidth=\"1\">\n      <aapt:attr name=\"android:fillColor\">\n          <gradient\n                  android:startY=\"0\"\n                  android:startX=\"150\"\n                  android:endY=\"0\"\n                  android:endX=\"000\"\n                  android:type=\"linear\">\n              <item android:offset=\"0\" android:color=\"#E44D4D\"/>\n              <item android:offset=\"1\" android:color=\"#E76161\"/>\n          </gradient>\n      </aapt:attr>\n  </path>\n  </group>\n</vector>"
  },
  {
    "path": "app/src/prerelease/res/mipmap-anydpi-v26/ic_banner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@drawable/ic_banner_background\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/prerelease/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_cloudstream_monochrome\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/prerelease/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_cloudstream_monochrome\"/>\n</adaptive-icon>"
  },
  {
    "path": "app/src/prerelease/res/values/ic_launcher_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"ic_launcher_background\">#000000</color>\n</resources>"
  },
  {
    "path": "app/src/prerelease/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">CloudStream Beta</string>\n</resources>"
  },
  {
    "path": "app/src/test/java/com/lagradost/cloudstream3/ProviderTests.kt",
    "content": "package com.lagradost.cloudstream3\n\n// import com.lagradost.cloudstream3.APIHolder.allProviders\n// import com.lagradost.cloudstream3.mvvm.logError\n// import com.lagradost.cloudstream3.utils.Qualities\n// import com.lagradost.cloudstream3.utils.SubtitleHelper\n// import kotlinx.coroutines.runBlocking\n// import org.junit.Assert\n// import org.junit.Test\n\nclass ProviderTests {\n//     private fun getAllProviders(): List<MainAPI> {\n//         return allProviders.filter { !it.usesWebView }\n//     }\n\n//     private suspend fun loadLinks(api: MainAPI, url: String?): Boolean {\n//         Assert.assertNotNull(\"Api ${api.name} has invalid url on episode\", url)\n//         if (url == null) return true\n//         var linksLoaded = 0\n//         try {\n//             val success = api.loadLinks(url, false, {}) { link ->\n//                 Assert.assertTrue(\n//                     \"Api ${api.name} returns link with invalid Quality\",\n//                     Qualities.values().map { it.value }.contains(link.quality)\n//                 )\n//                 Assert.assertTrue(\n//                     \"Api ${api.name} returns link with invalid url\",\n//                     link.url.length > 4\n//                 )\n//                 linksLoaded++\n//             }\n//             if (success) {\n//                 return linksLoaded > 0\n//             }\n//             Assert.assertTrue(\"Api ${api.name} has returns false on .loadLinks\", success)\n//         } catch (e: Exception) {\n//             if (e.cause is NotImplementedError) {\n//                 Assert.fail(\"Provider has not implemented .loadLinks\")\n//             }\n//             logError(e)\n//         }\n//         return true\n//     }\n\n//     private suspend fun testSingleProviderApi(api: MainAPI): Boolean {\n//         val searchQueries = listOf(\"over\", \"iron\", \"guy\")\n//         var correctResponses = 0\n//         var searchResult: List<SearchResponse>? = null\n//         for (query in searchQueries) {\n//             val response = try {\n//                 api.search(query, 1)\n//             } catch (e: Exception) {\n//                 if (e.cause is NotImplementedError) {\n//                     Assert.fail(\"Provider has not implemented .search\")\n//                 }\n//                 logError(e)\n//                 null\n//             }?.items\n//             if (!response.isNullOrEmpty()) {\n//                 correctResponses++\n//                 if (searchResult == null) {\n//                     searchResult = response\n//                 }\n//             }\n//         }\n\n//         if (correctResponses == 0 || searchResult == null) {\n//             System.err.println(\"Api ${api.name} did not return any valid search responses\")\n//             return false\n//         }\n\n//         try {\n//             var validResults = false\n//             for (result in searchResult) {\n//                 Assert.assertEquals(\n//                     \"Invalid apiName on response on ${api.name}\",\n//                     result.apiName,\n//                     api.name\n//                 )\n//                 val load = api.load(result.url) ?: continue\n//                 Assert.assertEquals(\n//                     \"Invalid apiName on load on ${api.name}\",\n//                     load.apiName,\n//                     result.apiName\n//                 )\n//                 Assert.assertTrue(\n//                     \"Api ${api.name} on load does not contain any of the supportedTypes\",\n//                     api.supportedTypes.contains(load.type)\n//                 )\n//                 when (load) {\n//                     is AnimeLoadResponse -> {\n//                         val gotNoEpisodes =\n//                             load.episodes.keys.isEmpty() || load.episodes.keys.any { load.episodes[it].isNullOrEmpty() }\n\n//                         if (gotNoEpisodes) {\n//                             println(\"Api ${api.name} got no episodes on ${load.url}\")\n//                             continue\n//                         }\n\n//                         val url = (load.episodes[load.episodes.keys.first()])?.first()?.data\n//                         validResults = loadLinks(api, url)\n//                         if (!validResults) continue\n//                     }\n//                     is MovieLoadResponse -> {\n//                         val gotNoEpisodes = load.dataUrl.isBlank()\n//                         if (gotNoEpisodes) {\n//                             println(\"Api ${api.name} got no movie on ${load.url}\")\n//                             continue\n//                         }\n\n//                         validResults = loadLinks(api, load.dataUrl)\n//                         if (!validResults) continue\n//                     }\n//                     is TvSeriesLoadResponse -> {\n//                         val gotNoEpisodes = load.episodes.isEmpty()\n//                         if (gotNoEpisodes) {\n//                             println(\"Api ${api.name} got no episodes on ${load.url}\")\n//                             continue\n//                         }\n\n//                         validResults = loadLinks(api, load.episodes.first().data)\n//                         if (!validResults) continue\n//                     }\n//                 }\n//                 break\n//             }\n\n//             Assert.assertTrue(\"Api ${api.name} did not load on any}\", validResults)\n//         } catch (e: Exception) {\n//             if (e.cause is NotImplementedError) {\n//                 Assert.fail(\"Provider has not implemented .load\")\n//             }\n//             logError(e)\n//             return false\n//         }\n//         return true\n//     }\n\n//     @Test\n//     fun providersExist() {\n//         Assert.assertTrue(getAllProviders().isNotEmpty())\n//     }\n\n//     @Test\n//     fun providerCorrectData() {\n//         val langTagsIETF = SubtitleHelper.languages.map { it.IETF_tag }\n//         Assert.assertFalse(\"langTagsIETF does not contain any languages\", langTagsIETF.isNullOrEmpty())\n//         for (api in getAllProviders()) {\n//             Assert.assertTrue(\"Api does not contain a mainUrl\", api.mainUrl != \"NONE\")\n//             Assert.assertTrue(\"Api does not contain a name\", api.name != \"NONE\")\n//             Assert.assertTrue(\n//                 \"Api ${api.name} does not contain a valid language code\",\n//                 langTagsIETF.contains(api.lang)\n//             )\n//             Assert.assertTrue(\n//                 \"Api ${api.name} does not contain any supported types\",\n//                 api.supportedTypes.isNotEmpty()\n//             )\n//         }\n//     }\n\n//     @Test\n//     fun providerCorrectHomepage() {\n//         runBlocking {\n//             getAllProviders().amap { api ->\n//                 if (api.hasMainPage) {\n//                     try {\n//                         val homepage = api.getMainPage()\n//                         when {\n//                             homepage == null -> {\n//                                 Assert.fail(\"Homepage provider ${api.name} did not correctly load homepage!\")\n//                             }\n//                             homepage.items.isEmpty() -> {\n//                                 Assert.fail(\"Homepage provider ${api.name} does not contain any items!\")\n//                             }\n//                             homepage.items.any { it.list.isEmpty() } -> {\n//                                 Assert.fail(\"Homepage provider ${api.name} does not have any items on result!\")\n//                             }\n//                         }\n//                     } catch (e: Exception) {\n//                         if (e.cause is NotImplementedError) {\n//                             Assert.fail(\"Provider marked as hasMainPage, while in reality is has not been implemented\")\n//                         }\n//                         logError(e)\n//                     }\n//                 }\n//             }\n//         }\n//     }\n\n// //    @Test\n// //    fun testSingleProvider() {\n// //        testSingleProviderApi(ThenosProvider())\n// //    }\n\n//     @Test\n//     suspend fun providerCorrect() {\n//         val invalidProvider = ArrayList<Pair<MainAPI, Exception?>>()\n//         val providers = getAllProviders()\n//         providers.amap { api ->\n//             try {\n//                 println(\"Trying $api\")\n//                 if (testSingleProviderApi(api)) {\n//                     println(\"Success $api\")\n//                 } else {\n//                     System.err.println(\"Error $api\")\n//                     invalidProvider.add(Pair(api, null))\n//                 }\n//             } catch (e: Exception) {\n//                 logError(e)\n//                 invalidProvider.add(Pair(api, e))\n//             }\n//         }\n\n//         println(\"Invalid providers are: \")\n//         for (provider in invalidProvider) {\n//             println(\"${provider.first}\")\n//         }\n//     }\n}"
  },
  {
    "path": "app/src/test/java/com/lagradost/cloudstream3/SubtitleSelectionTest.kt",
    "content": "package com.lagradost.cloudstream3\n\nimport com.lagradost.cloudstream3.ui.player.SubtitleData\nimport com.lagradost.cloudstream3.ui.player.SubtitleOrigin\nimport org.junit.Assert.assertEquals\nimport org.junit.Assert.assertNull\nimport org.junit.Test\n\n/** Ensure partial subtitle language finding is reliable. */\nclass SubtitleLanguageTagTest {\n    fun getQuickSubtitle(originalName: String, languageCode: String?): SubtitleData {\n        return SubtitleData(\n            originalName = originalName,\n            nameSuffix = \"1\",\n            url = \"https://example.com/test.vtt\",\n            origin = SubtitleOrigin.URL,\n            mimeType = \"text/vtt\",\n            headers = emptyMap(),\n            languageCode = languageCode\n        )\n    }\n\n    @Test\n    fun `returns languageCode directly if already valid IETF tag`() {\n        val subtitle = getQuickSubtitle(\n            originalName = \"Anything\",\n            languageCode = \"en\"\n        )\n\n        assertEquals(\"en\", subtitle.getIETF_tag())\n    }\n\n    @Test\n    fun `matches exact language name`() {\n        val subtitle = getQuickSubtitle(\n            originalName = \"English\",\n            languageCode = null\n        )\n\n        assertEquals(\"en\", subtitle.getIETF_tag())\n    }\n\n    @Test\n    fun `matches native language name`() {\n        val subtitle = getQuickSubtitle(\n            originalName = \"Español\",\n            languageCode = null\n        )\n\n        assertEquals(\"es\", subtitle.getIETF_tag())\n    }\n\n    @Test\n    fun `matches fuzzy partial language name`() {\n        val subtitle = getQuickSubtitle(\n            originalName = \"English [SUB]\",\n            languageCode = null\n        )\n\n        assertEquals(\"en\", subtitle.getIETF_tag())\n    }\n\n    @Test\n    fun `returns null when no language matches`() {\n        val subtitle = getQuickSubtitle(\n            originalName = \"Klingon\",\n            languageCode = null\n        )\n\n        assertNull(subtitle.getIETF_tag())\n    }\n\n\n    @Test\n    fun `returns the correct language variant`() {\n        val subtitle1 = getQuickSubtitle(\n            originalName = \"Chinese\",\n            languageCode = null\n        )\n        val subtitle2 = getQuickSubtitle(\n            originalName = \"Chinese (subtitle)\",\n            languageCode = null\n        )\n        val subtitleSimplified1 = getQuickSubtitle(\n            originalName = \"Chinese (simplified)\",\n            languageCode = null\n        )\n        val subtitleSimplified2 = getQuickSubtitle(\n            originalName = \"Chinese - simplified\",\n            languageCode = null\n        )\n        val subtitleSimplified3 = getQuickSubtitle(\n            originalName = \"Chinese simplified\",\n            languageCode = \"zhh\"\n        )\n        val subtitleSimplified4 = getQuickSubtitle(\n            originalName = \"Chinese (simplified)2\",\n            languageCode = \"zh-hans\"\n        )\n        val subtitleSimplified5 = getQuickSubtitle(\n            originalName = \"汉语\",\n            languageCode = null\n        )\n        val subtitleSimplified6 = getQuickSubtitle(\n            originalName = \"\",\n            languageCode = \"zh-hans\"\n        )\n        assertEquals(\"zh\", subtitle1.getIETF_tag())\n        assertEquals(\"zh\", subtitle2.getIETF_tag())\n        assertEquals(\"zh-hans\", subtitleSimplified1.getIETF_tag())\n        assertEquals(\"zh-hans\", subtitleSimplified2.getIETF_tag())\n        assertEquals(\"zh-hans\", subtitleSimplified3.getIETF_tag())\n        assertEquals(\"zh-hans\", subtitleSimplified4.getIETF_tag())\n        assertEquals(\"zh-hans\", subtitleSimplified5.getIETF_tag())\n        assertEquals(\"zh-hans\", subtitleSimplified6.getIETF_tag())\n    }\n\n\n    @Test\n    fun `returns exact language matches`() {\n        val subtitle = getQuickSubtitle(\n            originalName = \"en\",\n            languageCode = null\n        )\n\n        assertEquals(\"en\", subtitle.getIETF_tag())\n    }\n\n\n    @Test\n    fun `returns partial language matches`() {\n        val subtitle = getQuickSubtitle(\n            originalName = \"Englis\",\n            languageCode = null\n        )\n\n        assertEquals(\"en\", subtitle.getIETF_tag())\n    }\n}\n\n"
  },
  {
    "path": "build.gradle.kts",
    "content": "plugins {\n    alias(libs.plugins.android.application) apply false\n    alias(libs.plugins.android.lint) apply false\n    alias(libs.plugins.android.multiplatform.library) apply false\n    alias(libs.plugins.buildkonfig) apply false // Universal build config\n    alias(libs.plugins.dokka) apply false\n    alias(libs.plugins.kotlin.android) apply false\n    alias(libs.plugins.kotlin.jvm) apply false\n    alias(libs.plugins.kotlin.multiplatform) apply false\n}\n\nallprojects {\n    // https://docs.gradle.org/current/userguide/upgrading_major_version_9.html#test_task_fails_when_no_tests_are_discovered\n    tasks.withType<AbstractTestTask>().configureEach {\n        failOnNoDiscoveredTests = false\n    }\n}\n"
  },
  {
    "path": "discoverium.yml",
    "content": "app:\n  name: CloudStream\n  authors: recloudstream\n  category: entertainment\n  description: Android app for streaming and downloading media.\n  icon: https://raw.githubusercontent.com/recloudstream/cloudstream/refs/heads/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png\n  releases:\n    url: https://github.com/recloudstream/cloudstream/releases"
  },
  {
    "path": "docs/.gitignore",
    "content": "/build"
  },
  {
    "path": "docs/build.gradle.kts",
    "content": "plugins {\n    alias(libs.plugins.kotlin.jvm)\n    alias(libs.plugins.dokka)\n}\n\ndependencies {\n    dokka(project(\":app:\"))\n    dokka(project(\":library:\"))\n}\n\ndokka {\n    moduleName = \"Cloudstream\"\n}\n"
  },
  {
    "path": "fastlane/metadata/android/af/changelogs/2.txt",
    "content": "- Wysigingsregister bygevoeg!\n"
  },
  {
    "path": "fastlane/metadata/android/af/full_description.txt",
    "content": "CloudStream-3 laat jou toe om films, TV-reekse en Anime te stroom of aflaai.\n\nDie app kom sonder enige advertensies of ontledings en\nondersteun verskeie lokprent- en filmwebwerwe, en bied selfs meer, bv.\n\nBoekmerke\n\nAflaai van onderskrifte\n\nChromecast-ondersteuning\n"
  },
  {
    "path": "fastlane/metadata/android/af/short_description.txt",
    "content": "Laai af en stroom flieks, TV-reekse en anime.\n"
  },
  {
    "path": "fastlane/metadata/android/af/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/am/changelogs/2.txt",
    "content": "- Changelog ታክሏል!\n"
  },
  {
    "path": "fastlane/metadata/android/am/full_description.txt",
    "content": "CloudStream-3 ፊልሞችን፣ ተከታታይ ቲቪ እና አኒሜ በዥረት እንዲመለከቱ እና እንዲያወርዱ ያስችልዎታል።\n\nመተግበሪያው ያለ ምንም ማስታወቂያዎች እና ትንታኔዎች እና\nበርካታ የፊልም ማስታወቂያ እና ሳይቶችን ይደግፋል፣ እና ሌሎችም፣ ለምሳሌ\n\nዕልባቶች\n\nየግርጌ ጽሑፍ ውርዶች\n\nChromecast ድጋፍ\n"
  },
  {
    "path": "fastlane/metadata/android/am/short_description.txt",
    "content": "ፊልሞችን፣ ተከታታይ ቲቪዎችን እና አኒሜ በዥረት ይመልከቱ እና ያውርዱ።\n"
  },
  {
    "path": "fastlane/metadata/android/am/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/apc/changelogs/2.txt",
    "content": "- نزاد سجل التغيير!\n"
  },
  {
    "path": "fastlane/metadata/android/apc/full_description.txt",
    "content": "\"كلاود ستريم-3\" بخليكون تعملو ستريم للأفلام والمسلسلات والأنيمي.\n\nالآپليكايشن بيجي بلا دعايات أو أناليتيكس\nوبيحتوي ع كذا موقع للترايليرز والأفلام وإلخ.\n\nإشارات مرجعية\n\nتنزيل الترجمة\n\nبيدعم \"كروم كاست\"\n"
  },
  {
    "path": "fastlane/metadata/android/apc/short_description.txt",
    "content": "عملو ستريم للأفلام والمسلسلات والأنمي.\n"
  },
  {
    "path": "fastlane/metadata/android/apc/title.txt",
    "content": "كلاود ستريم\n"
  },
  {
    "path": "fastlane/metadata/android/ar/changelogs/2.txt",
    "content": "- تمت إضافة سجل التغيير!\n"
  },
  {
    "path": "fastlane/metadata/android/ar/full_description.txt",
    "content": "يتيح لك كلاود ستريم -3 بث وتنزيل الأفلام والمسلسلات التلفزيونية والأنيمي.\n\nيأتي التطبيق بدون أي إعلانات وتحليلات.\nو يدعم العديد من مواقع البث الاولي(التريلر) والأفلام والمزيد. وتشمل الميزات:\n\nإشارات مرجعية\n\nقم بتنزيل ودفق الأفلام والبرامج التلفزيونية والأنيمي\n\nتنزيلات الترجمة\n\nدعم كروم كاست\n"
  },
  {
    "path": "fastlane/metadata/android/ar/short_description.txt",
    "content": "بث وتحميل الأفلام والأنمي والمسلسلات التلفزيونية.\n"
  },
  {
    "path": "fastlane/metadata/android/ar/title.txt",
    "content": "كلاود ستريم\n"
  },
  {
    "path": "fastlane/metadata/android/ar-SA/changelogs/2.txt",
    "content": "تمت إضافة سجل التغيير!\n"
  },
  {
    "path": "fastlane/metadata/android/ar-SA/full_description.txt",
    "content": "يسمح لك كلاود ستريم -3 ببث وتنزيل الأفلام, المسلسلات التلفزيونية, والأنيمي. \n\nيأتي التطبيق بدون أي إعلانات وتحليلات و\n يدعم العديد من مواقع البث الاولي(التريلر) ,والأفلام, والمزيد.\n\nإشارات مرجعية\n\nتنزيلات الترجمة\n\nدعم كروم كاست\n"
  },
  {
    "path": "fastlane/metadata/android/ar-SA/short_description.txt",
    "content": "بث وتحميل الأفلام, الأنمي, والمسلسلات التلفزيونية.\n"
  },
  {
    "path": "fastlane/metadata/android/ar-SA/title.txt",
    "content": "كلاودستريم\n"
  },
  {
    "path": "fastlane/metadata/android/as/changelogs/2.txt",
    "content": "- পৰিৱৰ্তনলগ যোগ কৰা হৈছে!\n"
  },
  {
    "path": "fastlane/metadata/android/as/full_description.txt",
    "content": "ক্লাউডষ্ট্ৰিম-৩ৰ সৈতে চলচ্চিত্ৰ, টিভি শৃঙ্খলা আৰু এনিমে ষ্ট্ৰিম আৰু ডাউনলোড কৰক।\n\nএই এপত কোনো বিজ্ঞাপন বা বিশ্লেষণ নাই আৰু\nএকাধিক ট্ৰেইলাৰ আৰু চলচ্চিত্ৰ ছাইট সমৰ্থন কৰে, আৰু বহুতো, যেনে:\n\nবুকমাৰ্ক\n\nউপশিৰোনামা ডাউনলোড\n\nক্ৰ’মকাষ্ট সমৰ্থন\n"
  },
  {
    "path": "fastlane/metadata/android/as/short_description.txt",
    "content": "চলচ্চিত্ৰ, টিভি শৃঙ্খলা আৰু এনিমে ষ্ট্ৰিম আৰু ডাউনলোড কৰক।\n"
  },
  {
    "path": "fastlane/metadata/android/as/title.txt",
    "content": "ক্লাউডষ্ট্ৰিম\n"
  },
  {
    "path": "fastlane/metadata/android/be/changelogs/2.txt",
    "content": "- Дададзены спіс змен!\n"
  },
  {
    "path": "fastlane/metadata/android/be/full_description.txt",
    "content": "CloudStream-3 дазваляе вам трансліраваць і спампоўваць фільмы, тэлесерыялы і анімэ.\n\nПраграма пастаўляецца без рэкламы і аналітыкі і\nпадтрымлівае шматлікія сайты з трэйлерамі і фільмамі і іншае, напрыклад\n\nЗакладкі\n\nСпампоўку субцітраў\n\nChromecast\n"
  },
  {
    "path": "fastlane/metadata/android/be/short_description.txt",
    "content": "Трансліруйце і спампоўвайце фільмы, тэлесерыялы і анімэ.\n"
  },
  {
    "path": "fastlane/metadata/android/be/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/bg/changelogs/2.txt",
    "content": "- Добавен е Changelog!\n"
  },
  {
    "path": "fastlane/metadata/android/bg/full_description.txt",
    "content": "CloudStream-3 Ви позволява да стриймвате и изтегляте филми, сериали и аниме.\n\nПриложението не съдържа реклами и аналитики и\nподдържа няколко сайтове за трейлъри и филми и още, например:\n\nОтметки\n\nИзтегляне на субтитри\n\nПоддръжка на Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/bg/short_description.txt",
    "content": "Стриймване и изтегляне филми, сериали и аниме.\n"
  },
  {
    "path": "fastlane/metadata/android/bg/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/ca/changelogs/2.txt",
    "content": "- Registre de canvis afegit!\n"
  },
  {
    "path": "fastlane/metadata/android/ca/full_description.txt",
    "content": "Cloudstream-3 et permet mirar i descarregar pel·licules, sèries televisives i anime\n\nL'aplicació no conté publicitat ni rastrejament, i\nsuporta diverses pàgines de tràilers i pel·licules, i més, com ara:\n\nFavorits\n\nDescàrrega de subtítols\n\nCompatibilitat amb Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/ca/short_description.txt",
    "content": "Mira i descarrega pel·licules, sèries televisives i anime.\n"
  },
  {
    "path": "fastlane/metadata/android/ca/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/ckb/changelogs/2.txt",
    "content": "- گۆڕانکاريەکان زيادکرا!\n"
  },
  {
    "path": "fastlane/metadata/android/ckb/full_description.txt",
    "content": "CloudStream-3 ڕێگەت پێدەدات فیلم و زنجیرەی تیڤی و ئەنیمێ ستریم و دابەزێنى.\n\nئەپەکە بەبێ هیچ ڕیکلام و شیکارییەک دێت هەروەها\nپشتگیری لە چەندین سایتی ترەیلەر و فیلم دەکات، و زیاتر، بۆ نموونە.\n\nئاماژەکان\n\nداونڵۆدکردنى ‌ژێرنووس\n\nپشتگيرى chromecast دەکات\n"
  },
  {
    "path": "fastlane/metadata/android/ckb/short_description.txt",
    "content": "ستریم و دابەزاندنی فیلم، و زنجیرە تەلەفزیۆنی و ئەنیمێ.\n"
  },
  {
    "path": "fastlane/metadata/android/ckb/title.txt",
    "content": "کلاود ستريم\n"
  },
  {
    "path": "fastlane/metadata/android/cs-CZ/changelogs/2.txt",
    "content": "- Přidán seznam změn!\n"
  },
  {
    "path": "fastlane/metadata/android/cs-CZ/full_description.txt",
    "content": "CloudStream-3 umožňuje streamovat a stahovat filmy, televizní seriály a anime.\n\nAplikace je bez reklam a analytik a podporuje\nspoustu stránek s trailery a filmy a další, např.\n\nZáložky\n\nStahování titulků\n\nPodpora Chromecastu\n"
  },
  {
    "path": "fastlane/metadata/android/cs-CZ/short_description.txt",
    "content": "Streamování a stahování filmů, TV seriálů a anime.\n"
  },
  {
    "path": "fastlane/metadata/android/cs-CZ/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/de-DE/changelogs/2.txt",
    "content": "- Änderungsprotokoll hinzugefügt!\n"
  },
  {
    "path": "fastlane/metadata/android/de-DE/full_description.txt",
    "content": "Mit CloudStream-3 kannst du Filme, TV-Serien und Anime streamen und herunterladen.\n\nDie App kommt ganz ohne Werbung und Analytik aus.\nSie unterstützt zahlreiche Trailer, Filmseiten und vieles mehr, unter anderem:\n\nLesezeichen\n\nDownloads von Untertiteln\n\nChromecast-Unterstützung\n"
  },
  {
    "path": "fastlane/metadata/android/de-DE/short_description.txt",
    "content": "Filme, Fernsehserien und Animes streamen und herunterladen.\n"
  },
  {
    "path": "fastlane/metadata/android/de-DE/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/el-GR/changelogs/2.txt",
    "content": "- Προστέθηκε ο κατάλογος αλλαγών!\n"
  },
  {
    "path": "fastlane/metadata/android/el-GR/full_description.txt",
    "content": "Το CloudStream-3 σάς επιτρέπει να μεταδώσετε και να κατεβάζετε Ταινίες, Τηλεοπτικές σειρές και Anime.\n\nΗ εφαρμογή έρχεται χωρίς διαφημίσεις και αναλυτικά στοιχεία και\nυποστηρίζει πολλούς ιστότοπους με τρέιλερ ταινιών και πολλά άλλα, π.χ.\n\nΣελιδοδείκτες\n\nΛήψεις υποτίτλων\n\nΥποστήριξη Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/el-GR/short_description.txt",
    "content": "Μετάδοση και λήψη ταινιών, τηλεοπτικών σειρών και anime.\n"
  },
  {
    "path": "fastlane/metadata/android/el-GR/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/2.txt",
    "content": "- Changelog added!\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/full_description.txt",
    "content": "CloudStream-3 lets you stream and download Movies, TV-Series and Anime.\n\nThe app comes without any ads and analytics and\nsupports multiple trailer & movie sites, and more, e.g.\n\nBookmarks\n\nSubtitle downloads\n\nChromecast support\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/short_description.txt",
    "content": "Stream and download movies, TV series and anime.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/es-AR/changelogs/2.txt",
    "content": "- Changelog añadido!\n"
  },
  {
    "path": "fastlane/metadata/android/es-AR/full_description.txt",
    "content": "CloudStream-3 le permite transmitir y descargar películas, series de TV y Anime.\n\nLa aplicación viene sin anuncios y análisis y\nsoporta múltiples sitios de película de trailer y más, por ejemplo.\n\nMarcas\n\nSubtítulos descargas\n\nApoyo Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/es-AR/short_description.txt",
    "content": "Mirá y descarga Películas, Series y Anime.\n"
  },
  {
    "path": "fastlane/metadata/android/es-AR/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/es-ES/changelogs/2.txt",
    "content": "- ¡Registro de cambios añadido!\n"
  },
  {
    "path": "fastlane/metadata/android/es-ES/full_description.txt",
    "content": "CloudStream-3 te permite ver y descargar películas, series de TV y anime.\n\nLa aplicación viene sin ningún tipo de anuncios y análisis y\nsoporta varias páginas de trailers y películas, y más, como:\n\nMarcadores\n\nDescargas de subtítulos\n\nCompatible con Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/es-ES/short_description.txt",
    "content": "Vea y descargue películas, series de televisión y anime.\n"
  },
  {
    "path": "fastlane/metadata/android/es-ES/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/fa-IR/changelogs/2.txt",
    "content": "- تغییرات اضافه شد!\n"
  },
  {
    "path": "fastlane/metadata/android/fa-IR/full_description.txt",
    "content": "CloudStream-3 به شما امکان می دهد فیلم ها، سریال های تلویزیونی و انیمه ها را پخش و دانلود کنید.\nاین برنامه بدون هیچ گونه تبلیغات و تجزیه و تحلیل ارائه می‌شود و\nاز چندین سایت تریلر و فیلم و موارد دیگر پشتیبانی می‌کند به عنوان مثال :\nنشانک‌ها\nدانلود زیرنویس\nپشتیبانی از کروم کست\n"
  },
  {
    "path": "fastlane/metadata/android/fa-IR/short_description.txt",
    "content": "فیلم‌ها، سریال‌های تلویزیونی و انیمه‌ها را پخش و دانلود کنید.\n"
  },
  {
    "path": "fastlane/metadata/android/fa-IR/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/fr-FR/changelogs/2.txt",
    "content": "- Ajout du journal des modifications !\n"
  },
  {
    "path": "fastlane/metadata/android/fr-FR/full_description.txt",
    "content": "CloudStream-3 vous permet de regarder et de télécharger des Films, des Séries TV et des Animes.\n\nL'application n'a aucune publicité, aucun traçage et\nla prise en charge de différentes bandes-annonces & sites, et plus, par exemple\n\nSignets\n\nTéléchargement des sous-titres\n\nPrise en charge de Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/fr-FR/short_description.txt",
    "content": "Regarder et télécharger des films, des séries TV et des animes.\n"
  },
  {
    "path": "fastlane/metadata/android/fr-FR/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/hi-IN/changelogs/2.txt",
    "content": "- चेंजलॉग जोड़ा गया!\n"
  },
  {
    "path": "fastlane/metadata/android/hi-IN/full_description.txt",
    "content": "क्लाउडस्ट्रीम-3 आपको फ़िल्में, टीवी शृंखलाएँ और एनिमे स्ट्रीम एवं डाउनलोड करने की सुविधा देता है।\n\nऐप विज्ञापन और विश्लेषिकी से मुक्त है एवं\nअनेकों ट्रेलर और मूवी साइटों के समर्थन जैसी सुविधाएँ देता है, जैसे कि –\n\nपृष्ठचिह्न\n\nउपशीर्षक डाउनलोड\n\nक्रोमकास्ट समर्थन\n"
  },
  {
    "path": "fastlane/metadata/android/hi-IN/short_description.txt",
    "content": "फ़िल्में, टीवी धारावाहिक और एनिमे स्ट्रीम और डाउनलोड करें।\n"
  },
  {
    "path": "fastlane/metadata/android/hi-IN/title.txt",
    "content": "क्लाउडस्ट्रीम\n"
  },
  {
    "path": "fastlane/metadata/android/hr/changelogs/2.txt",
    "content": "- Dodan je dnevnik promjena!\n"
  },
  {
    "path": "fastlane/metadata/android/hr/full_description.txt",
    "content": "CloudStream-3 omogućuje gledanje i preuzimanje filmova, TV serija i animea.\n\nAplikacija ne koristi oglase i analitike te\npodržava stranice s trailerima, filmovima i više, npr.\n\nOznake\n\nPreuzimanja titlova\n\nChromecast podrška\n"
  },
  {
    "path": "fastlane/metadata/android/hr/short_description.txt",
    "content": "Gledajte i preuzmite filmove, TV serije i anime.\n"
  },
  {
    "path": "fastlane/metadata/android/hr/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/hu-HU/changelogs/2.txt",
    "content": "- Változáslista hozzáadva!\n"
  },
  {
    "path": "fastlane/metadata/android/hu-HU/full_description.txt",
    "content": "A CloudStream-3 segítségével streamelhet vagy letölthet filmeket, TV sorozatokat vagy animéket..\n\nAz app nem tartalmaz semmilyen reklámot vagy követést,\nés támogat többféle film és előzetes oldalt, és sok minden mást, pl.\n\nKönyvjelzőket\n\nFelirat Letöltést\n\nChromecast támogatást\n"
  },
  {
    "path": "fastlane/metadata/android/hu-HU/short_description.txt",
    "content": "Streameljen vagy töltsön le filmeket, TV sorozatokat vagy animét.\n"
  },
  {
    "path": "fastlane/metadata/android/hu-HU/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/id/changelogs/2.txt",
    "content": "- Log perubahan ditambahkan!\n"
  },
  {
    "path": "fastlane/metadata/android/id/full_description.txt",
    "content": "CloudStream-3 memungkinkan Anda melakukan streaming dan mengunduh Film, Serial TV, dan Anime.\n\nAplikasi ini hadir tanpa iklan dan analitik apa pun dan\nmendukung beberapa situs cuplikan & film, dan banyak lagi, misalnya.\n\nBookmark\n\nPengunduhan subtitle\n\nDukungan Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/id/short_description.txt",
    "content": "Stream dan unduh film, seri TV, dan anime.\n"
  },
  {
    "path": "fastlane/metadata/android/id/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/it-IT/changelogs/2.txt",
    "content": "- Aggiunto registro delle modifiche!\n"
  },
  {
    "path": "fastlane/metadata/android/it-IT/full_description.txt",
    "content": "CloudStream-3 ti consente di riprodurre in streaming e scaricare film, serie TV e anime.\n\nL'app viene fornita senza pubblicità e tracking.\nSupporta più siti di trailer e film e altro ancora, ad esempio:\n\nPreferiti\n\nDownload di sottotitoli\n\nSupporto a Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/it-IT/short_description.txt",
    "content": "Scarica e riproduci in streaming film, serie TV e anime.\n"
  },
  {
    "path": "fastlane/metadata/android/it-IT/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/ja-JP/changelogs/2.txt",
    "content": "- 変更履歴追加!\n"
  },
  {
    "path": "fastlane/metadata/android/ja-JP/full_description.txt",
    "content": "CloudStream-3は映画、TVシリーズ、アニメのストリーミングとダウンロードを可能にします。\n\nこのアプリは広告やアナリティクスが一切なく、\n、複数の予告編や映画サイトなどをサポートしています。\n\nブックマーク\n\n字幕ダウンロード\n\nChromecastサポート\n"
  },
  {
    "path": "fastlane/metadata/android/ja-JP/short_description.txt",
    "content": "映画、TVシリーズ、アニメのストリーミングとダウンロード。\n"
  },
  {
    "path": "fastlane/metadata/android/ja-JP/title.txt",
    "content": "クラウドストリーム\n"
  },
  {
    "path": "fastlane/metadata/android/ko-KR/changelogs/2.txt",
    "content": "- 변경기록이 추가됨!\n"
  },
  {
    "path": "fastlane/metadata/android/ko-KR/full_description.txt",
    "content": "클라우트스트림-3는 영화, TV-연속극 및 애니메이션 스트리밍을 할 수 있고 내려받을 수 있습니다.\n\n이 앱은 광고나 분석 없이 제공되고\n여러 예고편 & 영화 사이트 등을 지원합니다.\n\n북마크\n\n자막 내려받기\n\n크롬캐스트 지원\n"
  },
  {
    "path": "fastlane/metadata/android/ko-KR/short_description.txt",
    "content": "영화, TV 시리즈 및 애니메이션 스트림과 내려받기.\n"
  },
  {
    "path": "fastlane/metadata/android/ko-KR/title.txt",
    "content": "클라우드스티림\n"
  },
  {
    "path": "fastlane/metadata/android/lt/changelogs/2.txt",
    "content": "-Pridėtas pokyčių žurnalas!\n"
  },
  {
    "path": "fastlane/metadata/android/lt/full_description.txt",
    "content": "CloudStream-3 leidžia transliuoti ir atsisiųsti filmus, TV serialus ir anime.\n\nPrograma pateikiama be jokių reklamų ir analitikų ir\npalaiko daugybę anonsų ir filmų svetainių ir dar daugiau, pvz.\n\nŽymės\n\nSubtitrų atsisiuntimai\n\nChromecast palaikymas\n"
  },
  {
    "path": "fastlane/metadata/android/lt/short_description.txt",
    "content": "Transliuokite ir atsisiųskite filmus, TV serialus ir anime.\n"
  },
  {
    "path": "fastlane/metadata/android/lt/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/lv/changelogs/2.txt",
    "content": "- Pievienots izmaiņu žurnāls!\n"
  },
  {
    "path": "fastlane/metadata/android/lv/full_description.txt",
    "content": "CloudStream-3 ļauj straumēt un lejupielādēt filmas, seriālus, raidījumus un anime.\n\nLietotne nesatur reklāmu un analītiku un\natbalsta daudzas reklāmrullīšu un filmu vietnes, kā arī, piem.\n\nGrāmatzīmes\n\nSubtitru lejupielādi\n\nChromecast\n"
  },
  {
    "path": "fastlane/metadata/android/lv/short_description.txt",
    "content": "Straumēt un lejupielādēt filmas, seriālus, raidījumus un anime.\n"
  },
  {
    "path": "fastlane/metadata/android/lv/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/mk-MK/changelogs/2.txt",
    "content": "- Дневникот на промени е додаден!\n"
  },
  {
    "path": "fastlane/metadata/android/mk-MK/full_description.txt",
    "content": "CloudStream-3 овозможува пренос и преземање филмови, ТВ-серии и аниме.\n\nАпликацијата доаѓа без никакви реклами и аналитика и\nподдржува повеќе страници за трејлери и филмови, и повеќе, на пр.\n\nОбележувачи\n\nПреземања на преводи\n\nПоддршка за Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/mk-MK/short_description.txt",
    "content": "Гледај и преземај филмови, ТВ серии и аниме.\n"
  },
  {
    "path": "fastlane/metadata/android/mk-MK/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/ml-IN/changelogs/2.txt",
    "content": "-ചേഞ്ച്ലോഗ് ചേർത്തു!\n"
  },
  {
    "path": "fastlane/metadata/android/ml-IN/full_description.txt",
    "content": "ക്ലൗഡ് സ്ട്രീം-3 സിനിമകൾ, ടിവി സീരീസ്, ആനിമേഷൻ എന്നിവ സ്ട്രീം ചെയ്യാനും ഡൗൺലോഡ് ചെയ്യാനും നിങ്ങളെ അനുവദിക്കുന്നു.\n\nപരസ്യങ്ങളും അനലിറ്റിക്‌സും കൂടാതെ ആപ്പ് വരുന്നു ഒപ്പം\nഒന്നിലധികം ട്രെയിലർ, മൂവി സൈറ്റുകൾ എന്നിവയും മറ്റും പിന്തുണയ്ക്കുന്നു, ഉദാഹരണം\n\nബുക്ക്മാർക്കുകൾ\n\nഉപശീർഷകം ഡൗൺലോഡുകൾ\n\nക്രോംകാസ്റ്റ് പിന്തുണ\n"
  },
  {
    "path": "fastlane/metadata/android/ml-IN/short_description.txt",
    "content": "സ്ട്രീം ഒപ്പം ഡൗൺലോഡ് സിനിമകളും, ടിവി സീരീസുകളും, ആനിമേഷനും .\n"
  },
  {
    "path": "fastlane/metadata/android/ml-IN/title.txt",
    "content": "ക്ലൗഡ് സ്ട്രീം\n"
  },
  {
    "path": "fastlane/metadata/android/mt/changelogs/2.txt",
    "content": "- Changelog miżjud!\n"
  },
  {
    "path": "fastlane/metadata/android/mt/full_description.txt",
    "content": "CloudStream-3 iħallik tistrimja u tniżżel Films, Serje TV u Anime.\n\nL-app tiġi mingħajr reklami u analytics u\njappoġġja siti multipli ta' trejlers u films, u aktar, eż.\n\nBookmarks\n\nDownloads tas-sottotitli\n\nAppoġġ tal-Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/mt/short_description.txt",
    "content": "Tistrimja u tniżżel films, serje tat-TV u Anime.\n"
  },
  {
    "path": "fastlane/metadata/android/mt/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/nl-NL/short_description.txt",
    "content": "Stream en download films, tv-shows en anime.\n"
  },
  {
    "path": "fastlane/metadata/android/nl-NL/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/no-NO/changelogs/2.txt",
    "content": "- Endringslogg tillagt.\n"
  },
  {
    "path": "fastlane/metadata/android/no-NO/full_description.txt",
    "content": "CloudStream-3 lar deg strømme og laste ned filmer, TV-serier, og anime. Programmet er reklamefritt, og det utføres ingen analyse. Flere førfilmer og filmsteder støttes, med mer.\nNoen av funksjonene.\n\nBokmerker\n\nNedlasting av undertekster\n\nChromecast-støtte\n"
  },
  {
    "path": "fastlane/metadata/android/no-NO/short_description.txt",
    "content": "Se filmer, TV-serier og anime direkte eller last ned\n"
  },
  {
    "path": "fastlane/metadata/android/no-NO/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/or/changelogs/2.txt",
    "content": "- ପରିବର୍ତ୍ତନ ପୋଥି ଯୋଡ଼ାଗଲା!\n"
  },
  {
    "path": "fastlane/metadata/android/pa/changelogs/2.txt",
    "content": "- ਚੇਂਜਲੌਗ ਜੋੜਿਆ ਗਿਆ!\n"
  },
  {
    "path": "fastlane/metadata/android/pa/full_description.txt",
    "content": "ਕਲਾਊਡਸਟ੍ਰੀਮ-3 ਤੁਹਾਨੂੰ ਮੂਵੀਜ਼, ਟੀਵੀ-ਸੀਰੀਜ਼ ਅਤੇ ਐਨੀਮੇ ਨੂੰ ਸਟ੍ਰੀਮ ਅਤੇ ਡਾਊਨਲੋਡ ਕਰਨ ਦਿੰਦਾ ਹੈ।\n\nਐਪ ਬਿਨਾਂ ਕਿਸੇ ਵਿਗਿਆਪਨ ਅਤੇ ਵਿਸ਼ਲੇਸ਼ਣ ਦੇ ਆਉਂਦੀ ਹੈ ਅਤੇ\nਮਲਟੀਪਲ ਟ੍ਰੇਲਰ ਅਤੇ ਮੂਵੀ ਸਾਈਟਾਂ ਦਾ ਸਮਰਥਨ ਕਰਦਾ ਹੈ ਅਤੇ ਹੋਰ, ਜਿਵੇਂ ਕਿ\n\nਬੁੱਕਮਾਰਕਸ\n\nਉਪਸਿਰਲੇਖ ਡਾਊਨਲੋਡ\n\nਕਰੋਮਕਾਸਟ ਦਾ ਸਮਰਥਨ\n"
  },
  {
    "path": "fastlane/metadata/android/pa/short_description.txt",
    "content": "ਫਿਲਮਾਂ, ਟੀਵੀ-ਸੀਰੀਜ਼ ਅਤੇ ਐਨੀਮੇ ਨੂੰ ਸਟ੍ਰੀਮ ਅਤੇ ਡਾਊਨਲੋਡ ਕਰੋ।\n"
  },
  {
    "path": "fastlane/metadata/android/pa/title.txt",
    "content": "ਕਲਾਊਡਸਟ੍ਰੀਮ\n"
  },
  {
    "path": "fastlane/metadata/android/pl-PL/changelogs/2.txt",
    "content": "- Dodano dziennik zmian!\n"
  },
  {
    "path": "fastlane/metadata/android/pl-PL/full_description.txt",
    "content": "CloudStream-3 umożliwia strumieniowe przesyłanie i pobieranie filmów, seriali telewizyjnych i anime.\n\nAplikacja jest dostarczana bez reklam i analityki, obsługuje\nwiele witryn ze zwiastunami, filmami i nie tylko, np.\n\nZakładki\n\nPobieranie napisów\n\nObsługa Chromecasta\n"
  },
  {
    "path": "fastlane/metadata/android/pl-PL/short_description.txt",
    "content": "Streamuj i pobieraj filmy, seriale telewizyjne i anime.\n"
  },
  {
    "path": "fastlane/metadata/android/pl-PL/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/pt/changelogs/2.txt",
    "content": "- Adicionado o registo de alterações!\n"
  },
  {
    "path": "fastlane/metadata/android/pt/full_description.txt",
    "content": "O CloudStream-3 permite-lhe transmitir e descarregar filmes, séries de TV e anime.\n\nA aplicação é fornecida sem quaisquer anúncios e análises e\nsuporta vários sites de trailers e filmes, e muito mais, por exemplo\n\nMarcadores\n\nDownloads de legendas\n\nSuporte para Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/pt/short_description.txt",
    "content": "Transmita e transfira filmes, séries de TV e anime.\n"
  },
  {
    "path": "fastlane/metadata/android/pt/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/pt-BR/changelogs/2.txt",
    "content": "- Histórico de mudanças adicionado!\n"
  },
  {
    "path": "fastlane/metadata/android/pt-BR/full_description.txt",
    "content": "O CloudStream-3 permite que você faça transmissões, download de filmes, séries, e anime.\n\nO aplicativo não contém anúncios ou ferramentas de análise,\ne suporta múltiplos sites de filmes e trailers, e muito mais, como:\n\nFavoritos\n\nDownload de legendas\n\nSuporte à Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/pt-BR/short_description.txt",
    "content": "Faça transmissões, download de filmes, séries, e anime.\n"
  },
  {
    "path": "fastlane/metadata/android/pt-BR/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/ro/changelogs/2.txt",
    "content": "- Changelog adăugat!\n"
  },
  {
    "path": "fastlane/metadata/android/ro/full_description.txt",
    "content": "CloudStream-3 vă permite să difuzați și să descărcați filme, seriale TV și anime.\n\nAplicația vine fără reclame și analize și\nsuportă mai multe site-uri de rulare și filme, și nu numai, de ex.\n\nMarcaje\n\nDescărcări de subtitrări\n\nSuport pentru Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/ro/short_description.txt",
    "content": "Urmăriți și descărcați filme, seriale TV și anime.\n"
  },
  {
    "path": "fastlane/metadata/android/ro/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/ru-RU/changelogs/2.txt",
    "content": "- Добавлен список изменений!\n"
  },
  {
    "path": "fastlane/metadata/android/ru-RU/full_description.txt",
    "content": "CloudStream-3 позволяет транслировать и скачивать фильмы, сериалы и аниме.\n\nПриложение поставляется без рекламы и аналитики и\nподдерживает множество сайтов с трейлерами и фильмами, а также многое другое, например\n\nКнижные закладки\n\nЗагрузка субтитров\n\nПоддержка Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/ru-RU/short_description.txt",
    "content": "Транслируйте и скачивайте фильмы, сериалы и аниме.\n"
  },
  {
    "path": "fastlane/metadata/android/ru-RU/title.txt",
    "content": "Облачный поток\n"
  },
  {
    "path": "fastlane/metadata/android/sk/changelogs/2.txt",
    "content": "- Zoznam zmien pridaný!\n"
  },
  {
    "path": "fastlane/metadata/android/sk/full_description.txt",
    "content": "CloudStream-3 vám umožní streamovať sťahovať filmy, TV série a Anime.\n\nAplikácia prichádza bez akýchkoľvek reklám a analýz a\npodporuje viaceré prívesy a filmové stránky a ďalšie, napr.\n\nAktuality\n\nPrenosy titulkov\n\nPodpora Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/sk/short_description.txt",
    "content": "Stream a sťahovanie filmov, televízny seriálov a anime.\n"
  },
  {
    "path": "fastlane/metadata/android/sk/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/sv-SE/changelogs/2.txt",
    "content": "- Ändringslogg tillagd!\n"
  },
  {
    "path": "fastlane/metadata/android/sv-SE/full_description.txt",
    "content": "CloudStream-3 låter dig streama och ladda ner filmer, TV-serier och anime.\n\nAppen levereras utan annonser och analyser och\nstöder flera trailer- och film webbplatser och mer, t.ex.\n\nBokmärken\n\nNedladdning av undertexter\n\nStöd för Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/sv-SE/short_description.txt",
    "content": "Streama och ladda ner filmer, TV serier och anime.\n"
  },
  {
    "path": "fastlane/metadata/android/sv-SE/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/ta-IN/changelogs/2.txt",
    "content": "- சேஞ்ச்லாக் சேர்க்கப்பட்டது!\n"
  },
  {
    "path": "fastlane/metadata/android/ta-IN/full_description.txt",
    "content": "Cloudstream-3 உங்களை திரைப்படங்கள், தொலைக்காட்சி தொடர்கள் மற்றும் அனிம்களை ஸ்ட்ரீம் செய்யவும் பதிவிறக்கவும் அனுமதிக்கிறது.\n\nஇந்த பயன்பாட்டில் எந்தவித விளம்பரங்களும் பகுப்பாய்வுகளும் இல்லாமல் வருகிறது மற்றும்\nபல டிரெய்லர் & திரைப்படத் தளங்கள் மற்றும் பலவற்றை ஆதரிக்கிறது, உதாரணத்திற்கு\n\nபுக்மார்க்குகள்\n\nவசன பதிவிறக்கங்கள்\n\nChromecast-இன் ஆதரவு\n"
  },
  {
    "path": "fastlane/metadata/android/ta-IN/short_description.txt",
    "content": "திரைப்படங்கள், டிவி தொடர்கள் மற்றும் அனிமே ஸ்ட்ரீம் செய்து பதிவிறக்கவும்.\n"
  },
  {
    "path": "fastlane/metadata/android/ta-IN/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/tr-TR/changelogs/2.txt",
    "content": "- Sürüm notları eklendi!\n"
  },
  {
    "path": "fastlane/metadata/android/tr-TR/full_description.txt",
    "content": "CloudStream-3, Filmleri, TV Dizilerini ve Animeleri izlemenize ve indirmenize olanak tanır.\n\nUygulama herhangi bir reklam ve analitik içermez ve\nbirden fazla fragman & film sitesini ve daha fazlasını destekler, örneğin:\n\nYer imleri\n\nAltyazı indirmeleri\n\nChromecast desteği\n"
  },
  {
    "path": "fastlane/metadata/android/tr-TR/short_description.txt",
    "content": "Filmleri, TV dizilerini ve animeleri yayınlayın ve indirin.\n"
  },
  {
    "path": "fastlane/metadata/android/tr-TR/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/uk/changelogs/2.txt",
    "content": "– Додано журнал змін!\n"
  },
  {
    "path": "fastlane/metadata/android/uk/full_description.txt",
    "content": "CloudStream-3 дозволяє транслювати та завантажувати фільми, серіали та аніме.\n\nЗастосунок не містить реклами та аналітики й\nпідтримує безліч сайтів з трейлерами, фільмами тощо, а також багато іншого, наприклад:\n\nЗакладки\n\nЗавантаження субтитрів\n\nПідтримка Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/uk/short_description.txt",
    "content": "Транслюйте та завантажуйте фільми, серіали та аніме.\n"
  },
  {
    "path": "fastlane/metadata/android/uk/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/ur/changelogs/2.txt",
    "content": "- Changelog شامل کر لیا گیا!\n"
  },
  {
    "path": "fastlane/metadata/android/ur/full_description.txt",
    "content": "CloudStream-3 آپ کو فلمیں، ٹی وی سیریز اور Anime سٹریم اور ڈاؤن لوڈ کرنے دیتا ہے۔\n\nایپ کسی بھی قسم کے اشتہارات اور analytics کے بغیر آتی ہے اور یہ اپپ\nمتعدد ٹریلرز، مووی سائٹس، اور مزید خصوصیات کو سپورٹ کرتا ہے، جیسے\n\nبک مارکس\n\nسب ٹائٹل ڈاؤن لوڈز\n\nChromecast سپورٹ\n"
  },
  {
    "path": "fastlane/metadata/android/ur/short_description.txt",
    "content": "فلمیں، ٹی وی سیریز، اور anime کو سٹریم اور ڈاؤن لوڈ کریں۔\n"
  },
  {
    "path": "fastlane/metadata/android/ur/title.txt",
    "content": "کلاؤڈسٹریم\n"
  },
  {
    "path": "fastlane/metadata/android/vi/changelogs/2.txt",
    "content": "- Đã thêm Nhật ký thay đổi!\n"
  },
  {
    "path": "fastlane/metadata/android/vi/full_description.txt",
    "content": "CloudStream-3 cho phép bạn xem và tải xuống phim lẻ, phim bộ và anime.\n\nỨng dụng không có quảng cáo hay và phân tích nào,\nđồng thời hỗ trợ nhiều trang web xem phim, v.v.\n\nĐánh dấu\n\nTải phụ đề\n\nHỗ trợ Chromecast\n"
  },
  {
    "path": "fastlane/metadata/android/vi/short_description.txt",
    "content": "Xem và tải xuống phim lẻ, phim bộ và anime.\n"
  },
  {
    "path": "fastlane/metadata/android/vi/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/zh-CN/changelogs/2.txt",
    "content": "- 新增更新日志！\n"
  },
  {
    "path": "fastlane/metadata/android/zh-CN/full_description.txt",
    "content": "CloudStream-3可以让你串流和下载电影、剧集和动漫。\n\n这款应用没有任何广告和隐私分析并且\n它支持多个预告片和电影网站等。特点包括：\n\n书签\n\n下载字幕\n\n支持投屏\n"
  },
  {
    "path": "fastlane/metadata/android/zh-CN/short_description.txt",
    "content": "串流和下载电影、剧集和动漫。\n"
  },
  {
    "path": "fastlane/metadata/android/zh-CN/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "fastlane/metadata/android/zh-TW/changelogs/2.txt",
    "content": "- 新增更新紀錄！\n"
  },
  {
    "path": "fastlane/metadata/android/zh-TW/full_description.txt",
    "content": "CloudStream-3 讓您能串流與下載電影、劇集、與動漫。\n\n這款應用程式沒有任何廣告與隱私分析，並且\n支援多個預告片與電影站點、以及更多功能，例如：\n\n書籤管理\n\n字幕下載\n\nChromecast 支援\n"
  },
  {
    "path": "fastlane/metadata/android/zh-TW/short_description.txt",
    "content": "串流或下載電影、劇集與動漫。\n"
  },
  {
    "path": "fastlane/metadata/android/zh-TW/title.txt",
    "content": "CloudStream\n"
  },
  {
    "path": "gradle/libs.versions.toml",
    "content": "# https://docs.gradle.org/current/userguide/plugins.html#sec:version_catalog_plugin_application\n# https://docs.gradle.org/current/userguide/dependency_versions.html#sec:strict-version\n[versions]\nactivityKtx = \"1.12.4\"\nandroidGradlePlugin = \"8.13.2\"\nappcompat = \"1.7.1\"\nbiometric = \"1.4.0-alpha05\"\nbuildkonfigGradlePlugin = \"0.17.1\"\ncoil = \"3.3.0\"\ncolorpicker = \"6b46b49bd5\"\nconscryptAndroid = { strictly = \"2.5.2\" } # 2.5.3 crashes everything\nconstraintlayout = \"2.2.1\"\ncoreKtx = \"1.17.0\"\ndesugar_jdk_libs_nio = \"2.1.5\"\ndokkaGradlePlugin = \"2.1.0\"\nespressoCore = \"3.7.0\"\nfragmentKtx = \"1.8.9\"\nfuzzywuzzy = \"1.4.0\"\njacksonModuleKotlin = { strictly = \"2.13.1\" } # Later versions don't support minSdk <26 (Crashes on Android TV's and FireSticks)\njson = \"20251224\"\njsoup = \"1.21.2\"\njunit = \"4.13.2\"\njunitKtx = \"1.3.0\"\njunitVersion = \"1.3.0\"\njuniversalchardet = \"2.5.0\"\nkotlinGradlePlugin = \"2.3.0\"\nkotlinxCoroutinesCore = \"1.10.2\"\nlifecycleKtx = \"2.10.0\"\nmaterial = \"1.14.0-alpha09\"\nmedia3 = \"1.9.2\"\nnavigationKtx = \"2.9.7\"\nnewpipeextractor = \"v0.25.2\"\nnextlibMedia3 = \"1.9.1-0.11.0\"\nnicehttp = \"0.4.16\"\noverlappingpanels = \"0.1.5\"\npaletteKtx = \"1.0.0\"\npreferenceKtx = \"1.2.1\"\npreviewseekbarMedia3 = \"1.1.1.0\"\nqrcodeKotlin = \"4.5.0\"\nrhino = { strictly = \"1.8.1\" } # Requires minSdk 26 or later beginning at version 1.9.0\nsafefile = \"0.0.8\"\nshimmer = \"0.5.0\"\ntmdbJava = \"2.13.0\"\ntorrentserver = \"7861970e038b35cd8c6918384e49caf26903e09e\"\ntvprovider = \"1.1.0\"\nvideo = \"1.0.0\"\nworkRuntimeKtx = \"2.11.1\"\nzipline = \"1.24.0\"\n\njvmTarget = \"1.8\"\njdkToolchain = \"17\"\nminSdk = \"23\"\ncompileSdk = \"36\"\ntargetSdk = \"36\"\n\n[libraries]\nactivity-ktx = { module = \"androidx.activity:activity-ktx\", version.ref = \"activityKtx\" }\nappcompat = { module = \"androidx.appcompat:appcompat\", version.ref = \"appcompat\" }\nbiometric = { module = \"androidx.biometric:biometric\", version.ref = \"biometric\" }\ncoil = { module = \"io.coil-kt.coil3:coil\", version.ref = \"coil\" }\ncoil-network-okhttp = { module = \"io.coil-kt.coil3:coil-network-okhttp\", version.ref = \"coil\" }\ncolorpicker = { module = \"com.github.recloudstream:color-picker-android\", version.ref = \"colorpicker\" }\nconscrypt-android = { module = \"org.conscrypt:conscrypt-android\", version.ref = \"conscryptAndroid\" }\nconstraintlayout = { module = \"androidx.constraintlayout:constraintlayout\", version.ref = \"constraintlayout\" }\ncore = { module = \"androidx.test:core\" }\ncore-ktx = { module = \"androidx.core:core-ktx\", version.ref = \"coreKtx\" }\ndatabinding = { module = \"androidx.databinding:viewbinding\", version.ref = \"androidGradlePlugin\" }\ndesugar_jdk_libs_nio = { module = \"com.android.tools:desugar_jdk_libs_nio\", version.ref = \"desugar_jdk_libs_nio\" }\nespresso-core = { module = \"androidx.test.espresso:espresso-core\", version.ref = \"espressoCore\" }\next-junit = { module = \"androidx.test.ext:junit\", version.ref = \"junitVersion\" }\nfragment-ktx = { module = \"androidx.fragment:fragment-ktx\", version.ref = \"fragmentKtx\" }\nfuzzywuzzy = { module = \"me.xdrop:fuzzywuzzy\", version.ref = \"fuzzywuzzy\" }\njackson-module-kotlin = { module = \"com.fasterxml.jackson.module:jackson-module-kotlin\", version.ref = \"jacksonModuleKotlin\" }\njson = { module = \"org.json:json\", version.ref = \"json\" }\njsoup = { module = \"org.jsoup:jsoup\", version.ref = \"jsoup\" }\njunit = { module = \"junit:junit\", version.ref = \"junit\" }\njunit-ktx = { module = \"androidx.test.ext:junit-ktx\", version.ref = \"junitKtx\" }\njuniversalchardet = { module = \"com.github.albfernandez:juniversalchardet\", version.ref = \"juniversalchardet\" }\nkotlinx-coroutines-core = { module = \"org.jetbrains.kotlinx:kotlinx-coroutines-core\", version.ref = \"kotlinxCoroutinesCore\" }\nlifecycle-livedata-ktx = { module = \"androidx.lifecycle:lifecycle-livedata-ktx\", version.ref = \"lifecycleKtx\" }\nlifecycle-viewmodel-ktx = { module = \"androidx.lifecycle:lifecycle-viewmodel-ktx\", version.ref = \"lifecycleKtx\" }\nmaterial = { module = \"com.google.android.material:material\", version.ref = \"material\" }\nmedia3-cast = { module = \"androidx.media3:media3-cast\", version.ref = \"media3\" }\nmedia3-common = { module = \"androidx.media3:media3-common\", version.ref = \"media3\" }\nmedia3-container  = { module = \"androidx.media3:media3-container\", version.ref = \"media3\" }\nmedia3-datasource-cronet = { group = \"androidx.media3\", name = \"media3-datasource-cronet\", version.ref = \"media3\" }\nmedia3-datasource-okhttp = { module = \"androidx.media3:media3-datasource-okhttp\", version.ref = \"media3\" }\nmedia3-exoplayer = { module = \"androidx.media3:media3-exoplayer\", version.ref = \"media3\" }\nmedia3-exoplayer-dash = { module = \"androidx.media3:media3-exoplayer-dash\", version.ref = \"media3\" }\nmedia3-exoplayer-hls = { module = \"androidx.media3:media3-exoplayer-hls\", version.ref = \"media3\" }\nmedia3-session = { module = \"androidx.media3:media3-session\", version.ref = \"media3\" }\nmedia3-ui = { module = \"androidx.media3:media3-ui\", version.ref = \"media3\" }\nnavigation-fragment-ktx = { module = \"androidx.navigation:navigation-fragment-ktx\", version.ref = \"navigationKtx\" }\nnavigation-ui-ktx = { module = \"androidx.navigation:navigation-ui-ktx\", version.ref = \"navigationKtx\" }\nnewpipeextractor = { module = \"com.github.teamnewpipe:NewPipeExtractor\", version.ref = \"newpipeextractor\" }\nnextlib-media3ext = { module = \"io.github.anilbeesetti:nextlib-media3ext\", version.ref = \"nextlibMedia3\" }\nnextlib-mediainfo = { module = \"io.github.anilbeesetti:nextlib-mediainfo\", version.ref = \"nextlibMedia3\" }\nnicehttp = { module = \"com.github.Blatzar:NiceHttp\", version.ref = \"nicehttp\" }\noverlappingpanels = { module = \"com.github.discord:OverlappingPanels\", version.ref = \"overlappingpanels\" }\npalette-ktx = { module = \"androidx.palette:palette-ktx\", version.ref = \"paletteKtx\" }\npreference-ktx = { module = \"androidx.preference:preference-ktx\", version.ref = \"preferenceKtx\" }\npreviewseekbar-media3 = { module = \"com.github.rubensousa:previewseekbar-media3\", version.ref = \"previewseekbarMedia3\" }\nqrcode-kotlin = { module = \"io.github.g0dkar:qrcode-kotlin\", version.ref = \"qrcodeKotlin\" }\nrhino = { module = \"org.mozilla:rhino\", version.ref = \"rhino\" }\nsafefile = { module = \"com.github.LagradOst:SafeFile\", version.ref = \"safefile\" }\nshimmer = { module = \"com.facebook.shimmer:shimmer\", version.ref = \"shimmer\" }\ntmdb-java = { module = \"com.uwetrottmann.tmdb2:tmdb-java\", version.ref = \"tmdbJava\" }\ntorrentserver = { module = \"com.github.recloudstream:torrentserver\", version.ref = \"torrentserver\" }\ntvprovider = { module = \"androidx.tvprovider:tvprovider\", version.ref = \"tvprovider\" }\nvideo = { module = \"com.google.android.mediahome:video\", version.ref = \"video\" }\nwork-runtime-ktx = { module = \"androidx.work:work-runtime-ktx\", version.ref = \"workRuntimeKtx\" }\nzipline = { module = \"app.cash.zipline:zipline-android\", version.ref = \"zipline\" }\n\n[plugins]\nandroid-application = { id = \"com.android.application\", version.ref = \"androidGradlePlugin\" }\nandroid-lint = { id = \"com.android.lint\", version.ref = \"androidGradlePlugin\" }\nandroid-multiplatform-library = { id = \"com.android.kotlin.multiplatform.library\", version.ref = \"androidGradlePlugin\" }\nbuildkonfig = { id = \"com.codingfeline.buildkonfig\", version.ref = \"buildkonfigGradlePlugin\" }\ndokka = { id = \"org.jetbrains.dokka\", version.ref = \"dokkaGradlePlugin\" }\nkotlin-android = { id = \"org.jetbrains.kotlin.android\", version.ref = \"kotlinGradlePlugin\" }\nkotlin-jvm = { id = \"org.jetbrains.kotlin.jvm\" , version.ref = \"kotlinGradlePlugin\" }\nkotlin-multiplatform = { id = \"org.jetbrains.kotlin.multiplatform\", version.ref = \"kotlinGradlePlugin\" }\n\n[bundles]\ncoil = [\"coil\", \"coil-network-okhttp\"]\nlifecycle = [\"lifecycle-livedata-ktx\", \"lifecycle-viewmodel-ktx\"]\nmedia3 = [\"media3-cast\", \"media3-common\", \"media3-container\", \"media3-datasource-cronet\", \"media3-datasource-okhttp\", \"media3-exoplayer\", \"media3-exoplayer-dash\", \"media3-exoplayer-hls\", \"media3-session\", \"media3-ui\"]\nnavigation = [\"navigation-fragment-ktx\", \"navigation-ui-ktx\"]\nnextlib = [\"nextlib-media3ext\", \"nextlib-mediainfo\"]\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\n# Binary-only ZIP Checksum: https://gradle.org/release-checksums/\ndistributionSha256Sum=b266d5ff6b90eada6dc3b20cb090e3731302e553a27c5d3e4df1f0d76beaff06\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-9.3.1-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx4G -Dfile.encoding=UTF-8\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n# AndroidX package structure to make it clearer which packages are bundled with the\n# Android operating system, and which are packaged with your app\"s APK\n# https://developer.android.com/topic/libraries/support-library/androidx-rn\nandroid.useAndroidX=true\n# Automatically convert third-party libraries to use AndroidX\n# android.enableJetifier=true\n# Kotlin code style for this project: \"official\" or \"obsolete\":\nkotlin.code.style=official\nandroid.nonTransitiveRClass=true\n\norg.gradle.caching=true\norg.gradle.configuration-cache=true\n\n# Compiling with Java 8 is deprecated but we still use it for now\nandroid.javaCompile.suppressSourceTargetDeprecationWarning=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\\n' \"$PWD\" ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -jar \"$APP_HOME/gradle/wrapper/gradle-wrapper.jar\" \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n@rem SPDX-License-Identifier: Apache-2.0\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -jar \"%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\" %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "jitpack.yml",
    "content": "jdk:\n  - openjdk17 # Same JDK as github workflow\n"
  },
  {
    "path": "library/.gitignore",
    "content": "/build"
  },
  {
    "path": "library/build.gradle.kts",
    "content": "import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties\nimport com.codingfeline.buildkonfig.compiler.FieldSpec\nimport org.jetbrains.dokka.gradle.engine.parameters.KotlinPlatform\nimport org.jetbrains.dokka.gradle.engine.parameters.VisibilityModifier\nimport org.jetbrains.kotlin.gradle.dsl.JvmTarget\nimport org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile\n\nplugins {\n    id(\"maven-publish\") // Gradle core plugin\n    alias(libs.plugins.kotlin.multiplatform)\n    alias(libs.plugins.android.lint)\n    alias(libs.plugins.android.multiplatform.library)\n    alias(libs.plugins.buildkonfig)\n    alias(libs.plugins.dokka)\n}\n\nval javaTarget = JvmTarget.fromTarget(libs.versions.jvmTarget.get())\n\nkotlin {\n    version = \"1.0.1\"\n\n    android {\n        // If this is the same com.lagradost.cloudstream3.R stops working\n        namespace = \"com.lagradost.api\"\n\n        compileSdk = libs.versions.compileSdk.get().toInt()\n        minSdk = libs.versions.minSdk.get().toInt()\n\n        compilerOptions {\n            jvmTarget.set(javaTarget)\n        }\n\n        lint {\n            targetSdk = libs.versions.targetSdk.get().toInt()\n        }\n    }\n\n    jvm()\n\n    compilerOptions {\n        freeCompilerArgs.addAll(\n            \"-Xexpect-actual-classes\",\n            \"-Xannotation-default-target=param-property\"\n        )\n    }\n\n    sourceSets {\n        all {\n            languageSettings {\n                optIn(\"com.lagradost.cloudstream3.InternalAPI\")\n                optIn(\"com.lagradost.cloudstream3.Prerelease\")\n            }\n        }\n\n        commonMain.dependencies {\n            implementation(libs.nicehttp) // HTTP Lib\n            implementation(libs.jackson.module.kotlin) // JSON Parser\n            implementation(libs.kotlinx.coroutines.core)\n            implementation(libs.fuzzywuzzy) // Match Extractors\n            implementation(libs.jsoup) // HTML Parser\n            implementation(libs.rhino) // Run JavaScript\n            implementation(libs.newpipeextractor)\n            implementation(libs.tmdb.java) // TMDB API v3 Wrapper Made with RetroFit\n        }\n    }\n}\n\ntasks.withType<KotlinJvmCompile> {\n    compilerOptions {\n        jvmTarget.set(javaTarget)\n    }\n}\n\nbuildkonfig {\n    packageName = \"com.lagradost.api\"\n    exposeObjectWithName = \"BuildConfig\"\n\n    defaultConfigs {\n        // Reads local.properties\n        val localProperties = gradleLocalProperties(rootDir, project.providers)\n        buildConfigField(\n            FieldSpec.Type.STRING,\n            \"MDL_API_KEY\",\n            (System.getenv(\"MDL_API_KEY\") ?: localProperties[\"mdl.key\"]).toString()\n        )\n    }\n}\n\npublishing {\n    publications {\n        withType<MavenPublication> {\n            groupId = \"com.lagradost.api\"\n        }\n    }\n}\n\ndokka {\n    moduleName = \"Library\"\n    dokkaSourceSets {\n        configureEach {\n            analysisPlatform = KotlinPlatform.AndroidJVM\n            documentedVisibilities(\n                VisibilityModifier.Public,\n                VisibilityModifier.Protected\n            )\n\n            sourceLink {\n                localDirectory = file(\"..\")\n                remoteUrl(\"https://github.com/recloudstream/cloudstream/tree/master\")\n                remoteLineSuffix = \"#L\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "library/lint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lint>\n    <issue id=\"TrulyRandom\">\n        <ignore path=\"**/CryptoJS.class\" />\n    </issue>\n</lint>\n"
  },
  {
    "path": "library/src/androidMain/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest />"
  },
  {
    "path": "library/src/androidMain/kotlin/com/lagradost/api/ContextHelper.android.kt",
    "content": "package com.lagradost.api\n\nimport android.content.Context\nimport java.lang.ref.WeakReference\n\nvar ctx: WeakReference<Context>? = null\n\n/**\n * Helper function for Android specific context. Not usable in JVM.\n * Do not use this unless absolutely necessary.\n */\nactual fun getContext(): Any? {\n    return ctx?.get()\n}\n\nactual fun setContext(context: WeakReference<Any>) {\n    val actualContext = context.get() as? Context\n    if (actualContext != null) {\n        ctx = WeakReference(actualContext)\n    }\n}"
  },
  {
    "path": "library/src/androidMain/kotlin/com/lagradost/api/Log.kt",
    "content": "package com.lagradost.api\n\nimport android.util.Log\n\nactual object Log {\n    actual fun d(tag: String, message: String) {\n        Log.d(tag, message)\n    }\n\n    actual fun i(tag: String, message: String) {\n        Log.i(tag, message)\n    }\n\n    actual fun w(tag: String, message: String) {\n        Log.w(tag, message)\n    }\n\n    actual fun e(tag: String, message: String) {\n        Log.e(tag, message)\n    }\n}"
  },
  {
    "path": "library/src/androidMain/kotlin/com/lagradost/cloudstream3/network/WebViewResolver.android.kt",
    "content": "package com.lagradost.cloudstream3.network\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.net.http.SslError\nimport android.os.Handler\nimport android.os.Looper\nimport android.webkit.*\nimport com.lagradost.api.Log\nimport com.lagradost.api.getContext\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.debugException\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.utils.Coroutines.main\nimport com.lagradost.cloudstream3.utils.Coroutines.mainWork\nimport com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf\nimport com.lagradost.nicehttp.requestCreator\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.runBlocking\nimport okhttp3.Interceptor\nimport okhttp3.Request\nimport okhttp3.Response\nimport java.net.URI\n\n/**\n * When used as Interceptor additionalUrls cannot be returned, use WebViewResolver(...).resolveUsingWebView(...)\n * @param interceptUrl will stop the WebView when reaching this url.\n * @param additionalUrls this will make resolveUsingWebView also return all other requests matching the list of Regex.\n * @param userAgent if null then will use the default user agent\n * @param useOkhttp will try to use the okhttp client as much as possible, but this might cause some requests to fail. Disable for cloudflare.\n * @param script pass custom js to execute\n * @param scriptCallback will be called with the result from custom js\n * @param timeout close webview after timeout\n * */\nactual class WebViewResolver actual constructor(\n    val interceptUrl: Regex,\n    val additionalUrls: List<Regex>,\n    val userAgent: String?,\n    val useOkhttp: Boolean,\n    val script: String?,\n    val scriptCallback: ((String) -> Unit)?,\n    val timeout: Long\n) :\n    Interceptor {\n\n    actual companion object {\n        actual var webViewUserAgent: String? = null\n        actual val DEFAULT_TIMEOUT = 60_000L\n        private const val TAG = \"WebViewResolver\"\n\n        @JvmName(\"getWebViewUserAgent1\")\n        fun getWebViewUserAgent(): String? {\n            return webViewUserAgent ?: (getContext() as? Context)?.let { ctx ->\n                runBlocking {\n                    mainWork {\n                        WebView(ctx).settings.userAgentString.also { userAgent ->\n                            webViewUserAgent = userAgent\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    override fun intercept(chain: Interceptor.Chain): Response {\n        val request = chain.request()\n        return runBlocking {\n            val fixedRequest = resolveUsingWebView(request).first\n            return@runBlocking chain.proceed(fixedRequest ?: request)\n        }\n    }\n\n    actual suspend fun resolveUsingWebView(\n        url: String,\n        referer: String?,\n        method: String,\n        requestCallBack: (Request) -> Boolean,\n    ): Pair<Request?, List<Request>> =\n        resolveUsingWebView(url, referer, emptyMap(), method, requestCallBack)\n\n    actual suspend fun resolveUsingWebView(\n        url: String,\n        referer: String?,\n        headers: Map<String, String>,\n        method: String,\n        requestCallBack: (Request) -> Boolean,\n    ): Pair<Request?, List<Request>> {\n        return try {\n            resolveUsingWebView(\n                requestCreator(method, url, referer = referer, headers = headers), requestCallBack\n            )\n        } catch (e: java.lang.IllegalArgumentException) {\n            logError(e)\n            debugException { \"ILLEGAL URL IN resolveUsingWebView!\" }\n            return null to emptyList()\n        }\n    }\n\n    @SuppressLint(\"SetJavaScriptEnabled\")\n    actual suspend fun resolveUsingWebView(\n        request: Request,\n        requestCallBack: (Request) -> Boolean\n    ): Pair<Request?, List<Request>> {\n        val url = request.url.toString()\n        val headers = request.headers\n        Log.i(TAG, \"Initial web-view request: $url\")\n        var webView: WebView? = null\n        // Extra assurance it exits as it should.\n        var shouldExit = false\n\n        fun destroyWebView() {\n            main {\n                webView?.stopLoading()\n                webView?.destroy()\n                webView = null\n                shouldExit = true\n                Log.i(TAG, \"Destroyed webview\")\n            }\n        }\n\n        var fixedRequest: Request? = null\n        val extraRequestList = threadSafeListOf<Request>()\n\n        main {\n            // Useful for debugging\n            WebView.setWebContentsDebuggingEnabled(true)\n            try {\n                webView = WebView(\n                    (getContext() as? Context)\n                        ?: throw RuntimeException(\"No base context in WebViewResolver\")\n                ).apply {\n                    // Bare minimum to bypass captcha\n                    settings.javaScriptEnabled = true\n                    settings.domStorageEnabled = true\n\n                    webViewUserAgent = settings.userAgentString\n                    // Don't set user agent, setting user agent will make cloudflare break.\n                    if (userAgent != null) {\n                        settings.userAgentString = userAgent\n                    }\n                    // Blocks unnecessary images, remove if captcha fucks.\n//                    settings.blockNetworkImage = true\n                }\n\n                webView?.webViewClient = object : WebViewClient() {\n                    override fun shouldInterceptRequest(\n                        view: WebView,\n                        request: WebResourceRequest\n                    ): WebResourceResponse? = runBlocking {\n                        val webViewUrl = request.url.toString()\n                        Log.i(TAG, \"Loading WebView URL: $webViewUrl\")\n\n                        if (script != null) {\n                            val handler = Handler(Looper.getMainLooper())\n                            handler.post {\n                                view.evaluateJavascript(script)\n                                { scriptCallback?.invoke(it) }\n                            }\n                        }\n\n                        if (interceptUrl.containsMatchIn(webViewUrl)) {\n                            fixedRequest = request.toRequest()?.also {\n                                requestCallBack(it)\n                            }\n                            Log.i(TAG, \"Web-view request finished: $webViewUrl\")\n                            destroyWebView()\n                            return@runBlocking null\n                        }\n\n                        if (additionalUrls.any { it.containsMatchIn(webViewUrl) }) {\n                            request.toRequest()?.also {\n                                if (requestCallBack(it)) destroyWebView()\n                            }?.let(extraRequestList::add)\n                        }\n\n                        // Suppress image requests as we don't display them anywhere\n                        // Less data, low chance of causing issues.\n                        // blockNetworkImage also does this job but i will keep it for the future.\n                        val blacklistedFiles = listOf(\n                            \".jpg\",\n                            \".png\",\n                            \".webp\",\n                            \".mpg\",\n                            \".mpeg\",\n                            \".jpeg\",\n                            \".webm\",\n                            \".mp4\",\n                            \".mp3\",\n                            \".gifv\",\n                            \".flv\",\n                            \".asf\",\n                            \".mov\",\n                            \".mng\",\n                            \".mkv\",\n                            \".ogg\",\n                            \".avi\",\n                            \".wav\",\n                            \".woff2\",\n                            \".woff\",\n                            \".ttf\",\n                            \".css\",\n                            \".vtt\",\n                            \".srt\",\n                            \".ts\",\n                            \".gif\",\n                            // Warning, this might fuck some future sites, but it's used to make Sflix work.\n                            \"wss://\"\n                        )\n\n                        /** NOTE!  request.requestHeaders is not perfect!\n                         *  They don't contain all the headers the browser actually gives.\n                         *  Overriding with okhttp might fuck up otherwise working requests,\n                         *  e.g the recaptcha request.\n                         * */\n                        return@runBlocking try {\n                            when {\n                                blacklistedFiles.any { URI(webViewUrl).path.contains(it) } || webViewUrl.endsWith(\n                                    \"/favicon.ico\"\n                                ) -> WebResourceResponse(\n                                    \"image/png\",\n                                    null,\n                                    null\n                                )\n\n                                webViewUrl.contains(\"recaptcha\") || webViewUrl.contains(\"/cdn-cgi/\") -> super.shouldInterceptRequest(\n                                    view,\n                                    request\n                                )\n\n                                useOkhttp && request.method == \"GET\" -> app.get(\n                                    webViewUrl,\n                                    headers = request.requestHeaders\n                                ).okhttpResponse.toWebResourceResponse()\n\n                                useOkhttp && request.method == \"POST\" -> app.post(\n                                    webViewUrl,\n                                    headers = request.requestHeaders\n                                ).okhttpResponse.toWebResourceResponse()\n\n                                else -> super.shouldInterceptRequest(\n                                    view,\n                                    request\n                                )\n                            }\n                        } catch (_: Exception) {\n                            null\n                        }\n                    }\n\n                    @SuppressLint(\"WebViewClientOnReceivedSslError\")\n                    override fun onReceivedSslError(\n                        view: WebView?,\n                        handler: SslErrorHandler?,\n                        error: SslError?\n                    ) {\n                        handler?.proceed() // Ignore ssl issues\n                    }\n                }\n                webView?.loadUrl(url, headers.toMap())\n            } catch (e: Exception) {\n                logError(e)\n            }\n        }\n\n        var loop = 0\n        // Timeouts after this amount, 60s\n        val totalTime = timeout\n\n        val delayTime = 100L\n\n        // A bit sloppy, but couldn't find a better way\n        while (loop < totalTime / delayTime && !shouldExit) {\n            if (fixedRequest != null) return fixedRequest to extraRequestList\n            delay(delayTime)\n            loop += 1\n        }\n\n        Log.i(TAG, \"Web-view timeout after ${totalTime / 1000}s\")\n        destroyWebView()\n        return fixedRequest to extraRequestList\n    }\n}\n\nfun WebResourceRequest.toRequest(): Request? {\n    val webViewUrl = this.url.toString()\n\n    // If invalid url then it can crash with\n    // java.lang.IllegalArgumentException: Expected URL scheme 'http' or 'https' but was 'data'\n    // At Request.Builder().url(addParamsToUrl(url, params))\n    return safe {\n        requestCreator(\n            this.method,\n            webViewUrl,\n            this.requestHeaders,\n        )\n    }\n}\n\nfun Response.toWebResourceResponse(): WebResourceResponse {\n    val contentTypeValue = this.header(\"Content-Type\")\n    // 1. contentType. 2. charset\n    val typeRegex = Regex(\"\"\"(.*);(?:.*charset=(.*)(?:|;)|)\"\"\")\n    return if (contentTypeValue != null) {\n        val found = typeRegex.find(contentTypeValue)\n        val contentType = found?.groupValues?.getOrNull(1)?.ifBlank { null } ?: contentTypeValue\n        val charset = found?.groupValues?.getOrNull(2)?.ifBlank { null }\n        WebResourceResponse(contentType, charset, this.body.byteStream())\n    } else {\n        WebResourceResponse(\"application/octet-stream\", null, this.body.byteStream())\n    }\n}\n"
  },
  {
    "path": "library/src/androidMain/kotlin/com/lagradost/cloudstream3/utils/Coroutines.android.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport android.os.Handler\nimport android.os.Looper\n\nactual fun runOnMainThreadNative(work: () -> Unit) {\n    val mainHandler = Handler(Looper.getMainLooper())\n    mainHandler.post {\n        work()\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/api/ContextHelper.kt",
    "content": "package com.lagradost.api\n\nimport java.lang.ref.WeakReference\n\n/**\n * Set context for android specific code such as webview.\n * Does nothing on JVM.\n */\nexpect fun setContext(context: WeakReference<Any>)\n/**\n * Helper function for Android specific context.\n * Do not use this unless absolutely necessary.\n * setContext() must be called before this is called.\n * @return Context if on android, null if not.\n */\nexpect fun getContext(): Any?\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/api/Log.kt",
    "content": "package com.lagradost.api\n\nexpect object Log {\n    fun d(tag: String, message: String)\n    fun i(tag: String, message: String)\n    fun w(tag: String, message: String)\n    fun e(tag: String, message: String)\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt",
    "content": "@file:Suppress(\n    \"UNUSED\",\n    \"UnusedReceiverParameter\",\n    \"MemberVisibilityCanBePrivate\"\n)\n\npackage com.lagradost.cloudstream3\n\nimport com.fasterxml.jackson.annotation.JsonAutoDetect\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.fasterxml.jackson.databind.DeserializationFeature\nimport com.fasterxml.jackson.databind.json.JsonMapper\nimport com.fasterxml.jackson.module.kotlin.kotlinModule\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.syncproviders.SyncIdName\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.Coroutines.mainWork\nimport com.lagradost.cloudstream3.utils.Coroutines.threadSafeListOf\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromCodeToLangTagIETF\nimport com.lagradost.cloudstream3.utils.SubtitleHelper.fromLanguageToTagIETF\nimport com.lagradost.nicehttp.RequestBodyTypes\nimport okhttp3.Interceptor\nimport okhttp3.MediaType.Companion.toMediaTypeOrNull\nimport okhttp3.RequestBody.Companion.toRequestBody\nimport java.net.URI\nimport java.text.SimpleDateFormat\nimport java.util.*\nimport kotlin.io.encoding.Base64\nimport kotlin.io.encoding.ExperimentalEncodingApi\nimport kotlin.math.absoluteValue\nimport kotlin.math.roundToInt\n\n/**\n * API available only on prerelease builds.\n * Using it will cause stable to crash with `NoSuchMethodException`.\n */\n@MustBeDocumented // Same as java.lang.annotation.Documented\n@Retention(AnnotationRetention.BINARY) // This is only an IDE hint, and will not be used in the runtime\n@RequiresOptIn(\n    message = \"This API is only available on prerelease builds. \" +\n              \"Using it will cause CloudStream stable to crash.\",\n    level = RequiresOptIn.Level.ERROR\n)\nannotation class Prerelease\n\n@Retention(AnnotationRetention.BINARY) // This is only an IDE hint, and will not be used in the runtime\n@RequiresOptIn(\n    message = \"This API is marked as internal and should not be used by extensions. \" +\n              \"Using it could cause catastrophic build or runtime errors and may \" +\n              \"be changed or removed at any time.\",\n    level = RequiresOptIn.Level.ERROR\n)\nannotation class InternalAPI\n\n/**\n * Defines the constant for the all languages preference, if this is set then it is\n * the equivalent of all languages being set\n **/\nconst val AllLanguagesName = \"universal\"\n\nconst val USER_AGENT =\n    \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36\"\n\nclass ErrorLoadingException(message: String? = null) : Exception(message)\n\n//val baseHeader = mapOf(\"User-Agent\" to USER_AGENT)\nval mapper = JsonMapper.builder().addModule(kotlinModule())\n    .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build()!!\n\nobject APIHolder {\n    val unixTime: Long\n        get() = System.currentTimeMillis() / 1000L\n    val unixTimeMS: Long\n        get() = System.currentTimeMillis()\n\n    // ConcurrentModificationException is possible!!!\n    val allProviders = threadSafeListOf<MainAPI>()\n\n    fun initAll() {\n        synchronized(allProviders) {\n            for (api in allProviders) {\n                api.init()\n            }\n        }\n        apiMap = null\n    }\n\n    /** String extension function to Capitalize first char of string.*/\n    fun String.capitalize(): String {\n        return this.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }\n    }\n\n    var apis: List<MainAPI> = threadSafeListOf()\n    var apiMap: Map<String, Int>? = null\n\n    fun addPluginMapping(plugin: MainAPI) {\n        synchronized(apis) {\n            apis = apis + plugin\n        }\n        initMap(true)\n    }\n\n    fun removePluginMapping(plugin: MainAPI) {\n        synchronized(apis) {\n            apis = apis.filter { it != plugin }\n        }\n        initMap(true)\n    }\n\n    private fun initMap(forcedUpdate: Boolean = false) {\n        synchronized(apis) {\n            if (apiMap == null || forcedUpdate)\n                apiMap = apis.mapIndexed { index, api -> api.name to index }.toMap()\n        }\n    }\n\n    fun getApiFromNameNull(apiName: String?): MainAPI? {\n        if (apiName == null) return null\n        synchronized(allProviders) {\n            initMap()\n            synchronized(apis) {\n                return apiMap?.get(apiName)?.let { apis.getOrNull(it) }\n                // Leave the ?. null check, it can crash regardless\n                    ?: allProviders.firstOrNull { it.name == apiName }\n            }\n        }\n    }\n\n    fun getApiFromUrlNull(url: String?): MainAPI? {\n        if (url == null) return null\n        synchronized(allProviders) {\n            allProviders.forEach { api ->\n                if (url.startsWith(api.mainUrl)) return api\n            }\n        }\n        return null\n    }\n\n    /**\n     * Gets the website captcha token\n     * discovered originally by https://github.com/ahmedgamal17\n     * optimized by https://github.com/justfoolingaround\n     *\n     * @param url the main url, likely the same website you found the key from.\n     * @param key used to fill https://www.google.com/recaptcha/api.js?render=....\n     *\n     * @param referer the referer for the google.com/recaptcha/api.js... request, optional.\n     * */\n\n    // Try document.select(\"script[src*=https://www.google.com/recaptcha/api.js?render=]\").attr(\"src\").substringAfter(\"render=\")\n    // To get the key\n    suspend fun getCaptchaToken(url: String, key: String, referer: String? = null): String? {\n        try {\n            val uri = URI.create(url)\n            val domain = base64Encode(\n                (uri.scheme + \"://\" + uri.host + \":443\").encodeToByteArray(),\n            ).replace(\"\\n\", \"\").replace(\"=\", \".\")\n\n            val vToken =\n                app.get(\n                    \"https://www.google.com/recaptcha/api.js?render=$key\",\n                    referer = referer,\n                    cacheTime = 0\n                )\n                    .text\n                    .substringAfter(\"releases/\")\n                    .substringBefore(\"/\")\n            val recapToken =\n                app.get(\"https://www.google.com/recaptcha/api2/anchor?ar=1&hl=en&size=invisible&cb=cs3&k=$key&co=$domain&v=$vToken\")\n                    .document\n                    .selectFirst(\"#recaptcha-token\")?.attr(\"value\")\n            if (recapToken != null) {\n                return app.post(\n                    \"https://www.google.com/recaptcha/api2/reload?k=$key\",\n                    data = mapOf(\n                        \"v\" to vToken,\n                        \"k\" to key,\n                        \"c\" to recapToken,\n                        \"co\" to domain,\n                        \"sa\" to \"\",\n                        \"reason\" to \"q\"\n                    ), cacheTime = 0\n                ).text\n                    .substringAfter(\"rresp\\\",\\\"\")\n                    .substringBefore(\"\\\"\")\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n        return null\n    }\n\n    private var trackerCache: HashMap<String, AniSearch> = hashMapOf()\n\n    /** backwards compatibility, use getTracker4 instead */\n    suspend fun getTracker(\n        titles: List<String>,\n        types: Set<TrackerType>?,\n        year: Int?,\n    ): Tracker? = getTracker(titles, types, year, false)\n\n    /**\n     * Get anime tracker information based on title, year and type.\n     * Both titles are attempted to be matched with both Romaji and English title.\n     * Uses the anilist api.\n     *\n     * @param titles uses first index to search, but if you have multiple titles and want extra guarantee to match you can also have that\n     * @param types Optional parameter to narrow down the scope to Movies, TV, etc. See TrackerType.getTypes()\n     * @param year Optional parameter to only get anime with a specific year\n     **/\n    suspend fun getTracker(\n        titles: List<String>,\n        types: Set<TrackerType>?,\n        year: Int?,\n        lessAccurate: Boolean\n    ): Tracker? {\n        return try {\n            require(titles.isNotEmpty()) { \"titles must no be empty when calling getTracker\" }\n\n            val mainTitle = titles[0]\n            val search =\n                trackerCache[mainTitle]\n                    ?: searchAnilist(mainTitle)?.also {\n                        trackerCache[mainTitle] = it\n                    } ?: return null\n\n            val res = search.data?.page?.media?.find { media ->\n                val matchingYears = year == null || media.seasonYear == year\n                val matchingTitles = media.title?.let { title ->\n                    titles.any { userTitle ->\n                        title.isMatchingTitles(userTitle)\n                    }\n                } ?: false\n\n                val matchingTypes = types?.any { it.name.equals(media.format, true) } == true\n                if (lessAccurate) matchingTitles || matchingTypes && matchingYears else matchingTitles && matchingTypes && matchingYears\n            } ?: return null\n\n            Tracker(\n                res.idMal,\n                null,\n                res.id.toString(),\n                res.coverImage?.extraLarge ?: res.coverImage?.large,\n                res.bannerImage\n            )\n        } catch (t: Throwable) {\n            logError(t)\n            null\n        }\n    }\n\n    /** Searches Anilist using title.\n     * @param title Title string of the show\n     * @return [AniSearch] data class holds search info.\n     * */\n    private suspend fun searchAnilist(\n        title: String?,\n    ): AniSearch? {\n        val query = \"\"\"\n        query (\n          ${'$'}page: Int = 1\n          ${'$'}search: String\n          ${'$'}sort: [MediaSort] = [POPULARITY_DESC, SCORE_DESC]\n          ${'$'}type: MediaType\n        ) {\n          Page(page: ${'$'}page, perPage: 20) {\n            media(\n              search: ${'$'}search\n              sort: ${'$'}sort\n              type: ${'$'}type\n            ) {\n              id\n              idMal\n              title { romaji english }\n              coverImage { extraLarge large }\n              bannerImage\n              seasonYear\n              format\n            }\n          }\n        }\n    \"\"\".trimIndent().trim()\n\n        val data = mapOf(\n            \"query\" to query,\n            \"variables\" to mapOf(\n                \"search\" to title,\n                \"sort\" to \"SEARCH_MATCH\",\n                \"type\" to \"ANIME\",\n            )\n        ).toJson().toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull())\n\n        return app.post(\"https://graphql.anilist.co\", requestBody = data)\n            .parsedSafe()\n    }\n}\n\n/*\n// THIS IS WORK IN PROGRESS API\ninterface ITag {\n    val name: UiText\n}\n\ndata class SimpleTag(override val name: UiText, val data: String) : ITag\n\nenum class SelectType {\n    SingleSelect,\n    MultiSelect,\n    MultiSelectAndExclude,\n}\n\nenum class SelectValue {\n    Selected,\n    Excluded,\n}\n\ninterface GenreSelector {\n    val title: UiText\n    val id : Int\n}\n\ndata class TagSelector(\n    override val title: UiText,\n    override val id : Int,\n    val tags: Set<ITag>,\n    val defaultTags : Set<ITag> = setOf(),\n    val selectType: SelectType = SelectType.SingleSelect,\n) : GenreSelector\n\ndata class BoolSelector(\n    override val title: UiText,\n    override val id : Int,\n\n    val defaultValue : Boolean = false,\n) : GenreSelector\n\ndata class InputField(\n    override val title: UiText,\n    override val id : Int,\n\n    val hint : UiText? = null,\n) : GenreSelector\n\n// This response describes how a user might filter the homepage or search results\ndata class GenreResponse(\n    val searchSelectors : List<GenreSelector>,\n    val filterSelectors: List<GenreSelector> = searchSelectors\n) */\n\n/*\n0 = Site not good\n1 = All good\n2 = Slow, heavy traffic\n3 = restricted, must donate 30 benenes to use\n */\nconst val PROVIDER_STATUS_KEY = \"PROVIDER_STATUS_KEY\"\nconst val PROVIDER_STATUS_BETA_ONLY = 3\nconst val PROVIDER_STATUS_SLOW = 2\nconst val PROVIDER_STATUS_OK = 1\nconst val PROVIDER_STATUS_DOWN = 0\n\ndata class ProvidersInfoJson(\n    @JsonProperty(\"name\") var name: String,\n    @JsonProperty(\"url\") var url: String,\n    @JsonProperty(\"credentials\") var credentials: String? = null,\n    @JsonProperty(\"status\") var status: Int,\n)\n\ndata class SettingsJson(\n    @JsonProperty(\"enableAdult\") var enableAdult: Boolean = false,\n)\n\n\ndata class MainPageData(\n    val name: String,\n    val data: String,\n    val horizontalImages: Boolean = false\n)\n\ndata class MainPageRequest(\n    val name: String,\n    val data: String,\n    val horizontalImages: Boolean,\n    //TODO genre selection or smth\n)\n\n/** Create [MainPageData] from url, name Strings & layout (Horizontal/Vertical) Boolean.\n * @param url page Url string.\n * @param name page Name string.\n * @param horizontalImages Boolean to control item card layout.\n * */\nfun mainPage(url: String, name: String, horizontalImages: Boolean = false): MainPageData {\n    return MainPageData(name = name, data = url, horizontalImages = horizontalImages)\n}\n\n/** return list of MainPageData with url to name, make for more readable code\n * @param elements parameter of [MainPageData] class of data*/\nfun mainPageOf(vararg elements: MainPageData): List<MainPageData> {\n    return elements.toList()\n}\n\n/** return list of MainPageData with url to name, make for more readable code\n * @param elements parameter of <String, String> map of url and name */\nfun mainPageOf(vararg elements: Pair<String, String>): List<MainPageData> {\n    return elements.map { (url, name) -> MainPageData(name = name, data = url) }\n}\n\nfun newHomePageResponse(\n    name: String,\n    list: List<SearchResponse>,\n    hasNext: Boolean? = null,\n): HomePageResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    return HomePageResponse(\n        listOf(HomePageList(name, list)),\n        hasNext = hasNext ?: list.isNotEmpty()\n    )\n}\n\nfun newHomePageResponse(\n    data: MainPageRequest,\n    list: List<SearchResponse>,\n    hasNext: Boolean? = null,\n): HomePageResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    return HomePageResponse(\n        listOf(HomePageList(data.name, list, data.horizontalImages)),\n        hasNext = hasNext ?: list.isNotEmpty()\n    )\n}\n\nfun newHomePageResponse(list: HomePageList, hasNext: Boolean? = null): HomePageResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    return HomePageResponse(listOf(list), hasNext = hasNext ?: list.list.isNotEmpty())\n}\n\nfun newHomePageResponse(list: List<HomePageList>, hasNext: Boolean? = null): HomePageResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    return HomePageResponse(list, hasNext = hasNext ?: list.any { it.list.isNotEmpty() })\n}\n\nfun newSearchResponseList(\n    list: List<SearchResponse>,\n    hasNext: Boolean? = null,\n): SearchResponseList {\n    @Suppress(\"DEPRECATION_ERROR\")\n    return SearchResponseList(\n        list,\n        hasNext = hasNext ?: list.isNotEmpty()\n    )\n}\n\nfun List<SearchResponse>.toNewSearchResponseList(hasNext: Boolean? = null) : SearchResponseList {\n    return newSearchResponseList(this, hasNext)\n}\n\n/**Every provider will **not** have try catch built in, so handle exceptions when calling these functions*/\nabstract class MainAPI {\n    companion object {\n        var overrideData: HashMap<String, ProvidersInfoJson>? = null\n        var settingsForProvider: SettingsJson = SettingsJson()\n    }\n\n    fun init() {\n        overrideData?.get(this.javaClass.simpleName)?.let { data ->\n            overrideWithNewData(data)\n        }\n    }\n\n    fun overrideWithNewData(data: ProvidersInfoJson) {\n        if (!canBeOverridden) return\n        this.name = data.name\n        if (data.url.isNotBlank() && data.url != \"NONE\")\n            this.mainUrl = data.url\n        this.storedCredentials = data.credentials\n    }\n\n    /** Name of the plugin that will used in UI */\n    open var name = \"NONE\"\n\n    /** Main Url of the plugin that can be used directly in code or to be replaced using Clone site feature in settings */\n    open var mainUrl = \"NONE\"\n    open var storedCredentials: String? = null\n    open var canBeOverridden: Boolean = true\n\n    /** if this is turned on then it will request the homepage one after the other,\n    used to delay if they block many request at the same time*/\n    open var sequentialMainPage: Boolean = false\n\n    /** in milliseconds, this can be used to add more delay between homepage requests\n     *  on first load if sequentialMainPage is turned on */\n    open var sequentialMainPageDelay: Long = 0L\n\n    /** in milliseconds, this can be used to add more delay between homepage requests when scrolling */\n    open var sequentialMainPageScrollDelay: Long = 0L\n\n    /** used to keep track when last homepage request was in unixtime ms */\n    var lastHomepageRequest: Long = 0L\n\n    /**\n     * The language as an IETF BCP 47 conformant tag.\n     * Check [com.lagradost.cloudstream3.utils.SubtitleHelper].\n     *\n     * See locales on:\n     * https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/availableLocales.json\n     * https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry\n     * https://android.googlesource.com/platform/frameworks/base/+/android-16.0.0_r2/core/res/res/values/locale_config.xml\n     * https://iso639-3.sil.org/code_tables/639/data/all\n    */\n    open var lang = \"en\"\n\n    /**If link is stored in the \"data\" string, so links can be instantly loaded*/\n    open val instantLinkLoading = false\n\n    /**Set false if links require referer or for some reason cant be played on a chromecast*/\n    open val hasChromecastSupport = true\n\n    /**If all links are encrypted then set this to false*/\n    open val hasDownloadSupport = true\n\n    /**Used for testing and can be used to disable the providers if WebView is not available*/\n    open val usesWebView = false\n\n    /** Determines which plugin a given provider is from. This is the full path to the plugin. */\n    var sourcePlugin: String? = null\n\n    open val hasMainPage = false\n    open val hasQuickSearch = false\n\n    /**\n     * The timeout on the `loadLinks` functions in milliseconds,\n     * By default this should be around a few minutes to prevent any unexpected recursive call/extraction to drain resources,\n     * however if you need very long extraction times, you can can request it by changing this variable.\n     *\n     * Note that this is only a hint, and may not get respected if you request something too long.\n     * */\n    open val loadLinksTimeoutMs: Long? = null\n\n    /**\n     * The timeout on the `getMainPage` functions in milliseconds.\n     *\n     * Note that this is only a hint, and may not get respected if you request something too long.\n     * */\n    open val getMainPageTimeoutMs: Long? = null\n\n    /**\n     * The timeout on the `search` functions in milliseconds.\n     *\n     * Note that this is only a hint, and may not get respected if you request something too long.\n     * */\n    open val searchTimeoutMs: Long? = null\n\n    /**\n     * The timeout on the `quickSearch` functions in milliseconds.\n     *\n     * Note that this is only a hint, and may not get respected if you request something too long.\n     * */\n    open val quickSearchTimeoutMs: Long? = null\n\n    /**\n     * The timeout on the `loadSearch` functions in milliseconds.\n     *\n     * Note that this is only a hint, and may not get respected if you request something too long.\n     * */\n    open val loadTimeoutMs: Long? = null\n\n\n    /**\n     * A set of which ids the provider can open with getLoadUrl()\n     * If the set contains SyncIdName.Imdb then getLoadUrl() can be started with\n     * an Imdb class which inherits from SyncId.\n     *\n     * getLoadUrl() is then used to get page url based on that ID.\n     *\n     * Example:\n     * \"tt6723592\" -> getLoadUrl(ImdbSyncId(\"tt6723592\")) -> \"mainUrl/imdb/tt6723592\" -> load(\"mainUrl/imdb/tt6723592\")\n     *\n     * This is used to launch pages from personal lists or recommendations using IDs.\n     **/\n    open val supportedSyncNames = setOf<SyncIdName>()\n\n    open val supportedTypes = setOf(\n        TvType.Movie,\n        TvType.TvSeries,\n        TvType.Cartoon,\n        TvType.Anime,\n        TvType.OVA,\n    )\n\n    open val vpnStatus = VPNStatus.None\n    open val providerType = ProviderType.DirectProvider\n\n    //emptyList<MainPageData>() //\n    open val mainPage = listOf(MainPageData(\"\", \"\", false))\n\n    // @WorkerThread\n    open suspend fun getMainPage(\n        page: Int,\n        request: MainPageRequest,\n    ): HomePageResponse? {\n        throw NotImplementedError()\n    }\n\n    /** Paginated search, starts with page: 1 */\n    open suspend fun search(query: String, page: Int): SearchResponseList? {\n        val searchResults = search(query) ?: return null\n\n        return newSearchResponseList(\n            searchResults,\n            false\n        )\n    }\n\n    // @WorkerThread\n    open suspend fun search(query: String): List<SearchResponse>? {\n        throw NotImplementedError()\n    }\n\n    // @WorkerThread\n    open suspend fun quickSearch(query: String): List<SearchResponse>? {\n        throw NotImplementedError()\n    }\n\n    // @WorkerThread\n    /**\n     * Based on data from search() or getMainPage() it generates a LoadResponse,\n     * basically opening the info page from a link.\n     * */\n    open suspend fun load(url: String): LoadResponse? {\n        throw NotImplementedError()\n    }\n\n    /**\n     * Largely redundant feature for most providers.\n     *\n     * This job runs in the background when a link is playing in exoplayer.\n     * First implemented to do polling for sflix to keep the link from getting expired.\n     *\n     * This function might be updated to include exoplayer timestamps etc in the future\n     * if the need arises.\n     * */\n    // @WorkerThread\n    open suspend fun extractorVerifierJob(extractorData: String?) {\n        throw NotImplementedError()\n    }\n\n    /**Callback is fired once a link is found, will return true if method is executed successfully\n     * @param data dataUrl string returned from [load] function.\n     * @see newMovieLoadResponse\n     * @see newTvSeriesLoadResponse\n     * @see newLiveStreamLoadResponse\n     * @see newAnimeLoadResponse\n     * @see newTorrentLoadResponse\n     * */\n    // @WorkerThread\n    open suspend fun loadLinks(\n        data: String,\n        isCasting: Boolean,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ): Boolean {\n        throw NotImplementedError()\n    }\n\n    /** An okhttp interceptor for used in OkHttpDataSource */\n    open fun getVideoInterceptor(extractorLink: ExtractorLink): Interceptor? {\n        return null\n    }\n\n    /**\n     * Get the load() url based on a sync ID like IMDb or MAL.\n     * Only contains SyncIds based on supportedSyncUrls.\n     **/\n    open suspend fun getLoadUrl(name: SyncIdName, id: String): String? {\n        return null\n    }\n}\n\n/** Might need a different implementation for desktop*/\nfun base64Decode(string: String): String {\n    return String(base64DecodeArray(string), Charsets.ISO_8859_1)\n}\n\n@OptIn(ExperimentalEncodingApi::class)\nfun base64DecodeArray(string: String): ByteArray {\n    return Base64.decode(string)\n}\n\n@OptIn(ExperimentalEncodingApi::class)\nfun base64Encode(array: ByteArray): String {\n    return Base64.encode(array)\n}\n\nfun MainAPI.fixUrlNull(url: String?): String? {\n    if (url.isNullOrEmpty()) {\n        return null\n    }\n    return fixUrl(url)\n}\n\nfun MainAPI.fixUrl(url: String): String {\n    if (url.startsWith(\"http\") ||\n        // Do not fix JSON objects and arrays when passed as urls.\n        url.startsWith(\"{\\\"\") || url.startsWith(\"[\")\n    ) {\n        return url\n    }\n    if (url.isEmpty()) {\n        return \"\"\n    }\n\n    val startsWithNoHttp = url.startsWith(\"//\")\n    if (startsWithNoHttp) {\n        return \"https:$url\"\n    } else {\n        if (url.startsWith('/')) {\n            return mainUrl + url\n        }\n        return \"$mainUrl/$url\"\n    }\n}\n\n/** Sort the urls based on quality\n * @param urls Set of [ExtractorLink]\n * */\nfun sortUrls(urls: Set<ExtractorLink>): List<ExtractorLink> {\n    return urls.sortedBy { t -> -t.quality }\n}\n\n/** Capitalize the first letter of string.\n * @param str String to be capitalized\n * @return non-nullable String\n * @see capitalizeStringNullable\n * */\nfun capitalizeString(str: String): String {\n    return capitalizeStringNullable(str) ?: str\n}\n\n/** Capitalize the first letter of string.\n * @param str String to be capitalized\n * @return nullable String\n * @see capitalizeString\n * */\nfun capitalizeStringNullable(str: String?): String? {\n    if (str == null)\n        return null\n    return try {\n        str.replaceFirstChar(Char::titlecase)\n    } catch (e: Exception) {\n        str\n    }\n}\n\nfun fixTitle(str: String): String {\n    return str.split(\" \").joinToString(\" \") {\n        it.lowercase()\n            .replaceFirstChar(Char::titlecase)\n    }\n}\n\n/**\n * Get rhino context in a safe way as it needs to be initialized on the main thread.\n *\n * Make sure you get the scope using: val scope: Scriptable = rhino.initSafeStandardObjects()\n *\n * Use like the following: rhino.evaluateString(scope, js, \"JavaScript\", 1, null)\n **/\nsuspend fun getRhinoContext(): org.mozilla.javascript.Context {\n    return Coroutines.mainWork {\n        val rhino = org.mozilla.javascript.Context.enter()\n        rhino.initSafeStandardObjects()\n        rhino.setInterpretedMode(true)\n        rhino\n    }\n}\n\n/** https://www.imdb.com/title/tt2861424/ -> tt2861424\n * @param url Imdb Url you need to get the Id from.\n * @return imdb id formatted string\n * @see imdbUrlToIdNullable\n * */\nfun imdbUrlToId(url: String): String? {\n    return Regex(\"/title/(tt[0-9]*)\").find(url)?.groupValues?.get(1)\n        ?: Regex(\"tt[0-9]{5,}\").find(url)?.groupValues?.get(0)\n}\n\n/** https://www.imdb.com/title/tt2861424/ -> tt2861424\n * @param url Imdb Url you need to get the Id from.\n * @return imdb id formatted nullable string\n * @see imdbUrlToId\n * */\nfun imdbUrlToIdNullable(url: String?): String? {\n    if (url == null) return null\n    return imdbUrlToId(url)\n}\n\n/** enum class determines provider type:\n *\n * MetaProvider: When data is fetched from a 3rd party site like imdb\n *\n * DirectProvider: When all data is from the site\n * */\nenum class ProviderType {\n    MetaProvider,\n    DirectProvider,\n}\n\n/** enum class determines VPN status (Non, MightBeNeeded or Torrent) */\nenum class VPNStatus {\n    None,\n    MightBeNeeded,\n    Torrent,\n}\n\n/** enum class determines Show status (Completed or Ongoing) */\nenum class ShowStatus {\n    Completed,\n    Ongoing,\n}\n\nenum class DubStatus(val id: Int) {\n    None(-1),\n    Dubbed(1),\n    Subbed(0),\n}\n\n/** This is the primary way to store score/rating. Use Score.from or Score.from10 to parse the score\n * as it does not have a public constructor. Use toInt/toFloat to get back the score.\n *\n * Internally it stores it as an int up to 10^9 to represent up to 10 significant digits. So think\n * of this as a decimal class specifically for ratings.\n * */\n@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)\nclass Score private constructor(\n    /** Decimal between [0, 10^9] representing the min score and max score respectively */\n    @JsonProperty(\"data\")\n    private val data: Int,\n) {\n    override fun hashCode(): Int = this.data.hashCode()\n    override fun equals(other: Any?): Boolean = other is Score && this.data == other.data\n\n    @Deprecated(\n        \"toOld() is deprecated. Use other Score methods instead.\",\n        level = DeprecationLevel.ERROR\n    )\n    fun toOld(): Int = toInt(10000)\n\n    fun toByte(maxScore: Int): Byte = toLong(maxScore).toByte()\n\n    fun toInt(maxScore: Int = 10): Int = toLong(maxScore).toInt()\n\n    fun toLong(maxScore: Int = 10): Long = (data.toLong() * maxScore.toLong()) / MAX.toLong()\n\n    fun toFloat(maxScore: Int = 10): Float =\n        (data.toFloat() / MAX.toFloat()) * maxScore.toFloat()\n\n    fun toDouble(maxScore: Int = 10): Double =\n        (data.toDouble() / MAX.toDouble()) * maxScore.toDouble()\n\n    override fun toString(): String = this.toString(10)\n\n    /** Formats the rating to a human readable format (with no rounding)\n     *\n     * However it may also return null if the score is less than the minimum score,\n     * this is to avoid 0.0/10.0 in case of default = 0\n     * */\n    @Throws(IllegalArgumentException::class)\n    fun toStringNull(\n        minScore: Double,\n        maxScore: Int,\n        decimals: Int = 1,\n        removeTrailingZeros: Boolean = true,\n        decimalChar: Char = '.'\n    ): String? {\n        if (toDouble() < minScore) return null\n        return toString(maxScore, decimals, removeTrailingZeros, decimalChar)\n    }\n\n    /** Formats the rating to a human readable format (with no rounding) */\n    @Throws(IllegalArgumentException::class)\n    fun toString(\n        maxScore: Int,\n        decimals: Int = 1,\n        removeTrailingZeros: Boolean = true,\n        decimalChar: Char = '.'\n    ): String {\n        require(maxScore in 1..1000) {\n            \"maxScore ∈ [1,1000]\"\n        }\n        require(decimals in 0..MAX_ZEROS) {\n            \"decimals ∈ [0,$MAX_ZEROS]\"\n        }\n        var number = data.toLong() * maxScore.toLong()\n        val chars = CharArray(MAX_ZEROS + 6)\n\n        for (i in chars.indices) {\n            chars[i] = (number % 10L).toInt().digitToChar()\n            number /= 10L\n        }\n\n        var trailingZeros = MAX_ZEROS - decimals\n        for (i in (MAX_ZEROS - decimals) until chars.size) {\n            if (chars[i] != '0') {\n                break\n            }\n            trailingZeros += 1\n        }\n\n        var leadingZeros = 0\n        for (i in chars.indices.reversed()) {\n            if (chars[i] != '0') {\n                break\n            }\n            leadingZeros += 1\n        }\n\n        val stringBuilder = StringBuilder()\n        for (i in maxOf(MAX_ZEROS, (chars.size - leadingZeros - 1)) downTo MAX_ZEROS) {\n            stringBuilder.append(chars[i])\n        }\n\n        val end = if (removeTrailingZeros) {\n            maxOf(MAX_ZEROS - decimals, trailingZeros)\n        } else {\n            MAX_ZEROS - decimals\n        }\n\n        if (end <= MAX_ZEROS - 1) {\n            stringBuilder.append(decimalChar)\n            for (i in MAX_ZEROS - 1 downTo end) {\n                stringBuilder.append(chars[i])\n            }\n        }\n\n        return stringBuilder.toString()\n    }\n\n    companion object {\n        const val MAX: Int = 1000_000_000\n        const val MIN: Int = 0\n        const val MAX_ZEROS: Int = 9\n        private const val TAG: String = \"Score\"\n\n        @Deprecated(\n            \"Score.fromOld is deprecated. Use other Score.from* methods instead.\",\n            level = DeprecationLevel.ERROR\n        )\n        fun fromOld(value: Int?): Score? {\n            if (value == null) return null\n            if (value < 0 || value > 10000) {\n                com.lagradost.api.Log.w(TAG, \"old: $value ∉ [0, 10000]\")\n                return null\n            }\n            return Score(value * 100_000)\n        }\n\n        /** `value ∈ [0, maxScore]` */\n        fun from(value: Int?, maxScore: Int): Score? {\n            if (value == null) {\n                return null\n            }\n            if (value < 0 || value > maxScore) {\n                com.lagradost.api.Log.w(TAG, \"fromInt: $value ∉ [0, $maxScore]\")\n                return null\n            }\n            return Score((MAX / maxScore) * value)\n        }\n\n        /** `value ∈ [0.0, maxScore]` */\n        fun from(value: Double?, maxScore: Int): Score? {\n            if (value == null) {\n                return null\n            }\n            if (value < 0.0 || value > maxScore) {\n                com.lagradost.api.Log.w(TAG, \"fromDouble: $value ∉ [0.0, $maxScore]\")\n                return null\n            }\n            return Score(((MAX / maxScore).toDouble() * value).roundToInt())\n        }\n\n        /** `value ∈ [0.0f, maxScore]` */\n        fun from(value: Float?, maxScore: Int): Score? {\n            if (value == null) {\n                return null\n            }\n            if (value < 0.0 || value > maxScore) {\n                com.lagradost.api.Log.w(TAG, \"fromFloat: $value ∉ [0.0f, $maxScore]\")\n                return null\n            }\n            return Score(((MAX / maxScore).toFloat() * value).roundToInt())\n        }\n\n        /** `value ∈ [\"0.0\", maxScore]` */\n        fun from(value: String?, maxScore: Int): Score? =\n            from(value?.trim()?.toDoubleOrNull()?.absoluteValue, maxScore)\n\n        /** `value ∈ [0, 5]` */\n        fun from5(value: Int?): Score? = from(value, 5)\n\n        /** `value ∈ [0, 10]` */\n        fun from10(value: Int?): Score? = from(value, 10)\n\n        /** `value ∈ [0, 100]` */\n        fun from100(value: Int?): Score? = from(value, 100)\n\n        /** `value ∈ [0.0, 5.0]` */\n        fun from5(value: Double?): Score? = from(value, 5)\n\n        /** `value ∈ [0.0, 10.0]` */\n        fun from10(value: Double?): Score? = from(value, 10)\n\n        /** `value ∈ [0.0, 100.0]` */\n        fun from100(value: Double?): Score? = from(value, 100)\n\n        /** `value ∈ [0.0f, 5.0f]` */\n        fun from5(value: Float?): Score? = from(value, 5)\n\n        /** `value ∈ [0.0f, 10.0f]` */\n        fun from10(value: Float?): Score? = from(value, 10)\n\n        /** `value ∈ [0.0f, 100.0f]` */\n        fun from100(value: Float?): Score? = from(value, 100)\n\n        /** `value ∈ [\"0.0\", \"5.0\"]` */\n        fun from5(value: String?): Score? = from(value, 5)\n\n        /** `value ∈ [\"0.0\", \"10.0\"]` */\n        fun from10(value: String?): Score? = from(value, 10)\n\n        /** `value ∈ [\"0.0\", \"100.0\"]` */\n        fun from100(value: String?): Score? = from(value, 100)\n    }\n}\n\n@Suppress(\"UNUSED_PARAMETER\")\nenum class TvType(value: Int?) {\n    Movie(1),\n    AnimeMovie(2),\n    TvSeries(3),\n    Cartoon(4),\n    Anime(5),\n    OVA(6),\n    Torrent(7),\n    Documentary(8),\n    AsianDrama(9),\n    Live(10),\n    NSFW(11),\n    Others(12),\n    Music(13),\n    AudioBook(14),\n\n    /** Won't load the built in player, make your own interaction */\n    CustomMedia(15),\n\n    Audio(16),\n    Podcast(17),\n}\n\nenum class AutoDownloadMode(val value: Int) {\n    Disable(0),\n    FilterByLang(1),\n    All(2),\n    NsfwOnly(3);\n\n    companion object {\n        infix fun getEnum(value: Int): AutoDownloadMode? =\n            entries.firstOrNull { it.value == value }\n    }\n}\n\n/** Extension function of [TvType] to check if the type is Movie.\n * @return If the type is AnimeMovie, Live, Movie, Torrent returns true otherwise returns false.\n * */\nfun TvType.isMovieType(): Boolean {\n    return when (this) {\n        TvType.AnimeMovie,\n        TvType.Live,\n        TvType.Movie,\n        TvType.Torrent -> true\n\n        else -> false\n    }\n}\n\n/** Extension function of [TvType] to check if the type is Audio.\n * @return If the type is Audio, AudioBook, Music, PodCast returns true otherwise returns false.\n * */\nfun TvType.isAudioType(): Boolean {\n    return when (this) {\n        TvType.Audio,\n        TvType.AudioBook,\n        TvType.Music,\n        TvType.Podcast -> true\n\n        else -> false\n    }\n}\n\n/** Extension function of [TvType] to check if the type is Live stream.\n * @return If the type is Live returns true, otherwise returns false.\n * */\nfun TvType.isLiveStream(): Boolean {\n    return this == TvType.Live\n}\n\n/** Extension function of [TvType] to check if the type has an Anime opening.\n * @return If the type is Anime or OVA returns true otherwise returns false.\n * */\nfun TvType.isAnimeOp(): Boolean {\n    return this == TvType.Anime || this == TvType.OVA\n}\n\n/** Data class for the Subtitle file info.\n * @property lang Subtitle file language.\n * @property url Subtitle file url to download/load the file.\n * @see newSubtitleFile\n * */\n@ConsistentCopyVisibility\ndata class SubtitleFile private constructor(\n    var lang: String,\n    var url: String,\n    var headers: Map<String, String>?\n) {\n    @Deprecated(\"Use newSubtitleFile method\", level = DeprecationLevel.WARNING)\n    constructor(lang: String, url: String) : this(lang = lang, url = url, headers = null)\n\n    /** Language code to properly filter auto select / download subtitles */\n    val langTag: String?\n        get() = fromCodeToLangTagIETF(lang) ?: fromLanguageToTagIETF(lang, true)\n\n    /** Backwards compatible copy */\n    fun copy(\n        lang: String = this.lang, url: String = this.url\n    ): SubtitleFile = SubtitleFile(lang = lang, url = url, headers = this.headers)\n}\n\n// No `MainAPI.` to be able to use this in extractors\nsuspend fun newSubtitleFile(\n    lang: String,\n    url: String,\n    initializer: suspend SubtitleFile.() -> Unit = { }\n): SubtitleFile {\n    @Suppress(\"DEPRECATION\")\n    val builder = SubtitleFile(\n        lang, url\n    )\n    builder.initializer()\n\n    return builder\n}\n\n/** Data class for the Audio file/track info.\n * @property lang Audio track language.\n * @property url Audio file url to download/load the file.\n * @property label Optional label to display (e.g., \"English 5.1\", \"Japanese Stereo\").\n * @property headers Optional headers for the audio file request.\n * @see newAudioFile\n * */\n@Prerelease\n@ConsistentCopyVisibility\ndata class AudioFile internal constructor(\n    var url: String,\n    var headers: Map<String, String>? = null\n)\n\n/** Creates an AudioFile with optional initializer for setting additional properties.\n * @param url Audio file url.\n * @param initializer Lambda to configure additional properties like headers.\n * @return Configured AudioFile instance.\n * */\n@Prerelease\nsuspend fun newAudioFile(\n    url: String,\n    initializer: suspend AudioFile.() -> Unit = { }\n): AudioFile {\n    val builder = AudioFile(url)\n    builder.initializer()\n    return builder\n}\n\n/** Data class for the Homepage response info.\n * @property items List of [HomePageList] items.\n * @property hasNext if there is a next page or not.\n * */\ndata class HomePageResponse\n@Deprecated(\"Use newHomePageResponse method\", level = DeprecationLevel.ERROR)\nconstructor(\n    val items: List<HomePageList>,\n    val hasNext: Boolean = false\n)\n\n/** Data class for the Homepage list info.\n * @property name name of the category shows on homepage UI.\n * @property list list of [SearchResponse] items that will be added to the category.\n * @property isHorizontalImages here you can control how the items' cards will be appeared on the UI (Horizontal or Vertical) cards.\n * */\ndata class HomePageList(\n    val name: String,\n    var list: List<SearchResponse>,\n    val isHorizontalImages: Boolean = false\n)\n\n/** Data class for the Search results.\n * @property items list of [SearchResponse] items that will be added to the search row.\n * @property hasNext if there is a next page or not.\n * */\ndata class SearchResponseList\n@Deprecated(\"Use newSearchResponseList method\", level = DeprecationLevel.ERROR)\nconstructor(\n    val items: List<SearchResponse>,\n    val hasNext: Boolean = false\n)\n\n/** enum class holds search quality.\n *\n * [Movie release types](https://en.wikipedia.org/wiki/Pirated_movie_release_types)**/\n@Suppress(\"UNUSED_PARAMETER\")\nenum class SearchQuality(value: Int?) {\n    Cam(1),\n    CamRip(2),\n    HdCam(3),\n    Telesync(4), // TS\n    WorkPrint(5),\n    Telecine(6), // TC\n    HQ(7),\n    HD(8),\n    HDR(9), // high dynamic range\n    BlueRay(10),\n    DVD(11),\n    SD(12),\n    FourK(13),\n    UHD(14),\n    SDR(15), // standard dynamic range\n    WebRip(16)\n}\n\n/** Returns [SearchQuality] from String.\n * @param string String text that will be converted into [SearchQuality].\n * */\nfun getQualityFromString(string: String?): SearchQuality? {\n    //Add anything to here if you find a site that uses some specific naming convention\n    val check = (string ?: return null).trim().lowercase().replace(\" \", \"\")\n\n    return when (check) {\n        \"cam\" -> SearchQuality.Cam\n        \"camrip\" -> SearchQuality.CamRip\n        \"hdcam\" -> SearchQuality.HdCam\n        \"hdtc\" -> SearchQuality.HdCam\n        \"hdts\" -> SearchQuality.HdCam\n        \"highquality\" -> SearchQuality.HQ\n        \"hq\" -> SearchQuality.HQ\n        \"highdefinition\" -> SearchQuality.HD\n        \"hdrip\" -> SearchQuality.HD\n        \"hd\" -> SearchQuality.HD\n        \"hdtv\" -> SearchQuality.HD\n        \"rip\" -> SearchQuality.CamRip\n        \"telecine\" -> SearchQuality.Telecine\n        \"tc\" -> SearchQuality.Telecine\n        \"telesync\" -> SearchQuality.Telesync\n        \"ts\" -> SearchQuality.Telesync\n        \"dvd\" -> SearchQuality.DVD\n        \"dvdrip\" -> SearchQuality.DVD\n        \"dvdscr\" -> SearchQuality.DVD\n        \"blueray\" -> SearchQuality.BlueRay\n        \"bluray\" -> SearchQuality.BlueRay\n        \"blu\" -> SearchQuality.BlueRay\n        \"fhd\" -> SearchQuality.HD\n        \"br\" -> SearchQuality.BlueRay\n        \"standard\" -> SearchQuality.SD\n        \"sd\" -> SearchQuality.SD\n        \"4k\" -> SearchQuality.FourK\n        \"uhd\" -> SearchQuality.UHD // may also be 4k or 8k\n        \"blue\" -> SearchQuality.BlueRay\n        \"wp\" -> SearchQuality.WorkPrint\n        \"workprint\" -> SearchQuality.WorkPrint\n        \"webrip\" -> SearchQuality.WebRip\n        \"webdl\" -> SearchQuality.WebRip\n        \"web\" -> SearchQuality.WebRip\n        \"hdr\" -> SearchQuality.HDR\n        \"sdr\" -> SearchQuality.SDR\n        else -> null\n    }\n}\n\n\n/**\n * For APIs using the mainUrl in the prefix for `MainAPI::load`,\n * this function replaces the `scheme`, `host` and `port` from an old link to the new mainUrl.\n *\n * https://en.wikipedia.org/wiki/Uniform_Resource_Identifier\n * ```text\n *           userinfo       host      port\n *           ┌──┴───┐ ┌──────┴──────┐ ┌┴─┐\n *   https://john.doe@www.example.com:1234/forum/questions/?tag=networking&order=newest#:~:text=whatever\n *   └─┬─┘   └─────────────┬─────────────┘└───────┬───────┘ └────────────┬────────────┘ └───────┬───────┘\n *   scheme            authority                path                   query                 fragment\n * ```\n */\nfun MainAPI.updateUrl(url: String): String {\n    try {\n        val original = URI(url)\n        val updated = URI(mainUrl)\n\n        // URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment)\n        return URI(\n            updated.scheme,\n            original.userInfo,\n            updated.host,\n            updated.port,\n            original.path,\n            original.query,\n            original.fragment\n        ).toString()\n    } catch (t: Throwable) {\n        logError(t)\n        return url\n    }\n}\n\n/** Abstract interface of SearchResponse. */\ninterface SearchResponse {\n    val name: String\n    val url: String\n    val apiName: String\n    var type: TvType?\n    var posterUrl: String?\n    var posterHeaders: Map<String, String>?\n    var id: Int?\n    var quality: SearchQuality?\n    var score: Score?\n}\n\nfun MainAPI.newTorrentSearchResponse(\n    name: String,\n    url: String,\n    type: TvType = TvType.Torrent,\n    fix: Boolean = true,\n    initializer: TorrentSearchResponse.() -> Unit = { },\n): TorrentSearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = TorrentSearchResponse(\n        name = name,\n        url = if (fix) fixUrl(url) else url,\n        apiName = this.name,\n        type = type,\n        // The initializer will handle this\n        posterUrl = null\n    )\n    builder.initializer()\n    return builder\n}\n\nfun MainAPI.newMovieSearchResponse(\n    name: String,\n    url: String,\n    type: TvType = TvType.Movie,\n    fix: Boolean = true,\n    initializer: MovieSearchResponse.() -> Unit = { },\n): MovieSearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = MovieSearchResponse(name, if (fix) fixUrl(url) else url, this.name, type)\n    builder.initializer()\n\n    return builder\n}\n\nfun MainAPI.newLiveSearchResponse(\n    name: String,\n    url: String,\n    type: TvType = TvType.Live,\n    fix: Boolean = true,\n    initializer: LiveSearchResponse.() -> Unit = { },\n): LiveSearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = LiveSearchResponse(\n        name = name,\n        url = if (fix) fixUrl(url) else url,\n        apiName = this.name,\n        type = type\n    )\n    builder.initializer()\n    return builder\n}\n\nfun MainAPI.newTvSeriesSearchResponse(\n    name: String,\n    url: String,\n    type: TvType = TvType.TvSeries,\n    fix: Boolean = true,\n    initializer: TvSeriesSearchResponse.() -> Unit = { },\n): TvSeriesSearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = TvSeriesSearchResponse(name, if (fix) fixUrl(url) else url, this.name, type)\n    builder.initializer()\n\n    return builder\n}\n\nfun MainAPI.newAnimeSearchResponse(\n    name: String,\n    url: String,\n    type: TvType = TvType.Anime,\n    fix: Boolean = true,\n    initializer: AnimeSearchResponse.() -> Unit = { },\n): AnimeSearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = AnimeSearchResponse(name, if (fix) fixUrl(url) else url, this.name, type)\n    builder.initializer()\n\n    return builder\n}\n\n/** Extension function that adds quality to [SearchResponse]\n * @param quality as string\n * */\nfun SearchResponse.addQuality(quality: String) {\n    this.quality = getQualityFromString(quality)\n}\n\n/** Extension function that adds poster to [SearchResponse]\n * @param url nullable string for poster url\n * @param headers Optional <String, String> map of request headers\n * */\nfun SearchResponse.addPoster(url: String?, headers: Map<String, String>? = null) {\n    this.posterUrl = url\n    this.posterHeaders = headers\n}\n\n/** Extension function that adds poster to [LoadResponse]\n * @param url nullable string for poster url\n * @param headers Optional <String, String> map of request headers\n * */\nfun LoadResponse.addPoster(url: String?, headers: Map<String, String>? = null) {\n    this.posterUrl = url\n    this.posterHeaders = headers\n}\n\n/** enum class of Actor roles (Main, Supporting, Background).*/\nenum class ActorRole {\n    Main,\n    Supporting,\n    Background,\n}\n\n/** Data class hold Actor personal information\n * @property name Actor name.\n * @property image Url nullable String to Actor image (Optional).\n * */\ndata class Actor(\n    val name: String,\n    val image: String? = null,\n)\n\n/** Data class hold Actor information\n * @property actor [Actor] personal info, name & image.\n * @property role [ActorRole] (Optional).\n * @property roleString Actor role as a string (Optional).\n * @property voiceActor Voice [Actor] personal info, can be used in case of Animation for voice actors. (Optional).\n * */\ndata class ActorData(\n    val actor: Actor,\n    val role: ActorRole? = null,\n    val roleString: String? = null,\n    val voiceActor: Actor? = null,\n)\n\n/** Data class of [SearchResponse] interface for Anime.\n * @see newAnimeSearchResponse\n * */\ndata class AnimeSearchResponse\n@Deprecated(\"Use newAnimeSearchResponse\", level = DeprecationLevel.ERROR)\nconstructor(\n    override val name: String,\n    override val url: String,\n    override val apiName: String,\n    override var type: TvType? = null,\n\n    override var posterUrl: String? = null,\n    var year: Int? = null,\n    var dubStatus: EnumSet<DubStatus>? = null,\n\n    var otherName: String? = null,\n    var episodes: MutableMap<DubStatus, Int> = mutableMapOf(),\n\n    override var id: Int? = null,\n    override var quality: SearchQuality? = null,\n    override var posterHeaders: Map<String, String>? = null,\n    override var score: Score? = null,\n) : SearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    @Deprecated(\n        \"Use newAnimeSearchResponse\",\n        level = DeprecationLevel.ERROR\n    )\n    constructor(\n        name: String,\n        url: String,\n        apiName: String,\n        type: TvType? = null,\n\n        posterUrl: String? = null,\n        year: Int? = null,\n        dubStatus: EnumSet<DubStatus>? = null,\n\n        otherName: String? = null,\n        episodes: MutableMap<DubStatus, Int> = mutableMapOf(),\n\n        id: Int? = null,\n        quality: SearchQuality? = null,\n        posterHeaders: Map<String, String>? = null,\n    ) : this(\n        name,\n        url,\n        apiName,\n        type,\n        posterUrl,\n        year,\n        dubStatus,\n        otherName,\n        episodes,\n        id,\n        quality,\n        posterHeaders, null\n    )\n}\n\nfun AnimeSearchResponse.addDubStatus(status: DubStatus, episodes: Int? = null) {\n    this.dubStatus = dubStatus?.also { it.add(status) } ?: EnumSet.of(status)\n    if (this.type?.isMovieType() != true)\n        if (episodes != null && episodes > 0)\n            this.episodes[status] = episodes\n}\n\nfun AnimeSearchResponse.addDubStatus(isDub: Boolean, episodes: Int? = null) {\n    addDubStatus(if (isDub) DubStatus.Dubbed else DubStatus.Subbed, episodes)\n}\n\nfun AnimeSearchResponse.addDub(episodes: Int?) {\n    if (episodes == null || episodes <= 0) return\n    addDubStatus(DubStatus.Dubbed, episodes)\n}\n\nfun AnimeSearchResponse.addSub(episodes: Int?) {\n    if (episodes == null || episodes <= 0) return\n    addDubStatus(DubStatus.Subbed, episodes)\n}\n\nfun AnimeSearchResponse.addDubStatus(\n    dubExist: Boolean,\n    subExist: Boolean,\n    dubEpisodes: Int? = null,\n    subEpisodes: Int? = null\n) {\n    if (dubExist)\n        addDubStatus(DubStatus.Dubbed, dubEpisodes)\n\n    if (subExist)\n        addDubStatus(DubStatus.Subbed, subEpisodes)\n}\n\nfun AnimeSearchResponse.addDubStatus(status: String, episodes: Int? = null) {\n    if (status.contains(\"(dub)\", ignoreCase = true)) {\n        addDubStatus(DubStatus.Dubbed, episodes)\n    } else if (status.contains(\"(sub)\", ignoreCase = true)) {\n        addDubStatus(DubStatus.Subbed, episodes)\n    }\n}\n\n/** Data class of [SearchResponse] interface for Torrent.\n * @see newTorrentSearchResponse\n * */\ndata class TorrentSearchResponse\n@Deprecated(\"Use newTorrentSearchResponse\", level = DeprecationLevel.ERROR)\nconstructor(\n    override val name: String,\n    override val url: String,\n    override val apiName: String,\n    override var type: TvType?,\n\n    override var posterUrl: String?,\n    override var id: Int? = null,\n    override var quality: SearchQuality? = null,\n    override var posterHeaders: Map<String, String>? = null,\n    override var score: Score? = null,\n) : SearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    @Deprecated(\n        \"Use newTorrentSearchResponse\",\n        level = DeprecationLevel.ERROR\n    )\n    constructor(\n        name: String,\n        url: String,\n        apiName: String,\n        type: TvType?,\n        posterUrl: String?,\n        id: Int? = null,\n        quality: SearchQuality? = null,\n        posterHeaders: Map<String, String>? = null\n    ) : this(name, url, apiName, type, posterUrl, id, quality, posterHeaders, null)\n}\n\n/** Data class of [SearchResponse] interface for Movies.\n * @see newMovieSearchResponse\n * */\ndata class MovieSearchResponse\n@Deprecated(\"Use newMovieSearchResponse\", level = DeprecationLevel.ERROR)\nconstructor(\n    override val name: String,\n    override val url: String,\n    override val apiName: String,\n    override var type: TvType? = null,\n\n    override var posterUrl: String? = null,\n    var year: Int? = null,\n    override var id: Int? = null,\n    override var quality: SearchQuality? = null,\n    override var posterHeaders: Map<String, String>? = null,\n    override var score: Score? = null,\n) : SearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    @Deprecated(\n        \"Use newMovieSearchResponse\",\n        level = DeprecationLevel.ERROR\n    )\n    constructor(\n        name: String,\n        url: String,\n        apiName: String,\n        type: TvType?,\n        posterUrl: String?,\n        year: Int? = null,\n        id: Int? = null,\n        quality: SearchQuality? = null,\n        posterHeaders: Map<String, String>? = null\n    ) : this(name, url, apiName, type, posterUrl, id, year, quality, posterHeaders, null)\n}\n\n/** Data class of [SearchResponse] interface for Live streams.\n * @see newLiveSearchResponse\n * */\ndata class LiveSearchResponse\n@Deprecated(\"Use newLiveSearchResponse\", level = DeprecationLevel.ERROR)\nconstructor(\n    override val name: String,\n    override val url: String,\n    override val apiName: String,\n    override var type: TvType? = null,\n\n    override var posterUrl: String? = null,\n    override var id: Int? = null,\n    override var quality: SearchQuality? = null,\n    override var posterHeaders: Map<String, String>? = null,\n    var lang: String? = null,\n    override var score: Score? = null,\n) : SearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    @Deprecated(\n        \"Use newLiveSearchResponse\",\n        level = DeprecationLevel.ERROR\n    )\n    constructor(\n        name: String,\n        url: String,\n        apiName: String,\n        type: TvType?,\n        posterUrl: String?,\n        id: Int? = null,\n        quality: SearchQuality? = null,\n        posterHeaders: Map<String, String>? = null,\n        lang: String? = null,\n    ) : this(name, url, apiName, type, posterUrl, id, quality, posterHeaders, lang, null)\n}\n\n/** Data class of [SearchResponse] interface for Tv series.\n * @see newTvSeriesSearchResponse\n * */\ndata class TvSeriesSearchResponse\n@Deprecated(\"Use newTvSeriesSearchResponse\", level = DeprecationLevel.ERROR)\nconstructor(\n    override val name: String,\n    override val url: String,\n    override val apiName: String,\n    override var type: TvType? = null,\n\n    override var posterUrl: String? = null,\n    var year: Int? = null,\n    var episodes: Int? = null,\n    override var id: Int? = null,\n    override var quality: SearchQuality? = null,\n    override var posterHeaders: Map<String, String>? = null,\n    override var score: Score? = null,\n) : SearchResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    @Deprecated(\n        \"Use newTvSeriesSearchResponse\",\n        level = DeprecationLevel.ERROR\n    )\n    constructor(\n        name: String,\n        url: String,\n        apiName: String,\n        type: TvType?,\n        posterUrl: String?,\n        year: Int? = null,\n        episodes: Int? = null,\n        id: Int? = null,\n        quality: SearchQuality? = null,\n        posterHeaders: Map<String, String>? = null,\n    ) : this(\n        name,\n        url,\n        apiName,\n        type,\n        posterUrl,\n        year,\n        episodes,\n        id,\n        quality,\n        posterHeaders,\n        null\n    )\n}\n\n/** Data class of Trailer data.\n * @property extractorUrl Url string of the Trailer video.\n * @property referer Nullable string of referer to be used in network request.\n * @property raw determines if [extractorUrl] should be used as direct Trailer video link instead of extracting it.\n * */\ndata class TrailerData(\n    val extractorUrl: String,\n    val referer: String?,\n    val raw: Boolean,\n    val headers: Map<String, String> = mapOf(),\n    // var mirrors: List<ExtractorLink>,\n    // var subtitles: List<SubtitleFile> = emptyList(),\n)\n\n/** Abstract interface of LoadResponse responses\n * @property name Title of the media, appears on result page.\n * @property url Url of the media.\n * @property apiName Plugin name, appears on result page.\n * @property type [TvType] of the media .\n * @property posterUrl Url of the media poster, appears on Top of result page.\n * @property year Year of the media, appears on result page.\n * @property plot Plot of the media, appears on result page.\n * @property score Rating of the media, appears on result page.\n * Use it with addScore or by assigning a score like `Score.from(string/float/int/double, 10)` or `Score.from10(string/float/int/double)`\n * @property tags Tags of the media, appears on result page.\n * @property duration duration of the media, appears on result page.\n * @property trailers list of the media [TrailerData], used to load trailers.\n * @property recommendations list of the [SearchResponse] related to media, appears on result page.\n * @property actors list of the [ActorData] casted in the media, appears on result page.\n * @property comingSoon determines if the media is released or coming soon.\n * @property syncData Online sync services compatible with the media.\n * @property posterHeaders headers map used by network request to get the poster.\n * @property backgroundPosterUrl Url of the media background poster.\n * @property logoUrl Image URL used as a visual title replacement.If the logo loads successfully, it is shown instead of the text title. If the logo is null or fails to load, the text title is displayed.\n * @property contentRating content rating of the media, appears on result page.\n * @property uniqueUrl The key used for storing the persistent data about an entry.\n * On older versions `url` was used instead, but this was added to support JSON that can change as the url parameter.\n *\n * If you have JSON that can change you can set `url = jsonObject.toJson()` and `uniqueId = jsonObject.id.toString()`\n * */\ninterface LoadResponse {\n    var name: String\n    var url: String\n    var apiName: String\n    var type: TvType\n    var posterUrl: String?\n    var year: Int?\n    var plot: String?\n\n    var score: Score?\n    var tags: List<String>?\n    var duration: Int? // in minutes\n    var trailers: MutableList<TrailerData>\n\n    var recommendations: List<SearchResponse>?\n    var actors: List<ActorData>?\n    var comingSoon: Boolean\n    var syncData: MutableMap<String, String>\n    var posterHeaders: Map<String, String>?\n    var backgroundPosterUrl: String?\n\n    @Prerelease\n    var logoUrl: String?\n    var contentRating: String?\n\n    var uniqueUrl: String\n\n    @Deprecated(\n        \"`rating` is the old scoring system, use score instead\",\n        replaceWith = ReplaceWith(\"score\"),\n        level = DeprecationLevel.ERROR\n    )\n    var rating: Int?\n        set(value) {\n            @Suppress(\"DEPRECATION_ERROR\")\n            this.score = Score.fromOld(value)\n        }\n        @Suppress(\"DEPRECATION_ERROR\")\n        get() = score?.toOld()\n\n    companion object {\n        var malIdPrefix = \"\" //malApi.idPrefix\n\n        var kitsuIdPrefix = \"\" //kitsuApi.idPrefix\n        var aniListIdPrefix = \"\" //aniListApi.idPrefix\n        var simklIdPrefix = \"\" //simklApi.idPrefix\n        var isTrailersEnabled = true\n\n        /**\n         * The ID string is a way to keep a collection of services in one single ID using a map\n         * This adds a database service (like imdb) to the string and returns the new string.\n         */\n        fun addIdToString(idString: String?, database: SimklSyncServices, id: String?): String? {\n            if (id == null) return idString\n            return (readIdFromString(idString) + mapOf(database to id)).toJson()\n        }\n\n        /** Read the id string to get all other ids */\n        fun readIdFromString(idString: String?): Map<SimklSyncServices, String> {\n            return tryParseJson(idString) ?: return emptyMap()\n        }\n\n        fun LoadResponse.isMovie(): Boolean {\n            return this.type.isMovieType() || this is MovieLoadResponse\n        }\n\n        @JvmName(\"addActorNames\")\n        fun LoadResponse.addActors(actors: List<String>?) {\n            this.actors = actors?.map { ActorData(Actor(it)) }\n        }\n\n        @JvmName(\"addActors\")\n        fun LoadResponse.addActors(actors: List<Pair<Actor, String?>>?) {\n            this.actors = actors?.map { (actor, role) -> ActorData(actor, roleString = role) }\n        }\n\n        @JvmName(\"addActorsRole\")\n        fun LoadResponse.addActors(actors: List<Pair<Actor, ActorRole?>>?) {\n            this.actors = actors?.map { (actor, role) -> ActorData(actor, role = role) }\n        }\n\n        /**\n         * Internal helper function to add simkl ids from other databases.\n         */\n        private fun LoadResponse.addSimklId(\n            database: SimklSyncServices,\n            id: String?\n        ) {\n            safe {\n                this.syncData[simklIdPrefix] =\n                    addIdToString(this.syncData[simklIdPrefix], database, id.toString())\n                        ?: return@safe\n            }\n        }\n\n        @JvmName(\"addActorsOnly\")\n        fun LoadResponse.addActors(actors: List<Actor>?) {\n            this.actors = actors?.map { actor -> ActorData(actor) }\n        }\n\n        fun LoadResponse.getMalId(): String? {\n            return this.syncData[malIdPrefix]\n        }\n\n        fun LoadResponse.getKitsuId(): String? {\n            return this.syncData[kitsuIdPrefix]\n        }\n        fun LoadResponse.getAniListId(): String? {\n            return this.syncData[aniListIdPrefix]\n        }\n\n        fun LoadResponse.getImdbId(): String? {\n            return safe {\n                readIdFromString(this.syncData[simklIdPrefix])[SimklSyncServices.Imdb]\n            }\n        }\n\n        fun LoadResponse.getTMDbId(): String? {\n            return safe {\n                readIdFromString(this.syncData[simklIdPrefix])[SimklSyncServices.Tmdb]\n            }\n        }\n\n        fun LoadResponse.addMalId(id: Int?) {\n            this.syncData[malIdPrefix] = (id ?: return).toString()\n            this.addSimklId(SimklSyncServices.Mal, id.toString())\n        }\n\n        @Prerelease\n        fun LoadResponse.addKitsuId(id: Int?) {\n            this.syncData[kitsuIdPrefix] = (id ?: return).toString()\n        }\n\n        fun LoadResponse.addAniListId(id: Int?) {\n            this.syncData[aniListIdPrefix] = (id ?: return).toString()\n            this.addSimklId(SimklSyncServices.AniList, id.toString())\n        }\n\n        fun LoadResponse.addSimklId(id: Int?) {\n            this.addSimklId(SimklSyncServices.Simkl, id.toString())\n        }\n\n        fun LoadResponse.addImdbUrl(url: String?) {\n            addImdbId(imdbUrlToIdNullable(url))\n        }\n\n        /**better to call addTrailer with multiple trailers directly instead of calling this multiple times*/\n        @Suppress(\"RedundantSuspendModifier\")\n        suspend fun LoadResponse.addTrailer(\n            trailerUrl: String?,\n            referer: String? = null,\n            addRaw: Boolean = false\n        ) {\n            if (!isTrailersEnabled || trailerUrl.isNullOrBlank()) return\n            this.trailers.add(TrailerData(trailerUrl, referer, addRaw))\n            /*val links = arrayListOf<ExtractorLink>()\n            val subs = arrayListOf<SubtitleFile>()\n            if (!loadExtractor(\n                    trailerUrl,\n                    referer,\n                    { subs.add(it) },\n                    { links.add(it) }) && addRaw\n            ) {\n                this.trailers.add(\n                    TrailerData(\n                        listOf(\n                            ExtractorLink(\n                                \"\",\n                                \"Trailer\",\n                                trailerUrl,\n                                referer ?: \"\",\n                                Qualities.Unknown.value,\n                                trailerUrl.contains(\".m3u8\")\n                            )\n                        ), listOf()\n                    )\n                )\n            } else {\n                this.trailers.add(TrailerData(links, subs))\n            }*/\n        }\n\n        /*\n        fun LoadResponse.addTrailer(newTrailers: List<ExtractorLink>) {\n            trailers.addAll(newTrailers.map { TrailerData(listOf(it)) })\n        }*/\n\n        @Suppress(\"RedundantSuspendModifier\")\n        suspend fun LoadResponse.addTrailer(\n            trailerUrl: String?,\n            referer: String? = null,\n            addRaw: Boolean = false,\n            headers: Map<String, String> = mapOf()\n        ) {\n            if (!isTrailersEnabled || trailerUrl.isNullOrBlank()) return\n            this.trailers.add(TrailerData(trailerUrl, referer, addRaw, headers))\n        }\n\n        @Suppress(\"RedundantSuspendModifier\")\n        suspend fun LoadResponse.addTrailer(\n            trailerUrls: List<String>?,\n            referer: String? = null,\n            addRaw: Boolean = false\n        ) {\n            if (!isTrailersEnabled || trailerUrls == null) return\n            trailers.addAll(trailerUrls.map { TrailerData(it, referer, addRaw) })\n            /*val trailers = trailerUrls.filter { it.isNotBlank() }.amap { trailerUrl ->\n                val links = arrayListOf<ExtractorLink>()\n                val subs = arrayListOf<SubtitleFile>()\n                if (!loadExtractor(\n                        trailerUrl,\n                        referer,\n                        { subs.add(it) },\n                        { links.add(it) }) && addRaw\n                ) {\n                    arrayListOf(\n                        ExtractorLink(\n                            \"\",\n                            \"Trailer\",\n                            trailerUrl,\n                            referer ?: \"\",\n                            Qualities.Unknown.value,\n                            trailerUrl.contains(\".m3u8\")\n                        )\n                    ) to arrayListOf()\n                } else {\n                    links to subs\n                }\n            }.map { (links, subs) -> TrailerData(links, subs) }\n            this.trailers.addAll(trailers)*/\n        }\n\n        fun LoadResponse.addImdbId(id: String?) {\n            // TODO add IMDb sync\n            this.addSimklId(SimklSyncServices.Imdb, id)\n        }\n\n        @Suppress(\"UNUSED_PARAMETER\")\n        fun LoadResponse.addTraktId(id: String?) {\n            // TODO add Trakt sync\n        }\n\n        @Suppress(\"UNUSED_PARAMETER\")\n        fun LoadResponse.addKitsuId(id: String?) {\n            // TODO add Kitsu sync\n        }\n\n        fun LoadResponse.addTMDbId(id: String?) {\n            // TODO add TMDb sync\n            this.addSimklId(SimklSyncServices.Tmdb, id)\n        }\n\n        fun LoadResponse.addScore(score: String?, maxValue: Int = 10) {\n            this.score = Score.from(score, maxValue)\n        }\n\n        fun LoadResponse.addScore(score: Score?) {\n            this.score = score\n        }\n\n        @Deprecated(\n            \"Use addScore\",\n            replaceWith = ReplaceWith(\"addScore\"),\n            level = DeprecationLevel.ERROR\n        )\n        fun LoadResponse.addRating(text: String?) {\n            this.score = Score.from10(text)\n        }\n\n        @Deprecated(\n            \"Use addScore\",\n            replaceWith = ReplaceWith(\"addScore\"),\n            level = DeprecationLevel.ERROR\n        )\n        fun LoadResponse.addRating(value: Int?) {\n            @Suppress(\"DEPRECATION_ERROR\")\n            this.score = Score.fromOld(value)\n        }\n\n        fun LoadResponse.addDuration(input: String?) {\n            this.duration = getDurationFromString(input) ?: this.duration\n        }\n    }\n}\n\nfun getDurationFromString(input: String?): Int? {\n    val cleanInput = input?.trim()?.replace(\" \", \"\") ?: return null\n    //Use first as sometimes the text passes on the 2 other Regex, but failed to provide accurate return value\n    Regex(\"(\\\\d+\\\\shr)|(\\\\d+\\\\shour)|(\\\\d+\\\\smin)|(\\\\d+\\\\ssec)\").findAll(input).let { values ->\n        var seconds = 0\n        values.forEach {\n            val timeText = it.value\n            if (timeText.isNotBlank()) {\n                val time = timeText.filter { s -> s.isDigit() }.trim().toInt()\n                val scale = timeText.filter { s -> !s.isDigit() }.trim()\n                //println(\"Scale: $scale\")\n                val timeval = when (scale) {\n                    \"hr\", \"hour\" -> time * 60 * 60\n                    \"min\" -> time * 60\n                    \"sec\" -> time\n                    else -> 0\n                }\n                seconds += timeval\n            }\n        }\n        if (seconds > 0) {\n            return seconds / 60\n        }\n    }\n    Regex(\"([0-9]*)h.*?([0-9]*)m\").find(cleanInput)?.groupValues?.let { values ->\n        if (values.size == 3) {\n            val hours = values[1].toIntOrNull()\n            val minutes = values[2].toIntOrNull()\n            if (minutes != null && hours != null) {\n                return hours * 60 + minutes\n            }\n        }\n    }\n    Regex(\"([0-9]*)m\").find(cleanInput)?.groupValues?.let { values ->\n        if (values.size == 2) {\n            val returnValue = values[1].toIntOrNull()\n            if (returnValue != null) {\n                return returnValue\n            }\n        }\n    }\n    return null\n}\n\n/** Extension function of [LoadResponse] to check if it's Episode based.\n * @return True if the response is [EpisodeResponse] and its type is Episode based.\n * */\nfun LoadResponse?.isEpisodeBased(): Boolean {\n    if (this == null) return false\n    return this is EpisodeResponse && this.type.isEpisodeBased()\n}\n\n/** Extension function of [LoadResponse] to check if it's Anime based.\n * @return True if the response type is Anime or OVA.\n * @see TvType\n * */\nfun LoadResponse?.isAnimeBased(): Boolean {\n    if (this == null) return false\n    return (this.type == TvType.Anime || this.type == TvType.OVA) // && (this is AnimeLoadResponse)\n}\n\n/**\n * Extension function to determine if the [TvType] is episode-based.\n * This function checks if the type corresponds to an episode-based format. Episode-based types will be placed\n * in subfolders that include the sanitized title name. This check is used for other logic as well.\n *\n * @return true if the [TvType] is episode-based, otherwise false.\n */\nfun TvType?.isEpisodeBased(): Boolean {\n    return when (this) {\n        TvType.Anime,\n        TvType.AsianDrama,\n        TvType.Cartoon,\n        TvType.TvSeries -> true\n\n        else -> false\n    }\n}\n\n/**\n * Extension function to get the folder prefix based on the [TvType].\n * Non-episode-based types will return a base folder name, while episode-based types will\n * have their files placed in subfolders using a sanitized title name.\n *\n * For the actual folder path, refer to `ResultViewModel2().getFolder()`, which combines\n * the folder prefix and, if necessary, the sanitized name to a sub-folder. The folder prefix\n * will be used in the root directory of the configured downloads directory.\n *\n * @return the folder prefix corresponding to the [TvType], which is used as the root directory.\n */\nfun TvType.getFolderPrefix(): String {\n    return when (this) {\n        TvType.Anime -> \"Anime\"\n        TvType.AnimeMovie -> \"Movies\"\n        TvType.AsianDrama -> \"AsianDramas\"\n        TvType.Audio -> \"Audio\"\n        TvType.AudioBook -> \"AudioBooks\"\n        TvType.Cartoon -> \"Cartoons\"\n        TvType.CustomMedia -> \"Media\"\n        TvType.Documentary -> \"Documentaries\"\n        TvType.Live -> \"LiveStreams\"\n        TvType.Movie -> \"Movies\"\n        TvType.Music -> \"Music\"\n        TvType.NSFW -> \"NSFW\"\n        TvType.OVA -> \"OVAs\"\n        TvType.Others -> \"Others\"\n        TvType.Podcast -> \"Podcasts\"\n        TvType.Torrent -> \"Torrents\"\n        TvType.TvSeries -> \"TVSeries\"\n    }\n}\n\n/** Data class holds next airing Episode info.\n * @param episode Next airing Episode number.\n * @param unixTime Next airing Time in Unix time format.\n * @param season Season number of next airing episode (Optional).\n * */\ndata class NextAiring(\n    val episode: Int,\n    val unixTime: Long,\n    val season: Int? = null,\n)\n\n/** Data class holds season info.\n * @param season To be mapped with episode season, not shown in UI if displaySeason is defined\n * @param name To be shown next to the season like \"Season $displaySeason $name\" but if displaySeason is null then \"$name\"\n * @param displaySeason What to be displayed next to the season name, if null then the name is the only thing shown.\n * */\ndata class SeasonData(\n    val season: Int,\n    val name: String? = null,\n    val displaySeason: Int? = null, // will use season if null\n)\n\n/** Abstract interface of EpisodeResponse */\ninterface EpisodeResponse {\n    var showStatus: ShowStatus?\n    var nextAiring: NextAiring?\n    var seasonNames: List<SeasonData>?\n    fun getLatestEpisodes(): Map<DubStatus, Int?>\n\n    /** Count all episodes in all previous seasons up until this episode to get a total count.\n     * Example:\n     *      Season 1: 10 episodes.\n     *      Season 2: 6 episodes.\n     *\n     * getTotalEpisodeIndex(episode = 3, season = 2) -> 10 + 3 = 13\n     * */\n    fun getTotalEpisodeIndex(episode: Int, season: Int): Int\n}\n\n@JvmName(\"addSeasonNamesString\")\nfun EpisodeResponse.addSeasonNames(names: List<String>) {\n    this.seasonNames = if (names.isEmpty()) null else names.mapIndexed { index, s ->\n        SeasonData(\n            season = index + 1,\n            s\n        )\n    }\n}\n\n@JvmName(\"addSeasonNamesSeasonData\")\nfun EpisodeResponse.addSeasonNames(names: List<SeasonData>) {\n    this.seasonNames = names.ifEmpty { null }\n}\n\n/** Data class of [LoadResponse] interface for Torrent.\n * @see newTorrentLoadResponse\n */\ndata class TorrentLoadResponse\n@Deprecated(\"Use newTorrentLoadResponse method\", level = DeprecationLevel.ERROR)\nconstructor(\n    override var name: String,\n    override var url: String,\n    override var apiName: String,\n    var magnet: String?,\n    var torrent: String?,\n    override var plot: String?,\n    override var type: TvType = TvType.Torrent,\n    override var posterUrl: String? = null,\n    override var year: Int? = null,\n    override var score: Score? = null,\n    override var tags: List<String>? = null,\n    override var duration: Int? = null,\n    override var trailers: MutableList<TrailerData> = mutableListOf(),\n    override var recommendations: List<SearchResponse>? = null,\n    override var actors: List<ActorData>? = null,\n    override var comingSoon: Boolean = false,\n    override var syncData: MutableMap<String, String> = mutableMapOf(),\n    override var posterHeaders: Map<String, String>? = null,\n    override var backgroundPosterUrl: String? = null,\n    override var logoUrl: String? = null,\n    override var contentRating: String? = null,\n    override var uniqueUrl: String = url\n) : LoadResponse\n\nsuspend fun MainAPI.newTorrentLoadResponse(\n    name: String,\n    url: String,\n    magnet: String? = null,\n    torrent: String? = null,\n    initializer: suspend TorrentLoadResponse.() -> Unit = { }\n): TorrentLoadResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = TorrentLoadResponse(\n        name = name,\n        url = url,\n        apiName = this.name,\n        magnet = magnet,\n        torrent = torrent,\n        // The initializer will handle this\n        plot = null,\n        comingSoon = magnet.isNullOrBlank() && torrent.isNullOrBlank()\n    )\n    builder.initializer()\n    return builder\n}\n\n/** Data class of [LoadResponse] interface for Anime.\n * @see newAnimeLoadResponse\n * */\ndata class AnimeLoadResponse\n@Deprecated(\"Use newAnimeLoadResponse method\", level = DeprecationLevel.ERROR)\nconstructor(\n    var engName: String? = null,\n    var japName: String? = null,\n    override var name: String,\n    override var url: String,\n    override var apiName: String,\n    override var type: TvType,\n\n    override var posterUrl: String? = null,\n    override var year: Int? = null,\n\n    var episodes: MutableMap<DubStatus, List<Episode>> = mutableMapOf(),\n    override var showStatus: ShowStatus? = null,\n\n    override var plot: String? = null,\n    override var tags: List<String>? = null,\n    var synonyms: List<String>? = null,\n\n    override var score: Score? = null,\n    override var duration: Int? = null,\n    override var trailers: MutableList<TrailerData> = mutableListOf(),\n    override var recommendations: List<SearchResponse>? = null,\n    override var actors: List<ActorData>? = null,\n    override var comingSoon: Boolean = false,\n    override var syncData: MutableMap<String, String> = mutableMapOf(),\n    override var posterHeaders: Map<String, String>? = null,\n    override var nextAiring: NextAiring? = null,\n    override var seasonNames: List<SeasonData>? = null,\n    override var backgroundPosterUrl: String? = null,\n    override var logoUrl: String? = null,\n    override var contentRating: String? = null,\n    override var uniqueUrl: String = url\n) : LoadResponse, EpisodeResponse {\n\n    override fun getLatestEpisodes(): Map<DubStatus, Int?> {\n        return episodes.map { (status, episodes) ->\n            val maxSeason = episodes.maxOfOrNull { it.season ?: Int.MIN_VALUE }\n                .takeUnless { it == Int.MIN_VALUE }\n            status to episodes\n                .filter { it.season == maxSeason }\n                .maxOfOrNull { it.episode ?: Int.MIN_VALUE }\n                .takeUnless { it == Int.MIN_VALUE }\n        }.toMap()\n    }\n\n    override fun getTotalEpisodeIndex(episode: Int, season: Int): Int {\n        val displayMap = this.seasonNames?.associate { it.season to it.displaySeason } ?: emptyMap()\n\n        return this.episodes.maxOf { (_, episodes) ->\n            episodes.count { episodeData ->\n                // Prioritize display season as actual season may be something random to fit multiple seasons into one.\n                val episodeSeason =\n                    displayMap[episodeData.season] ?: episodeData.season ?: Int.MIN_VALUE\n                // Count all episodes from season 1 to below the current season.\n                episodeSeason in 1..<season\n            }\n        } + episode\n    }\n}\n\n/**\n * If episodes already exist appends the list.\n * */\nfun AnimeLoadResponse.addEpisodes(status: DubStatus, episodes: List<Episode>?) {\n    if (episodes.isNullOrEmpty()) return\n    this.episodes[status] = (this.episodes[status] ?: emptyList()) + episodes\n}\n\nsuspend fun MainAPI.newAnimeLoadResponse(\n    name: String,\n    url: String,\n    type: TvType,\n    comingSoonIfNone: Boolean = true,\n    initializer: suspend AnimeLoadResponse.() -> Unit = { },\n): AnimeLoadResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = AnimeLoadResponse(name = name, url = url, apiName = this.name, type = type)\n    builder.initializer()\n    if (comingSoonIfNone) {\n        builder.comingSoon = true\n        for (key in builder.episodes.keys)\n            if (!builder.episodes[key].isNullOrEmpty()) {\n                builder.comingSoon = false\n                break\n            }\n    }\n    return builder\n}\n\n/** Data class of [LoadResponse] interface for Live streams.\n * @see newLiveStreamLoadResponse\n * */\ndata class LiveStreamLoadResponse\n@Deprecated(\"Use newLiveStreamLoadResponse method\", level = DeprecationLevel.ERROR)\nconstructor(\n    override var name: String,\n    override var url: String,\n    override var apiName: String,\n    var dataUrl: String,\n\n    override var posterUrl: String? = null,\n    override var year: Int? = null,\n    override var plot: String? = null,\n\n    override var type: TvType = TvType.Live,\n    override var score: Score? = null,\n    override var tags: List<String>? = null,\n    override var duration: Int? = null,\n    override var trailers: MutableList<TrailerData> = mutableListOf(),\n    override var recommendations: List<SearchResponse>? = null,\n    override var actors: List<ActorData>? = null,\n    override var comingSoon: Boolean = false,\n    override var syncData: MutableMap<String, String> = mutableMapOf(),\n    override var posterHeaders: Map<String, String>? = null,\n    override var backgroundPosterUrl: String? = null,\n    override var logoUrl: String? = null,\n    override var contentRating: String? = null,\n    override var uniqueUrl: String = url\n) : LoadResponse\n\nsuspend fun MainAPI.newLiveStreamLoadResponse(\n    name: String,\n    url: String,\n    dataUrl: String,\n    initializer: suspend LiveStreamLoadResponse.() -> Unit = { }\n): LiveStreamLoadResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = LiveStreamLoadResponse(\n        name = name,\n        url = url,\n        apiName = this.name,\n        dataUrl = dataUrl,\n        comingSoon = dataUrl.isBlank()\n    )\n    builder.initializer()\n    return builder\n}\n\n/** Data class of [LoadResponse] interface for Movies.\n * @see newMovieLoadResponse\n * */\ndata class MovieLoadResponse\n@Deprecated(\"Use newMovieLoadResponse method\", level = DeprecationLevel.ERROR)\nconstructor(\n    override var name: String,\n    override var url: String,\n    override var apiName: String,\n    override var type: TvType,\n    var dataUrl: String,\n\n    override var posterUrl: String? = null,\n    override var year: Int? = null,\n    override var plot: String? = null,\n\n    override var score: Score? = null,\n    override var tags: List<String>? = null,\n    override var duration: Int? = null,\n    override var trailers: MutableList<TrailerData> = mutableListOf(),\n    override var recommendations: List<SearchResponse>? = null,\n    override var actors: List<ActorData>? = null,\n    override var comingSoon: Boolean = false,\n    override var syncData: MutableMap<String, String> = mutableMapOf(),\n    override var posterHeaders: Map<String, String>? = null,\n    override var backgroundPosterUrl: String? = null,\n    override var logoUrl: String? = null,\n    override var contentRating: String? = null,\n    override var uniqueUrl: String = url\n) : LoadResponse\n\nsuspend fun <T> MainAPI.newMovieLoadResponse(\n    name: String,\n    url: String,\n    type: TvType,\n    data: T?,\n    initializer: suspend MovieLoadResponse.() -> Unit = { }\n): MovieLoadResponse {\n    // just in case\n    if (data is String) return newMovieLoadResponse(\n        name,\n        url,\n        type,\n        dataUrl = data,\n        initializer = initializer\n    )\n    val dataUrl = data?.toJson() ?: \"\"\n\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = MovieLoadResponse(\n        name = name,\n        url = url,\n        apiName = this.name,\n        type = type,\n        dataUrl = dataUrl,\n        comingSoon = dataUrl.isBlank()\n    )\n    builder.initializer()\n    return builder\n}\n\nsuspend fun MainAPI.newMovieLoadResponse(\n    name: String,\n    url: String,\n    type: TvType,\n    dataUrl: String,\n    initializer: suspend MovieLoadResponse.() -> Unit = { }\n): MovieLoadResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = MovieLoadResponse(\n        name = name,\n        url = url,\n        apiName = this.name,\n        type = type,\n        dataUrl = dataUrl,\n        comingSoon = dataUrl.isBlank()\n    )\n    builder.initializer()\n    return builder\n}\n\n/** Episode information that will be passed to LoadLinks function & showed on UI\n * @property data string used as main LoadLinks fun parameter.\n * @property name Name of the Episode.\n * @property season Season number.\n * @property episode Episode number.\n * @property posterUrl URL of Episode's poster image.\n * @property score Episode rating.\n * @property date Episode air date, see addDate.\n * @property runTime Episode runtime in seconds.\n * @see newEpisode\n * */\ndata class Episode\n@Deprecated(\"Use newEpisode method\", level = DeprecationLevel.ERROR)\nconstructor(\n    var data: String,\n    var name: String? = null,\n    var season: Int? = null,\n    var episode: Int? = null,\n    var posterUrl: String? = null,\n    var score: Score? = null,\n    var description: String? = null,\n    var date: Long? = null,\n    var runTime: Int? = null,\n) {\n    @Deprecated(\n        \"`rating` is the old scoring system, use score instead\",\n        replaceWith = ReplaceWith(\"score\"),\n        level = DeprecationLevel.ERROR\n    )\n    var rating: Int?\n        set(value) {\n            this.score = Score.from(value, 100)\n        }\n        get() = score?.toInt(100)\n}\n\nfun Episode.addDate(date: String?, format: String = \"yyyy-MM-dd\") {\n    try {\n        this.date = SimpleDateFormat(format, Locale.getDefault()).parse(date ?: return)?.time\n    } catch (e: Exception) {\n        logError(e)\n    }\n}\n\nfun Episode.addDate(date: Date?) {\n    this.date = date?.time\n}\n\nfun MainAPI.newEpisode(\n    url: String,\n    initializer: Episode.() -> Unit = { },\n    fix: Boolean = true,\n): Episode {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = Episode(\n        data = if (fix) fixUrl(url) else url\n    )\n    builder.initializer()\n    return builder\n}\n\nfun <T> MainAPI.newEpisode(\n    data: T,\n    initializer: Episode.() -> Unit = { }\n): Episode {\n    if (data is String) return newEpisode(\n        url = data,\n        initializer = initializer\n    ) // just in case java is wack\n\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = Episode(\n        data = data?.toJson() ?: throw ErrorLoadingException(\"invalid newEpisode\")\n    )\n    builder.initializer()\n    return builder\n}\n\ninterface IDownloadableMinimum {\n    val url: String\n    val referer: String\n    val headers: Map<String, String>\n}\n\n/**\n * Set of sync services simkl is compatible with.\n * Add more as required: https://simkl.docs.apiary.io/#reference/search/id-lookup/get-items-by-id\n */\nenum class SimklSyncServices(val originalName: String) {\n    Simkl(\"simkl\"),\n    Imdb(\"imdb\"),\n    Tmdb(\"tmdb\"),\n    AniList(\"anilist\"),\n    Mal(\"mal\"),\n}\n\n/** Data class of [LoadResponse] interface for Tv series.\n * @see newTvSeriesLoadResponse\n * */\ndata class TvSeriesLoadResponse\n@Deprecated(\"Use newTvSeriesLoadResponse method\", level = DeprecationLevel.ERROR)\nconstructor(\n    override var name: String,\n    override var url: String,\n    override var apiName: String,\n    override var type: TvType,\n    var episodes: List<Episode>,\n\n    override var posterUrl: String? = null,\n    override var year: Int? = null,\n    override var plot: String? = null,\n\n    override var showStatus: ShowStatus? = null,\n    override var score: Score? = null,\n    override var tags: List<String>? = null,\n    override var duration: Int? = null,\n    override var trailers: MutableList<TrailerData> = mutableListOf(),\n    override var recommendations: List<SearchResponse>? = null,\n    override var actors: List<ActorData>? = null,\n    override var comingSoon: Boolean = false,\n    override var syncData: MutableMap<String, String> = mutableMapOf(),\n    override var posterHeaders: Map<String, String>? = null,\n    override var nextAiring: NextAiring? = null,\n    override var seasonNames: List<SeasonData>? = null,\n    override var backgroundPosterUrl: String? = null,\n    override var logoUrl: String? = null,\n    override var contentRating: String? = null,\n    override var uniqueUrl: String = url\n) : LoadResponse, EpisodeResponse {\n    override fun getLatestEpisodes(): Map<DubStatus, Int?> {\n        val maxSeason =\n            episodes.maxOfOrNull { it.season ?: Int.MIN_VALUE }.takeUnless { it == Int.MIN_VALUE }\n        val max = episodes\n            .filter { it.season == maxSeason }\n            .maxOfOrNull { it.episode ?: Int.MIN_VALUE }\n            .takeUnless { it == Int.MIN_VALUE }\n        return mapOf(DubStatus.None to max)\n    }\n\n    override fun getTotalEpisodeIndex(episode: Int, season: Int): Int {\n        val displayMap = this.seasonNames?.associate { it.season to it.displaySeason } ?: emptyMap()\n\n        return episodes.count { episodeData ->\n            // Prioritize display season as actual season may be something random to fit multiple seasons into one.\n            val episodeSeason =\n                displayMap[episodeData.season] ?: episodeData.season ?: Int.MIN_VALUE\n            // Count all episodes from season 1 to below the current season.\n            episodeSeason in 1..<season\n        } + episode\n    }\n}\n\nsuspend fun MainAPI.newTvSeriesLoadResponse(\n    name: String,\n    url: String,\n    type: TvType,\n    episodes: List<Episode>,\n    initializer: suspend TvSeriesLoadResponse.() -> Unit = { }\n): TvSeriesLoadResponse {\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder = TvSeriesLoadResponse(\n        name = name,\n        url = url,\n        apiName = this.name,\n        type = type,\n        episodes = episodes,\n        comingSoon = episodes.isEmpty(),\n    )\n    builder.initializer()\n    return builder\n}\n\nfun fetchUrls(text: String?): List<String> {\n    if (text.isNullOrEmpty()) {\n        return listOf()\n    }\n    val linkRegex =\n        Regex(\"\"\"(https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b([-a-zA-Z0-9()@:%_+.~#?&/=]*))\"\"\")\n    return linkRegex.findAll(text).map { it.value.trim().removeSurrounding(\"\\\"\") }.toList()\n}\n\n@Deprecated(\n    \"toRatingInt() is deprecated. Use new score API instead.\",\n    level = DeprecationLevel.ERROR\n)\nfun String?.toRatingInt(): Int? =\n    this?.replace(\" \", \"\")?.trim()?.toDoubleOrNull()?.absoluteValue?.times(1000f)?.toInt()\n\ndata class Tracker(\n    val malId: Int? = null,\n    val kitsuId: String? = null,\n    val aniId: String? = null,\n    val image: String? = null,\n    val cover: String? = null,\n)\n\ndata class AniSearch(\n    @JsonProperty(\"data\") var data: Data? = Data()\n) {\n    data class Data(\n        @JsonProperty(\"Page\") var page: Page? = Page()\n    ) {\n        data class Page(\n            @JsonProperty(\"media\") var media: ArrayList<Media> = arrayListOf()\n        ) {\n            data class Media(\n                @JsonProperty(\"title\") var title: Title? = null,\n                @JsonProperty(\"id\") var id: Int? = null,\n                @JsonProperty(\"idMal\") var idMal: Int? = null,\n                @JsonProperty(\"seasonYear\") var seasonYear: Int? = null,\n                @JsonProperty(\"format\") var format: String? = null,\n                @JsonProperty(\"coverImage\") var coverImage: CoverImage? = null,\n                @JsonProperty(\"bannerImage\") var bannerImage: String? = null,\n            ) {\n                data class CoverImage(\n                    @JsonProperty(\"extraLarge\") var extraLarge: String? = null,\n                    @JsonProperty(\"large\") var large: String? = null,\n                )\n\n                data class Title(\n                    @JsonProperty(\"romaji\") var romaji: String? = null,\n                    @JsonProperty(\"english\") var english: String? = null,\n                ) {\n                    fun isMatchingTitles(title: String?): Boolean {\n                        if (title == null) return false\n                        return english.equals(title, true) || romaji.equals(title, true)\n                    }\n                }\n            }\n        }\n    }\n}\n\n/**\n * used for the getTracker() method\n **/\nenum class TrackerType {\n    MOVIE,\n    TV,\n    TV_SHORT,\n    ONA,\n    OVA,\n    SPECIAL,\n    MUSIC;\n\n    companion object {\n        fun getTypes(type: TvType): Set<TrackerType> {\n            return when (type) {\n                TvType.Movie -> setOf(MOVIE)\n                TvType.AnimeMovie -> setOf(MOVIE)\n                TvType.TvSeries -> setOf(TV, TV_SHORT)\n                TvType.Anime -> setOf(TV, TV_SHORT, ONA, OVA)\n                TvType.OVA -> setOf(OVA, SPECIAL, ONA)\n                TvType.Others -> setOf(MUSIC)\n                else -> emptySet()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt",
    "content": "package com.lagradost.cloudstream3\n\nimport com.fasterxml.jackson.databind.DeserializationFeature\nimport com.fasterxml.jackson.databind.ObjectMapper\nimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper\nimport com.lagradost.nicehttp.Requests\nimport com.lagradost.nicehttp.ResponseParser\nimport kotlin.reflect.KClass\n\n// Short name for requests client to make it nicer to use\n\nvar app = Requests(responseParser = object : ResponseParser {\n    val mapper: ObjectMapper = jacksonObjectMapper().configure(\n        DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,\n        false\n    )\n\n    override fun <T : Any> parse(text: String, kClass: KClass<T>): T {\n        return mapper.readValue(text, kClass.java)\n    }\n\n    override fun <T : Any> parseSafe(text: String, kClass: KClass<T>): T? {\n        return try {\n            mapper.readValue(text, kClass.java)\n        } catch (e: Exception) {\n            null\n        }\n    }\n\n    override fun writeValueAsString(obj: Any): String {\n        return mapper.writeValueAsString(obj)\n    }\n}).apply {\n    defaultHeaders = mapOf(\"user-agent\" to USER_AGENT)\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/ParCollections.kt",
    "content": "package com.lagradost.cloudstream3\n\nimport com.lagradost.cloudstream3.mvvm.logError\nimport kotlinx.coroutines.*\nimport kotlin.coroutines.cancellation.CancellationException\n\n/**\n * Short for \"Asynchronous Map\", runs on all values concurrently,\n * this means that if you are not doing networking, you should use a regular map\n */\n@Throws(CancellationException::class)\nsuspend fun <K, V, R> Map<out K, V>.amap(f: suspend (Map.Entry<K, V>) -> R): List<R> =\n    coroutineScope {\n        ensureActive()\n        map { async { f(it) } }.map { it.await() }\n    }\n\n/**\n * Short for \"Asynchronous Parallel Map\", but is not really parallel, only concurrent.\n */\n@Deprecated(\n    \"This blocks with runBlocking, and should not be used inside a suspended context\",\n    replaceWith = ReplaceWith(\"amap(f)\", \"com.lagradost.cloudstream3.amap\"),\n    level = DeprecationLevel.ERROR\n)\n@Throws(CancellationException::class)\nfun <K, V, R> Map<out K, V>.apmap(f: suspend (Map.Entry<K, V>) -> R): List<R> = runBlocking {\n    map { async { f(it) } }.map { it.await() }\n}\n\n/**\n * Short for \"Asynchronous Map\", runs on all values concurrently,\n * this means that if you are not doing networking, you should use a regular map\n */\n@Throws(CancellationException::class)\nsuspend fun <A, B> List<A>.amap(f: suspend (A) -> B): List<B> =\n    coroutineScope {\n        ensureActive()\n        map { async { f(it) } }.map { it.await() }\n    }\n\n/**\n * Short for \"Asynchronous Parallel Map\", but is not really parallel, only concurrent.\n */\n@Deprecated(\n    \"This blocks with runBlocking, and should not be used inside a suspended context\",\n    replaceWith = ReplaceWith(\"amap(f)\", \"com.lagradost.cloudstream3.amap\"),\n    level = DeprecationLevel.ERROR\n)\n@Throws(CancellationException::class)\nfun <A, B> List<A>.apmap(f: suspend (A) -> B): List<B> = runBlocking {\n    map { async { f(it) } }.map { it.await() }\n}\n\n/**\n * Short for \"Asynchronous Parallel Map\" with an Index, but is not really parallel, only concurrent.\n */\n@Deprecated(\n    \"This blocks with runBlocking, and should not be used inside a suspended context\",\n    replaceWith = ReplaceWith(\"amapIndexed(f)\", \"com.lagradost.cloudstream3.amapIndexed\"),\n    level = DeprecationLevel.ERROR\n)\n@Throws(CancellationException::class)\nfun <A, B> List<A>.apmapIndexed(f: suspend (index: Int, A) -> B): List<B> = runBlocking {\n    mapIndexed { index, a -> async { f(index, a) } }.map { it.await() }\n}\n\n/**\n * Short for \"Asynchronous Map\" with an Index, runs on all values concurrently,\n * this means that if you are not doing networking, you should use a regular mapIndexed\n */\n@Throws(CancellationException::class)\nsuspend fun <A, B> List<A>.amapIndexed(f: suspend (index: Int, A) -> B): List<B> =\n    coroutineScope {\n        ensureActive()\n        mapIndexed { index, a -> async { f(index, a) } }.map { it.await() }\n    }\n\n/**\n * Short for \"Argument Asynchronous Map\" because it allows for a variadic number of paramaters.\n *\n * Runs all different functions at the same time and awaits for all to be finished, then returns\n * a list of all those items or null if they fail. However Unit is often used.\n */\n@Deprecated(\n    \"This blocks with runBlocking, and should not be used inside a suspended context\",\n    replaceWith = ReplaceWith(\"runAllAsync(transforms)\", \"com.lagradost.cloudstream3.runAllAsync\"),\n    level = DeprecationLevel.ERROR\n)\n@Throws(CancellationException::class)\nfun <R> argamap(\n    vararg transforms: suspend () -> R,\n) : List<R?> = runBlocking {\n    transforms.map {\n        async {\n            try {\n                it.invoke()\n            } catch (e: Exception) {\n                logError(e)\n                null\n            }\n        }\n    }.map { it.await() }\n}\n\n/**\n * Runs all different functions at the same time and awaits for all to be finished, then returns\n * a list of all those items or null if they fail. However Unit is often used.\n */\n@Throws(CancellationException::class)\nsuspend fun <R> runAllAsync(\n    vararg transforms: suspend () -> R,\n) : List<R?> = coroutineScope {\n    ensureActive()\n    transforms.map { fn ->\n        async {\n            try {\n                fn.invoke()\n            } catch (e: Exception) {\n                logError(e)\n                null\n            }\n        }\n    }.map { it.await() }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Acefile.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\n\nopen class Acefile : ExtractorApi() {\n    override val name = \"Acefile\"\n    override val mainUrl = \"https://acefile.co\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val id = \"/(?:d|download|player|f|file)/(\\\\w+)\".toRegex().find(url)?.groupValues?.get(1)\n        val script = getAndUnpack(app.get(\"$mainUrl/player/${id ?: return}\").text)\n        val service = \"\"\"service\\s*=\\s*['\"]([^'\"]+)\"\"\".toRegex().find(script)?.groupValues?.get(1)\n        val serverUrl = \"\"\"['\"](\\S+check&id\\S+?)['\"]\"\"\".toRegex().find(script)?.groupValues?.get(1)\n            ?.replace(\"\\\"+service+\\\"\", service ?: return)\n\n        val video = app.get(serverUrl ?: return, referer = \"$mainUrl/\").parsedSafe<Source>()?.data\n\n        callback.invoke(\n            newExtractorLink(\n                this.name,\n                this.name,\n                video ?: return\n            )\n        )\n\n    }\n\n    data class Source(\n        val data: String? = null,\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Bigwarp.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class BigwarpIO : ExtractorApi() {\n    override var name = \"Bigwarp\"\n    override var mainUrl = \"https://bigwarp.io\"\n    override val requiresReferer = false\n\n    private val sourceRegex = Regex(\"\"\"file:\\s*['\"](.*?)['\"],label:\\s*['\"](.*?)['\"]\"\"\")\n    private val qualityRegex = Regex(\"\"\"\\d+x(\\d+) .*\"\"\")\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val resp = app.get(url).text\n\n        for (sourceMatch in sourceRegex.findAll(resp)) {\n            val label = sourceMatch.groupValues[2]\n\n            callback.invoke(\n                newExtractorLink(\n                    name,\n                    \"$name ${label.split(\" \", limit = 2).getOrNull(1)}\",\n                    sourceMatch.groupValues[1], // streams are usually in mp4 format\n                ) {\n                    this.referer = url\n                    this.quality =\n                        qualityRegex.find(label)?.groupValues?.getOrNull(1)?.toIntOrNull()\n                            ?: Qualities.Unknown.value\n                }\n            )\n        }\n    }\n}\n\nclass BgwpCC : BigwarpIO() {\n    override var mainUrl = \"https://bgwp.cc\"\n}\n\nclass BigwarpArt : BigwarpIO() {\n    override var mainUrl = \"https://bigwarp.art\"\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Blogger.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\n\nopen class Blogger : ExtractorApi() {\n    override val name = \"Blogger\"\n    override val mainUrl = \"https://www.blogger.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val sources = mutableListOf<ExtractorLink>()\n        with(app.get(url).document) {\n            this.select(\"script\").map { script ->\n                if (script.data().contains(\"\\\"streams\\\":[\")) {\n                    val data = script.data().substringAfter(\"\\\"streams\\\":[\")\n                        .substringBefore(\"]\")\n                    tryParseJson<List<ResponseSource>>(\"[$data]\")?.map {\n                        sources.add(\n                            newExtractorLink(\n                                name,\n                                name,\n                                it.play_url,\n                            ) {\n                                this.referer = \"https://www.youtube.com/\"\n                                this.quality = when (it.format_id) {\n                                    18 -> 360\n                                    22 -> 720\n                                    else -> Qualities.Unknown.value\n                                }\n                            }\n                        )\n                    }\n                }\n            }\n        }\n        return sources\n    }\n\n    private data class ResponseSource(\n        @JsonProperty(\"play_url\") val play_url: String,\n        @JsonProperty(\"format_id\") val format_id: Int\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.Prerelease\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.base64DecodeArray\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport java.net.URI\nimport java.nio.charset.StandardCharsets\nimport javax.crypto.Cipher\nimport javax.crypto.spec.GCMParameterSpec\nimport javax.crypto.spec.SecretKeySpec\n\n@Prerelease\nclass Bysezejataos  : ByseSX() {\n    override var name = \"Bysezejataos\"\n    override var mainUrl = \"https://bysezejataos.com\"\n}\n\n@Prerelease\nclass ByseBuho : ByseSX() {\n    override var name = \"ByseBuho\"\n    override var mainUrl = \"https://bysebuho.com\"\n}\n\n@Prerelease\nclass ByseVepoin : ByseSX() {\n    override var name = \"ByseVepoin\"\n    override var mainUrl = \"https://bysevepoin.com\"\n}\n\n@Prerelease\nclass ByseQekaho : ByseSX() {\n    override var name = \"ByseQekaho\"\n    override var mainUrl = \"https://byseqekaho.com\"\n}\n\n@Prerelease\nopen class ByseSX : ExtractorApi() {\n    override var name = \"Byse\"\n    override var mainUrl = \"https://byse.sx\"\n    override val requiresReferer = true\n\n    private fun b64UrlDecode(s: String): ByteArray {\n        val fixed = s.replace('-', '+').replace('_', '/')\n        val pad = (4 - fixed.length % 4) % 4\n        return base64DecodeArray(fixed + \"=\".repeat(pad))\n    }\n\n    private fun getBaseUrl(url: String): String {\n        return URI(url).let { \"${it.scheme}://${it.host}\" }\n    }\n\n    private fun getCodeFromUrl(url: String): String {\n        val path = URI(url).path ?: \"\"\n        return path.trimEnd('/').substringAfterLast('/')\n    }\n\n    private suspend fun getDetails(mainUrl: String): DetailsRoot? {\n        val base = getBaseUrl(mainUrl)\n        val code = getCodeFromUrl(mainUrl)\n        val url = \"$base/api/videos/$code/embed/details\"\n        return app.get(url).parsedSafe<DetailsRoot>()\n    }\n\n    private suspend fun getPlayback(mainUrl: String): PlaybackRoot? {\n        val details = getDetails(mainUrl) ?: return null\n        val embedFrameUrl = details.embedFrameUrl\n        val embedBase = getBaseUrl(embedFrameUrl)\n        val code = getCodeFromUrl(embedFrameUrl)\n        val playbackUrl = \"$embedBase/api/videos/$code/embed/playback\"\n        val headers = mapOf(\n            \"accept\" to \"*/*\",\n            \"accept-language\" to \"en-US,en;q=0.5\",\n            \"priority\" to \"u=1, i\",\n            \"referer\" to embedFrameUrl,\n            \"x-embed-parent\" to mainUrl,\n        )\n        return app.get(playbackUrl, headers = headers).parsedSafe<PlaybackRoot>()\n    }\n\n    private fun buildAesKey(playback: Playback): ByteArray {\n        val p1 = b64UrlDecode(playback.keyParts[0])\n        val p2 = b64UrlDecode(playback.keyParts[1])\n        return p1 + p2\n    }\n\n    private fun decryptPlayback(playback: Playback): String? {\n        val keyBytes = buildAesKey(playback)\n        val ivBytes = b64UrlDecode(playback.iv)\n        val cipherBytes = b64UrlDecode(playback.payload)\n\n        val cipher = Cipher.getInstance(\"AES/GCM/NoPadding\")\n        val spec = GCMParameterSpec(128, ivBytes)\n        val secretKey = SecretKeySpec(keyBytes, \"AES\")\n        cipher.init(Cipher.DECRYPT_MODE, secretKey, spec)\n\n        val plainBytes = cipher.doFinal(cipherBytes)\n        var jsonStr = String(plainBytes, StandardCharsets.UTF_8)\n\n        if (jsonStr.startsWith(\"\\uFEFF\")) jsonStr = jsonStr.substring(1)\n\n        val root = try {\n            tryParseJson<PlaybackDecrypt>((jsonStr))\n        } catch (_: Exception) {\n            return null\n        }\n\n        return root?.sources?.firstOrNull()?.url\n    }\n\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val refererUrl = getBaseUrl(url)\n        val playbackRoot = getPlayback(url) ?: return\n        val streamUrl  = decryptPlayback(playbackRoot.playback) ?: return\n\n\n        val headers = mapOf(\"Referer\" to refererUrl)\n        M3u8Helper.generateM3u8(\n            name,\n            streamUrl,\n            mainUrl,\n            headers = headers\n        ).forEach(callback)\n    }\n}\n\ndata class DetailsRoot(\n    val id: Long,\n    val code: String,\n    val title: String,\n    @JsonProperty(\"poster_url\")\n    val posterUrl: String,\n    val description: String,\n    @JsonProperty(\"created_at\")\n    val createdAt: String,\n    @JsonProperty(\"owner_private\")\n    val ownerPrivate: Boolean,\n    @JsonProperty(\"embed_frame_url\")\n    val embedFrameUrl: String,\n)\n\ndata class PlaybackRoot(\n    val playback: Playback,\n)\n\ndata class Playback(\n    val algorithm: String,\n    val iv: String,\n    val payload: String,\n    @JsonProperty(\"key_parts\")\n    val keyParts: List<String>,\n    @JsonProperty(\"expires_at\")\n    val expiresAt: String,\n    @JsonProperty(\"decrypt_keys\")\n    val decryptKeys: DecryptKeys,\n    val iv2: String,\n    val payload2: String,\n)\n\ndata class DecryptKeys(\n    @JsonProperty(\"edge_1\")\n    val edge1: String,\n    @JsonProperty(\"edge_2\")\n    val edge2: String,\n    @JsonProperty(\"legacy_fallback\")\n    val legacyFallback: String,\n)\n\ndata class PlaybackDecrypt(\n    val sources: List<PlaybackDecryptSource>,\n)\n\ndata class PlaybackDecryptSource(\n    val quality: String,\n    val label: String,\n    @JsonProperty(\"mime_type\")\n    val mimeType: String,\n    val url: String,\n    @JsonProperty(\"bitrate_kbps\")\n    val bitrateKbps: Long,\n    val height: Any?,\n)\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Cda.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport java.net.URLDecoder\n\nopen class Cda : ExtractorApi() {\n    override var mainUrl = \"https://ebd.cda.pl\"\n    override var name = \"Cda\"\n    override val requiresReferer = false\n\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val mediaId = url\n            .split(\"/\").last()\n            .split(\"?\").first()\n        val doc = app.get(\n            \"https://ebd.cda.pl/647x500/$mediaId\", headers = mapOf(\n                \"Referer\" to \"https://ebd.cda.pl/647x500/$mediaId\",\n                \"User-Agent\" to USER_AGENT,\n                \"Cookie\" to \"cda.player=html5\"\n            )\n        ).document\n        val dataRaw = doc.selectFirst(\"[player_data]\")?.attr(\"player_data\") ?: return null\n        val playerData = tryParseJson<PlayerData>(dataRaw) ?: return null\n        return listOf(\n            newExtractorLink(\n                source = name,\n                name = name,\n                url = getFile(playerData.video.file),\n            ) {\n                this.referer = \"https://ebd.cda.pl/647x500/$mediaId\"\n                this.quality = Qualities.Unknown.value\n            }\n        )\n    }\n\n    private fun rot13(a: String): String {\n        return a.map {\n            when {\n                it in 'A'..'M' || it in 'a'..'m' -> it + 13\n                it in 'N'..'Z' || it in 'n'..'z' -> it - 13\n                else -> it\n            }\n        }.joinToString(\"\")\n    }\n\n    private fun cdaUggc(a: String): String {\n        val decoded = rot13(a)\n        return if (decoded.endsWith(\"adc.mp4\")) decoded.replace(\"adc.mp4\", \".mp4\")\n        else decoded\n    }\n\n    private fun cdaDecrypt(b: String): String {\n        var a = b\n            .replace(\"_XDDD\", \"\")\n            .replace(\"_CDA\", \"\")\n            .replace(\"_ADC\", \"\")\n            .replace(\"_CXD\", \"\")\n            .replace(\"_QWE\", \"\")\n            .replace(\"_Q5\", \"\")\n            .replace(\"_IKSDE\", \"\")\n        a = URLDecoder.decode(a, \"UTF-8\")\n        a = a.map { char ->\n            if (char.code in 33..126) {\n                return@map String.format(\"%c\", 33 + (char.code + 14) % 94)\n            } else {\n                return@map char\n            }\n        }.joinToString(\"\")\n        a = a\n            .replace(\".cda.mp4\", \"\")\n            .replace(\".2cda.pl\", \".cda.pl\")\n            .replace(\".3cda.pl\", \".cda.pl\")\n        return if (a.contains(\"/upstream\")) \"https://\" + a.replace(\"/upstream\", \".mp4/upstream\")\n        else \"https://${a}.mp4\"\n    }\n\n    private fun getFile(a: String) = when {\n        a.startsWith(\"uggc\") -> cdaUggc(a)\n        !a.startsWith(\"http\") -> cdaDecrypt(a)\n        else -> a\n    }\n\n    data class VideoPlayerData(\n        val file: String,\n        val qualities: Map<String, String> = mapOf(),\n        val quality: String?,\n        val ts: Int?,\n        val hash2: String?\n    )\n\n    data class PlayerData(\n        val video: VideoPlayerData\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/CineMMRedirect.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.loadExtractor\nimport okhttp3.HttpUrl.Companion.toHttpUrl\n\n// deobfuscated from https://hglink.to/main.js?v=1.1.3 using https://deobfuscate.io/\nprivate val mirrors = arrayOf(\n    \"hgplaycdn.com\",\n    \"habetar.com\",\n    \"yuguaab.com\",\n    \"guxhag.com\",\n    \"auvexiug.com\",\n    \"xenolyzb.com\",\n    \"haxloppd.com\",\n    \"cavanhabg.com\",\n    \"dumbalag.com\",\n    \"uasopt.com\"\n)\n\nclass HgplayCDN: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://hgplaycdn.com\"\n}\n\nclass Habetar: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://habetar.com\"\n}\n\nclass Yuguaab: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://yuguaab.com\"\n}\n\nclass Guxhag: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://guxhag.com\"\n}\n\nclass Auvexiug: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://auvexiug.com\"\n}\n\nclass Xenolyzb: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://xenolyzb.com\"\n}\n\nclass Haxloppd: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://haxloppd.com\"\n}\n\nclass Cavanhabg: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://cavanhabg.com\"\n}\n\nclass Dumbalag: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://dumbalag.com\"\n}\n\nclass Uasopt: VidHidePro() {\n    override val name: String = \"CineMM\"\n    override val mainUrl: String = \"https://uasopt.com\"\n}\n\nclass Dhcplay: CineMMRedirect() {\n    override val mainUrl: String = \"https://dhcplay.com\"\n}\n\nclass HglinkTo: CineMMRedirect() {\n    override val mainUrl: String = \"https://hglink.to\"\n}\n\n// These providers redirect to one of the other mirrors immediately,\n// i.e. they pick a random one of the links above\nabstract class CineMMRedirect : ExtractorApi() {\n    override val name: String = \"CineMMRedirect\"\n    override val requiresReferer: Boolean = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val videoId = url.toHttpUrl().encodedPath\n        val mirror = mirrors.random()\n\n        // re-use existing extractors by calling the ExtractorApi\n        // of the randomly selected mirror URL\n        val mirrorUrlWithVideoId = \"https://$mirror$videoId\"\n        loadExtractor(mirrorUrlWithVideoId, referer, subtitleCallback, callback)\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/CloudMailRuExtractor.kt",
    "content": "// ! Bu araç @Kraptor123 tarafından | @kekikanime için yazılmıştır.\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.base64Encode\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class CloudMailRu : ExtractorApi() {\n    override val name            = \"CloudMailRu\"\n    override val mainUrl         = \"https://cloud.mail.ru\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n//        Log.d(\"kraptor_${this.name}\",\"url = $url\")\n        val headers = mapOf(\n            \"Accept\" to \"*/*\",\n            \"Connection\" to \"keep-alive\",\n            \"Sec-Fetch-Dest\" to \"empty\",\n            \"Sec-Fetch-Mode\" to \"cors\",\n            \"Sec-Fetch-Site\" to \"cross-site\",\n            \"Origin\" to mainUrl,\n            \"User-Agent\" to USER_AGENT,\n        )\n        val vidId      = url.substringAfter(\"public/\").toByteArray()\n        val vidIdEnc   = base64Encode(vidId)\n        val videoReq   = app.get(url, headers=headers).text\n        val regex      = Regex(pattern = \"videowl_view\\\":\\\\{\\\"count\\\":\\\"1\\\",\\\"url\\\":\\\"([^\\\"]*)\\\"\\\\}\", options = setOf(RegexOption.IGNORE_CASE))\n        val videoMatch = regex.find(videoReq)?.groupValues?.get(1).toString()\n        val videoUrl   = \"$videoMatch/0p/$vidIdEnc.m3u8?double_encode=1\"\n//        Log.d(\"kraptor_${this.name}\",\"videoMatch = $videoMatch hani base64 = $vidIdEnc vidurl = $videoUrl\")\n\n\n        callback.invoke(\n            newExtractorLink(\n                source  = this.name,\n                name    = this.name,\n                url     = videoUrl,\n                type    = INFER_TYPE\n            ) {\n                this.referer = \"$mainUrl/\"\n                this.quality = Qualities.Unknown.value\n                this.headers = headers\n            }\n        )\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\n\nopen class ContentX : ExtractorApi() {\n    override val name            = \"ContentX\"\n    override val mainUrl         = \"https://contentx.me\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef   = referer ?: \"\"\n\n        val iSource  = app.get(url, referer=extRef).text\n        val iExtract = Regex(\"\"\"window\\.openPlayer\\('([^']+)'\"\"\").find(iSource)!!.groups[1]?.value ?: throw ErrorLoadingException(\"iExtract is null\")\n\n        val subUrls = mutableSetOf<String>()\n        Regex(\"\"\"\\\"file\\\":\\\"([^\\\"]+)\\\",\\\"label\\\":\\\"([^\\\"]+)\\\"\"\"\").findAll(iSource).forEach {\n            val (subUrl, subLang) = it.destructured\n\n            if (subUrl in subUrls) { return@forEach }\n            subUrls.add(subUrl)\n\n            subtitleCallback.invoke(\n                newSubtitleFile(\n                    lang = subLang.replace(\"\\\\u0131\", \"ı\").replace(\"\\\\u0130\", \"İ\").replace(\"\\\\u00fc\", \"ü\").replace(\"\\\\u00e7\", \"ç\"),\n                    url  = fixUrl(subUrl.replace(\"\\\\\", \"\"))\n                )\n            )\n        }\n\n        val vidSource  = app.get(\"${mainUrl}/source2.php?v=${iExtract}\", referer=extRef).text\n        val vidExtract = Regex(\"\"\"file\\\":\\\"([^\\\"]+)\"\"\").find(vidSource)!!.groups[1]?.value ?: throw ErrorLoadingException(\"vidExtract is null\")\n        val m3uLink    = vidExtract.replace(\"\\\\\", \"\")\n\n        callback.invoke(\n            newExtractorLink(\n                source  = this.name,\n                name    = this.name,\n                url     = m3uLink,\n                type = ExtractorLinkType.M3U8\n            ) {\n                this.referer = url\n                this.quality = Qualities.Unknown.value\n            }\n        )\n\n        val iDublaj = Regex(\"\"\",\\\"([^']+)\\\",\\\"Türkçe\"\"\").find(iSource)!!.groups[1]?.value\n        if (iDublaj != null) {\n            val dublajSource  = app.get(\"${mainUrl}/source2.php?v=${iDublaj}\", referer=extRef).text\n            val dublajExtract = Regex(\"\"\"file\\\":\\\"([^\\\"]+)\"\"\").find(dublajSource)!!.groups[1]?.value ?: throw ErrorLoadingException(\"dublajExtract is null\")\n            val dublajLink    = dublajExtract.replace(\"\\\\\", \"\")\n\n            callback.invoke(\n                newExtractorLink(\n                    source  = \"${this.name} Türkçe Dublaj\",\n                    name    = \"${this.name} Türkçe Dublaj\",\n                    url     = dublajLink,\n                    type = ExtractorLinkType.M3U8\n                ) {\n                    this.referer = url\n                    this.quality = Qualities.Unknown.value\n                }\n            )\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Dailymotion.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.google.gson.Gson\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8\nimport java.net.URI\n\n\n\nclass Geodailymotion : Dailymotion() {\n    override val name = \"GeoDailymotion\"\n    override val mainUrl = \"https://geo.dailymotion.com\"\n}\n\nopen class Dailymotion : ExtractorApi() {\n    override val mainUrl = \"https://www.dailymotion.com\"\n    override val name = \"Dailymotion\"\n    override val requiresReferer = false\n    private val baseUrl = \"https://www.dailymotion.com\"\n\n    private val videoIdRegex = \"^[kx][a-zA-Z0-9]+$\".toRegex()\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val embedUrl = getEmbedUrl(url) ?: return\n        val id = getVideoId(embedUrl) ?: return\n        val metaDataUrl = \"$baseUrl/player/metadata/video/$id\"\n\n        val response = app.get(metaDataUrl, referer = embedUrl).text\n        val gson = Gson()\n        val meta = gson.fromJson(response, MetaData::class.java)\n\n        meta.qualities?.get(\"auto\")?.forEach { quality ->\n            val videoUrl = quality.url\n            if (!videoUrl.isNullOrEmpty() && videoUrl.contains(\".m3u8\")) {\n                getStream(videoUrl, this.name, callback)\n            }\n        }\n\n        meta.subtitles?.data?.forEach { (_, subData) ->\n            subData.urls.forEach { subUrl ->\n                subtitleCallback(\n                    newSubtitleFile(\n                        subData.label,\n                        subUrl\n                    )\n                )\n            }\n        }\n    }\n\n\n    private fun getEmbedUrl(url: String): String? {\n        if (url.contains(\"/embed/\") || url.contains(\"/video/\")) return url\n        if (url.contains(\"geo.dailymotion.com\")) {\n            val videoId = url.substringAfter(\"video=\")\n            return \"$baseUrl/embed/video/$videoId\"\n        }\n        return null\n    }\n\n\n    private fun getVideoId(url: String): String? {\n        val path = URI(url).path\n        val id = path.substringAfter(\"/video/\")\n        return if (id.matches(videoIdRegex)) id else null\n    }\n\n    private suspend fun getStream(\n        streamLink: String,\n        name: String,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        return generateM3u8(name, streamLink, \"\").forEach(callback)\n    }\n\n\n    data class MetaData(\n        val qualities: Map<String, List<Quality>>?,\n        val subtitles: SubtitlesWrapper?\n    )\n\n    data class Quality(\n        val type: String?,\n        val url: String?\n    )\n\n    data class SubtitlesWrapper(\n        val enable: Boolean,\n        val data: Map<String, SubtitleData>?\n    )\n\n    data class SubtitleData(\n        val label: String,\n        val urls: List<String>\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/DoodExtractor.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport java.net.URI\n\nclass Doodspro : DoodLaExtractor() {\n    override var mainUrl = \"https://doods.pro\"\n}\n\nclass Dsvplay : DoodLaExtractor() {\n    override var mainUrl = \"https://dsvplay.com\"\n}\n\nclass D0000d : DoodLaExtractor() {\n    override var mainUrl = \"https://d0000d.com\"\n}\n\nclass D000dCom : DoodLaExtractor() {\n    override var mainUrl = \"https://d000d.com\"\n}\n\nclass DoodstreamCom : DoodLaExtractor() {\n    override var mainUrl = \"https://doodstream.com\"\n}\n\nclass Dooood : DoodLaExtractor() {\n    override var mainUrl = \"https://dooood.com\"\n}\n\nclass DoodWfExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.wf\"\n}\n\nclass DoodCxExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.cx\"\n}\n\nclass DoodShExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.sh\"\n}\nclass DoodWatchExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.watch\"\n}\n\nclass DoodPmExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.pm\"\n}\n\nclass DoodToExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.to\"\n}\n\nclass DoodSoExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.so\"\n}\n\nclass DoodWsExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.ws\"\n}\n\nclass DoodYtExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.yt\"\n}\n\nclass DoodLiExtractor : DoodLaExtractor() {\n    override var mainUrl = \"https://dood.li\"\n}\n\nclass Ds2play : DoodLaExtractor() {\n    override var mainUrl = \"https://ds2play.com\"\n}\n\nclass Ds2video : DoodLaExtractor() {\n    override var mainUrl = \"https://ds2video.com\"\n}\n\nclass Vide0Net: DoodLaExtractor() {\n    override var mainUrl = \"https://vide0.net\"\n}\n\nclass MyVidPlay : DoodLaExtractor() {\n    override var mainUrl = \"https://myvidplay.com\"\n}\n\nopen class DoodLaExtractor : ExtractorApi() {\n    override var name = \"DoodStream\"\n    override var mainUrl = \"https://dood.la\"\n    override val requiresReferer = false\n\n    private val alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val embedUrl = url.replace(\"/d/\", \"/e/\")\n        val req = app.get(embedUrl)\n        val host = getBaseUrl(req.url)\n        val response0 = req.text\n        val md5 = host + (Regex(\"/pass_md5/[^']*\").find(response0)?.value ?: return)\n        val trueUrl = app.get(md5, referer = req.url).text + createHashTable() + \"?token=\" + md5.substringAfterLast(\"/\")\n        val quality = Regex(\"\\\\d{3,4}p\")\n            .find(response0.substringAfter(\"<title>\").substringBefore(\"</title>\"))\n            ?.groupValues\n            ?.getOrNull(0)\n\n        callback.invoke(\n            newExtractorLink(\n                this.name,\n                this.name,\n                trueUrl,\n            ) {\n                this.referer = \"$mainUrl/\"\n                this.quality = getQualityFromName(quality)\n            }\n        )\n    }\n\n    private fun createHashTable(): String {\n        return buildString {\n            repeat(10) {\n                append(alphabet.random())\n            }\n        }\n    }\n\n    private fun getBaseUrl(url: String): String {\n        return URI(url).let {\n            \"${it.scheme}://${it.host}\"\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Embedgram.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.httpsify\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Embedgram : ExtractorApi() {\n    override val name = \"Embedgram\"\n    override val mainUrl = \"https://embedgram.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val document = app.get(url, referer = referer).document\n        val link = document.select(\"video source:last-child\").attr(\"src\")\n        val quality = document.select(\"video source:last-child\").attr(\"title\")\n        callback.invoke(\n            newExtractorLink(\n                this.name,\n                this.name,\n                httpsify(link),\n            ) {\n                this.referer = \"$mainUrl/\"\n                this.quality = getQualityFromName(quality)\n                this.headers = mapOf(\n                    \"Range\" to \"bytes=0-\"\n                )\n            }\n        )\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/EmturbovidExtractor.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class EmturbovidExtractor : ExtractorApi() {\n    override var name = \"Emturbovid\"\n    override var mainUrl = \"https://emturbovid.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val response = app.get(\n            url, referer = referer ?: \"$mainUrl/\"\n        )\n        val playerScript =\n            response.document.selectXpath(\"//script[contains(text(),'var urlPlay')]\")\n                .html()\n\n        val sources = mutableListOf<ExtractorLink>()\n        if (playerScript.isNotBlank()) {\n            val m3u8Url =\n                playerScript.substringAfter(\"var urlPlay = '\").substringBefore(\"'\")\n\n            sources.add(\n                newExtractorLink(\n                    source = name,\n                    name = name,\n                    url = m3u8Url,\n                    type = ExtractorLinkType.M3U8\n                ) {\n                    this.referer = \"$mainUrl/\"\n                    this.quality = Qualities.Unknown.value\n                }\n            )\n        }\n        return sources\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Evolaod.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.app\n\nclass Evoload1 : Evoload() {\n    override var mainUrl = \"https://evoload.io\"\n}\n\nopen class Evoload : ExtractorApi() {\n    override val name: String = \"Evoload\"\n    override val mainUrl: String = \"https://www.evoload.io\"\n    //private val srcRegex = Regex(\"\"\"video .*src=\"(.*)\"\"\"\"\")  // would be possible to use the parse and find src attribute\n    override val requiresReferer = true\n\n\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val id = url.replace(\"https://evoload.io/e/\", \"\")  // wanted media id\n        val csrv_token = app.get(\"https://csrv.evosrv.com/captcha?m412548=\").text  // whatever that is\n        val captchaPass = app.get(\"https://cd2.evosrv.com/html/jsx/e.jsx\").text.take(300).split(\"captcha_pass = '\")[1].split(\"\\'\")[0]  //extract the captcha pass from the js response (located in the 300 first chars)\n        val payload = mapOf(\"code\" to id, \"csrv_token\" to csrv_token, \"pass\" to captchaPass)\n        val r = app.post(\"https://evoload.io/SecurePlayer\", data=(payload)).text\n        val link = Regex(\"src\\\":\\\"(.*?)\\\"\").find(r)?.destructured?.component1() ?: return listOf()\n        return listOf(\n            newExtractorLink(\n                name,\n                name,\n                link,\n            ) {\n                this.referer = url\n                this.quality = Qualities.Unknown.value\n            }\n        )\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Fastream.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8\nimport com.lagradost.cloudstream3.utils.getAndUnpack\nimport org.jsoup.nodes.Document\n\nopen class Fastream: ExtractorApi() {\n    override var mainUrl = \"https://fastream.to\"\n    override var name = \"Fastream\"\n    override val requiresReferer = false\n    suspend fun getstream(\n        response: Document,\n        sources: ArrayList<ExtractorLink>): Boolean{\n        response.select(\"script\").amap { script ->\n            if (script.data().contains(Regex(\"eval\\\\(function\\\\(p,a,c,k,e,[rd]\"))) {\n                val unpacked = getAndUnpack(script.data())\n                //val m3u8regex = Regex(\"((https:|http:)\\\\/\\\\/.*\\\\.m3u8)\")\n                val newm3u8link = unpacked.substringAfter(\"file:\\\"\").substringBefore(\"\\\"\")\n                //val m3u8link = m3u8regex.find(unpacked)?.value ?: return@forEach\n                generateM3u8(\n                    name,\n                    newm3u8link,\n                    mainUrl\n                ).forEach { link ->\n                    sources.add(link)\n                }\n            }\n        }\n        return true\n    }\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val sources = ArrayList<ExtractorLink>()\n        val idregex = Regex(\"emb.html\\\\?(.*)=\")\n        if (url.contains(Regex(\"(emb.html.*fastream)\"))) {\n            val id = idregex.find(url)?.destructured?.component1() ?: \"\"\n            val response = app.post(\"https://fastream.to/dl\", allowRedirects = false,\n                data = mapOf(\n                    \"op\" to \"embed\",\n                    \"file_code\" to id,\n                    \"auto\" to \"1\"\n                )\n            ).document\n            getstream(response, sources)\n        }\n        val response = app.get(url, referer = url).document\n        getstream(response, sources)\n        return sources\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Filemoon.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.network.WebViewResolver\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.JsUnpacker\nimport com.lagradost.cloudstream3.utils.M3u8Helper\n\n\nclass FileMoon : FilemoonV2() {\n    override var mainUrl = \"https://filemoon.to\"\n    override var name = \"FileMoon\"\n}\n\nclass FileMoonIn : FilemoonV2() {\n    override var mainUrl = \"https://filemoon.in\"\n    override var name = \"FileMoon\"\n}\n\nclass FileMoonSx : FilemoonV2() {\n    override var mainUrl = \"https://filemoon.sx\"\n    override var name = \"FileMoonSx\"\n}\n\n\nopen class FilemoonV2 : ExtractorApi() {\n    override var name = \"Filemoon\"\n    override var mainUrl = \"https://filemoon.to\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val defaultHeaders = mapOf(\n            \"Referer\" to url,\n            \"Sec-Fetch-Dest\" to \"iframe\",\n            \"Sec-Fetch-Mode\" to \"navigate\",\n            \"Sec-Fetch-Site\" to \"cross-site\",\n            \"User-Agent\" to \"Mozilla/5.0 (X11; Linux x86_64; rv:137.0) Gecko/20100101 Firefox/137.0\"\n        )\n\n        val initialResponse = app.get(url, defaultHeaders)\n        val iframeSrcUrl = initialResponse.document.selectFirst(\"iframe\")?.attr(\"src\")\n\n        if (iframeSrcUrl.isNullOrEmpty()) {\n            val fallbackScriptData = initialResponse.document\n                .selectFirst(\"script:containsData(function(p,a,c,k,e,d))\")\n                ?.data().orEmpty()\n            val unpackedScript = JsUnpacker(fallbackScriptData).unpack()\n\n            val videoUrl = unpackedScript?.let {\n                Regex(\"\"\"sources:\\[\\{file:\"(.*?)\"\"\"\").find(it)?.groupValues?.get(1)\n            }\n\n            if (!videoUrl.isNullOrEmpty()) {\n                M3u8Helper.generateM3u8(\n                    name,\n                    videoUrl,\n                    mainUrl,\n                    headers = defaultHeaders\n                ).forEach(callback)\n            } else {\n                Log.d(\"FilemoonV2\", \"No iframe and no video URL found in script fallback.\")\n            }\n            return\n        }\n\n        // If iframe was found, continue processing\n        val iframeHeaders = defaultHeaders + (\"Accept-Language\" to \"en-US,en;q=0.5\")\n        val iframeResponse = app.get(iframeSrcUrl, headers = iframeHeaders)\n\n        val iframeScriptData = iframeResponse.document\n            .selectFirst(\"script:containsData(function(p,a,c,k,e,d))\")\n            ?.data().orEmpty()\n\n        val unpackedScript = JsUnpacker(iframeScriptData).unpack()\n\n        val videoUrl = unpackedScript?.let {\n            Regex(\"\"\"sources:\\[\\{file:\"(.*?)\"\"\"\").find(it)?.groupValues?.get(1)\n        }\n\n        if (!videoUrl.isNullOrEmpty()) {\n            M3u8Helper.generateM3u8(\n                name,\n                videoUrl,\n                mainUrl,\n                headers = defaultHeaders\n            ).forEach(callback)\n        } else {\n            // Last-resort fallback using WebView interception\n            val resolver = WebViewResolver(\n                interceptUrl = Regex(\"\"\"(m3u8|master\\.txt)\"\"\"),\n                additionalUrls = listOf(Regex(\"\"\"(m3u8|master\\.txt)\"\"\")),\n                useOkhttp = false,\n                timeout = 15_000L\n            )\n\n            val interceptedUrl = app.get(\n                iframeSrcUrl,\n                referer = referer,\n                interceptor = resolver\n            ).url\n\n            if (interceptedUrl.isNotEmpty()) {\n                M3u8Helper.generateM3u8(\n                    name,\n                    interceptedUrl,\n                    mainUrl,\n                    headers = defaultHeaders\n                ).forEach(callback)\n            } else {\n                Log.d(\"FilemoonV2\", \"No video URL intercepted in WebView fallback.\")\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Filesim.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.network.WebViewResolver\n\nclass Multimoviesshg : Filesim() {\n    override var mainUrl = \"https://multimoviesshg.com\"\n}\n\nclass Guccihide : Filesim() {\n    override val name = \"Guccihide\"\n    override var mainUrl = \"https://guccihide.com\"\n}\n\nclass Ahvsh : Filesim() {\n    override val name = \"Ahvsh\"\n    override var mainUrl = \"https://ahvsh.com\"\n}\n\nclass Moviesm4u : Filesim() {\n    override val mainUrl = \"https://moviesm4u.com\"\n    override val name = \"Moviesm4u\"\n}\n\nclass StreamhideTo : Filesim() {\n    override val mainUrl = \"https://streamhide.to\"\n    override val name = \"Streamhide\"\n}\n\nclass StreamhideCom : Filesim() {\n    override var name: String = \"Streamhide\"\n    override var mainUrl: String = \"https://streamhide.com\"\n}\n\nclass Movhide : Filesim() {\n    override var name: String = \"Movhide\"\n    override var mainUrl: String = \"https://movhide.pro\"\n}\n\nclass Ztreamhub : Filesim() {\n    override val mainUrl: String = \"https://ztreamhub.com\" //Here 'cause works\n    override val name = \"Zstreamhub\"\n}\n\nopen class Filesim : ExtractorApi() {\n    override val name = \"Filesim\"\n    override val mainUrl = \"https://files.im\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val embedUrl = url.replace(\"/download/\", \"/e/\")\n        var pageResponse = app.get(embedUrl, referer = referer)\n\n        val iframeElement = pageResponse.document.selectFirst(\"iframe\")\n        if (iframeElement != null) {\n            val iframeUrl = iframeElement.attr(\"src\")\n            pageResponse = app.get(\n                iframeUrl,\n                headers = mapOf(\n                    \"Accept-Language\" to \"en-US,en;q=0.5\",\n                    \"Sec-Fetch-Dest\" to \"iframe\"\n                ),\n                referer = pageResponse.url\n            )\n        }\n\n        val scriptData = if (!getPacked(pageResponse.text).isNullOrEmpty()) {\n            getAndUnpack(pageResponse.text)\n        } else {\n            pageResponse.document.selectFirst(\"script:containsData(sources:)\")?.data()\n        }\n\n        val m3u8Url = scriptData?.let {\n            Regex(\"\"\"file:\\s*\"(.*?m3u8.*?)\"\"\"\").find(it)?.groupValues?.getOrNull(1)\n        }\n\n        if (!m3u8Url.isNullOrEmpty()) {\n            M3u8Helper.generateM3u8(\n                name,\n                m3u8Url,\n                mainUrl\n            ).forEach(callback)\n        } else {\n            // Fallback using WebViewResolver\n            val resolver = WebViewResolver(\n                interceptUrl = Regex(\"\"\"(m3u8|master\\.txt)\"\"\"),\n                additionalUrls = listOf(Regex(\"\"\"(m3u8|master\\.txt)\"\"\")),\n                useOkhttp = false,\n                timeout = 15_000L\n            )\n\n            val interceptedUrl = app.get(\n                url = pageResponse.url,\n                referer = referer,\n                interceptor = resolver\n            ).url\n\n            if (interceptedUrl.isNotEmpty()) {\n                M3u8Helper.generateM3u8(\n                    name,\n                    interceptedUrl,\n                    mainUrl\n                ).forEach(callback)\n            } else {\n                Log.d(\"Filesim\", \"No m3u8 found via script or WebView fallback.\")\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GDMirrorbot.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.google.gson.JsonParser\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.base64Decode\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.loadExtractor\nimport java.net.URI\n\nclass Techinmind: GDMirrorbot() {\n    override var name = \"Techinmind Cloud AIO\"\n    override var mainUrl = \"https://stream.techinmind.space\"\n    override var requiresReferer = true\n}\n\nopen class GDMirrorbot : ExtractorApi() {\n    override var name = \"GDMirrorbot\"\n    override var mainUrl = \"https://gdmirrorbot.nl\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val (sid, host) = if (!url.contains(\"key=\")) {\n            Pair(url.substringAfterLast(\"embed/\"), getBaseUrl(app.get(url).url))\n        } else {\n            var pageText = app.get(url).text\n            val finalId = Regex(\"\"\"FinalID\\s*=\\s*\"([^\"]+)\"\"\"\").find(pageText)?.groupValues?.get(1)\n            val myKey = Regex(\"\"\"myKey\\s*=\\s*\"([^\"]+)\"\"\"\").find(pageText)?.groupValues?.get(1)\n            val idType = Regex(\"\"\"idType\\s*=\\s*\"([^\"]+)\"\"\"\").find(pageText)?.groupValues?.get(1) ?: \"imdbid\"\n            val baseUrl = Regex(\"\"\"let\\s+baseUrl\\s*=\\s*\"([^\"]+)\"\"\"\").find(pageText)?.groupValues?.get(1)\n            val hostUrl = baseUrl?.let { getBaseUrl(it) }\n\n            if (finalId != null && myKey != null) {\n                val apiUrl = if (url.contains(\"/tv/\")) {\n                    val season = Regex(\"\"\"/tv/\\d+/(\\d+)/\"\"\").find(url)?.groupValues?.get(1) ?: \"1\"\n                    val episode = Regex(\"\"\"/tv/\\d+/\\d+/(\\d+)\"\"\").find(url)?.groupValues?.get(1) ?: \"1\"\n                    \"$mainUrl/myseriesapi?tmdbid=$finalId&season=$season&epname=$episode&key=$myKey\"\n                } else {\n                    \"$mainUrl/mymovieapi?$idType=$finalId&key=$myKey\"\n                }\n                pageText = app.get(apiUrl).text\n            }\n\n            val jsonElement = JsonParser.parseString(pageText)\n            if (!jsonElement.isJsonObject) return\n            val jsonObject = jsonElement.asJsonObject\n\n            val embedId = url.substringAfterLast(\"/\")\n            val sidValue = jsonObject[\"data\"]?.asJsonArray\n                ?.takeIf { it.size() > 0 }\n                ?.get(0)?.asJsonObject\n                ?.get(\"fileslug\")?.asString\n                ?.takeIf { it.isNotBlank() } ?: embedId\n\n            Pair(sidValue, hostUrl)\n        }\n\n        val postData = mapOf(\"sid\" to sid)\n        val responseText = app.post(\"$host/embedhelper.php\", data = postData).text\n\n        val rootElement = JsonParser.parseString(responseText)\n        if (!rootElement.isJsonObject) return\n        val root = rootElement.asJsonObject\n\n        val siteUrls = root[\"siteUrls\"]?.asJsonObject ?: return\n        val siteFriendlyNames = root[\"siteFriendlyNames\"]?.asJsonObject\n\n        val decodedMresult = when {\n            root[\"mresult\"]?.isJsonObject == true -> root[\"mresult\"]!!.asJsonObject\n            root[\"mresult\"]?.isJsonPrimitive == true -> try {\n                base64Decode(root[\"mresult\"]!!.asString)\n                    .let { JsonParser.parseString(it).asJsonObject }\n            } catch (e: Exception) {\n                Log.e(\"GDMirrorbot\", \"Failed to decode mresult: $e\")\n                return\n            }\n            else -> return\n        }\n\n        siteUrls.keySet().intersect(decodedMresult.keySet()).forEach { key ->\n            val base = siteUrls[key]?.asString?.trimEnd('/') ?: return@forEach\n            val path = decodedMresult[key]?.asString?.trimStart('/') ?: return@forEach\n            val fullUrl = \"$base/$path\"\n            val friendlyName = siteFriendlyNames?.get(key)?.asString ?: key\n\n            try {\n                when (friendlyName) {\n                    \"StreamHG\",\"EarnVids\" -> VidHidePro().getUrl(fullUrl, referer, subtitleCallback, callback)\n                    \"RpmShare\", \"UpnShare\", \"StreamP2p\" -> VidStack().getUrl(fullUrl, referer, subtitleCallback, callback)\n                    else -> loadExtractor(fullUrl, referer ?: mainUrl, subtitleCallback, callback)\n                }\n            } catch (e: Exception) {\n                Log.e(\"GDMirrorbot\", \"Failed to extract from $friendlyName at $fullUrl: $e\")\n            }\n        }\n    }\n\n    private fun getBaseUrl(url: String): String {\n        return URI(url).let { \"${it.scheme}://${it.host}\" }\n    }\n}\n\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GUpload.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.base64Decode\nimport com.lagradost.cloudstream3.utils.AppUtils\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class GUpload: ExtractorApi() {\n    override val name: String = \"GUpload\"\n    override val mainUrl: String = \"https://gupload.xyz\"\n    override val requiresReferer: Boolean = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val response = app.get(url, referer = referer).text\n\n        val playerConfigEncoded = response.substringAfter(\"decodePayload('\").substringBefore(\"');\")\n        val playerConfigString = base64Decode(playerConfigEncoded).substringAfter(\"|\")\n\n        val playerConfig = AppUtils.parseJson<VideoInfo>(playerConfigString)\n\n        callback.invoke(\n            newExtractorLink(\n                source = name,\n                name = name,\n                url = playerConfig.videoUrl.replace(\"\\\\\", \"\"),\n            ) {\n                Regex(\"/(\\\\d+p)\\\\.\").find(playerConfig.videoUrl)?.groupValues?.get(1)?.let {\n                    quality = getQualityFromName(it)\n                }\n            }\n        )\n    }\n\n    private data class VideoInfo(\n        @JsonProperty(\"videoUrl\") val videoUrl: String,\n        @JsonProperty(\"posterUrl\") val posterUrl: String? = null,\n        @JsonProperty(\"videoId\") val videoId: String? = null,\n        @JsonProperty(\"primaryColor\") val primaryColor: String? = null,\n        @JsonProperty(\"audioTracks\") val audioTracks: List<Any?> = emptyList(),\n        @JsonProperty(\"subtitleTracks\") val subtitleTracks: List<Any?> = emptyList(),\n        @JsonProperty(\"vastFallbackList\") val vastFallbackList: List<String> = emptyList(),\n        @JsonProperty(\"videoOwnerId\") val videoOwnerId: Long = 0,\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GamoVideo.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\n\n\nopen class GamoVideo : ExtractorApi() {\n    override val name = \"GamoVideo\"\n    override val mainUrl = \"https://gamovideo.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?\n    ): List<ExtractorLink>? {\n        return app.get(url, referer = referer).document.select(\"script\")\n            .firstOrNull { it.html().contains(\"sources:\") }!!.html().substringAfter(\"file: \\\"\")\n            .substringBefore(\"\\\",\").let {\n            listOf(\n                newExtractorLink(\n                    name,\n                    name,\n                    it,\n                ) {\n                    this.referer = url\n                    this.quality = Qualities.Unknown.value\n                }\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gdriveplayer.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport org.jsoup.nodes.Element\n\nclass DatabaseGdrive2 : Gdriveplayer() {\n    override var mainUrl = \"https://databasegdriveplayer.co\"\n}\n\nclass DatabaseGdrive : Gdriveplayer() {\n    override var mainUrl = \"https://series.databasegdriveplayer.co\"\n}\n\nclass Gdriveplayerapi : Gdriveplayer() {\n    override val mainUrl: String = \"https://gdriveplayerapi.com\"\n}\n\nclass Gdriveplayerapp : Gdriveplayer() {\n    override val mainUrl: String = \"https://gdriveplayer.app\"\n}\n\nclass Gdriveplayerfun : Gdriveplayer() {\n    override val mainUrl: String = \"https://gdriveplayer.fun\"\n}\n\nclass Gdriveplayerio : Gdriveplayer() {\n    override val mainUrl: String = \"https://gdriveplayer.io\"\n}\n\nclass Gdriveplayerme : Gdriveplayer() {\n    override val mainUrl: String = \"https://gdriveplayer.me\"\n}\n\nclass Gdriveplayerbiz : Gdriveplayer() {\n    override val mainUrl: String = \"https://gdriveplayer.biz\"\n}\n\nclass Gdriveplayerorg : Gdriveplayer() {\n    override val mainUrl: String = \"https://gdriveplayer.org\"\n}\n\nclass Gdriveplayerus : Gdriveplayer() {\n    override val mainUrl: String = \"https://gdriveplayer.us\"\n}\n\nclass Gdriveplayerco : Gdriveplayer() {\n    override val mainUrl: String = \"https://gdriveplayer.co\"\n}\n\nopen class Gdriveplayer : ExtractorApi() {\n    override val name = \"Gdrive\"\n    override val mainUrl = \"https://gdriveplayer.to\"\n    override val requiresReferer = false\n\n    private fun unpackJs(script: Element): String? {\n        return script.select(\"script\").find { it.data().contains(\"eval(function(p,a,c,k,e,d)\") }\n            ?.data()?.let { getAndUnpack(it) }\n    }\n\n    private fun Regex.first(str: String): String? {\n        return find(str)?.groupValues?.getOrNull(1)\n    }\n\n    private fun String.addMarks(str: String): String {\n        return this.replace(Regex(\"\\\"?$str\\\"?\"), \"\\\"$str\\\"\")\n    }\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val document = app.get(url).document\n\n        val eval = unpackJs(document)?.replace(\"\\\\\", \"\") ?: return\n        val data = Regex(\"data='(\\\\S+?)'\").first(eval) ?: return\n        val password = Regex(\"null,['|\\\"](\\\\w+)['|\\\"]\").first(eval)\n            ?.split(Regex(\"\\\\D+\"))\n            ?.joinToString(\"\") {\n                Char(it.toInt()).toString()\n            }.let { Regex(\"var pass = \\\"(\\\\S+?)\\\"\").first(it ?: return)?.toByteArray() }\n            ?: throw ErrorLoadingException(\"can't find password\")\n        val decryptedData = cryptoAESHandler(data, password, false, \"AES/CBC/NoPadding\")?.let { getAndUnpack(it) }?.replace(\"\\\\\", \"\")\n\n        val sourceData = decryptedData?.substringAfter(\"sources:[\")?.substringBefore(\"],\")\n        val subData = decryptedData?.substringAfter(\"tracks:[\")?.substringBefore(\"],\")\n\n        Regex(\"\\\"file\\\":\\\"(\\\\S+?)\\\".*?res=(\\\\d+)\").findAll(sourceData ?: return).map {\n            it.groupValues[1] to it.groupValues[2]\n        }.toList().distinctBy { it.second }.map { (link, quality) ->\n            callback.invoke(\n                newExtractorLink(\n                    source = this.name,\n                    name = this.name,\n                    url = \"${httpsify(link)}&res=$quality\",\n                ) {\n                    this.referer = mainUrl\n                    this.quality = quality.toIntOrNull() ?: Qualities.Unknown.value\n                    this.headers = mapOf(\"Range\" to \"bytes=0-\")\n                }\n            )\n        }\n\n        subData?.addMarks(\"file\")?.addMarks(\"kind\")?.addMarks(\"label\").let { dataSub ->\n            tryParseJson<List<Tracks>>(\"[$dataSub]\")?.map { sub ->\n                subtitleCallback.invoke(\n                    newSubtitleFile(\n                        sub.label,\n                        httpsify(sub.file)\n                    )\n                )\n            }\n        }\n\n    }\n\n    data class Tracks(\n        @JsonProperty(\"file\") val file: String,\n        @JsonProperty(\"kind\") val kind: String,\n        @JsonProperty(\"label\") val label: String\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GenericM3U8.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.network.WebViewResolver\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\n\n\nopen class GenericM3U8 : ExtractorApi() {\n    override var name = \"Upstream\"\n    override var mainUrl = \"https://upstream.to\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val response = app.get(\n            url, interceptor = WebViewResolver(\n                Regex(\"\"\"master\\.m3u8\"\"\")\n            )\n        )\n        val sources = mutableListOf<ExtractorLink>()\n        if (response.url.contains(\"m3u8\"))\n            M3u8Helper.generateM3u8(\n                name,\n                response.url,\n                url,\n                headers = response.headers.toMap()\n            ).forEach { link ->\n                sources.add(link)\n            }\n        return sources\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gofile.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Gofile : ExtractorApi() {\n    override val name = \"Gofile\"\n    override val mainUrl = \"https://gofile.io\"\n    override val requiresReferer = false\n    private val mainApi = \"https://api.gofile.io\"\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val id = Regex(\"/(?:\\\\?c=|d/)([\\\\da-zA-Z-]+)\").find(url)?.groupValues?.get(1) ?: return\n\n        val token = app.post(\n            \"$mainApi/accounts\",\n        ).parsedSafe<AccountResponse>()?.data?.token ?: return\n\n        val globalRes = app.get(\"$mainUrl/dist/js/config.js\").text\n        val wt = Regex(\"\"\"appdata\\.wt\\s*=\\s*[\\\"']([^\\\"']+)[\\\"']\"\"\").find(globalRes)?.groupValues?.get(1) ?: return\n\n        val headers = mapOf(\n            \"Authorization\" to \"Bearer $token\",\n            \"X-Website-Token\" to wt\n        )\n\n        val parsedResponse = app.get(\n            \"$mainApi/contents/$id?contentFilter=&page=1&pageSize=1000&sortField=name&sortDirection=1\",\n            headers = headers\n        ).parsedSafe<GofileResponse>()\n\n        val childrenMap = parsedResponse?.data?.children ?: return\n\n        for ((_, file) in childrenMap) {\n            if (file.link.isNullOrEmpty() || file.type != \"file\") continue\n            val fileName = file.name ?: \"\"\n            val size = file.size ?: 0L\n            val formattedSize = formatBytes(size)\n\n            callback.invoke(\n                newExtractorLink(\n                    \"Gofile\",\n                    \"[Gofile] $fileName [$formattedSize]\",\n                    file.link,\n                    ExtractorLinkType.VIDEO\n                ) {\n                    this.quality = getQuality(fileName)\n                    this.headers = mapOf(\"Cookie\" to \"accountToken=$token\")\n                }\n            )\n        }\n    }\n\n    private fun getQuality(str: String?): Int {\n        return Regex(\"(\\\\d{3,4})[pP]\").find(str ?: \"\")?.groupValues?.getOrNull(1)?.toIntOrNull()\n            ?: Qualities.Unknown.value\n    }\n\n    private fun formatBytes(bytes: Long): String {\n        return when {\n            bytes < 1024L * 1024 * 1024 -> \"%.2f MB\".format(bytes.toDouble() / (1024 * 1024))\n            else -> \"%.2f GB\".format(bytes.toDouble() / (1024 * 1024 * 1024))\n        }\n    }\n\n    data class AccountResponse(\n        @JsonProperty(\"data\") val data: AccountData? = null\n    )\n\n    data class AccountData(\n        @JsonProperty(\"token\") val token: String? = null\n    )\n\n    data class GofileResponse(\n        @JsonProperty(\"data\") val data: GofileData? = null\n    )\n\n    data class GofileData(\n        @JsonProperty(\"children\") val children: Map<String, GofileFile>? = null\n    )\n\n    data class GofileFile(\n        @JsonProperty(\"type\") val type: String? = null,\n        @JsonProperty(\"name\") val name: String? = null,\n        @JsonProperty(\"link\") val link: String? = null,\n        @JsonProperty(\"size\") val size: Long? = 0L\n    )\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GoodstreamExtractor.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass GoodstreamExtractor : ExtractorApi() {\n    override var name = \"Goodstream\"\n    override val mainUrl = \"https://goodstream.uno\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        app.get(url).document.select(\"script\").map { script ->\n            if (script.data().contains(Regex(\"file|player\"))) {\n                val urlRegex = Regex(\"file: \\\"(https:\\\\/\\\\/[a-z0-9.\\\\/-_?=&]+)\\\",\")\n                urlRegex.find(script.data())?.groupValues?.get(1).let { link ->\n                    callback.invoke(\n                        newExtractorLink(\n                            name,\n                            name,\n                            link!!,\n                        ) {\n                            this.referer = mainUrl\n                        }\n                    )\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDMomPlayerExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.extractors.helper.AesHelper\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper\nimport com.fasterxml.jackson.module.kotlin.readValue\n\nopen class HDMomPlayer : ExtractorApi() {\n    override val name            = \"HDMomPlayer\"\n    override val mainUrl         = \"https://hdmomplayer.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val m3uLink:String?\n        val extRef  = referer ?: \"\"\n        val iSource = app.get(url, referer=extRef).text\n\n        val bePlayer = Regex(\"\"\"bePlayer\\('([^']+)',\\s*'(\\{[^\\}]+\\})'\\);\"\"\").find(iSource)?.groupValues\n        if (bePlayer != null) {\n            val bePlayerPass = bePlayer.get(1)\n            val bePlayerData = bePlayer.get(2)\n            val encrypted    = AesHelper.cryptoAESHandler(bePlayerData, bePlayerPass.toByteArray(), false)?.replace(\"\\\\\", \"\") ?: throw ErrorLoadingException(\"failed to decrypt\")\n\n            m3uLink = Regex(\"\"\"video_location\\\":\\\"([^\\\"]+)\"\"\").find(encrypted)?.groupValues?.get(1)\n        } else {\n            m3uLink = Regex(\"\"\"file:\\\"([^\\\"]+)\"\"\").find(iSource)?.groupValues?.get(1)\n\n            val trackStr = Regex(\"\"\"tracks:\\[([^\\]]+)\"\"\").find(iSource)?.groupValues?.get(1)\n            if (trackStr != null) {\n                val tracks:List<Track> = jacksonObjectMapper().readValue(\"[${trackStr}]\")\n\n                for (track in tracks) {\n                    if (track.file == null || track.label == null) continue\n                    if (track.label.contains(\"Forced\")) continue\n\n                    subtitleCallback.invoke(\n                        newSubtitleFile(\n                            lang = track.label,\n                            url  = fixUrl(mainUrl + track.file)\n                        )\n                    )\n                }\n            }\n        }\n\n        callback.invoke(\n            newExtractorLink(\n                source  = this.name,\n                name    = this.name,\n                url     = m3uLink ?: throw ErrorLoadingException(\"m3u link not found\"),\n                type = ExtractorLinkType.M3U8\n            ) {\n                this.referer = url\n                this.quality = Qualities.Unknown.value\n            }\n        )\n    }\n\n    data class Track(\n        @JsonProperty(\"file\")     val file: String?,\n        @JsonProperty(\"label\")    val label: String?,\n        @JsonProperty(\"kind\")     val kind: String?,\n        @JsonProperty(\"language\") val language: String?,\n        @JsonProperty(\"default\")  val default: String?\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDPlayerSystemExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\nimport com.fasterxml.jackson.annotation.JsonProperty\n\nopen class HDPlayerSystem : ExtractorApi() {\n    override val name            = \"HDPlayerSystem\"\n    override val mainUrl         = \"https://hdplayersystem.live\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef  = referer ?: \"\"\n        val vidId   = if (url.contains(\"video/\")) {\n            url.substringAfter(\"video/\")\n        } else {\n            url.substringAfter(\"?data=\")\n        }\n        val postUrl = \"${mainUrl}/player/index.php?data=${vidId}&do=getVideo\"\n\n        val response = app.post(\n            postUrl,\n            data = mapOf(\n                \"hash\" to vidId,\n                \"r\"    to extRef\n            ),\n            referer = extRef,\n            headers = mapOf(\n                \"Content-Type\"     to \"application/x-www-form-urlencoded; charset=UTF-8\",\n                \"X-Requested-With\" to \"XMLHttpRequest\"\n            )\n        )\n\n        val videoResponse = response.parsedSafe<SystemResponse>() ?: throw ErrorLoadingException(\"failed to parse response\")\n        val m3uLink       = videoResponse.securedLink\n\n        callback.invoke(\n            newExtractorLink(\n                source  = this.name,\n                name    = this.name,\n                url     = m3uLink\n            ) {\n                this.referer = extRef\n            }\n        )\n    }\n\n    data class SystemResponse(\n        @JsonProperty(\"hls\")         val hls: String,\n        @JsonProperty(\"videoImage\")  val videoImage: String? = null,\n        @JsonProperty(\"videoSource\") val videoSource: String,\n        @JsonProperty(\"securedLink\") val securedLink: String\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDStreamAbleExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nclass HDStreamAble : PeaceMakerst() {\n    override var name    = \"HDStreamAble\"\n    override var mainUrl = \"https://hdstreamable.com\"\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nclass Hotlinger : ContentX() {\n    override var name    = \"Hotlinger\"\n    override var mainUrl = \"https://hotlinger.com\"\n}\n\nclass FourCX : ContentX() {\n    override var name    = \"FourCX\"\n    override var mainUrl = \"https://four.contentx.me\"\n}\n\nclass PlayRu : ContentX() {\n    override var name    = \"PlayRu\"\n    override var mainUrl = \"https://playru.net\"\n}\n\nclass FourPlayRu : ContentX() {\n    override var name    = \"FourPlayRu\"\n    override var mainUrl = \"https://four.playru.net\"\n}\n\nclass Pichive : ContentX() {\n    override var name    = \"Pichive\"\n    override var mainUrl = \"https://pichive.online\"\n}\n\nclass FourPichive : ContentX() {\n    override var name    = \"FourPichive\"\n    override var mainUrl = \"https://four.pichive.online\"\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HubCloud.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.Prerelease\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.loadExtractor\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport java.net.URI\n\n@Prerelease\nclass HubCloud : ExtractorApi() {\n    override val name = \"Hub-Cloud\"\n    override val mainUrl = \"https://hubcloud.*\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val tag = \"HubCloud\"\n        val realUrl = url.takeIf {\n            try { URI(it).toURL(); true } catch (e: Exception) { Log.e(tag, \"Invalid URL: ${e.message}\"); false }\n        } ?: return\n\n        val baseUrl=getBaseUrl(realUrl)\n\n        val href = try {\n            if (\"hubcloud.php\" in realUrl) {\n                realUrl\n            } else {\n                val rawHref = app.get(realUrl).document.select(\"#download\").attr(\"href\")\n                if (rawHref.startsWith(\"http\", ignoreCase = true)) {\n                    rawHref\n                } else {\n                    baseUrl.trimEnd('/') + \"/\" + rawHref.trimStart('/')\n                }\n            }\n        } catch (e: Exception) {\n            Log.e(tag, \"Failed to extract href: ${e.message}\")\n            \"\"\n        }\n\n        if (href.isBlank()) {\n            Log.w(tag, \"No valid href found\")\n            return\n        }\n\n        val document = app.get(href).document\n        val size = document.selectFirst(\"i#size\")?.text().orEmpty()\n        val header = document.selectFirst(\"div.card-header\")?.text().orEmpty()\n\n        val headerDetails = cleanTitle(header)\n\n        val labelExtras = buildString {\n            if (headerDetails.isNotEmpty()) append(\"[$headerDetails]\")\n            if (size.isNotEmpty()) append(\"[$size]\")\n        }\n        val quality = getIndexQuality(header)\n\n        document.select(\"div.card-body h2 a.btn\").amap { element ->\n            val link = element.attr(\"href\")\n            val text = element.text()\n\n            when {\n                text.contains(\"FSL Server\", ignoreCase = true) -> {\n                    callback.invoke(\n                        newExtractorLink(\n                            \"$referer [FSL Server]\",\n                            \"$referer [FSL Server] $labelExtras\",\n                            link,\n                        ) { this.quality = quality }\n                    )\n                }\n\n                text.contains(\"Download File\", ignoreCase = true) -> {\n                    callback.invoke(\n                        newExtractorLink(\n                            \"$referer\",\n                            \"$referer $labelExtras\",\n                            link,\n                        ) { this.quality = quality }\n                    )\n                }\n\n                text.contains(\"BuzzServer\", ignoreCase = true) -> {\n                    val buzzResp = app.get(\"$link/download\", referer = link, allowRedirects = false)\n                    val dlink = buzzResp.headers[\"hx-redirect\"].orEmpty()\n                    if (dlink.isNotBlank()) {\n                        callback.invoke(\n                            newExtractorLink(\n                                \"$referer [BuzzServer]\",\n                                \"$referer [BuzzServer] $labelExtras\",\n                                dlink,\n                            ) { this.quality = quality }\n                        )\n                    } else {\n                        Log.w(tag, \"BuzzServer: No redirect\")\n                    }\n                }\n\n                text.contains(\"pixeldra\", ignoreCase = true) || text.contains(\"pixel\", ignoreCase = true) -> {\n                    val baseUrlLink = getBaseUrl(link)\n                    val finalURL = if (link.contains(\"download\", true)) link\n                    else \"$baseUrlLink/api/file/${link.substringAfterLast(\"/\")}?download\"\n\n                    callback(\n                        newExtractorLink(\n                            \"Pixeldrain\",\n                            \"Pixeldrain $labelExtras\",\n                            finalURL\n                        ) { this.quality = quality }\n                    )\n                }\n\n                text.contains(\"S3 Server\", ignoreCase = true) -> {\n                    callback.invoke(\n                        newExtractorLink(\n                            \"$referer S3 Server\",\n                            \"$referer S3 Server $labelExtras\",\n                            link,\n                        ) { this.quality = quality }\n                    )\n                }\n\n                text.contains(\"FSLv2\", ignoreCase = true) -> {\n                    callback.invoke(\n                        newExtractorLink(\n                            \"$referer FSLv2\",\n                            \"$referer FSLv2 $labelExtras\",\n                            link,\n                        ) { this.quality = quality }\n                    )\n                }\n\n                text.contains(\"Mega Server\", ignoreCase = true) -> {\n                    callback.invoke(\n                        newExtractorLink(\n                            \"$referer [Mega Server]\",\n                            \"$referer [Mega Server] $labelExtras\",\n                            link,\n                        ) { this.quality = quality }\n                    )\n                }\n                \n                else -> {\n                    loadExtractor(link, \"\", subtitleCallback, callback)\n                }\n            }\n        }\n    }\n\n    private fun getIndexQuality(str: String?): Int {\n        return Regex(\"(\\\\d{3,4})[pP]\").find(str.orEmpty())?.groupValues?.getOrNull(1)?.toIntOrNull()\n            ?: Qualities.P2160.value\n    }\n\n    private fun getBaseUrl(url: String): String {\n        return try {\n            URI(url).let { \"${it.scheme}://${it.host}\" }\n        } catch (_: Exception) {\n            \"\"\n        }\n    }\n\n    fun cleanTitle(title: String): String {\n        val parts = title.split(\".\", \"-\", \"_\")\n\n        val qualityTags = listOf(\n            \"WEBRip\", \"WEB-DL\", \"WEB\", \"BluRay\", \"HDRip\", \"DVDRip\", \"HDTV\",\n            \"CAM\", \"TS\", \"R5\", \"DVDScr\", \"BRRip\", \"BDRip\", \"DVD\", \"PDTV\",\n            \"HD\"\n        )\n\n        val audioTags = listOf(\n            \"AAC\", \"AC3\", \"DTS\", \"MP3\", \"FLAC\", \"DD5\", \"EAC3\", \"Atmos\"\n        )\n\n        val subTags = listOf(\n            \"ESub\", \"ESubs\", \"Subs\", \"MultiSub\", \"NoSub\", \"EnglishSub\", \"HindiSub\"\n        )\n\n        val codecTags = listOf(\n            \"x264\", \"x265\", \"H264\", \"HEVC\", \"AVC\"\n        )\n\n        val startIndex = parts.indexOfFirst { part ->\n            qualityTags.any { tag -> part.contains(tag, ignoreCase = true) }\n        }\n\n        val endIndex = parts.indexOfLast { part ->\n            subTags.any { tag -> part.contains(tag, ignoreCase = true) } ||\n                    audioTags.any { tag -> part.contains(tag, ignoreCase = true) } ||\n                    codecTags.any { tag -> part.contains(tag, ignoreCase = true) }\n        }\n\n        return if (startIndex != -1 && endIndex != -1 && endIndex >= startIndex) {\n            parts.subList(startIndex, endIndex + 1).joinToString(\".\")\n        } else if (startIndex != -1) {\n            parts.subList(startIndex, parts.size).joinToString(\".\")\n        } else {\n            parts.takeLast(3).joinToString(\".\")\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Hxfile.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\n\nclass Neonime7n : Hxfile() {\n    override val name = \"Neonime7n\"\n    override val mainUrl = \"https://neonime.fun\"\n    override val redirect = false\n}\n\nclass Neonime8n : Hxfile() {\n    override val name = \"Neonime8n\"\n    override val mainUrl = \"https://8njctn.neonime.net\"\n    override val redirect = false\n}\n\nclass KotakAnimeid : Hxfile() {\n    override val name = \"KotakAnimeid\"\n    override val mainUrl = \"https://nontonanimeid.bio\"\n    override val requiresReferer = true\n}\n\nclass Yufiles : Hxfile() {\n    override val name = \"Yufiles\"\n    override val mainUrl = \"https://yufiles.com\"\n}\n\nclass Aico : Hxfile() {\n    override val name = \"Aico\"\n    override val mainUrl = \"https://aico.pw\"\n}\n\nopen class Hxfile : ExtractorApi() {\n    override val name = \"Hxfile\"\n    override val mainUrl = \"https://hxfile.co\"\n    override val requiresReferer = false\n    open val redirect = true\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val sources = mutableListOf<ExtractorLink>()\n        val document = app.get(url, allowRedirects = redirect, referer = referer).document\n        with(document) {\n            this.select(\"script\").map { script ->\n                if (script.data().contains(\"eval(function(p,a,c,k,e,d)\")) {\n                    val data =\n                        getAndUnpack(script.data()).substringAfter(\"sources:[\").substringBefore(\"]\")\n                    tryParseJson<List<ResponseSource>>(\"[$data]\")?.map {\n                        sources.add(\n                            newExtractorLink(\n                                name,\n                                name,\n                                it.file,\n                            ) {\n                                this.referer = mainUrl\n                                this.quality = when {\n                                    url.contains(\"hxfile.co\") -> getQualityFromName(\n                                        Regex(\"\\\\d\\\\.(.*?).mp4\").find(\n                                            document.select(\"title\").text()\n                                        )?.groupValues?.get(1).toString()\n                                    )\n                                    else -> getQualityFromName(it.label)\n                                }\n                            }\n                        )\n                    }\n                } else if (script.data().contains(\"\\\"sources\\\":[\")) {\n                    val data = script.data().substringAfter(\"\\\"sources\\\":[\").substringBefore(\"]\")\n                    tryParseJson<List<ResponseSource>>(\"[$data]\")?.map {\n                        sources.add(\n                            newExtractorLink(\n                                name,\n                                name,\n                                it.file,\n                            ) {\n                                this.referer = mainUrl\n                                this.quality = when {\n                                    it.label?.contains(\"HD\") == true -> Qualities.P720.value\n                                    it.label?.contains(\"SD\") == true -> Qualities.P480.value\n                                    else -> getQualityFromName(it.label)\n                                }\n                            }\n                        )\n                    }\n                }\n                else {\n                    null\n                }\n            }\n        }\n        return sources\n    }\n\n    private data class ResponseSource(\n        @JsonProperty(\"file\") val file: String,\n        @JsonProperty(\"type\") val type: String?,\n        @JsonProperty(\"label\") val label: String?\n    )\n\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/InternetArchive.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.StringUtils.decodeUri\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport org.jsoup.nodes.Document\n\nopen class InternetArchive : ExtractorApi() {\n    override val mainUrl = \"https://archive.org\"\n    override val requiresReferer = false\n    override val name = \"Internet Archive\"\n\n    companion object {\n        private var archivedItems: MutableMap<String, Document> = mutableMapOf()\n    }\n\n    override fun getExtractorUrl(id: String): String {\n        return \"$mainUrl/details/$id\"\n    }\n\n    // https://archive.org/details/the-the-infected\n    // https://archive.org/details/TheEdgeOfTheEarth\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val document = archivedItems[url] ?: run {\n            try {\n                val doc = app.get(url).document\n                archivedItems[url] = doc\n                doc\n            } catch (e: Exception) {\n                logError(e)\n                return\n            }\n        }\n\n        val subtitleLinks = document.select(\"a[href*=\\\"/download/\\\"]\").filter { element ->\n            val subtitleUrl = element.attr(\"href\")\n            subtitleUrl.endsWith(\".vtt\", true) ||\n                    subtitleUrl.endsWith(\".srt\", true)\n        }\n\n        subtitleLinks.forEach {\n            val subtitleUrl = mainUrl + it.attr(\"href\")\n            val fileName = subtitleUrl.substringAfterLast('/')\n            val subtitleFile = newSubtitleFile(\n                lang = fileName.substringBeforeLast(\".\")\n                    .substringAfterLast(\".\"),\n                url = subtitleUrl\n            )\n            subtitleCallback(subtitleFile)\n        }\n\n        val fileLinks = document.select(\"a[href*=\\\"/download/\\\"]\").filter { element ->\n            val mediaUrl = element.attr(\"href\")\n\n            mediaUrl.endsWith(\".mp4\", true) ||\n                    mediaUrl.endsWith(\".mpg\", true) ||\n                    mediaUrl.endsWith(\".mkv\", true) ||\n                    mediaUrl.endsWith(\".avi\", true) ||\n                    mediaUrl.endsWith(\".ogv\", true) ||\n                    mediaUrl.endsWith(\".ogg\", true) ||\n                    mediaUrl.endsWith(\".mp3\", true) ||\n                    mediaUrl.endsWith(\".wav\", true) ||\n                    mediaUrl.endsWith(\".flac\", true)\n        }\n\n        val select = fileLinks.ifEmpty {\n            document.head().select(\"meta[property=\\\"og:video\\\"]\")\n        }\n\n        select.forEach {\n            val mediaUrl = when {\n                it.hasAttr(\"href\") -> mainUrl + it.attr(\"href\")\n                it.hasAttr(\"content\") -> it.attr(\"content\")\n                else -> return@forEach\n            }\n\n            val fileName = mediaUrl.substringAfterLast('/')\n            val quality = when {\n                fileName.contains(\"1080\", true) -> Qualities.P1080.value\n                fileName.contains(\"720\", true) -> Qualities.P720.value\n                fileName.contains(\"480\", true) -> Qualities.P480.value\n                else -> Qualities.Unknown.value\n            }\n\n            if (mediaUrl.isNotEmpty()) {\n                val name = if (mediaUrl.count() > 1) {\n                    val fileExtension = mediaUrl.substringAfterLast(\".\")\n                    val fileNameCleaned = fileName.decodeUri().substringBeforeLast('.')\n                    \"$fileNameCleaned ($fileExtension)\"\n                } else this.name\n                callback(\n                    newExtractorLink(\n                        this.name,\n                        name,\n                        mediaUrl\n                    ) {\n                        this.quality = quality\n                    }\n                )\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/JWPlayer.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass Meownime : JWPlayer() {\n    override val name = \"Meownime\"\n    override val mainUrl = \"https://meownime.ltd\"\n}\n\nclass DesuOdchan : JWPlayer() {\n    override val name = \"DesuOdchan\"\n    override val mainUrl = \"https://desustream.me/odchan/\"\n}\n\nclass DesuArcg : JWPlayer() {\n    override val name = \"DesuArcg\"\n    override val mainUrl = \"https://desustream.me/arcg/\"\n}\n\nclass DesuDrive : JWPlayer() {\n    override val name = \"DesuDrive\"\n    override val mainUrl = \"https://desustream.me/desudrive/\"\n}\n\nclass DesuOdvip : JWPlayer() {\n    override val name = \"DesuOdvip\"\n    override val mainUrl = \"https://desustream.me/odvip/\"\n}\n\nopen class JWPlayer : ExtractorApi() {\n    override val name = \"JWPlayer\"\n    override val mainUrl = \"https://www.jwplayer.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val sources = mutableListOf<ExtractorLink>()\n        with(app.get(url).document) {\n            val data = this.select(\"script\").mapNotNull { script ->\n                if (script.data().contains(\"sources: [\")) {\n                    script.data().substringAfter(\"sources: [\")\n                        .substringBefore(\"],\").replace(\"'\", \"\\\"\")\n                } else if (script.data().contains(\"otakudesu('\")) {\n                    script.data().substringAfter(\"otakudesu('\")\n                        .substringBefore(\"');\")\n                } else {\n                    null\n                }\n            }\n\n            tryParseJson<List<ResponseSource>>(\"$data\")?.map {\n                sources.add(\n                    newExtractorLink(\n                        name,\n                        name,\n                        it.file,\n                    ) {\n                        this.referer = url\n                        this.quality = getQualityFromName(\n                            Regex(\"(\\\\d{3,4}p)\").find(it.file)?.groupValues?.get(\n                                1\n                            )\n                        )\n                    }\n                )\n            }\n        }\n        return sources\n    }\n\n    private data class ResponseSource(\n        @JsonProperty(\"file\") val file: String,\n        @JsonProperty(\"type\") val type: String?,\n        @JsonProperty(\"label\") val label: String?\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Jeniusplay.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\n\nopen class Jeniusplay : ExtractorApi() {\n    override val name = \"Jeniusplay\"\n    override val mainUrl = \"https://jeniusplay.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val document = app.get(url, referer = \"$mainUrl/\").document\n        val hash = url.split(\"/\").last().substringAfter(\"data=\")\n\n        val m3uLink = app.post(\n            url = \"$mainUrl/player/index.php?data=$hash&do=getVideo\",\n            data = mapOf(\"hash\" to hash, \"r\" to \"$referer\"),\n            referer = url,\n            headers = mapOf(\"X-Requested-With\" to \"XMLHttpRequest\")\n        ).parsed<ResponseSource>().videoSource\n\n        M3u8Helper.generateM3u8(\n            this.name,\n            m3uLink,\n            url,\n        ).forEach(callback)\n\n\n        document.select(\"script\").map { script ->\n            if (script.data().contains(\"eval(function(p,a,c,k,e,d)\")) {\n                val subData =\n                    getAndUnpack(script.data()).substringAfter(\"\\\"tracks\\\":[\").substringBefore(\"],\")\n                tryParseJson<List<Tracks>>(\"[$subData]\")?.map { subtitle ->\n                    subtitleCallback.invoke(\n                        newSubtitleFile(\n                            getLanguage(subtitle.label ?: \"\"),\n                            subtitle.file\n                        )\n                    )\n                }\n            }\n        }\n    }\n\n    private fun getLanguage(str: String): String {\n        return when {\n            str.contains(\"indonesia\", true) || str\n                .contains(\"bahasa\", true) -> \"Indonesian\"\n            else -> str\n        }\n    }\n\n    data class ResponseSource(\n        @JsonProperty(\"hls\") val hls: Boolean,\n        @JsonProperty(\"videoSource\") val videoSource: String,\n        @JsonProperty(\"securedLink\") val securedLink: String?,\n    )\n\n    data class Tracks(\n        @JsonProperty(\"kind\") val kind: String?,\n        @JsonProperty(\"file\") val file: String,\n        @JsonProperty(\"label\") val label: String?,\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Krakenfiles.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.httpsify\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Krakenfiles : ExtractorApi() {\n    override val name = \"Krakenfiles\"\n    override val mainUrl = \"https://krakenfiles.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val id = Regex(\"/(?:view|embed-video)/([\\\\da-zA-Z]+)\").find(url)?.groupValues?.get(1)\n        val doc = app.get(\"$mainUrl/embed-video/$id\").document\n        val link = doc.selectFirst(\"source\")?.attr(\"src\")\n\n        callback.invoke(\n            newExtractorLink(\n                this.name,\n                this.name,\n                httpsify(link ?: return),\n            )\n        )\n\n    }\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Linkbox.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Linkbox : ExtractorApi() {\n    override val name = \"Linkbox\"\n    override val mainUrl = \"https://www.linkbox.to\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val token = Regex(\"\"\"(?:/f/|/file/|\\?id=)(\\w+)\"\"\").find(url)?.groupValues?.get(1)\n        val id = app.get(\"$mainUrl/api/file/share_out_list/?sortField=utime&sortAsc=0&pageNo=1&pageSize=50&shareToken=$token\").parsedSafe<Responses>()?.data?.itemId\n        app.get(\"$mainUrl/api/file/detail?itemId=$id\", referer = url)\n            .parsedSafe<Responses>()?.data?.itemInfo?.resolutionList?.map { link ->\n                callback.invoke(\n                    newExtractorLink(\n                        name,\n                        name,\n                        link.url ?: return@map null,\n                    ) {\n                        this.referer = url\n                        this.quality = getQualityFromName(link.resolution)\n                    }\n                )\n            }\n    }\n\n    data class Resolutions(\n        @JsonProperty(\"url\") val url: String? = null,\n        @JsonProperty(\"resolution\") val resolution: String? = null,\n    )\n\n    data class ItemInfo(\n        @JsonProperty(\"resolutionList\") val resolutionList: ArrayList<Resolutions>? = arrayListOf(),\n    )\n\n    data class Data(\n        @JsonProperty(\"itemInfo\") val itemInfo: ItemInfo? = null,\n        @JsonProperty(\"itemId\") val itemId: String? = null,\n    )\n\n    data class Responses(\n        @JsonProperty(\"data\") val data: Data? = null,\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/LuluStream.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\n\nclass Luluvdoo : LuluStream() {\n    override var mainUrl = \"https://luluvdoo.com\"\n}\n\nclass Lulustream1 : LuluStream() {\n    override val name = \"Lulustream\"\n    override val mainUrl = \"https://lulustream.com\"\n}\n\nclass Lulustream2 : LuluStream() {\n    override val name = \"Lulustream\"\n    override val mainUrl = \"https://kinoger.pw\"\n}\n\nopen class LuluStream : ExtractorApi() {\n    override val  name = \"LuluStream\"\n    override val mainUrl = \"https://luluvdo.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val filecode = url.substringAfterLast(\"/\")\n        val postUrl = \"$mainUrl/dl\"\n        val post = app.post(\n            postUrl,\n            data = mapOf(\n                \"op\" to \"embed\",\n                \"file_code\" to filecode,\n                \"auto\" to \"1\",\n                \"referer\" to (referer ?: \"\")\n            )\n        ).document\n        post.selectFirst(\"script:containsData(vplayer)\")?.data()\n            ?.let { script ->\n                Regex(\"file:\\\"(.*)\\\"\").find(script)?.groupValues?.get(1)?.let { link ->\n                    callback(\n                        newExtractorLink(\n                            name,\n                            name,\n                            link,\n                        ) {\n                            this.referer = mainUrl\n                            this.quality = Qualities.P1080.value\n                        }\n                    )\n                }\n            }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/M3u8Manifest.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\n//{\"auto\":\"/manifests/movies/15559/1624728920/qDwu5BOsfAwfTmnnjmkmXA/master.m3u8\",\"1080p\":\"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/1080p/index.m3u8\",\"720p\":\"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/720p/index.m3u8\",\"360p\":\"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/360p/index.m3u8\",\"480p\":\"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/480p/index.m3u8\"}\nobject M3u8Manifest {\n    // URL = first, QUALITY = second\n    fun extractLinks(m3u8Data: String): ArrayList<Pair<String, String>> {\n        val data: ArrayList<Pair<String, String>> = ArrayList()\n        Regex(\"\\\"(.*?)\\\":\\\"(.*?)\\\"\").findAll(m3u8Data).forEach {\n            var quality = it.groupValues[1].replace(\"auto\", \"Auto\")\n            if (quality != \"Auto\" && !quality.endsWith('p')) quality += \"p\"\n            val url = it.groupValues[2]\n            data.add(Pair(url, quality))\n        }\n        return data\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/MailRuExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\nimport com.fasterxml.jackson.annotation.JsonProperty\n\nopen class MailRu : ExtractorApi() {\n    override val name            = \"MailRu\"\n    override val mainUrl         = \"https://my.mail.ru\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef = referer ?: \"\"\n\n        val vidId     = url.substringAfter(\"video/embed/\").trim()\n        val videoReq  = app.get(\"${mainUrl}/+/video/meta/${vidId}\", referer=url)\n        val videoKey  = videoReq.cookies[\"video_key\"].toString()\n\n        val videoData = AppUtils.tryParseJson<MailRuData>(videoReq.text) ?: throw ErrorLoadingException(\"Video not found\")\n\n        for (video in videoData.videos) {\n\n            val videoUrl = if (video.url.startsWith(\"//\")) \"https:${video.url}\" else video.url\n\n            callback.invoke(\n                newExtractorLink(\n                    source  = this.name,\n                    name    = this.name,\n                    url     = videoUrl,\n                    type    = ExtractorLinkType.M3U8\n                ) {\n                    this.referer = url\n                    this.headers = mapOf(\"Cookie\" to \"video_key=${videoKey}\")\n                    this.quality = getQualityFromName(video.key)\n                }\n            )\n        }\n    }\n\n    data class MailRuData(\n        @JsonProperty(\"provider\") val provider: String,\n        @JsonProperty(\"videos\")   val videos: List<MailRuVideoData>\n    )\n\n    data class MailRuVideoData(\n        @JsonProperty(\"url\") val url: String,\n        @JsonProperty(\"key\") val key: String\n    )\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Maxstream.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\n\nopen class Maxstream : ExtractorApi() {\n    override var name = \"Maxstream\"\n    override var mainUrl = \"https://maxstream.video/\"\n    override val requiresReferer = false\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()\n        val response = app.get(url).text\n        val jstounpack = Regex(\"cript\\\">eval((.|\\\\n)*?)</script>\").find(response)?.groups?.get(1)?.value\n        val unpacjed = JsUnpacker(jstounpack).unpack()\n        val extractedUrl = unpacjed?.let { Regex(\"\"\"src:\"((.|\\n)*?)\",type\"\"\").find(it) }?.groups?.get(1)?.value.toString()\n\n        M3u8Helper.generateM3u8(\n            name,\n            extractedUrl,\n            url,\n            headers = mapOf(\"referer\" to url)\n        ).forEach { link ->\n            extractedLinksList.add(link)\n        }\n\n        return extractedLinksList\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Mediafire.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Mediafire : ExtractorApi() {\n    override val name = \"Mediafire\"\n    override val mainUrl = \"https://www.mediafire.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val res = app.get(url, referer = referer).document\n        val title = res.select(\"div.dl-btn-label\").text()\n        val video = res.selectFirst(\"a#downloadButton\")?.attr(\"href\")\n\n        callback.invoke(\n            newExtractorLink(\n                this.name,\n                this.name,\n                video ?: return\n            ) {\n                this.quality = getQuality(title)\n            }\n        )\n\n    }\n\n    private fun getQuality(str: String?): Int {\n        return Regex(\"(\\\\d{3,4})[pP]\").find(str ?: \"\")?.groupValues?.getOrNull(1)?.toIntOrNull()\n            ?: Qualities.Unknown.value\n    }\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Minoplres.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\n\nopen class Minoplres : ExtractorApi() {\n\n    override val name = \"Minoplres\" // formerly SpeedoStream\n    override val requiresReferer = true\n    override val mainUrl = \"https://minoplres.xyz\" // formerly speedostream.bond\n    private val hostUrl = \"https://minoplres.xyz\"\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val sources = mutableListOf<ExtractorLink>()\n        app.get(url, referer = referer).document.select(\"script\").map { script ->\n            if (script.data().contains(\"jwplayer(\\\"vplayer\\\").setup(\")) {\n                val data = script.data().substringAfter(\"sources: [\")\n                    .substringBefore(\"],\").replace(\"file\", \"\\\"file\\\"\").trim()\n                tryParseJson<File>(data)?.let {\n                    M3u8Helper.generateM3u8(\n                        name,\n                        it.file,\n                        \"$hostUrl/\",\n                    ).forEach { m3uData -> sources.add(m3uData) }\n                }\n            }\n        }\n        return sources\n    }\n\n    private data class File(\n        @JsonProperty(\"file\") val file: String,\n    )\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/MixDrop.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\n\nclass MixDropPs : MixDrop() {\n    override var mainUrl = \"https://mixdrop.ps\"\n}\n\nclass Mdy : MixDrop() {\n    override var mainUrl = \"https://mdy48tn97.com\"\n}\n\nclass MxDropTo : MixDrop() {\n    override var mainUrl = \"https://mxdrop.to\"\n}\n\nclass MixDropSi : MixDrop() {\n    override var mainUrl = \"https://mixdrop.si\"\n}\n\nclass MixDropBz : MixDrop(){\n    override var mainUrl = \"https://mixdrop.bz\"\n}\n\nclass MixDropAg : MixDrop(){\n    override var mainUrl = \"https://mixdrop.ag\"\n}\n\nclass MixDropCh : MixDrop(){\n    override var mainUrl = \"https://mixdrop.ch\"\n}\nclass MixDropTo : MixDrop(){\n    override var mainUrl = \"https://mixdrop.to\"\n}\n\nopen class MixDrop : ExtractorApi() {\n    override var name = \"MixDrop\"\n    override var mainUrl = \"https://mixdrop.co\"\n    private val srcRegex = Regex(\"\"\"wurl.*?=.*?\"(.*?)\";\"\"\")\n    override val requiresReferer = false\n\n    override fun getExtractorUrl(id: String): String {\n        return \"$mainUrl/e/$id\"\n    }\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        with(app.get(url.replaceFirst(\"/f/\", \"/e/\"))) {\n            getAndUnpack(this.text).let { unpackedText ->\n                srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->\n                    return listOf(\n                        newExtractorLink(\n                            name,\n                            name,\n                            httpsify(link),\n                        ) {\n                            this.referer = url\n                            this.quality = Qualities.Unknown.value\n                        }\n                    )\n                }\n            }\n        }\n        return null\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Moviehab.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\n\nclass MoviehabNet : Moviehab() {\n    override var mainUrl = \"https://play.moviehab.asia\"\n}\n\nopen class Moviehab : ExtractorApi() {\n    override var name = \"Moviehab\"\n    override var mainUrl = \"https://play.moviehab.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val res = app.get(url)\n        res.document.select(\"video#player\").let {\n            //should redirect first for making it works\n            val link = app.get(\"$mainUrl/${it.select(\"source\").attr(\"src\")}\", referer = url).url\n            M3u8Helper.generateM3u8(\n                this.name,\n                link,\n                url\n            ).forEach(callback)\n\n            Regex(\"src[\\\"|'],\\\\s[\\\"|'](\\\\S+)[\\\"|']\\\\)\").find(res.text)?.groupValues?.get(1).let {sub ->\n                subtitleCallback.invoke(\n                    newSubtitleFile(\n                        it.select(\"track\").attr(\"label\"),\n                        \"$mainUrl/$sub\"\n                    )\n                )\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Mp4Upload.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.getAndUnpack\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Mp4Upload : ExtractorApi() {\n    override var name = \"Mp4Upload\"\n    override var mainUrl = \"https://www.mp4upload.com\"\n    private val srcRegex = Regex(\"\"\"player\\.src\\(\"(.*?)\"\"\"\")\n    private val srcRegex2 = Regex(\"\"\"player\\.src\\([\\w\\W]*src: \"(.*?)\"\"\"\")\n\n    override val requiresReferer = true\n    private val idMatch = Regex(\"\"\"mp4upload\\.com/(embed-|)([A-Za-z0-9]*)\"\"\")\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val realUrl = idMatch.find(url)?.groupValues?.get(2)?.let { id ->\n            \"$mainUrl/embed-$id.html\"\n        } ?: url\n        val response = app.get(realUrl)\n        val unpackedText = getAndUnpack(response.text)\n        val quality =\n            unpackedText.lowercase().substringAfter(\" height=\").substringBefore(\" \").toIntOrNull()\n        srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->\n            return listOf(\n                newExtractorLink(\n                    name,\n                    name,\n                    link,\n                ) {\n                    this.referer = url\n                    this.quality = quality ?: Qualities.Unknown.value\n                }\n            )\n        }\n        srcRegex2.find(unpackedText)?.groupValues?.get(1)?.let { link ->\n            return listOf(\n                newExtractorLink(\n                    name,\n                    name,\n                    link,\n                ) {\n                    this.referer = url\n                    this.quality = quality ?: Qualities.Unknown.value\n                }\n            )\n        }\n        return null\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/MultiQuality.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport java.net.URI\n\nopen class MultiQuality : ExtractorApi() {\n    override var name = \"MultiQuality\"\n    override var mainUrl = \"https://anihdplay.com\"\n    private val sourceRegex = Regex(\"\"\"file:\\s*['\"](.*?)['\"],label:\\s*['\"](.*?)['\"]\"\"\")\n    private val m3u8Regex = Regex(\"\"\".*?(\\d*).m3u8\"\"\")\n    private val urlRegex = Regex(\"\"\"(.*?)([^/]+$)\"\"\")\n    override val requiresReferer = false\n\n    override fun getExtractorUrl(id: String): String {\n        return \"$mainUrl/loadserver.php?id=$id\"\n    }\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()\n        with(app.get(url)) {\n            sourceRegex.findAll(this.text).forEach { sourceMatch ->\n                val extractedUrl = sourceMatch.groupValues[1]\n                // Trusting this isn't mp4, may fuck up stuff\n                if (URI(extractedUrl).path.endsWith(\".m3u8\")) {\n                    with(app.get(extractedUrl)) {\n                        m3u8Regex.findAll(this.text).forEach { match ->\n                            extractedLinksList.add(\n                                newExtractorLink(\n                                    source = name,\n                                    name = name,\n                                    url = urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[0],\n                                    type = ExtractorLinkType.M3U8\n                                ) {\n                                    this.referer = url\n                                    this.quality = getQualityFromName(match.groupValues[1])\n                                }\n                            )\n                        }\n\n                    }\n                } else if (extractedUrl.endsWith(\".mp4\")) {\n                    extractedLinksList.add(\n                        newExtractorLink(\n                            name,\n                            \"$name ${sourceMatch.groupValues[2]}\",\n                            extractedUrl,\n                        ) {\n                            this.referer = url.replace(\" \", \"%20\")\n                            this.quality = Qualities.Unknown.value\n                        }\n                    )\n                }\n            }\n            return extractedLinksList\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Mvidoo.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Mvidoo : ExtractorApi() {\n    override val name = \"Mvidoo\"\n    override val mainUrl = \"https://mvidoo.com\"\n    override val requiresReferer = true\n\n    private fun String.decodeHex(): String {\n        require(length % 2 == 0) { \"Must have an even length\" }\n        return String(\n            chunked(2)\n                .map { it.toInt(16).toByte() }\n                .toByteArray()\n        )\n    }\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val document = app.get(url, referer = referer).text\n        val data = Regex(\"\"\"\\{var\\s*[^\\s]+\\s*=\\s*(\\[[^]]+])\"\"\").find(document)?.groupValues?.get(1)\n            ?.removeSurrounding(\"[\", \"]\")?.replace(\"\\\"\", \"\")?.replace(\"\\\\x\", \"\")?.split(\",\")?.map { it.decodeHex() }?.reversed()?.joinToString(\"\") ?: return\n        Regex(\"source\\\\s*src=\\\"([^\\\"]+)\").find(data)?.groupValues?.get(1)?.let { link ->\n            callback.invoke(\n                newExtractorLink(\n                    this.name,\n                    this.name,\n                    link\n                ) {\n                    this.referer = \"$mainUrl/\"\n                    this.quality = Qualities.Unknown.value\n                    this.headers = mapOf(\n                        \"Range\" to \"bytes=0-\"\n                    )\n                }\n            )\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OdnoklassnikiExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.AppUtils\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Odnoklassniki : ExtractorApi() {\n    override val name            = \"Odnoklassniki\"\n    override val mainUrl         = \"https://odnoklassniki.ru\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val headers = mapOf(\n            \"Accept\" to \"*/*\",\n            \"Connection\" to \"keep-alive\",\n            \"Sec-Fetch-Dest\" to \"empty\",\n            \"Sec-Fetch-Mode\" to \"cors\",\n            \"Sec-Fetch-Site\" to \"cross-site\",\n            \"Origin\" to mainUrl,\n            \"User-Agent\" to USER_AGENT,\n        )\n        val embedUrl = url.replace(\"/video/\",\"/videoembed/\")\n        val videoReq  = app.get(embedUrl, headers=headers).text.replace(\"\\\\&quot;\", \"\\\"\").replace(\"\\\\\\\\\", \"\\\\\")\n            .replace(Regex(\"\\\\\\\\u([0-9A-Fa-f]{4})\")) { matchResult ->\n                Integer.parseInt(matchResult.groupValues[1], 16).toChar().toString()\n            }\n        val videosStr = Regex(\"\"\"\"videos\":(\\[[^]]*])\"\"\").find(videoReq)?.groupValues?.get(1) ?: throw ErrorLoadingException(\"Video not found\")\n        val videos    = AppUtils.tryParseJson<List<OkRuVideo>>(videosStr) ?: throw ErrorLoadingException(\"Video not found\")\n\n        for (video in videos) {\n\n            val videoUrl  = if (video.url.startsWith(\"//\")) \"https:${video.url}\" else video.url\n\n            val quality   = video.name.uppercase()\n                .replace(\"MOBILE\", \"144p\")\n                .replace(\"LOWEST\", \"240p\")\n                .replace(\"LOW\",    \"360p\")\n                .replace(\"SD\",     \"480p\")\n                .replace(\"HD\",     \"720p\")\n                .replace(\"FULL\",   \"1080p\")\n                .replace(\"QUAD\",   \"1440p\")\n                .replace(\"ULTRA\",  \"4k\")\n\n            callback.invoke(\n                newExtractorLink(\n                    source  = this.name,\n                    name    = this.name,\n                    url     = videoUrl,\n                    type    = INFER_TYPE\n                ) {\n                    this.referer = \"$mainUrl/\"\n                    this.quality = getQualityFromName(quality)\n                    this.headers = headers\n                }\n            )\n        }\n    }\n\n    data class OkRuVideo(\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"url\")  val url: String,\n    )\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OkRuExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.Prerelease\n\nopen class OkRuSSL : Odnoklassniki() {\n    override var name    = \"OkRuSSL\"\n    override var mainUrl = \"https://ok.ru\"\n}\n\nopen class OkRuHTTP : Odnoklassniki() {\n    override var name    = \"OkRuHTTP\"\n    override var mainUrl = \"http://ok.ru\"\n}\n\n@Prerelease\nclass OkRuSSLMobile : OkRuSSL() {\n    override var mainUrl = \"https://m.ok.ru\"\n}\n\n@Prerelease\nclass OkRuHTTPMobile : OkRuHTTP() {\n    override var mainUrl = \"http://m.ok.ru\"\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PeaceMakerstExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\nimport com.fasterxml.jackson.annotation.JsonProperty\n\nopen class PeaceMakerst : ExtractorApi() {\n    override val name            = \"PeaceMakerst\"\n    override val mainUrl         = \"https://peacemakerst.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val m3uLink:String?\n        val extRef  = referer ?: \"\"\n        val postUrl = \"${url}?do=getVideo\"\n\n        val response = app.post(\n            postUrl,\n            data = mapOf(\n                \"hash\" to url.substringAfter(\"video/\"),\n                \"r\"    to extRef,\n                \"s\"    to \"\"\n            ),\n            referer = extRef,\n            headers = mapOf(\n                \"Content-Type\"     to \"application/x-www-form-urlencoded; charset=UTF-8\",\n                \"X-Requested-With\" to \"XMLHttpRequest\"\n            )\n        )\n        if (response.text.contains(\"teve2.com.tr\\\\/embed\\\\/\")) {\n            val teve2Id       = response.text.substringAfter(\"teve2.com.tr\\\\/embed\\\\/\").substringBefore(\"\\\"\")\n            val teve2Response = app.get(\n                \"https://www.teve2.com.tr/action/media/${teve2Id}\",\n                referer = \"https://www.teve2.com.tr/embed/${teve2Id}\"\n            ).parsedSafe<Teve2ApiResponse>() ?: throw ErrorLoadingException(\"teve2 response is null\")\n\n            m3uLink           = teve2Response.media.link.serviceUrl + \"//\" + teve2Response.media.link.securePath\n        } else {\n            val videoResponse = response.parsedSafe<PeaceResponse>() ?: throw ErrorLoadingException(\"peace response is null\")\n            val videoSources  = videoResponse.videoSources\n            if (videoSources.isNotEmpty()) {\n                m3uLink = videoSources.lastOrNull()?.file\n            } else {\n                m3uLink = null\n            }\n        }\n\n        callback.invoke(\n            newExtractorLink(\n                source  = this.name,\n                name    = this.name,\n                url     = m3uLink ?: throw ErrorLoadingException(\"m3u link not found\"),\n            ) {\n                this.referer = extRef\n                this.quality = Qualities.Unknown.value\n            }\n        )\n    }\n\n    data class PeaceResponse(\n        @JsonProperty(\"videoImage\")   val videoImage: String?,\n        @JsonProperty(\"videoSources\") val videoSources: List<VideoSource>,\n        @JsonProperty(\"sIndex\")       val sIndex: String,\n        @JsonProperty(\"sourceList\")   val sourceList: Map<String, String>\n    )\n\n    data class VideoSource(\n        @JsonProperty(\"file\")  val file: String,\n        @JsonProperty(\"label\") val label: String,\n        @JsonProperty(\"type\")  val type: String\n    )\n\n    data class Teve2ApiResponse(\n        @JsonProperty(\"Media\") val media: Teve2Media\n    )\n\n    data class Teve2Media(\n        @JsonProperty(\"Link\") val link: Teve2Link\n    )\n\n    data class Teve2Link(\n        @JsonProperty(\"ServiceUrl\") val serviceUrl: String,\n        @JsonProperty(\"SecurePath\") val securePath: String\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Pelisplus.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.safeAsync\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.extractorApis\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.loadExtractor\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport org.jsoup.Jsoup\n\n/**\n * overrideMainUrl is necessary for for other vidstream clones like vidembed.cc\n * If they diverge it'd be better to make them separate.\n * */\nopen class Pelisplus(val mainUrl: String) {\n    val name: String = \"Vidstream\"\n\n    private fun getExtractorUrl(id: String): String {\n        return \"$mainUrl/play?id=$id\"\n    }\n\n    private fun getDownloadUrl(id: String): String {\n        return \"$mainUrl/download?id=$id\"\n    }\n\n    private val normalApis = arrayListOf(MultiQuality())\n\n    // https://gogo-stream.com/streaming.php?id=MTE3NDg5\n    suspend fun getUrl(\n        id: String,\n        isCasting: Boolean = false,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ): Boolean {\n        try {\n            normalApis.amap { api ->\n                val url = api.getExtractorUrl(id)\n                api.getSafeUrl(url, subtitleCallback = subtitleCallback, callback = callback)\n            }\n            val extractorUrl = getExtractorUrl(id)\n\n            /** Stolen from GogoanimeProvider.kt extractor */\n            safeAsync {\n                val link = getDownloadUrl(id)\n                println(\"Generated vidstream download link: $link\")\n                val page = app.get(link, referer = extractorUrl)\n\n                val pageDoc = Jsoup.parse(page.text)\n                val qualityRegex = Regex(\"(\\\\d+)P\")\n\n                //a[download]\n                pageDoc.select(\".dowload > a\").amap { element ->\n                    val href = element.attr(\"href\")\n                    val qual = if (element.text()\n                            .contains(\"HDP\")\n                    ) \"1080\" else qualityRegex.find(element.text())?.destructured?.component1()\n                        .toString()\n\n                    if (!loadExtractor(href, link, subtitleCallback, callback)) {\n                        callback.invoke(\n                            newExtractorLink(\n                                this.name,\n                                name = this.name,\n                                href\n                            ) {\n                                this.referer = page.url\n                                this.quality = getQualityFromName(qual)\n                            }\n                        )\n                    }\n                }\n            }\n\n            with(app.get(extractorUrl)) {\n                val document = Jsoup.parse(this.text)\n                val primaryLinks = document.select(\"ul.list-server-items > li.linkserver\")\n                //val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()\n\n                // All vidstream links passed to extractors\n                primaryLinks.distinctBy { it.attr(\"data-video\") }.forEach { element ->\n                    val link = element.attr(\"data-video\")\n                    //val name = element.text()\n\n                    // Matches vidstream links with extractors\n                    extractorApis.filter { !it.requiresReferer || !isCasting }.amap { api ->\n                        if (link.startsWith(api.mainUrl)) {\n                            api.getSafeUrl(link, extractorUrl, subtitleCallback, callback)\n                        }\n                    }\n                }\n                return true\n            }\n        } catch (e: Exception) {\n            return false\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PixelDrainExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\n\n@Prerelease\nclass PixelDrainDev : PixelDrain() {\n    override var mainUrl = \"https://pixeldrain.dev\"\n}\n\nopen class PixelDrain : ExtractorApi() {\n    override val name            = \"PixelDrain\"\n    override val mainUrl         = \"https://pixeldrain.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val mId = Regex(\"/u/(.*)\").find(url)?.groupValues?.get(1)\n        if (mId.isNullOrEmpty())\n        {\n            callback.invoke(\n                newExtractorLink(\n                    this.name,\n                    this.name,\n                    url\n                ) {\n                    this.referer = url\n                }\n            )\n        }\n        else {\n            callback.invoke(\n                newExtractorLink(\n                    this.name,\n                    this.name,\n                    \"$mainUrl/api/file/${mId}?download\",\n                ) {\n                    this.referer = url\n                }\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PlayLtXyz.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\n\nopen class PlayLtXyz: ExtractorApi() {\n    override val name: String = \"PlayLt\"\n    override val mainUrl: String = \"https://play.playlt.xyz\"\n    override val requiresReferer = true\n\n    private data class ResponseData(\n        @JsonProperty(\"data\") val data: String? = null\n    )\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val extractedLinksList = mutableListOf<ExtractorLink>()\n        //Log.i(this.name, \"Result => (url) $url\")\n        var idUser = \"\"\n        var idFile = \"\"\n        var bodyText = \"\"\n        val doc = app.get(url, referer = referer).document\n        //Log.i(this.name, \"Result => (url, script) $url / ${doc.select(\"script\")}\")\n        bodyText = doc.select(\"script\").firstOrNull {\n            val text = it.toString()\n            text.contains(\"var idUser\")\n        }?.toString() ?: \"\"\n        //Log.i(this.name, \"Result => (bodyText) $bodyText\")\n        if (bodyText.isNotBlank()) {\n            idUser = \"(?<=var idUser = \\\")(.*)(?=\\\";)\".toRegex().find(bodyText)\n                ?.groupValues?.get(0) ?: \"\"\n\n            idFile = \"(?<=var idfile = \\\")(.*)(?=\\\";)\".toRegex().find(bodyText)\n                ?.groupValues?.get(0) ?: \"\"\n        }\n        //Log.i(this.name, \"Result => (idUser, idFile) $idUser / $idFile\")\n        if (idUser.isNotBlank() && idFile.isNotBlank()) {\n            //val sess = HttpSession()\n            val ajaxHead = mapOf(\n                Pair(\"Origin\", mainUrl),\n                Pair(\"Referer\", mainUrl),\n                Pair(\"Sec-Fetch-Site\", \"same-site\"),\n                Pair(\"Sec-Fetch-Mode\", \"cors\"),\n                Pair(\"Sec-Fetch-Dest\", \"empty\")\n            )\n            val ajaxData = mapOf(\n                Pair(\"referrer\", referer ?: mainUrl),\n                Pair(\"typeend\", \"html\")\n            )\n\n            //idUser = 608f7c85cf0743547f1f1b4e\n            val posturl = \"https://api-plhq.playlt.xyz/apiv5/$idUser/$idFile\"\n            val data = app.post(posturl, headers = ajaxHead, data = ajaxData)\n            //Log.i(this.name, \"Result => (posturl) $posturl\")\n            if (data.isSuccessful) {\n                val itemstr = data.text\n                Log.i(this.name, \"Result => (data) $itemstr\")\n                tryParseJson<ResponseData?>(itemstr)?.let { item ->\n                    val linkUrl = item.data ?: \"\"\n                    if (linkUrl.isNotBlank()) {\n                        extractedLinksList.add(\n                            newExtractorLink(\n                                source = name,\n                                name = name,\n                                url = linkUrl,\n                                type = ExtractorLinkType.M3U8\n                            ) {\n                                this.referer = url\n                                this.quality = Qualities.Unknown.value\n                            }\n                        )\n                    }\n                }\n            }\n        }\n        return extractedLinksList\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PlayerVoxzer.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\n\n\nopen class PlayerVoxzer : ExtractorApi() {\n    override var name = \"Voxzer\"\n    override var mainUrl = \"https://player.voxzer.org\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val listurl = url.replace(\"/view/\",\"/list/\")\n        val urltext = app.get(listurl, referer = url).text\n        val m3u8regex = Regex(\"((https:|http:)\\\\/\\\\/.*\\\\.m3u8)\")\n        val sources = mutableListOf<ExtractorLink>()\n        val listm3 = m3u8regex.find(urltext)?.value\n        if (listm3?.contains(\"m3u8\") == true)\n            M3u8Helper.generateM3u8(\n                name,\n                listm3,\n                url,\n                headers = app.get(url).headers.toMap()\n            ).forEach { link ->\n                sources.add(link)\n            }\n        return sources\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Rabbitstream.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.base64DecodeArray\nimport com.lagradost.cloudstream3.base64Encode\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.AppUtils\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport java.nio.charset.StandardCharsets\nimport java.security.MessageDigest\nimport javax.crypto.Cipher\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\n\nclass Megacloud : Rabbitstream() {\n    override val name = \"Megacloud\"\n    override val mainUrl = \"https://megacloud.tv\"\n    override val embed = \"embed-2/ajax/e-1\"\n    private val scriptUrl = \"$mainUrl/js/player/a/prod/e1-player.min.js\"\n\n    override suspend fun extractRealKey(sources: String): Pair<String, String> {\n        val rawKeys = getKeys()\n        val sourcesArray = sources.toCharArray()\n\n        var extractedKey = \"\"\n        var currentIndex = 0\n        for (index in rawKeys) {\n            val start = index[0] + currentIndex\n            val end = start + index[1]\n            for (i in start until end) {\n                extractedKey += sourcesArray[i].toString()\n                sourcesArray[i] = ' '\n            }\n            currentIndex += index[1]\n        }\n\n        return extractedKey to sourcesArray.joinToString(\"\").replace(\" \", \"\")\n    }\n\n    private suspend fun getKeys(): List<List<Int>> {\n        val script = app.get(scriptUrl).text\n        fun matchingKey(value: String): String {\n            return Regex(\",$value=((?:0x)?([0-9a-fA-F]+))\").find(script)?.groupValues?.get(1)\n                ?.removePrefix(\"0x\") ?: throw ErrorLoadingException(\"Failed to match the key\")\n        }\n\n        val regex = Regex(\"case\\\\s*0x[0-9a-f]+:(?![^;]*=partKey)\\\\s*\\\\w+\\\\s*=\\\\s*(\\\\w+)\\\\s*,\\\\s*\\\\w+\\\\s*=\\\\s*(\\\\w+);\")\n        val indexPairs = regex.findAll(script).toList().map { match ->\n            val matchKey1 = matchingKey(match.groupValues[1])\n            val matchKey2 = matchingKey(match.groupValues[2])\n            try {\n                listOf(matchKey1.toInt(16), matchKey2.toInt(16))\n            } catch (e: NumberFormatException) {\n                emptyList()\n            }\n        }.filter { it.isNotEmpty() }\n\n        return indexPairs\n    }\n\n}\n\nclass Dokicloud : Rabbitstream() {\n    override val name = \"Dokicloud\"\n    override val mainUrl = \"https://dokicloud.one\"\n}\n\n// Code found in https://github.com/eatmynerds/key\n// special credits to @eatmynerds for providing key\nopen class Rabbitstream : ExtractorApi() {\n    override val name = \"Rabbitstream\"\n    override val mainUrl = \"https://rabbitstream.net\"\n    override val requiresReferer = false\n    open val embed = \"ajax/embed-4\"\n    open val key = \"https://raw.githubusercontent.com/eatmynerds/key/e4/key.txt\"\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val id = url.substringAfterLast(\"/\").substringBefore(\"?\")\n\n        val response = app.get(\n            \"$mainUrl/$embed/getSources?id=$id\",\n            referer = mainUrl,\n            headers = mapOf(\"X-Requested-With\" to \"XMLHttpRequest\")\n        )\n\n        val encryptedMap = response.parsedSafe<SourcesEncrypted>()\n        val sources = encryptedMap?.sources\n        val decryptedSources = if (sources == null || encryptedMap.encrypted == false) {\n            response.parsedSafe()\n        } else {\n            val (key, encData) = extractRealKey(sources)\n            val decrypted = decryptMapped<List<Sources>>(encData, key)\n            SourcesResponses(\n                sources = decrypted,\n                tracks = encryptedMap.tracks\n            )\n        }\n\n        decryptedSources?.sources?.map { source ->\n            M3u8Helper.generateM3u8(\n                name,\n                source?.file ?: return@map,\n                \"$mainUrl/\",\n            ).forEach(callback)\n        }\n\n        decryptedSources?.tracks?.map { track ->\n            subtitleCallback.invoke(\n                newSubtitleFile(\n                    track?.label ?: return@map,\n                    track.file ?: return@map\n                )\n            )\n        }\n\n\n    }\n\n    open suspend fun extractRealKey(sources: String): Pair<String, String> {\n        val rawKeys = parseJson<List<Int>>(app.get(key).text)\n        val extractedKey = base64Encode(rawKeys.map { it.toByte() }.toByteArray())\n        return extractedKey to sources\n    }\n\n    private inline fun <reified T> decryptMapped(input: String, key: String): T? {\n        val decrypt = decrypt(input, key)\n        return AppUtils.tryParseJson(decrypt)\n    }\n\n    private fun decrypt(input: String, key: String): String {\n        return decryptSourceUrl(\n            generateKey(\n                base64DecodeArray(input).copyOfRange(8, 16),\n                key.toByteArray()\n            ), input\n        )\n    }\n\n    private fun generateKey(salt: ByteArray, secret: ByteArray): ByteArray {\n        var key = md5(secret + salt)\n        var currentKey = key\n        while (currentKey.size < 48) {\n            key = md5(key + secret + salt)\n            currentKey += key\n        }\n        return currentKey\n    }\n\n    private fun md5(input: ByteArray): ByteArray {\n        return MessageDigest.getInstance(\"MD5\").digest(input)\n    }\n\n    private fun decryptSourceUrl(decryptionKey: ByteArray, sourceUrl: String): String {\n        val cipherData = base64DecodeArray(sourceUrl)\n        val encrypted = cipherData.copyOfRange(16, cipherData.size)\n        val aesCBC = Cipher.getInstance(\"AES/CBC/PKCS5Padding\")\n        aesCBC.init(\n            Cipher.DECRYPT_MODE,\n            SecretKeySpec(decryptionKey.copyOfRange(0, 32), \"AES\"),\n            IvParameterSpec(decryptionKey.copyOfRange(32, decryptionKey.size))\n        )\n        val decryptedData = aesCBC?.doFinal(encrypted) ?: throw ErrorLoadingException(\"Cipher not found\")\n        return String(decryptedData, StandardCharsets.UTF_8)\n    }\n\n    data class Tracks(\n        @JsonProperty(\"file\") val file: String? = null,\n        @JsonProperty(\"label\") val label: String? = null,\n        @JsonProperty(\"kind\") val kind: String? = null,\n    )\n\n    data class Sources(\n        @JsonProperty(\"file\") val file: String? = null,\n        @JsonProperty(\"type\") val type: String? = null,\n        @JsonProperty(\"label\") val label: String? = null,\n    )\n\n    data class SourcesResponses(\n        @JsonProperty(\"sources\") val sources: List<Sources?>? = emptyList(),\n        @JsonProperty(\"tracks\") val tracks: List<Tracks?>? = emptyList(),\n    )\n\n    data class SourcesEncrypted(\n        @JsonProperty(\"sources\") val sources: String? = null,\n        @JsonProperty(\"encrypted\") val encrypted: Boolean? = null,\n        @JsonProperty(\"tracks\") val tracks: List<Tracks?>? = emptyList(),\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/RapidVidExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\n\nopen class RapidVid : ExtractorApi() {\n    override val name            = \"RapidVid\"\n    override val mainUrl         = \"https://rapidvid.net\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef   = referer ?: \"\"\n        val videoReq = app.get(url, referer=extRef).text\n\n        val subUrls = mutableSetOf<String>()\n        Regex(\"\"\"captions\\\",\\\"file\\\":\\\"([^\\\"]+)\\\",\\\"label\\\":\\\"([^\\\"]+)\\\"\"\"\").findAll(videoReq).forEach {\n            val (subUrl, subLang) = it.destructured\n\n            if (subUrl in subUrls) { return@forEach }\n            subUrls.add(subUrl)\n\n            subtitleCallback.invoke(\n                newSubtitleFile(\n                    lang = subLang.replace(\"\\\\u0131\", \"ı\").replace(\"\\\\u0130\", \"İ\").replace(\"\\\\u00fc\", \"ü\").replace(\"\\\\u00e7\", \"ç\"),\n                    url  = fixUrl(subUrl.replace(\"\\\\\", \"\"))\n                )\n            )\n        }\n\n        var extractedValue   = Regex(\"\"\"file\": \"(.*)\",\"\"\").find(videoReq)?.groupValues?.get(1)\n        var decoded: String? = null\n\n        if (extractedValue != null) {\n            val bytes = extractedValue.split(\"\\\\x\").filter { it.isNotEmpty() }.map { it.toInt(16).toByte() }.toByteArray()\n            decoded   = String(bytes, Charsets.UTF_8)\n        } else {\n            val evalJWSsetup = Regex(\"\"\"\\};\\s*(eval\\(function[\\s\\S]*?)var played = \\d+;\"\"\").find(videoReq)?.groupValues?.get(1) ?: throw ErrorLoadingException(\"File not found\")\n            val JWSsetup      = getAndUnpack(getAndUnpack(evalJWSsetup)).replace(\"\\\\\\\\\", \"\\\\\")\n            extractedValue  = Regex(\"\"\"file\":\"(.*)\",\"label\"\"\").find(JWSsetup)?.groupValues?.get(1)?.replace(\"\\\\\\\\x\", \"\")\n\n            val bytes = extractedValue?.chunked(2)?.map { it.toInt(16).toByte() }?.toByteArray()\n            decoded   = bytes?.toString(Charsets.UTF_8) ?: throw ErrorLoadingException(\"File not found\")\n        }\n\n        callback.invoke(\n            newExtractorLink(\n                source  = this.name,\n                name    = this.name,\n                url     = decoded,\n                type    = ExtractorLinkType.M3U8\n            ) {\n                this.referer = extRef\n                this.quality = Qualities.Unknown.value\n            }\n        )\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SBPlay.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.APIHolder.unixTimeMS\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.getPostForm\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport org.jsoup.Jsoup\n\n//class SBPlay1 : SBPlay() {\n//    override var mainUrl = \"https://sbplay1.com\"\n//}\n\n//class SBPlay2 : SBPlay() {\n//    override var mainUrl = \"https://sbplay2.com\"\n//}\n\nopen class SBPlay : ExtractorApi() {\n    override var mainUrl = \"https://sbplay.one\"\n    override var name = \"SBPlay\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val response = app.get(url, referer = referer).text\n        val document = Jsoup.parse(response)\n\n        val links = ArrayList<ExtractorLink>()\n\n        val tree = document.select(\"table > tbody > tr > td > a\")\n        for (item in tree) {\n            val onDownload = item.attr(\"onclick\")\n            val name = \"${this.name} - ${item.text()}\"\n            try {\n                Regex(\"download_video\\\\('(.*?)','(.*?)','(.*?)'\\\\)\").matchEntire(onDownload)?.let {\n                    val id = it.groupValues[1]\n                    val mode = it.groupValues[2]\n                    val hash = it.groupValues[3]\n                    val href = \"https://sbplay.one/dl?op=download_orig&id=$id&mode=$mode&hash=$hash\"\n                    val hrefResponse = app.get(href).text\n                    app.post(\n                        \"https://sbplay.one/?op=notifications&open=&_=$unixTimeMS\",\n                        referer = href\n                    )\n                    val hrefDocument = Jsoup.parse(hrefResponse)\n                    val hrefSpan = hrefDocument.selectFirst(\"span > a\")\n                    if (hrefSpan == null) {\n                        getPostForm(href, hrefResponse)?.let { form ->\n                            val postDocument = Jsoup.parse(form)\n                            val downloadBtn =\n                                postDocument.selectFirst(\"a.downloadbtn\")?.attr(\"href\")\n                            if (downloadBtn.isNullOrEmpty()) {\n                                val hrefSpan2 = postDocument.selectFirst(\"span > a\")?.attr(\"href\")\n                                if (hrefSpan2?.startsWith(\"https://\") == true) {\n                                    links.add(\n                                        newExtractorLink(\n                                            this.name,\n                                            name,\n                                            hrefSpan2\n                                        )\n                                    )\n                                } else {\n                                    // no link found!!!\n                                }\n                            } else {\n                                links.add(\n                                    newExtractorLink(\n                                        this.name,\n                                        name,\n                                        downloadBtn\n                                    )\n                                )\n                            }\n                        }\n                    } else {\n                        val link = hrefSpan.attr(\"href\")\n                        links.add(\n                            newExtractorLink(\n                                this.name,\n                                name,\n                                link\n                            )\n                        )\n                    }\n                }\n            } catch (e: Exception) {\n                logError(e)\n            }\n        }\n\n        return links\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SecvideoOnline.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class SecvideoOnline : ExtractorApi() {\n    override val name: String = \"Secvideo1\"\n    override val mainUrl: String = \"https://secvideo1.online\"\n    override val requiresReferer: Boolean = false\n\n    private val fileListRegex = Regex(\"\"\"file:\\s*\"(.*)\\\"\"\"\")\n    private val subtitleListRegex = Regex(\"\"\"subtitle:\\s*\"(.*)\\\"\"\"\")\n    private val labelSourceRegex = Regex(\"\"\"\\[(.*?)\\](.*)\"\"\")\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val doc = app.get(url, referer = referer).document\n        for (script in doc.select(\"script\")) {\n            val files = fileListRegex.findAll(script.data())\n                .mapNotNull { it.groupValues.getOrNull(1)?.split(\",\") }\n                .flatten()\n                .distinct()\n\n            for (file in files) {\n                val labelAndSourceMatch = labelSourceRegex.find(file) ?: continue\n                callback.invoke(\n                    newExtractorLink(\n                        source = name,\n                        name = name,\n                        url = labelAndSourceMatch.groupValues[2]\n                    ) {\n                        quality = labelAndSourceMatch.groupValues[1].replace(\"p\", \"\").toIntOrNull()\n                            ?: Qualities.Unknown.value\n                        this.type = ExtractorLinkType.VIDEO\n                    }\n                )\n            }\n\n            val subtitles = subtitleListRegex.findAll(script.data())\n                .mapNotNull { it.groupValues.getOrNull(1)?.split(\",\") }\n                .flatten()\n                .distinct()\n\n            for (subtitle in subtitles) {\n                val languageAndSourceMatch = labelSourceRegex.find(subtitle) ?: continue\n                subtitleCallback.invoke(\n                    newSubtitleFile(\n                        lang = languageAndSourceMatch.groupValues[1],\n                        url = languageAndSourceMatch.groupValues[2]\n                    )\n                )\n            }\n        }\n    }\n}\n\nclass FsstOnline : SecvideoOnline() {\n    override val name: String = \"FsstOnline\"\n    override val mainUrl: String = \"https://fsst.online\"\n}\n\nclass CsstOnline : SecvideoOnline() {\n    override val name: String = \"CsstOnline\"\n    override val mainUrl: String = \"https://csst.online\"\n}\n\nclass DsstOnline : SecvideoOnline() {\n    override val name: String = \"DsstOnline\"\n    override val mainUrl: String = \"https://dsst.online\"\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Sendvid.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8\n\nopen class Sendvid : ExtractorApi() {\n    override var name = \"Sendvid\"\n    override val mainUrl = \"https://sendvid.com\"\n    override val requiresReferer = false\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val doc = app.get(url).document\n        val urlString = doc.select(\"head meta[property=og:video:secure_url]\").attr(\"content\")\n        if (urlString.contains(\"m3u8\"))  {\n            generateM3u8(\n                name,\n                urlString,\n                mainUrl,\n            ).forEach(callback)\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SibNetExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\n\nopen class SibNet : ExtractorApi() {\n    override val name            = \"SibNet\"\n    override val mainUrl         = \"https://video.sibnet.ru\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef  = referer ?: \"\"\n        val iSource = app.get(url, referer=extRef).text\n        var m3uLink = Regex(\"\"\"player.src\\(\\[\\{src: \\\"([^\\\"]+)\"\"\").find(iSource)?.groupValues?.get(1) ?: throw ErrorLoadingException(\"m3u link not found\")\n\n        m3uLink = \"${mainUrl}${m3uLink}\"\n\n        callback.invoke(\n            newExtractorLink(\n                source  = this.name,\n                name    = this.name,\n                url     = m3uLink,\n            ) {\n                this.referer = url\n            }\n        )\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\nimport com.fasterxml.jackson.annotation.JsonProperty\n\nopen class Sobreatsesuyp : ExtractorApi() {\n    override val name            = \"Sobreatsesuyp\"\n    override val mainUrl         = \"https://sobreatsesuyp.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef = referer ?: \"\"\n\n        val videoReq = app.get(url, referer = extRef).text\n\n        val file     = Regex(\"\"\"file\\\":\\\"([^\\\"]+)\"\"\").find(videoReq)?.groupValues?.get(1) ?: throw ErrorLoadingException(\"File not found\")\n        val postLink = \"${mainUrl}/\" + file.replace(\"\\\\\", \"\")\n        val rawList  = app.post(postLink, referer = extRef).parsedSafe<List<Any>>() ?: throw ErrorLoadingException(\"Post link not found\")\n\n        val postJson: List<SobreatsesuypVideoData> = rawList.drop(1).map { item ->\n            val mapItem = item as Map<*, *>\n            SobreatsesuypVideoData(\n                title = mapItem[\"title\"] as? String,\n                file  = mapItem[\"file\"]  as? String\n            )\n        }\n\n        for (item in postJson) {\n            if (item.file == null || item.title == null) continue\n\n            val videoData = app.post(\"${mainUrl}/playlist/${item.file.substring(1)}.txt\", referer = extRef).text\n\n            callback.invoke(\n                newExtractorLink(\n                    source  = this.name,\n                    name    = \"${this.name} - ${item.title}\",\n                    url     = videoData,\n                ) {\n                    this.referer = extRef\n                }\n            )\n        }\n    }\n\n    data class SobreatsesuypVideoData(\n        @JsonProperty(\"title\") val title: String? = null,\n        @JsonProperty(\"file\")  val file: String?  = null\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamEmbed.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\n\nopen class StreamEmbed : ExtractorApi() {\n    override var name = \"StreamEmbed\"\n    override var mainUrl = \"https://watch.gxplayer.xyz\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val jsonString = app.get(url, referer = mainUrl).text\n            .substringAfter(\"var video = \").substringBefore(\";\")\n        val video = parseJson<Details>(jsonString)\n\n        M3u8Helper.generateM3u8(\n            this.name,\n            \"$mainUrl/m3u8/${video.uid}/${video.md5}/master.txt?s=1&id=${video.id}&cache=${video.status}\",\n            referer = \"$mainUrl/\",\n        ).forEach(callback)\n    }\n\n    private data class Details(\n        @JsonProperty(\"id\") val id: String,\n        @JsonProperty(\"uid\") val uid: String,\n        @JsonProperty(\"slug\") val slug: String,\n        @JsonProperty(\"title\") val title: String,\n        @JsonProperty(\"quality\") val quality: String,\n        @JsonProperty(\"type\") val type: String,\n        @JsonProperty(\"status\") val status: String,\n        @JsonProperty(\"md5\") val md5: String,\n    )\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamSB.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport kotlin.random.Random\n\nclass Sblona : StreamSB() {\n    override var name = \"Sblona\"\n    override var mainUrl = \"https://sblona.com\"\n}\n\nclass Lvturbo : StreamSB() {\n    override var name = \"Lvturbo\"\n    override var mainUrl = \"https://lvturbo.com\"\n}\n\nclass Sbrapid : StreamSB() {\n    override var name = \"Sbrapid\"\n    override var mainUrl = \"https://sbrapid.com\"\n}\n\nclass Sbface : StreamSB() {\n    override var name = \"Sbface\"\n    override var mainUrl = \"https://sbface.com\"\n}\n\nclass Sbsonic : StreamSB() {\n    override var name = \"Sbsonic\"\n    override var mainUrl = \"https://sbsonic.com\"\n}\n\nclass Vidgomunimesb : StreamSB() {\n    override var mainUrl = \"https://vidgomunimesb.xyz\"\n}\n\nclass Sbasian : StreamSB() {\n    override var mainUrl = \"https://sbasian.pro\"\n    override var name = \"Sbasian\"\n}\n\nclass Sbnet : StreamSB() {\n    override var name = \"Sbnet\"\n    override var mainUrl = \"https://sbnet.one\"\n}\n\nclass Keephealth : StreamSB() {\n    override var name = \"Keephealth\"\n    override var mainUrl = \"https://keephealth.info\"\n}\n\nclass Sbspeed : StreamSB() {\n    override var name = \"Sbspeed\"\n    override var mainUrl = \"https://sbspeed.com\"\n}\n\nclass Streamsss : StreamSB() {\n    override var mainUrl = \"https://streamsss.net\"\n}\n\nclass Sbflix : StreamSB() {\n    override var mainUrl = \"https://sbflix.xyz\"\n    override var name = \"Sbflix\"\n}\n\nclass Vidgomunime : StreamSB() {\n    override var mainUrl = \"https://vidgomunime.xyz\"\n}\n\nclass Sbthe : StreamSB() {\n    override var mainUrl = \"https://sbthe.com\"\n}\n\nclass Ssbstream : StreamSB() {\n    override var mainUrl = \"https://ssbstream.net\"\n}\n\nclass SBfull : StreamSB() {\n    override var mainUrl = \"https://sbfull.com\"\n}\n\nclass StreamSB1 : StreamSB() {\n    override var mainUrl = \"https://sbplay1.com\"\n}\n\nclass StreamSB2 : StreamSB() {\n    override var mainUrl = \"https://sbplay2.com\"\n}\n\nclass StreamSB3 : StreamSB() {\n    override var mainUrl = \"https://sbplay3.com\"\n}\n\nclass StreamSB4 : StreamSB() {\n    override var mainUrl = \"https://cloudemb.com\"\n}\n\nclass StreamSB5 : StreamSB() {\n    override var mainUrl = \"https://sbplay.org\"\n}\n\nclass StreamSB6 : StreamSB() {\n    override var mainUrl = \"https://embedsb.com\"\n}\n\nclass StreamSB7 : StreamSB() {\n    override var mainUrl = \"https://pelistop.co\"\n}\n\nclass StreamSB8 : StreamSB() {\n    override var mainUrl = \"https://streamsb.net\"\n}\n\nclass StreamSB9 : StreamSB() {\n    override var mainUrl = \"https://sbplay.one\"\n}\n\nclass StreamSB10 : StreamSB() {\n    override var mainUrl = \"https://sbplay2.xyz\"\n}\n\nclass StreamSB11 : StreamSB() {\n    override var mainUrl = \"https://sbbrisk.com\"\n}\n\nclass Sblongvu : StreamSB() {\n    override var mainUrl = \"https://sblongvu.com\"\n}\n\nopen class StreamSB : ExtractorApi() {\n    override var name = \"StreamSB\"\n    override var mainUrl = \"https://watchsb.com\"\n    override val requiresReferer = false\n    private val alphabet = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val regexID =\n            Regex(\"(embed-[a-zA-Z\\\\d]{0,8}[a-zA-Z\\\\d_-]+|/e/[a-zA-Z\\\\d]{0,8}[a-zA-Z\\\\d_-]+)\")\n        val id = regexID.findAll(url).map {\n            it.value.replace(Regex(\"(embed-|/e/)\"), \"\")\n        }.first()\n        val master = \"$mainUrl/375664356a494546326c4b797c7c6e756577776778623171737/${encodeId(id)}\"\n        val headers = mapOf(\n            \"watchsb\" to \"sbstream\",\n        )\n        val mapped = app.get(\n            master.lowercase(),\n            headers = headers,\n            referer = url,\n        ).parsedSafe<Main>()\n        M3u8Helper.generateM3u8(\n            name,\n            mapped?.streamData?.file ?: return,\n            url,\n            headers = headers\n        ).forEach(callback)\n\n        mapped.streamData.subs?.map {sub ->\n            subtitleCallback.invoke(\n                newSubtitleFile(\n                    sub.label.toString(),\n                    sub.file ?: return@map null,\n                )\n            )\n        }\n    }\n\n    private fun encodeId(id: String): String {\n        val code = \"${createHashTable()}||$id||${createHashTable()}||streamsb\"\n        return code.toCharArray().joinToString(\"\") { char ->\n            char.code.toString(16)\n        }\n    }\n\n    private fun createHashTable(): String {\n        return buildString {\n            repeat(12) {\n                append(alphabet[Random.nextInt(alphabet.length)])\n            }\n        }\n    }\n\n    data class Subs (\n        @JsonProperty(\"file\") val file: String? = null,\n        @JsonProperty(\"label\") val label: String? = null,\n    )\n\n    data class StreamData (\n        @JsonProperty(\"file\") val file: String,\n        @JsonProperty(\"cdn_img\") val cdnImg: String,\n        @JsonProperty(\"hash\") val hash: String,\n        @JsonProperty(\"subs\") val subs: ArrayList<Subs>? = arrayListOf(),\n        @JsonProperty(\"length\") val length: String,\n        @JsonProperty(\"id\") val id: String,\n        @JsonProperty(\"title\") val title: String,\n        @JsonProperty(\"backup\") val backup: String,\n    )\n\n    data class Main (\n        @JsonProperty(\"stream_data\") val streamData: StreamData,\n        @JsonProperty(\"status_code\") val statusCode: Int,\n    )\n\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamSilk.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\n\nopen class StreamSilk : ExtractorApi() {\n    override val name = \"StreamSilk\"\n    override val mainUrl = \"https://streamsilk.com\"\n    override val requiresReferer = true\n    private val srcRegex = Regex(\"var urlPlay =\\\\s*\\\"(.*?m3u8.*?)\\\"\")\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val response = app.get(url, headers = mapOf(\"Accept\" to \"*/*\"))\n        response.document.select(\"script\").firstOrNull {\n            it.html().contains(\"h,u,n,t,e,r\")\n        }?.html()?.let { hunted ->\n            JsHunter(hunted).dehunt()?.let { script ->\n                srcRegex.find(script)?.groupValues?.get(1)?.trim()?.let { link ->\n                    val headers = mapOf(\n                        \"Origin\" to mainUrl,\n                        \"Referer\" to \"$mainUrl/\",\n                        \"User-Agent\" to USER_AGENT,\n                    )\n                    M3u8Helper.generateM3u8(\n                        name,\n                        link,\n                        \"$mainUrl/\",\n                        headers = headers\n                    ).forEach(callback)\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamTape.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport org.mozilla.javascript.Context\n\nclass Watchadsontape : StreamTape() {\n    override var mainUrl = \"https://watchadsontape.com\"\n}\n\nclass StreamTapeNet : StreamTape() {\n    override var mainUrl = \"https://streamtape.net\"\n}\n\nclass StreamTapeXyz : StreamTape() {\n    override var mainUrl = \"https://streamtape.xyz\"\n}\n\nclass ShaveTape : StreamTape() {\n    override var mainUrl = \"https://shavetape.cash\"\n}\n\nopen class StreamTape : ExtractorApi() {\n    override var name = \"StreamTape\"\n    override var mainUrl = \"https://streamtape.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        with(app.get(url)) {\n            var result =\n                this.document.select(\"script\").firstOrNull { it.html().contains(\"botlink').innerHTML\") }\n                    ?.html()?.lines()?.firstOrNull{ it.contains(\"botlink').innerHTML\") }?.let {\n                        val scriptContent =\n                            it.substringAfter(\").innerHTML\").replaceFirst(\"=\", \"var url =\")\n                        val rhino = Context.enter()\n                        rhino.setInterpretedMode(true)\n                        val scope = rhino.initStandardObjects()\n                        var result = \"\"\n                        try {\n                            rhino.evaluateString(scope, scriptContent, \"url\", 1, null)\n                            result = scope.get(\"url\", scope).toString()\n                        }finally {\n                            rhino.close()\n                        }\n                        result\n                    }\n            if(!result.isNullOrEmpty()){\n                val extractedUrl = \"https:${result}&stream=1\"\n                return listOf(\n                    newExtractorLink(\n                        name,\n                        name,\n                        extractedUrl,\n                    ) {\n                        this.referer = url\n                        this.quality = Qualities.Unknown.value\n                    }\n                )\n            }\n        }\n        return null\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamWishExtractor.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport com.lagradost.cloudstream3.utils.getAndUnpack\nimport com.lagradost.cloudstream3.utils.getPacked\nimport com.lagradost.cloudstream3.network.WebViewResolver\n\n\n\nclass Mwish : StreamWishExtractor() {\n    override val name = \"Mwish\"\n    override val mainUrl = \"https://mwish.pro\"\n}\n\nclass Dwish : StreamWishExtractor() {\n    override val name = \"Dwish\"\n    override val mainUrl = \"https://dwish.pro\"\n}\n\nclass Ewish : StreamWishExtractor() {\n    override val name = \"Embedwish\"\n    override val mainUrl = \"https://embedwish.com\"\n}\n\nclass WishembedPro : StreamWishExtractor() {\n    override val name = \"Wishembed\"\n    override val mainUrl = \"https://wishembed.pro\"\n}\n\nclass Kswplayer : StreamWishExtractor() {\n    override val name = \"Kswplayer\"\n    override val mainUrl = \"https://kswplayer.info\"\n}\n\nclass Wishfast : StreamWishExtractor() {\n    override val name = \"Wishfast\"\n    override val mainUrl = \"https://wishfast.top\"\n}\n\nclass Streamwish2 : StreamWishExtractor() {\n    override val mainUrl = \"https://streamwish.site\"\n}\n\nclass SfastwishCom : StreamWishExtractor() {\n    override val name = \"Sfastwish\"\n    override val mainUrl = \"https://sfastwish.com\"\n}\n\nclass Strwish : StreamWishExtractor() {\n    override val name = \"Strwish\"\n    override val mainUrl = \"https://strwish.xyz\"\n}\n\nclass Strwish2 : StreamWishExtractor() {\n    override val name = \"Strwish\"\n    override val mainUrl = \"https://strwish.com\"\n}\n\nclass FlaswishCom : StreamWishExtractor() {\n    override val name = \"Flaswish\"\n    override val mainUrl = \"https://flaswish.com\"\n}\n\nclass Awish : StreamWishExtractor() {\n    override val name = \"Awish\"\n    override val mainUrl = \"https://awish.pro\"\n}\n\nclass Obeywish : StreamWishExtractor() {\n    override val name = \"Obeywish\"\n    override val mainUrl = \"https://obeywish.com\"\n}\n\nclass Jodwish : StreamWishExtractor() {\n    override val name = \"Jodwish\"\n    override val mainUrl = \"https://jodwish.com\"\n}\n\nclass Swhoi : StreamWishExtractor() {\n    override val name = \"Swhoi\"\n    override val mainUrl = \"https://swhoi.com\"\n}\n\nclass Multimovies : StreamWishExtractor() {\n    override val name = \"Multimovies\"\n    override val mainUrl = \"https://multimovies.cloud\"\n}\n\nclass UqloadsXyz : StreamWishExtractor() {\n    override val name = \"Uqloads\"\n    override val mainUrl = \"https://uqloads.xyz\"\n}\n\nclass Doodporn : StreamWishExtractor() {\n    override val name = \"Doodporn\"\n    override val mainUrl = \"https://doodporn.xyz\"\n}\n\nclass CdnwishCom : StreamWishExtractor() {\n    override val name = \"Cdnwish\"\n    override val mainUrl = \"https://cdnwish.com\"\n}\n\nclass Asnwish : StreamWishExtractor() {\n    override val name = \"Asnwish\"\n    override val mainUrl = \"https://asnwish.com\"\n}\n\nclass Nekowish : StreamWishExtractor() {\n    override val name = \"Nekowish\"\n    override val mainUrl = \"https://nekowish.my.id\"\n}\n\nclass Nekostream : StreamWishExtractor() {\n    override val name = \"Nekostream\"\n    override val mainUrl = \"https://neko-stream.click\"\n}\n\nclass Swdyu : StreamWishExtractor() {\n    override val name = \"Swdyu\"\n    override val mainUrl = \"https://swdyu.com\"\n}\n\nclass Wishonly : StreamWishExtractor() {\n    override val name = \"Wishonly\"\n    override val mainUrl = \"https://wishonly.site\"\n}\n\nclass Playerwish : StreamWishExtractor() {\n    override val name = \"Playerwish\"\n    override val mainUrl = \"https://playerwish.com\"\n}\n\nclass StreamHLS : StreamWishExtractor() {\n    override val name = \"StreamHLS\"\n    override val mainUrl = \"https://streamhls.to\"\n}\n\nclass HlsWish : StreamWishExtractor() {\n    override val name = \"HlsWish\"\n    override val mainUrl = \"https://hlswish.com\"\n}\n\nopen class StreamWishExtractor : ExtractorApi() {\n    override val name = \"Streamwish\"\n    override val mainUrl = \"https://streamwish.to\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val headers = mapOf(\n            \"Accept\" to \"*/*\",\n            \"Connection\" to \"keep-alive\",\n            \"Sec-Fetch-Dest\" to \"empty\",\n            \"Sec-Fetch-Mode\" to \"cors\",\n            \"Sec-Fetch-Site\" to \"cross-site\",\n            \"Referer\" to \"$mainUrl/\",\n            \"Origin\" to \"$mainUrl/\",\n            \"User-Agent\" to USER_AGENT\n        )\n\n        val pageResponse = app.get(resolveEmbedUrl(url), referer = referer)\n\n        val playerScriptData = when {\n            !getPacked(pageResponse.text).isNullOrEmpty() -> getAndUnpack(pageResponse.text)\n            pageResponse.document.select(\"script\").any { it.html().contains(\"jwplayer(\\\"vplayer\\\").setup(\") } ->\n                pageResponse.document.select(\"script\").firstOrNull {\n                    it.html().contains(\"jwplayer(\\\"vplayer\\\").setup(\")\n                }?.html()\n            else -> pageResponse.document.selectFirst(\"script:containsData(sources:)\")?.data()\n        }\n\n        val directStreamUrl = playerScriptData?.let {\n            Regex(\"\"\"file:\\s*\"(.*?m3u8.*?)\"\"\"\").find(it)?.groupValues?.getOrNull(1)\n        }\n\n        if (!directStreamUrl.isNullOrEmpty()) {\n            M3u8Helper.generateM3u8(\n                name,\n                directStreamUrl,\n                mainUrl,\n                headers = headers\n            ).forEach(callback)\n        } else {\n            val webViewM3u8Resolver = WebViewResolver(\n                interceptUrl = Regex(\"\"\"txt|m3u8\"\"\"),\n                additionalUrls = listOf(Regex(\"\"\"txt|m3u8\"\"\")),\n                useOkhttp = false,\n                timeout = 15_000L\n            )\n\n            val interceptedStreamUrl = app.get(\n                url,\n                referer = referer,\n                interceptor = webViewM3u8Resolver\n            ).url\n\n            if (interceptedStreamUrl.isNotEmpty()) {\n                M3u8Helper.generateM3u8(\n                    name,\n                    interceptedStreamUrl,\n                    mainUrl,\n                    headers = headers\n                ).forEach(callback)\n            } else {\n                Log.d(\"StreamwishExtractor\", \"No m3u8 found in fallback either.\")\n            }\n        }\n    }\n\n    private fun resolveEmbedUrl(inputUrl: String): String {\n        return if (inputUrl.contains(\"/f/\")) {\n            val videoId = inputUrl.substringAfter(\"/f/\")\n            \"$mainUrl/$videoId\"\n        } else if (inputUrl.contains(\"/e/\")) {\n            val videoId = inputUrl.substringAfter(\"/e/\")\n            \"$mainUrl/$videoId\"\n        } else {\n            inputUrl\n        }\n    }\n}\n\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamhub.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.JsUnpacker\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport java.net.URI\n\nopen class Streamhub : ExtractorApi() {\n    override var mainUrl = \"https://streamhub.to\"\n    override var name = \"Streamhub\"\n    override val requiresReferer = false\n\n    override fun getExtractorUrl(id: String): String {\n        return \"$mainUrl/e/$id\"\n    }\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val response = app.get(url).text\n        Regex(\"eval((.|\\\\n)*?)</script>\").find(response)?.groupValues?.get(1)?.let { jsEval ->\n            JsUnpacker(\"eval$jsEval\").unpack()?.let { unPacked ->\n                Regex(\"sources:\\\\[\\\\{src:\\\"(.*?)\\\"\").find(unPacked)?.groupValues?.get(1)?.let { link ->\n                    return listOf(\n                        newExtractorLink(\n                            source = this.name,\n                            this.name,\n                            link,\n                        )\n                    )\n                }\n            }\n        }\n        return null\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamlare.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.nicehttp.RequestBodyTypes\nimport okhttp3.MediaType.Companion.toMediaTypeOrNull\nimport okhttp3.RequestBody.Companion.toRequestBody\n\n\nclass Streamlare : Slmaxed() {\n    override val mainUrl = \"https://streamlare.com/\"\n}\n\nopen class Slmaxed : ExtractorApi() {\n    override val name = \"Streamlare\"\n    override val mainUrl = \"https://slmaxed.com/\"\n    override val requiresReferer = true\n\n    // https://slmaxed.com/e/oLvgezw3LjPzbp8E -> oLvgezw3LjPzbp8E\n    val embedRegex = Regex(\"\"\"/e/([^/]*)\"\"\")\n\n\n    data class JsonResponse(\n        @JsonProperty val status: String? = null,\n        @JsonProperty val message: String? = null,\n        @JsonProperty val type: String? = null,\n        @JsonProperty val token: String? = null,\n        @JsonProperty val result: Map<String, Result>? = null\n    )\n\n    data class Result(\n        @JsonProperty val label: String? = null,\n        @JsonProperty val file: String? = null,\n        @JsonProperty val type: String? = null\n    )\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val id = embedRegex.find(url)!!.groupValues[1]\n        val json = app.post(\n            \"${mainUrl}api/video/stream/get\",\n            requestBody = \"\"\"{\"id\":\"$id\"}\"\"\".toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull())\n        ).parsed<JsonResponse>()\n        return json.result?.mapNotNull {\n            it.value.let { result ->\n                newExtractorLink(\n                    this.name,\n                    this.name,\n                    result.file ?: return@mapNotNull null,\n                    type = if (result.type?.contains(\n                            \"hls\",\n                            ignoreCase = true\n                        ) == true\n                    ) ExtractorLinkType.M3U8 else INFER_TYPE\n                ) {\n                    this.referer = url\n                    this.quality =\n                        result.label?.replace(\"p\", \"\", ignoreCase = true)?.trim()?.toIntOrNull()\n                            ?: Qualities.Unknown.value\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamoUpload.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.getAndUnpack\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.M3u8Helper\n\nopen class StreamoUpload : ExtractorApi() {\n    override val name = \"StreamoUpload\"\n    override val mainUrl = \"https://streamoupload.xyz\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val sources = mutableListOf<ExtractorLink>()\n        val response = app.get(url, referer = referer)\n        val scriptElements = response.document.select(\"script\").map { script ->\n            if (script.data().contains(\"eval(function(p,a,c,k,e,d)\")) {\n                val data = getAndUnpack(script.data())\n                    .substringAfter(\"sources:[\")\n                    .substringBefore(\"],\")\n                    .replace(\"file\", \"\\\"file\\\"\")\n                    .trim()\n                tryParseJson<File>(data)?.let {\n                    M3u8Helper.generateM3u8(\n                        name,\n                        it.file,\n                        \"$mainUrl/\",\n                    ).forEach { m3uData -> sources.add(m3uData) }\n                }\n            }\n        }\n        return sources\n    }\n\n    private data class File(\n        @JsonProperty(\"file\") val file: String,\n    )\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamplay.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder.getCaptchaToken\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport java.net.URI\n\nopen class Streamplay : ExtractorApi() {\n    override val name = \"Streamplay\"\n    override val mainUrl = \"https://streamplay.to\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val request = app.get(url, referer = referer)\n        val redirectUrl = request.url\n        val mainServer = URI(redirectUrl).let {\n            \"${it.scheme}://${it.host}\"\n        }\n        val key = redirectUrl.substringAfter(\"embed-\").substringBefore(\".html\")\n        val token =\n            request.document.select(\"script\").find { it.data().contains(\"sitekey:\") }?.data()\n                ?.substringAfterLast(\"sitekey: '\")?.substringBefore(\"',\")?.let { captchaKey ->\n                    getCaptchaToken(\n                        redirectUrl,\n                        captchaKey,\n                        referer = \"$mainServer/\"\n                    )\n                } ?: throw ErrorLoadingException(\"can't bypass captcha\")\n        app.post(\n            \"$mainServer/player-$key-488x286.html\", data = mapOf(\n                \"op\" to \"embed\",\n                \"token\" to token\n            ),\n            referer = redirectUrl,\n            headers = mapOf(\n                \"Accept\" to \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\",\n                \"Content-Type\" to \"application/x-www-form-urlencoded\"\n            )\n        ).document.select(\"script\").find { script ->\n            script.data().contains(\"eval(function(p,a,c,k,e,d)\")\n        }?.let {\n            val data = getAndUnpack(it.data()).substringAfter(\"sources=[\").substringBefore(\",desc\")\n                .replace(\"file\", \"\\\"file\\\"\")\n                .replace(\"label\", \"\\\"label\\\"\")\n            tryParseJson<List<Source>>(\"[$data}]\")?.map { res ->\n                callback.invoke(\n                    newExtractorLink(\n                        this.name,\n                        this.name,\n                        res.file ?: return@map null,\n                    ) {\n                        this.referer = \"$mainServer/\"\n                        this.quality = when (res.label) {\n                            \"HD\" -> Qualities.P720.value\n                            \"SD\" -> Qualities.P480.value\n                            else -> Qualities.Unknown.value\n                        }\n                        this.headers = mapOf(\n                            \"Range\" to \"bytes=0-\"\n                        )\n                    }\n                )\n            }\n        }\n\n    }\n\n    data class Source(\n        @JsonProperty(\"file\") val file: String? = null,\n        @JsonProperty(\"label\") val label: String? = null,\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamup.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass Streamix(): Streamup() {\n    override val name: String = \"Streamix\"\n    override val mainUrl = \"https://streamix.so\"\n}\n\nclass Vidara(): Streamup() {\n    override val name: String = \"Vidara\"\n    override val mainUrl = \"https://vidara.to\"\n    override val apiPath: String = \"/api/stream\"\n}\n\nopen class Streamup() : ExtractorApi() {\n    override val name: String = \"Streamup\"\n    override val mainUrl: String = \"https://strmup.to\"\n    override val requiresReferer: Boolean = false\n    open val apiPath: String = \"/ajax/stream\"\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val fileCode = url.substringAfterLast(\"/\")\n        val fileInfo = app.get(\"$mainUrl$apiPath?filecode=$fileCode\")\n            .parsed<StreamUpFileInfo>()\n\n        callback.invoke(\n            newExtractorLink(\n                source = name,\n                name = name,\n                url = fileInfo.streamingUrl,\n                type = ExtractorLinkType.M3U8\n            )\n        )\n\n        fileInfo.subtitles?.forEach { subtitle ->\n            subtitleCallback.invoke(\n                newSubtitleFile(subtitle.language, subtitle.filePath)\n            )\n        }\n    }\n\n    private data class StreamUpFileInfo(\n        val title: String,\n        val thumbnail: String,\n        @JsonProperty(\"streaming_url\")\n        val streamingUrl: String,\n        val subtitles: List<StreamUpSubtitle>?\n    )\n\n    private data class StreamUpSubtitle(\n        @JsonProperty(\"file_path\")\n        val filePath: String,\n        @JsonProperty(\"language\")\n        val language: String,\n    )\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Supervideo.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\n\ndata class Files(\n    @JsonProperty(\"file\") val id: String,\n    @JsonProperty(\"label\") val label: String? = null,\n)\n\nopen class Supervideo : ExtractorApi() {\n    override var name = \"Supervideo\"\n    override var mainUrl = \"https://supervideo.cc\"\n    override val requiresReferer = false\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()\n        val response = app.get(url).text\n        val jstounpack = Regex(\"eval((.|\\\\n)*?)</script>\").find(response)?.groups?.get(1)?.value\n        val unpacjed = JsUnpacker(jstounpack).unpack()\n        val extractedUrl =\n            unpacjed?.let { Regex(\"\"\"sources:((.|\\n)*?)image\"\"\").find(it) }?.groups?.get(1)?.value.toString()\n                .replace(\"file\", \"\"\"\"file\"\"\"\").replace(\"label\", \"\"\"\"label\"\"\"\")\n                .substringBeforeLast(\",\")\n        val parsedlinks = parseJson<List<Files>>(extractedUrl)\n        parsedlinks.forEach { data ->\n            if (data.label.isNullOrBlank()) { // mp4 links (with labels) are slow. Use only m3u8 link.\n                M3u8Helper.generateM3u8(\n                    name,\n                    data.id,\n                    url,\n                    headers = mapOf(\"referer\" to url)\n                ).forEach { link ->\n                    extractedLinksList.add(link)\n                }\n            }\n        }\n        return extractedLinksList\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TRsTXExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\nimport com.fasterxml.jackson.annotation.JsonProperty\n\nopen class TRsTX : ExtractorApi() {\n    override val name            = \"TRsTX\"\n    override val mainUrl         = \"https://trstx.org\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef = referer ?: \"\"\n\n        val videoReq = app.get(url, referer=extRef).text\n\n        val file     = Regex(\"\"\"file\\\":\\\"([^\\\"]+)\"\"\").find(videoReq)?.groupValues?.get(1) ?: throw ErrorLoadingException(\"File not found\")\n        val postLink = \"${mainUrl}/\" + file.replace(\"\\\\\", \"\")\n        val rawList  = app.post(postLink, referer=extRef).parsedSafe<List<Any>>() ?: throw ErrorLoadingException(\"Post link not found\")\n\n        val postJson: List<TrstxVideoData> = rawList.drop(1).map { item ->\n            val mapItem = item as Map<*, *>\n            TrstxVideoData(\n                title = mapItem[\"title\"] as? String,\n                file  = mapItem[\"file\"]  as? String\n            )\n        }\n\n        val vidLinks = mutableSetOf<String>()\n        val vidMap   = mutableListOf<Map<String, String>>()\n        for (item in postJson) {\n            if (item.file == null || item.title == null) continue\n\n            val fileUrl   = \"${mainUrl}/playlist/\" + item.file.substring(1) + \".txt\"\n            val videoData = app.post(fileUrl, referer=extRef).text\n\n            if (videoData in vidLinks) { continue }\n            vidLinks.add(videoData)\n\n            vidMap.add(mapOf(\n                \"title\"     to item.title,\n                \"videoData\" to videoData\n            ))\n        }\n\n        for (mapEntry in vidMap) {\n            val title    = mapEntry[\"title\"] ?: continue\n            val m3uLink = mapEntry[\"videoData\"] ?: continue\n\n            callback.invoke(\n                newExtractorLink(\n                    source  = this.name,\n                    name    = \"${this.name} - ${title}\",\n                    url     = m3uLink,\n                ) {\n                    this.referer = extRef\n                }\n            )\n        }\n    }\n\n    data class TrstxVideoData(\n        @JsonProperty(\"title\") val title: String? = null,\n        @JsonProperty(\"file\")  val file: String?  = null\n    )\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Tantifilm.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Tantifilm : ExtractorApi() {\n    override var name = \"Tantifilm\"\n    override var mainUrl = \"https://cercafilm.net\"\n    override val requiresReferer = false\n\n    data class TantifilmJsonData (\n        @JsonProperty(\"success\") val success : Boolean,\n        @JsonProperty(\"data\") val data : List<TantifilmData>,\n        @JsonProperty(\"captions\")val captions : List<String>,\n        @JsonProperty(\"is_vr\") val is_vr : Boolean\n    )\n\n    data class TantifilmData (\n        @JsonProperty(\"file\") val file : String,\n        @JsonProperty(\"label\") val label : String,\n        @JsonProperty(\"type\") val type : String\n    )\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val link = \"$mainUrl/api/source/${url.substringAfterLast(\"/\")}\"\n        val response = app.post(link).text.replace(\"\"\"\\\"\"\",\"\")\n        val jsonvideodata = parseJson<TantifilmJsonData>(response)\n        return jsonvideodata.data.map {\n            newExtractorLink(\n                this.name,\n                this.name,\n                it.file+\".${it.type}\"\n            ) {\n                this.referer = mainUrl\n                this.quality = it.label.filter{ it.isDigit() }.toInt()\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TauVideoExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\nimport com.fasterxml.jackson.annotation.JsonProperty\n\nopen class TauVideo : ExtractorApi() {\n    override val name            = \"TauVideo\"\n    override val mainUrl         = \"https://tau-video.xyz\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef   = referer ?: \"\"\n        val videoKey = url.split(\"/\").last()\n        val videoUrl = \"${mainUrl}/api/video/${videoKey}\"\n\n        val api = app.get(videoUrl).parsedSafe<TauVideoUrls>() ?: throw ErrorLoadingException(\"TauVideo\")\n\n        for (video in api.urls) {\n            callback.invoke(\n                newExtractorLink(\n                    source  = this.name,\n                    name    = this.name,\n                    url     = video.url,\n                ) {\n                    this.referer = extRef\n                    this.quality = getQualityFromName(video.label)\n                }\n            )\n        }\n    }\n\n    data class TauVideoUrls(\n        @JsonProperty(\"urls\") val urls: List<TauVideoData>\n    )\n\n    data class TauVideoData(\n        @JsonProperty(\"url\")   val url: String,\n        @JsonProperty(\"label\") val label: String,\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Up4Stream.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.JsUnpacker\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.fixUrl\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport kotlinx.coroutines.delay\n\nclass Up4FunTop : Up4Stream() {\n    override var mainUrl: String = \"https://up4fun.top\"\n}\n\nopen class Up4Stream : ExtractorApi() {\n    override var name = \"Up4Stream\"\n    override var mainUrl = \"https://up4stream.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val movieId = url.substringAfterLast(\"/\").substringBefore(\".html\")\n\n        // redirect from \"wait 5 seconds\" page to actual movie page\n        val redirectResponse = app.get(url, cookies = mapOf(\"id\" to movieId))\n        val redirectForm = redirectResponse.document.selectFirst(\"form[method=POST]\") ?: return null\n        val redirectUrl = fixUrl(redirectForm.attr(\"action\"))\n        val redirectParams = redirectForm.select(\"input[type=hidden]\").associate { input ->\n            input.attr(\"name\") to input.attr(\"value\")\n        }\n\n        // wait for 5 seconds, otherwise the below md5 hash is invalid\n        delay(5000)\n        val response = app.post(redirectUrl, data = redirectParams).document\n\n        // starting here, this works similar to many other extractors like StreamWish\n        val extractedpack =\n            response.selectFirst(\"script:containsData(function(p,a,c,k,e,d))\")?.data()\n        if (extractedpack == null) {\n            Log.e(\"up4stream\", \"file not ready: delay too short\")\n        }\n\n        JsUnpacker(extractedpack).unpack()?.let { unPacked ->\n            Regex(\"sources:\\\\[\\\\{file:\\\"(.*?)\\\"\").find(unPacked)?.groupValues?.get(1)?.let { link ->\n                return listOf(\n                    newExtractorLink(\n                        this.name,\n                        this.name,\n                        link,\n                    ) {\n                        this.referer = referer.orEmpty()\n                        this.quality = Qualities.Unknown.value\n                    }\n                )\n            }\n        }\n        return null\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/UpstreamExtractor.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\n\nopen class UpstreamExtractor : ExtractorApi() {\n    override val name: String = \"Upstream\"\n    override val mainUrl: String = \"https://upstream.to\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        //Log.i(this.name, \"Result => (no extractor) ${url}\")\n        val doc = app.get(url, referer = referer).text\n        if (doc.isNotBlank()) {\n            var reg = Regex(\"(?<=master)(.*)(?=hls)\")\n            val result = reg.find(doc)?.groupValues?.map {\n                it.trim('|')\n            }?.toList()\n            reg = Regex(\"(?<=\\\\|file\\\\|)(.*)(?=\\\\|remove\\\\|)\")\n            val domainList = reg.find(doc)?.groupValues?.get(1)?.split(\"|\")\n            var domain = when (!domainList.isNullOrEmpty()) {\n                true -> {\n                    if (domainList.isNotEmpty()) {\n                        var domName = \"\"\n                        for (part in domainList) {\n                            domName = \"${part}.${domName}\"\n                        }\n                        domName.trimEnd('.')\n                    } else {\n                        \"\"\n                    }\n                }\n                false -> \"\"\n            }\n            //Log.i(this.name, \"Result => (domain) ${domain}\")\n            if (domain.isEmpty()) {\n                domain = \"s96.upstreamcdn.co\"\n                //Log.i(this.name, \"Result => (default domain) ${domain}\")\n            }\n\n            result?.forEach {\n                val linkUrl = \"https://${domain}/hls/${it}/master.m3u8\"\n                M3u8Helper.generateM3u8(\n                    this.name,\n                    linkUrl,\n                    \"$mainUrl/\",\n                    headers = mapOf(\"Origin\" to mainUrl)\n                ).forEach(callback)\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Uqload.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.*\n\n// import android.util.Log\n\nclass Uqload1 : Uqload() {\n    override var mainUrl = \"https://uqload.com\"\n}\n\nclass Uqload2 : Uqload() {\n    override var mainUrl = \"https://uqload.co\"\n}\n\nclass Uqloadcx : Uqload() {\n    override var mainUrl = \"https://uqload.cx\"\n}\n\nclass Uqloadbz : Uqload() {\n    override var mainUrl = \"https://uqload.bz\"\n}\n\nopen class Uqload : ExtractorApi() {\n    override var name: String = \"Uqload\"\n    override var mainUrl: String = \"https://www.uqload.com\"\n    override val requiresReferer = true\n\n    private val  srcRegex = Regex(\"\"\"sources:.*\"(.*?)\".*\"\"\")  // would be possible to use the parse and find src attribute\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        with(app.get(url)) {  // raised error ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED (3003) is due to the response: \"error_nofile\"\n            srcRegex.find(this.text)?.groupValues?.get(1)?.let { link ->\n                // Log.d(\"CS3debugUQload\",\"decoded URL: $link\")\n                callback.invoke(\n                    newExtractorLink(\n                        source = name,\n                        name = name,\n                        url = link\n                    ) {\n                        this.referer = \"$mainUrl/\"\n                    }\n                )\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Userload.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\nimport org.mozilla.javascript.Context\nimport org.mozilla.javascript.EvaluatorException\nimport org.mozilla.javascript.Scriptable\nimport java.util.*\n\n\nopen class Userload : ExtractorApi() {\n    override var name = \"Userload\"\n    override var mainUrl = \"https://userload.co\"\n    override val requiresReferer = false\n\n    private fun splitInput(input: String): List<String> {\n        var counter = 0\n        val array = ArrayList<String>()\n        var buffer = \"\"\n        for (c in input) {\n            when (c) {\n                '(' -> counter++\n                ')' -> counter--\n                else -> {}\n            }\n            buffer += c\n            if (counter == 0) {\n                if (buffer.isNotBlank() && buffer != \"+\")\n                    array.add(buffer)\n                buffer = \"\"\n            }\n        }\n        return array\n    }\n\n    private fun evaluateMath(mathExpression : String): String {\n        val rhino = Context.enter()\n        rhino.initStandardObjects()\n        rhino.setInterpretedMode(true)\n        val scope: Scriptable = rhino.initStandardObjects()\n        return try {\n            rhino.evaluateString(scope, \"eval($mathExpression)\", \"JavaScript\", 1, null).toString()\n        }\n        catch (e: EvaluatorException){\n            \"\"\n        }\n    }\n\n    private fun decodeVideoJs(text: String): List<String> {\n        text.replace(\"\"\"\\s+|/\\*.*?\\*/\"\"\".toRegex(), \"\")\n        val data = text.split(\"\"\"+(ﾟДﾟ)[ﾟoﾟ]\"\"\")[1]\n        val chars = data.split(\"\"\"+ (ﾟДﾟ)[ﾟεﾟ]+\"\"\").drop(1)\n        val newchars = chars.map { char ->\n            char.replace(\"(oﾟｰﾟo)\", \"u\")\n                .replace(\"c\", \"0\")\n                .replace(\"(ﾟДﾟ)['0']\", \"c\")\n                .replace(\"ﾟΘﾟ\", \"1\")\n                .replace(\"!+[]\", \"1\")\n                .replace(\"-~\", \"1+\")\n                .replace(\"o\", \"3\")\n                .replace(\"_\", \"3\")\n                .replace(\"ﾟｰﾟ\", \"4\")\n                .replace(\"(+\", \"(\")\n        }\n\n        val subchar = mutableListOf<String>()\n\n        newchars.dropLast(1).forEach { v ->\n            subchar.add(splitInput(v).map { evaluateMath(it).substringBefore(\".\") }.toString().filter { it.isDigit() })\n        }\n        var txtresult = \"\"\n        subchar.forEach{\n            txtresult = txtresult.plus(Char(it.toInt(8)))\n        }\n        val val1 = Regex(\"\"\"\"morocco=\"((.|\\\\n)*?)\"&mycountry=\"\"\"\").find(txtresult)?.groups?.get(1)?.value.toString().drop(1).dropLast(1)\n        val val2 = txtresult.substringAfter(\"\"\"&mycountry=\"+\"\"\").substringBefore(\")\")\n\n        return listOf(\n            val1,\n            val2\n        )\n\n\n    }\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n\n        val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()\n\n        val response = app.get(url).text\n        val jsToUnpack = Regex(\"ext/javascript\\\">eval((.|\\\\n)*?)</script>\").find(response)?.groups?.get(1)?.value\n        val unpacked = JsUnpacker(jsToUnpack).unpack()\n        val videoJs = app.get(\"$mainUrl/api/assets/userload/js/videojs.js\")\n        val videoJsToDecode = videoJs.text\n        val values = decodeVideoJs(videoJsToDecode)\n        val morocco = unpacked!!.split(\";\").filter { it.contains(values[0]) }[0].split(\"=\")[1].drop(1).dropLast(1)\n        val mycountry = unpacked.split(\";\").filter { it.contains(values[1]) }[0].split(\"=\")[1].drop(1).dropLast(1)\n        val videoLinkPage = app.post(\"$mainUrl/api/request/\", data = mapOf(\n            \"morocco\" to morocco,\n            \"mycountry\" to mycountry\n        ))\n        val videoLink = videoLinkPage.text\n        val nameSource = app.get(url).document.head().selectFirst(\"title\")!!.text()\n        extractedLinksList.add(\n            newExtractorLink(\n                name,\n                name,\n                videoLink\n            ) {\n                this.referer = mainUrl\n                this.quality = getQualityFromName(nameSource)\n            }\n        )\n\n        return extractedLinksList\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Userscloud.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Userscloud : ExtractorApi() {\n    override val name = \"Userscloud\"\n    override val mainUrl = \"https://userscloud.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val res = app.get(url).document\n        val video = res.selectFirst(\"video#vjsplayer source\")?.attr(\"src\")\n        val quality = res.selectFirst(\"div.innerTB h2 b\")?.text()\n        callback.invoke(\n            newExtractorLink(\n                this.name,\n                this.name,\n                video ?: return,\n            ) {\n                this.referer = \"$mainUrl/\"\n                this.quality = getQuality(quality)\n                this.headers = mapOf(\n                    \"Accept\" to \"video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5\",\n                    \"Range\" to \"bytes=0-\",\n                    \"Sec-Fetch-Dest\" to \"video\",\n                    \"Sec-Fetch-Mode\" to \"no-cors\",\n                )\n            }\n        )\n    }\n\n    private fun getQuality(str: String?): Int {\n        return Regex(\"(\\\\d{3,4})[pP]\").find(str ?: \"\")?.groupValues?.getOrNull(1)?.toIntOrNull()\n            ?: Qualities.Unknown.value\n    }\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Uservideo.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.AppUtils\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Uservideo : ExtractorApi() {\n    override val name: String = \"Uservideo\"\n    override val mainUrl: String = \"https://uservideo.xyz\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val script = app.get(url).document.selectFirst(\"script:containsData(hosts =)\")?.data()\n        val host = script?.substringAfter(\"hosts = [\\\"\")?.substringBefore(\"\\\"];\")\n        val servers = script?.substringAfter(\"servers = \\\"\")?.substringBefore(\"\\\";\")\n\n        val sources = app.get(\"$host/s/$servers\").text.substringAfter(\"\\\"sources\\\":[\").substringBefore(\"],\").let {\n            AppUtils.tryParseJson<List<Sources>>(\"[$it]\")\n        }\n        val quality = Regex(\"(\\\\d{3,4})[Pp]\").find(url)?.groupValues?.getOrNull(1)?.toIntOrNull()\n\n        sources?.map { source ->\n            callback.invoke(\n                newExtractorLink(\n                    name,\n                    name,\n                    source.src ?: return@map null\n                ) {\n                    this.referer = url\n                    this.quality = quality ?: Qualities.Unknown.value\n                }\n            )\n        }\n\n    }\n\n    data class Sources(\n        @JsonProperty(\"src\") val src: String? = null,\n        @JsonProperty(\"type\") val type: String? = null,\n        @JsonProperty(\"label\") val label: String? = null,\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vicloud.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Vicloud : ExtractorApi() {\n    override val name: String = \"Vicloud\"\n    override val mainUrl: String = \"https://vicloud.sbs\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val id = Regex(\"\\\"apiQuery\\\":\\\"(.*?)\\\"\").find(app.get(url).text)?.groupValues?.getOrNull(1)\n        app.get(\n            \"$mainUrl/api/?$id=&_=${System.currentTimeMillis()}\",\n            headers = mapOf(\n                \"X-Requested-With\" to \"XMLHttpRequest\"\n            ),\n            referer = url\n        ).parsedSafe<Responses>()?.sources?.map { source ->\n            callback.invoke(\n                newExtractorLink(\n                    name,\n                    name,\n                    source.file ?: return@map null,\n                ) {\n                    this.referer = url\n                    this.quality = getQualityFromName(source.label)\n                }\n            )\n        }\n\n    }\n\n    private data class Sources(\n        @JsonProperty(\"file\") val file: String? = null,\n        @JsonProperty(\"label\") val label: String? = null,\n    )\n\n    private data class Responses(\n        @JsonProperty(\"sources\") val sources: List<Sources>? = arrayListOf(),\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidHidePro.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8\n\nclass Ryderjet: VidHidePro() {\n    override var mainUrl = \"https://ryderjet.com\"\n}\n\nclass VidHideHub : VidHidePro() {\n    override var mainUrl = \"https://vidhidehub.com\"\n}\n\nclass VidHidePro1 : VidHidePro() {\n    override var mainUrl = \"https://filelions.live\"\n}\n\nclass VidHidePro2 : VidHidePro() {\n    override var mainUrl = \"https://filelions.online\"\n}\n\nclass VidHidePro3 : VidHidePro() {\n    override var mainUrl = \"https://filelions.to\"\n}\n\nclass VidHidePro4 : VidHidePro() {\n    override val mainUrl = \"https://kinoger.be\"\n}\n\nclass VidHidePro5: VidHidePro() {\n    override val mainUrl = \"https://vidhidevip.com\"\n}\n\nclass VidHidePro6 : VidHidePro() {\n    override val mainUrl = \"https://vidhidepre.com\"\n}\n\nclass Smoothpre: VidHidePro() {\n    override var name = \"EarnVids\"\n    override var mainUrl = \"https://smoothpre.com\"\n}\n\nclass Dhtpre: VidHidePro() {\n    override var name = \"EarnVids\"\n    override var mainUrl = \"https://dhtpre.com\"\n}\n\nclass Peytonepre : VidHidePro() {\n    override var name = \"EarnVids\"\n    override var mainUrl = \"https://peytonepre.com\"\n}\n\nopen class VidHidePro : ExtractorApi() {\n    override val name = \"VidHidePro\"\n    override val mainUrl = \"https://vidhidepro.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val headers = mapOf(\n            \"Sec-Fetch-Dest\" to \"empty\",\n            \"Sec-Fetch-Mode\" to \"cors\",\n            \"Sec-Fetch-Site\" to \"cross-site\",\n            \"Origin\" to mainUrl,\n\t        \"User-Agent\" to USER_AGENT,\n        )\n        \n        val response = app.get(getEmbedUrl(url), referer = referer)\n        val script = if (!getPacked(response.text).isNullOrEmpty()) {\n            var result = getAndUnpack(response.text)\n            if(result.contains(\"var links\")){\n                result = result.substringAfter(\"var links\")\n            }\n            result\n        } else {\n            response.document.selectFirst(\"script:containsData(sources:)\")?.data()\n        } ?: return\n\n        // m3u8 urls could be prefixed by 'file:', 'hls2:' or 'hls4:', so we just match ':'\n        Regex(\":\\\\s*\\\"(.*?m3u8.*?)\\\"\").findAll(script).forEach { m3u8Match ->\n            generateM3u8(\n                name,\n                fixUrl(m3u8Match.groupValues[1]),\n                referer = \"$mainUrl/\",\n                headers = headers\n            ).forEach(callback)\n        }\n    }\n\n    private fun getEmbedUrl(url: String): String {\n\t\treturn when {\n\t\t\turl.contains(\"/d/\") -> url.replace(\"/d/\", \"/v/\")\n\t\t\turl.contains(\"/download/\") -> url.replace(\"/download/\", \"/v/\")\n\t\t\turl.contains(\"/file/\") -> url.replace(\"/file/\", \"/v/\")\n\t\t\telse -> url.replace(\"/f/\", \"/v/\")\n\t\t}\n\t}\n\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidMoxyExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\n\nopen class VidMoxy : ExtractorApi() {\n    override val name            = \"VidMoxy\"\n    override val mainUrl         = \"https://vidmoxy.com\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef   = referer ?: \"\"\n        val videoReq = app.get(url, referer=extRef).text\n\n        val subUrls = mutableSetOf<String>()\n        Regex(\"\"\"captions\\\",\\\"file\\\":\\\"([^\\\"]+)\\\",\\\"label\\\":\\\"([^\\\"]+)\\\"\"\"\").findAll(videoReq).forEach {\n            val (subUrl, subLang) = it.destructured\n\n            if (subUrl in subUrls) { return@forEach }\n            subUrls.add(subUrl)\n\n            subtitleCallback.invoke(\n                newSubtitleFile(\n                    lang = subLang.replace(\"\\\\u0131\", \"ı\").replace(\"\\\\u0130\", \"İ\").replace(\"\\\\u00fc\", \"ü\").replace(\"\\\\u00e7\", \"ç\"),\n                    url  = fixUrl(subUrl.replace(\"\\\\\", \"\"))\n                )\n            )\n        }\n\n        var extractedValue  = Regex(\"\"\"file\": \"(.*)\",\"\"\").find(videoReq)?.groupValues?.get(1)\n        var decoded: String? = null\n\n        if (extractedValue != null) {\n            val bytes = extractedValue.split(\"\\\\x\").filter { it.isNotEmpty() }.map { it.toInt(16).toByte() }.toByteArray()\n            decoded   = String(bytes, Charsets.UTF_8)\n        } else {\n            val evaljwSetup = Regex(\"\"\"\\};\\s*(eval\\(function[\\s\\S]*?)var played = \\d+;\"\"\").find(videoReq)?.groupValues?.get(1) ?: throw ErrorLoadingException(\"File not found\")\n            val jwSetup     = getAndUnpack(getAndUnpack(evaljwSetup)).replace(\"\\\\\\\\\", \"\\\\\")\n            extractedValue  = Regex(\"\"\"file\":\"(.*)\",\"label\"\"\").find(jwSetup)?.groupValues?.get(1)?.replace(\"\\\\\\\\x\", \"\")\n\n            val bytes = extractedValue?.chunked(2)?.map { it.toInt(16).toByte() }?.toByteArray()\n            decoded   = bytes?.toString(Charsets.UTF_8) ?: throw ErrorLoadingException(\"File not found\")\n        }\n\n        callback.invoke(\n            newExtractorLink(\n                source  = this.name,\n                name    = this.name,\n                url     = decoded,\n                type = ExtractorLinkType.M3U8\n            ) {\n                this.referer = extRef\n                this.quality = Qualities.Unknown.value\n            }\n        )\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidNest.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class VidNest : ExtractorApi() {\n    override var name = \"VidNest\"\n    override var mainUrl = \"https://vidnest.io\"\n    override val requiresReferer = true\n\n    private val sourceRegex = Regex(\"\"\"sources:[\\W\\w]*?file:\\s*?[\"'](.*?)[\"']\"\"\")\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()\n        with(app.get(url, referer = referer)) {\n            sourceRegex.findAll(this.text).forEach { sourceMatch ->\n                val extractedUrl = sourceMatch.groupValues[1]\n                // Trusting this isn't mp4, may fuck up stuff\n                if (extractedUrl.contains(\".m3u8\")) {\n                    M3u8Helper.generateM3u8(\n                        name,\n                        extractedUrl,\n                        url,\n                        headers = mapOf(\"referer\" to this.url)\n                    ).forEach { link ->\n                        extractedLinksList.add(link)\n                    }\n                } else if (extractedUrl.contains(\".mp4\")) {\n                    extractedLinksList.add(\n                        newExtractorLink(\n                            source = name,\n                            name = name,\n                            url = extractedUrl,\n                        ) {\n                            this.referer = url.replace(\" \", \"%20\")\n                        }\n                    )\n                }\n            }\n            return extractedLinksList\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidStack.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.fixUrl\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport java.net.URI\nimport javax.crypto.Cipher\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\n\nclass Server1uns : VidStack() {\n    override var name = \"Vidstack\"\n    override var mainUrl = \"https://server1.uns.bio\"\n    override var requiresReferer = true\n}\n\n\nopen class VidStack : ExtractorApi() {\n    override var name = \"Vidstack\"\n    override var mainUrl = \"https://vidstack.io\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    )\n    {\n        val headers = mapOf(\"User-Agent\" to \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0\")\n        val hash = url.substringAfterLast(\"#\").substringAfter(\"/\")\n        val baseurl = getBaseUrl(url)\n\n        val encoded = app.get(\"$baseurl/api/v1/video?id=$hash\", headers = headers).text.trim()\n\n        val key = \"kiemtienmua911ca\"\n        val ivList = listOf(\"1234567890oiuytr\", \"0123456789abcdef\")\n\n        val decryptedText = ivList.firstNotNullOfOrNull { iv ->\n            try {\n                AesHelper.decryptAES(encoded, key, iv)\n            } catch (e: Exception) {\n                null\n            }\n        } ?: throw Exception(\"Failed to decrypt with all IVs\")\n\n        val m3u8 = Regex(\"\\\"source\\\":\\\"(.*?)\\\"\").find(decryptedText)\n            ?.groupValues?.get(1)\n            ?.replace(\"\\\\/\", \"/\") ?: \"\"\n        val subtitlePattern = Regex(\"\\\"([^\\\"]+)\\\":\\\\s*\\\"([^\\\"]+)\\\"\")\n        val subtitleSection = Regex(\"\\\"subtitle\\\":\\\\{(.*?)\\\\}\").find(decryptedText)?.groupValues?.get(1)\n\n        subtitleSection?.let { section ->\n            subtitlePattern.findAll(section).forEach { match ->\n                val lang = match.groupValues[1]\n                val rawPath = match.groupValues[2].split(\"#\")[0]\n                if (rawPath.isNotEmpty()) {\n                    val path = rawPath.replace(\"\\\\/\", \"/\")\n                    val subUrl = \"$mainUrl$path\"\n                    subtitleCallback(newSubtitleFile(lang, fixUrl(subUrl)))\n                }\n            }\n        }\n\n        callback.invoke(\n            newExtractorLink(\n                source = this.name,\n                name = this.name,\n                url = m3u8,\n                type = ExtractorLinkType.M3U8\n            ) {\n                this.referer = url\n                this.quality = Qualities.Unknown.value\n            }\n        )\n    }\n\n    private fun getBaseUrl(url: String): String {\n        return try {\n            URI(url).let { \"${it.scheme}://${it.host}\" }\n        } catch (e: Exception) {\n            Log.e(\"Vidstack\", \"getBaseUrl fallback: ${e.message}\")\n            mainUrl\n        }\n    }\n}\n\nobject AesHelper {\n    private const val TRANSFORMATION = \"AES/CBC/PKCS5PADDING\"\n\n    fun decryptAES(inputHex: String, key: String, iv: String): String {\n        val cipher = Cipher.getInstance(TRANSFORMATION)\n        val secretKey = SecretKeySpec(key.toByteArray(Charsets.UTF_8), \"AES\")\n        val ivSpec = IvParameterSpec(iv.toByteArray(Charsets.UTF_8))\n\n        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec)\n        val decryptedBytes = cipher.doFinal(inputHex.hexToByteArray())\n        return String(decryptedBytes, Charsets.UTF_8)\n    }\n\n    private fun String.hexToByteArray(): ByteArray {\n        check(length % 2 == 0) { \"Hex string must have an even length\" }\n        return chunked(2).map { it.toInt(16).toByte() }.toByteArray()\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Videa.kt",
    "content": "// Adapted for CloudStream - taken from https://github.com/vargalex/ResolveURL/blob/fix/videa-resolver-add-cookie/script.module.resolveurl/lib/resolveurl/plugins/videa.py\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.base64DecodeArray\n\n/**\n * Extractor for Videa.hu video hosting service\n * Handles encrypted XML responses and redirect chains\n */\nclass Videa : ExtractorApi() {\n    override val name = \"Videa\"\n    override val mainUrl = \"https://videa.hu\"\n    override val requiresReferer = false\n\n    private val videaSecret = \"xHb0ZvME5q8CBcoQi6AngerDu3FGO9fkUlwPmLVY_RTzj2hJIS4NasXWKy1td7p\"\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        var currentUrl = url\n        var key = \"\"\n        var lastUrl: String? = null\n        // Handle redirect loop until we get valid XML\n        while (true) {\n            val webUrl = getXmlUrl(currentUrl) { cookie -> /* no-op, cookie not used */ } ?: return\n            val response = app.get(webUrl)\n            val rawBytes = response.body.bytes()\n\n            // Check if response starts with XML declaration\n            val isXml = rawBytes.size >= 5 &&\n                    rawBytes[0] == 0x3C.toByte() &&  // '<'\n                    rawBytes[1] == 0x3F.toByte() &&  // '?'\n                    rawBytes[2] == 0x78.toByte() &&  // 'x'\n                    rawBytes[3] == 0x6D.toByte() &&  // 'm'\n                    rawBytes[4] == 0x6C.toByte()     // 'l'\n\n            val videaXml = if (isXml) {\n                String(rawBytes, Charsets.UTF_8)\n            } else {\n                // Handle encrypted XML response\n                val xsHeader = response.headers[\"X-Videa-Xs\"] ?: return\n                key += xsHeader\n                rc4DecryptBytes(rawBytes, key)\n            }\n\n            // Check for redirect in XML error\n            val redirectMatch = \"\"\"<error.*?\"noembed\".*>(.*)</error>\"\"\".toRegex().find(videaXml)\n\n            if (redirectMatch != null && redirectMatch.groupValues[1] != currentUrl) {\n                lastUrl = currentUrl\n                currentUrl = redirectMatch.groupValues[1]\n            } else {\n                parseVideoSources(videaXml, callback)\n                break\n            }\n        }\n    }\n\n    private suspend fun getXmlUrl(url: String, cookieCallback: (String) -> Unit = {}): String? {\n        val response = app.get(url)\n        val html = response.text\n\n        // Extract sl cookie if present\n        response.headers[\"Set-Cookie\"]?.let { cookieHeader ->\n            \"\"\"sl=([^;]+)\"\"\".toRegex().find(cookieHeader)?.let {\n                cookieCallback(it.value)\n            }\n        }\n\n        // Determine if this is a player URL or needs iframe extraction\n        val playerUrl = if (\"/player\" in url) {\n            url\n        } else {\n            val iframeMatch = \"\"\"<iframe.*?src=\"(/player\\?[^\\\"]+)\"\"\".toRegex().find(html)\n            iframeMatch?.let { \"$mainUrl${it.groupValues[1]}\" } ?: return null\n        }\n\n        // Get player page to extract tokens\n        val playerResponse = app.get(playerUrl)\n        val playerHtml = playerResponse.text\n\n        // Update cookie from player response\n        playerResponse.headers[\"Set-Cookie\"]?.let { cookieHeader ->\n            \"\"\"sl=([^;]+)\"\"\".toRegex().find(cookieHeader)?.let {\n                cookieCallback(it.value)\n            }\n        }\n\n        // Extract nonce and generate tokens\n        val nonceMatch = \"\"\"_xt\\s*=\\s*\"([^\"]+)\"\"\".toRegex().find(playerHtml) ?: return null\n        val (s, t, key) = generateTokens(nonceMatch.groupValues[1])\n\n        // Extract video parameter\n        val videoParam = when {\n            \"f=\" in playerUrl -> \"f=\" + playerUrl.substringAfter(\"f=\").substringBefore(\"&\")\n            \"v=\" in playerUrl -> \"v=\" + playerUrl.substringAfter(\"v=\").substringBefore(\"&\")\n            else -> return null\n        }\n\n        return \"$mainUrl/player/xml?platform=desktop&$videoParam&_s=$s&_t=$t\"\n    }\n\n    private fun generateTokens(nonce: String): Triple<String, String, String> {\n        val lo = nonce.take(32)\n        val s = nonce.substring(32)\n        var result = \"\"\n\n        for (i in 0 until 32) {\n            val index = videaSecret.indexOf(lo[i]) - 31\n            result += s[i - index]\n        }\n\n        // Generate random seed\n        val chars = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\"\n        val randomSeed = (1..8).map { chars.random() }.joinToString(\"\")\n\n        val key = result.substring(16) + randomSeed\n        return Triple(randomSeed, result.take(16), key)\n    }\n\n    private suspend fun parseVideoSources(xml: String, callback: (ExtractorLink) -> Unit) {\n        val sourceRegex = \"\"\"video_source\\s*name=\"([^\"]+)\".*exp=\"([^\"]+)\"[^>]*>([^<]+)\"\"\".toRegex()\n        val sources = sourceRegex.findAll(xml).toList()\n\n        for (sourceMatch in sources) {\n            val sourceName = sourceMatch.groupValues[1]\n            val exp = sourceMatch.groupValues[2]\n            var sourceUrl = sourceMatch.groupValues[3]\n\n            // Add https if needed\n            if (sourceUrl.startsWith(\"//\")) {\n                sourceUrl = \"https:$sourceUrl\"\n            }\n\n            // Extract hash for this source\n            val hashMatch = \"\"\"<hash_value_$sourceName>([^<]+)<\"\"\".toRegex().find(xml)\n\n            hashMatch?.let { match ->\n                val hash = match.groupValues[1]\n                val finalUrl = \"$sourceUrl?md5=$hash&expires=$exp\".replace(\"&amp;\", \"&\")\n\n                callback(\n                    newExtractorLink(\n                        name,\n                        \"$sourceName - $name\",\n                        finalUrl,\n                        ExtractorLinkType.VIDEO\n                    ) {\n                        this.quality = Qualities.Unknown.value\n                        this.referer = mainUrl\n                    }\n                )\n            }\n        }\n    }\n\n    private fun rc4DecryptBytes(encryptedBytes: ByteArray, key: String): String {\n        // Check if data is Base64 encoded\n        val isBase64 = encryptedBytes.all { byte ->\n            val char = byte.toInt() and 0xFF\n            char in 32..126 || char == 10 || char == 13\n        }\n\n        val actualEncryptedBytes = if (isBase64) {\n            val base64String = String(encryptedBytes, Charsets.UTF_8)\n                .replace(\"\\r\", \"\")\n                .replace(\"\\n\", \"\")\n                .replace(\" \", \"\")\n                .trim()\n            base64DecodeArray(base64String)\n        } else {\n            encryptedBytes\n        }\n\n        val keyBytes = key.toByteArray(Charsets.UTF_8)\n\n        // RC4 key-scheduling algorithm (KSA)\n        val s = IntArray(256) { it }\n        var j = 0\n        for (i in 0..255) {\n            j = (j + s[i] + (keyBytes[i % keyBytes.size].toInt() and 0xFF)) % 256\n            s[i] = s[j].also { s[j] = s[i] }\n        }\n\n        // RC4 pseudo-random generation algorithm (PRGA)\n        var i = 0\n        j = 0\n        val result = ByteArray(actualEncryptedBytes.size)\n        for (k in actualEncryptedBytes.indices) {\n            i = (i + 1) % 256\n            j = (j + s[i]) % 256\n            s[i] = s[j].also { s[j] = s[i] }\n            val keyStreamByte = s[(s[i] + s[j]) % 256]\n            result[k] = ((actualEncryptedBytes[k].toInt() and 0xFF) xor keyStreamByte).toByte()\n        }\n\n        return String(result, Charsets.UTF_8)\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VideoSeyredExtractor.kt",
    "content": "// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır.\n\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.*\nimport com.lagradost.cloudstream3.utils.*\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.fasterxml.jackson.module.kotlin.jacksonObjectMapper\nimport com.fasterxml.jackson.module.kotlin.readValue\n\nopen class VideoSeyred : ExtractorApi() {\n    override val name            = \"VideoSeyred\"\n    override val mainUrl         = \"https://videoseyred.in\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) {\n        val extRef   = referer ?: \"\"\n        val videoId  = url.substringAfter(\"embed/\").substringBefore(\"?\")\n        val videoUrl = \"${mainUrl}/playlist/${videoId}.json\"\n\n        val responseRaw                          = app.get(videoUrl)\n        val responseList:List<VideoSeyredSource> = jacksonObjectMapper().readValue(responseRaw.text) ?: throw ErrorLoadingException(\"VideoSeyred\")\n        val response                              = responseList[0]\n\n        for (track in response.tracks) {\n            if (track.label != null && track.kind == \"captions\") {\n                subtitleCallback.invoke(\n                    newSubtitleFile(\n                        lang = track.label,\n                        url  = fixUrl(track.file)\n                    )\n                )\n            }\n        }\n\n        for (source in response.sources) {\n            callback.invoke(\n                newExtractorLink(\n                    source  = this.name,\n                    name    = this.name,\n                    url     = source.file,\n                ) {\n                    this.referer = \"${mainUrl}/\"\n                    this.quality = Qualities.Unknown.value\n                }\n            )\n        }\n    }\n\n    data class VideoSeyredSource(\n        @JsonProperty(\"image\")   val image: String,\n        @JsonProperty(\"title\")   val title: String,\n        @JsonProperty(\"sources\") val sources: List<VSSource>,\n        @JsonProperty(\"tracks\")  val tracks: List<VSTrack>\n    )\n\n    data class VSSource(\n        @JsonProperty(\"file\")    val file: String,\n        @JsonProperty(\"type\")    val type: String,\n        @JsonProperty(\"default\") val default: String\n    )\n\n    data class VSTrack(\n        @JsonProperty(\"file\")     val file: String,\n        @JsonProperty(\"kind\")     val kind: String,\n        @JsonProperty(\"language\") val language: String? = null,\n        @JsonProperty(\"label\")    val label: String?    = null,\n        @JsonProperty(\"default\")  val default: String?  = null\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidhideExtractor.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nopen class VidhideExtractor : VidHidePro() {\n    override var name = \"VidHide\"\n    override var mainUrl = \"https://vidhide.com\"\n    override val requiresReferer = false\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidmoly.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport kotlinx.coroutines.delay\n\nclass Vidmolyme : Vidmoly() {\n    override val mainUrl = \"https://vidmoly.me\"\n}\n\nclass Vidmolyto : Vidmoly() {\n    override val mainUrl = \"https://vidmoly.to\"\n}\n\nclass Vidmolybiz : Vidmoly() {\n    override val mainUrl = \"https://vidmoly.biz\"\n}\n\nopen class Vidmoly : ExtractorApi() {\n    override val name = \"Vidmoly\"\n    override val mainUrl = \"https://vidmoly.net\"\n    override val requiresReferer = true\n\n    private fun String.addMarks(str: String): String {\n        return this.replace(Regex(\"\\\"?$str\\\"?\"), \"\\\"$str\\\"\")\n    }\n\n    private data class Source(\n        @JsonProperty(\"file\") val file: String? = null,\n    )\n\n    private data class SubSource(\n        @JsonProperty(\"file\") val file: String? = null,\n        @JsonProperty(\"label\") val label: String? = null,\n        @JsonProperty(\"kind\") val kind: String? = null,\n    )\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val headers = mapOf(\n            \"user-agent\" to USER_AGENT,\n            \"Sec-Fetch-Dest\" to \"iframe\"\n        )\n        \n        val newUrl = if (url.contains(\"/w/\")) \n            url.replaceFirst(\"/w/\", \"/embed-\") + \".html\" \n            else url\n        val script = app.get(newUrl, headers = headers, referer = referer)\n            .document.select(\"script\")\n            .firstOrNull { it.data().contains(\"sources:\") }\n            ?.data()\n        // Extracts and parses videoData\n        script?.substringAfter(\"sources: [\")\n            ?.substringBefore(\"]\")\n            ?.addMarks(\"file\")\n            ?.replace(\"'\",\"\\\"\")\n            ?.let { videoData ->\n                tryParseJson<Source>(videoData)?.file?.let { m3uLink ->\n                    M3u8Helper.generateM3u8(name, m3uLink, \"$mainUrl/\")\n                        .forEach(callback)\n                }\n            }\n        // Extracts and parses captions\n        script?.substringAfter(\"tracks: [\")\n            ?.substringBefore(\"]\")\n            ?.addMarks(\"file\")?.addMarks(\"label\")?.addMarks(\"kind\")\n            ?.replace(\"'\",\"\\\"\")\n            ?.let { subData ->\n                tryParseJson<List<SubSource>>(\"[$subData]\")\n                    ?.filter { it.kind == \"captions\" }\n                    ?.forEach {\n                        subtitleCallback(\n                            newSubtitleFile(it.label.toString(), fixUrl(it.file.toString()))\n                        )\n                    }\n            }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vido.kt",
    "content": "package com.lagradost.cloudstream3.extractors\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.getAndUnpack\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass Vido : ExtractorApi() {\n    override var name = \"Vido\"\n    override var mainUrl = \"https://vido.lol\"\n    private val srcRegex = Regex(\"\"\"sources:\\s*\\[\"(.*?)\"\\]\"\"\")\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val methode = app.get(url.replace(\"/e/\", \"/embed-\")) // fix wiflix and mesfilms\n        with(methode) {\n            if (!methode.isSuccessful) return null\n            //val quality = unpackedText.lowercase().substringAfter(\" height=\").substringBefore(\" \").toIntOrNull()\n            srcRegex.find(this.text)?.groupValues?.get(1)?.let { link ->\n                return listOf(\n                    newExtractorLink(\n                        source = name,\n                        name = name,\n                        url = link,\n                        type = ExtractorLinkType.M3U8\n                    ) {\n                        this.referer = url\n                        this.quality = Qualities.Unknown.value\n                    }\n                )\n            }\n        }\n        return null\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidoza.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.AppUtils\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass Videzz: Vidoza() {\n    override val mainUrl: String = \"https://videzz.net\"\n}\n\nopen class Vidoza: ExtractorApi() {\n    override val name: String = \"Vidoza\"\n    override val mainUrl: String = \"https://vidoza.net\"\n    override val requiresReferer: Boolean = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val response = app.get(url).document\n        val script = response.selectFirst(\"script:containsData(sourcesCode)\")?.data()\n            ?: throw RuntimeException(\"couldn't find script containing video data\")\n\n        // e.g. sourcesCode: [{ src: \"https://str38.vidoza.net/vod/v2/.../v.mp4\", type: \"video/mp4\", label:\"SD\", res:\"720\"}],\n        var sourcesArray = script.substringAfter(\"sourcesCode:\").substringBefore(\"\\n\")\n        arrayOf(\"src\", \"type\", \"label\", \"res\").forEach {\n            // add missing quotation marks, e.g. src: \"https...\" -> \"src\": \"https...\"\n            sourcesArray = sourcesArray\n                .replace(Regex(\"\"\"\"?$it\"?:\"\"\"), \"\"\"\"$it\":\"\"\")\n        }\n        val videoData = AppUtils.parseJson<VinovoDataList>(sourcesArray)\n\n        for (stream in videoData) {\n            callback.invoke(\n                newExtractorLink(\n                    source = name,\n                    name = name,\n                    url = stream.source\n                ) {\n                    quality = getQualityFromName(stream.resolution)\n                }\n            )\n        }\n    }\n\n    private class VinovoDataList: ArrayList<VinovoVideoData>()\n\n    private data class VinovoVideoData(\n        @JsonProperty(\"src\") val source: String,\n        @JsonProperty(\"type\") val type: String?,\n        @JsonProperty(\"label\") val label: String?,\n        @JsonProperty(\"res\") val resolution: String?,\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidsonic.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass Vidsonic() : ExtractorApi() {\n    override val name: String = \"Vidsonic\"\n    override val mainUrl: String = \"https://vidsonic.net\"\n    override val requiresReferer: Boolean = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        // Extracted JavaScript code that decodes the encrypted m3u8 stream URL:\n        //\n        // const _0x1 = '3363616238|3638666534|6264323565|3666616366|6636333662|6230626339|30613d3564|6d26743130|6b74693170|336563793d|64695f656c|6966263634|3332363033|3737313d73|6572697078|6526333d64|695f726576|7265733f38|75336d2e72|657473616d|2f7431306b|7469317033|6563792f38|392f657275|6365732f74|656e2e6369|6e6f736469|762e31302d|73752d7473|2f2f3a7370|747468';\n        // const _0x2 = function(_0x3) {\n        //    const _0x4 = _0x3.split('|').join('');\n        //    let _0x5 = '';\n        //     for (let _0x6 = 0; _0x6 < _0x4.length; _0x6 += 2) {\n        //       _0x5 += String.fromCharCode(parseInt(_0x4.substr(_0x6, 2), 16));\n        //     }\n        //     return _0x5.split('').reverse().join('');\n        // };\n        // const _0x7 = _0x2(_0x1); <-- now contains the stream URL\n\n        val response = app.get(url).text\n        val encodedStreamUrl = response\n            .substringAfter(\"const _0x1 = \")\n            .substringBefore(\";\")\n            .replace(\"'\", \"\")\n\n        // (improved) Java implementation of the JavaScript code from above\n        val streamUrl = encodedStreamUrl\n            .replace(\"|\", \"\")\n            // always two base16 digits together build one ASCII char\n            .chunked(2)\n            .map {\n                Integer.parseInt(it, 16).toChar()\n            }\n            .joinToString(\"\")\n            .reversed()\n\n        callback.invoke(\n            newExtractorLink(\n                source = name,\n                name = name,\n                url = streamUrl,\n                type = ExtractorLinkType.M3U8\n            )\n        )\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidstream.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.runAllAsync\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.extractorApis\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.loadExtractor\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport org.jsoup.Jsoup\n\n/**\n * overrideMainUrl is necessary for for other vidstream clones like vidembed.cc\n * If they diverge it'd be better to make them separate.\n * */\nclass Vidstream(val mainUrl: String) {\n    val name: String = \"Vidstream\"\n\n    private fun getExtractorUrl(id: String): String {\n        return \"$mainUrl/streaming.php?id=$id\"\n    }\n\n    private fun getDownloadUrl(id: String): String {\n        return \"$mainUrl/download?id=$id\"\n    }\n\n    private val normalApis = arrayListOf(MultiQuality())\n\n    // https://gogo-stream.com/streaming.php?id=MTE3NDg5\n    suspend fun getUrl(\n        id: String,\n        isCasting: Boolean = false,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit,\n    ): Boolean {\n        val extractorUrl = getExtractorUrl(id)\n        runAllAsync(\n            {\n                normalApis.amap { api ->\n                    val url = api.getExtractorUrl(id)\n                    api.getSafeUrl(\n                        url,\n                        callback = callback,\n                        subtitleCallback = subtitleCallback\n                    )\n                }\n            }, {\n                /** Stolen from GogoanimeProvider.kt extractor */\n                val link = getDownloadUrl(id)\n                println(\"Generated vidstream download link: $link\")\n                val page = app.get(link, referer = extractorUrl)\n\n                val pageDoc = Jsoup.parse(page.text)\n                val qualityRegex = Regex(\"(\\\\d+)P\")\n\n                //a[download]\n                pageDoc.select(\".dowload > a\").amap { element ->\n                    val href = element.attr(\"href\")\n                    val qual = if (element.text()\n                            .contains(\"HDP\")\n                    ) \"1080\" else qualityRegex.find(element.text())?.destructured?.component1()\n                        .toString()\n\n                    if (!loadExtractor(href, link, subtitleCallback, callback)) {\n                        callback.invoke(\n                            newExtractorLink(\n                                this.name,\n                                name = this.name,\n                                href,\n                                type = INFER_TYPE\n                            ) {\n                                this.referer = page.url\n                                this.quality = getQualityFromName(qual)\n                            }\n                        )\n                    }\n                }\n            }, {\n                with(app.get(extractorUrl)) {\n                    val document = Jsoup.parse(this.text)\n                    val primaryLinks = document.select(\"ul.list-server-items > li.linkserver\")\n                    //val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()\n\n                    // All vidstream links passed to extractors\n                    primaryLinks.distinctBy { it.attr(\"data-video\") }.forEach { element ->\n                        val link = element.attr(\"data-video\")\n                        //val name = element.text()\n\n                        // Matches vidstream links with extractors\n                        extractorApis.filter { !it.requiresReferer || !isCasting }.amap { api ->\n                            if (link.startsWith(api.mainUrl)) {\n                                api.getSafeUrl(link, extractorUrl, subtitleCallback, callback)\n                            }\n                        }\n                    }\n                }\n            }\n        )\n        return true\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vinovo.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass VinovoSi : VinovoTo() {\n    override var name = \"VinovoSi\"\n    override var mainUrl = \"https://vinovo.si\"\n}\n\nopen class VinovoTo : ExtractorApi() {\n    override val mainUrl: String = \"https://vinovo.to\"\n    override val name: String = \"VinovoTo\"\n    override val requiresReferer: Boolean = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val fixedUrl = url.replace(\"/d/\", \"/e/\")\n\n        val resp = app.get(fixedUrl, referer = referer)\n        val doc = resp.document\n\n        val videoBaseUrl = doc.selectFirst(\"video\")?.attr(\"data-base\") ?: return\n        val videoToken = doc.selectFirst(\"meta[name=token]\")?.attr(\"content\") ?: return\n        val fileCode = doc.selectFirst(\"meta[name=\\\"file_code\\\"]\")?.attr(\"content\") ?: return\n\n        val captchaToken = doc.selectFirst(\"meta[name=recaptcha]\")?.attr(\"content\") ?: return\n        val captchaSolution =\n            APIHolder.getCaptchaToken(fixedUrl, captchaToken, \"$mainUrl/\") ?: return\n\n        val streamInfo = app.post(\n            url = \"$mainUrl/api/file/url/$fileCode\",\n            data = mapOf(\"token\" to videoToken, \"recaptcha\" to captchaSolution),\n            headers = mapOf(\n                \"Origin\" to mainUrl,\n                \"X-Requested-With\" to \"XMLHttpRequest\"\n            ),\n            cookies = resp.cookies,\n            referer = fixedUrl\n        ).parsed<VinovoFileResp>()\n        val fileUrl = \"$videoBaseUrl/stream/${streamInfo.token}\"\n\n        callback.invoke(\n            newExtractorLink(source = name, name = name, url = fileUrl) {\n                val dataTitle = doc.selectFirst(\"video\")?.attr(\"data-title\").orEmpty()\n                quality = Regex(\"\"\"\\.(\\d+)p\\.\"\"\").find(dataTitle)?.groupValues?.getOrNull(1)\n                    ?.toIntOrNull() ?: Qualities.Unknown.value\n            }\n        )\n    }\n\n    private data class VinovoFileResp(\n        @JsonProperty(\"status\") val status: String,\n        @JsonProperty(\"token\") val token: String,\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VkExtractor.kt",
    "content": "// Made by @kraptor123 for cs-kraptor\npackage com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.Prerelease\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\n@Prerelease\nopen class VkExtractor : ExtractorApi() {\n    override val name = \"Vk\"\n    override val mainUrl = \"https://vkvideo.ru\"\n    override val requiresReferer = true\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val headers = mapOf(\n            \"User-Agent\" to \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:144.0) Gecko/20100101 Firefox/144.0\",\n            \"Accept\" to \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\n            \"Accept-Language\" to \"en-US,en;q=0.5\",\n            \"Sec-GPC\" to \"1\",\n            \"Connection\" to \"keep-alive\",\n            \"Upgrade-Insecure-Requests\" to \"1\",\n            \"Sec-Fetch-Dest\" to \"document\",\n            \"Sec-Fetch-Mode\" to \"navigate\",\n            \"Sec-Fetch-Site\" to \"none\",\n            \"Sec-Fetch-User\" to \"?1\",\n            \"Priority\" to \"u=0, i\",\n            \"Pragma\" to \"no-cache\",\n            \"Cache-Control\" to \"no-cache\"\n        )\n        val cookie = app.get(url, headers = headers, allowRedirects = false).cookies\n        val response = app.get(url, headers = headers, allowRedirects = false, cookies = cookie).text\n        val listUrl = listOf(\"url\", \"dash_sep\", \"hls\")\n\n        listUrl.forEach { linkType ->\n            if (linkType == \"url\") {\n                val regex = Regex(pattern = \"\\\"url([0-9]+)\\\":\\\"([^\\\"]*)\\\"\", options = setOf(RegexOption.IGNORE_CASE))\n                regex.findAll(response).forEach { url ->\n                    val video = url.groupValues[2].replace(\"\\\\\", \"\")\n                    val quality = url.groupValues[1].replace(\"\\\\\", \"\")\n                    callback.invoke(\n                        newExtractorLink(\n                            this.name,\n                            this.name,\n                            video,\n                            ExtractorLinkType.VIDEO\n                        ) {\n                            this.referer = \"${mainUrl}/\"\n                            this.headers = mapOf(\n                                \"User-Agent\" to \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:144.0) Gecko/20100101 Firefox/144.0\",\n                                \"Accept\" to \"*/*\",\n                                \"Accept-Language\" to \"en-US,en;q=0.5\",\n                                \"Referer\" to \"${mainUrl}/\",\n                            )\n                            this.quality = getQualityFromName(quality)\n                        })\n                }\n            } else {\n                val regex = Regex(pattern = \"\\\"$linkType\\\":\\\"([^\\\"]*)\\\"\", options = setOf(RegexOption.IGNORE_CASE))\n                val video = regex.find(response)?.groupValues?.getOrNull(1)?.replace(\"\\\\\", \"\") ?: return@forEach\n                val type = when {\n                    linkType.contains(\"hls\") -> \"HLS\"\n                    linkType.contains(\"dash\") -> \"Dash\"\n                    else -> \"\"\n                }\n                callback.invoke(\n                    newExtractorLink(\n                        \"${this.name} $type\",\n                        \"${this.name} $type\",\n                        video,\n                        when {\n                            linkType.contains(\"dash\") -> ExtractorLinkType.DASH\n                            linkType.contains(\"hls\") -> ExtractorLinkType.M3U8\n                            else -> ExtractorLinkType.VIDEO\n                        }\n                    ) {\n                        this.referer = \"${mainUrl}/\"\n                        this.headers = mapOf(\n                            \"User-Agent\" to \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:144.0) Gecko/20100101 Firefox/144.0\",\n                            \"Accept\" to \"*/*\",\n                            \"Accept-Language\" to \"en-US,en;q=0.5\",\n                            \"Referer\" to \"${mainUrl}/\",\n                        )\n                    })\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Voe.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.google.gson.JsonObject\nimport com.google.gson.JsonParser\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.base64Decode\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass Tubeless : Voe() {\n    override val name = \"Tubeless\"\n    override val mainUrl = \"https://tubelessceliolymph.com\"\n}\n\nclass Simpulumlamerop : Voe() {\n    override val name = \"Simplum\"\n    override var mainUrl = \"https://simpulumlamerop.com\"\n}\n\nclass Urochsunloath : Voe() {\n    override val name = \"Uroch\"\n    override var mainUrl = \"https://urochsunloath.com\"\n}\n\nclass NathanFromSubject : Voe() {\n    override val mainUrl = \"https://nathanfromsubject.com\"\n}\n\nclass Yipsu : Voe() {\n    override val name = \"Yipsu\"\n    override var mainUrl = \"https://yip.su\"\n}\n\nclass MetaGnathTuggers : Voe() {\n    override val name = \"Metagnath\"\n    override val mainUrl = \"https://metagnathtuggers.com\"\n}\n\nclass Voe1 : Voe() {\n    override val mainUrl = \"https://donaldlineelse.com\"\n}\n\nopen class Voe : ExtractorApi() {\n    override val name = \"Voe\"\n    override val mainUrl = \"https://voe.sx\"\n    override val requiresReferer = true\n    private val redirectRegex = Regex(\"\"\"window.location.href\\s*=\\s*'([^']+)';\"\"\")\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        var res = app.get(url, referer = referer)\n        val redirectUrl = redirectRegex.find(res.document.data())?.groupValues?.get(1)\n        if (redirectUrl != null) {\n            res = app.get(redirectUrl, referer = referer)\n        }\n        val encodedString = res.document.selectFirst(\"script[type=application/json]\")?.data()?.trim()?.substringAfter(\"[\\\"\")?.substringBeforeLast(\"\\\"]\")\n        if (encodedString == null) {\n            println(\"encoded string not found.\")\n            return\n        }\n        val decryptedJson = decryptF7(encodedString)\n        val m3u8 = decryptedJson.get(\"source\")?.asString\n        val mp4 = decryptedJson.get(\"direct_access_url\")?.asString\n\n        if (m3u8 != null) {\n            M3u8Helper.generateM3u8(\n                name,\n                m3u8,\n                \"$mainUrl/\",\n                headers = mapOf(\"Origin\" to \"$mainUrl/\")\n            ).forEach(callback)\n        }\n        if (mp4!=null)\n        {\n            callback.invoke(\n                newExtractorLink(\n                    source = \"$name MP4\",\n                    name = \"$name MP4\",\n                    url = mp4,\n                    INFER_TYPE\n                ) {\n                    this.referer = url\n                    this.quality = Qualities.Unknown.value\n                }\n            )\n        }\n    }\n\n    private fun decryptF7(p8: String): JsonObject {\n        return try {\n            val vF = rot13(p8)\n            val vF2 = replacePatterns(vF)\n            val vF3 = removeUnderscores(vF2)\n            val vF4 = base64Decode(vF3)\n            val vF5 = charShift(vF4, 3)\n            val vF6 = reverse(vF5)\n            val vAtob = base64Decode(vF6)\n\n            JsonParser.parseString(vAtob).asJsonObject\n        } catch (e: Exception) {\n            println(\"Decryption error: ${e.message}\")\n            JsonObject()\n        }\n    }\n\n    private fun rot13(input: String): String {\n        return input.map { c ->\n            when (c) {\n                in 'A'..'Z' -> ((c - 'A' + 13) % 26 + 'A'.code).toChar()\n                in 'a'..'z' -> ((c - 'a' + 13) % 26 + 'a'.code).toChar()\n                else -> c\n            }\n        }.joinToString(\"\")\n    }\n\n    private fun replacePatterns(input: String): String {\n        val patterns = listOf(\"@$\", \"^^\", \"~@\", \"%?\", \"*~\", \"!!\", \"#&\")\n        return patterns.fold(input) { result, pattern ->\n            result.replace(Regex(Regex.escape(pattern)), \"_\")\n        }\n    }\n\n    private fun removeUnderscores(input: String): String = input.replace(\"_\", \"\")\n\n    private fun charShift(input: String, shift: Int): String {\n        return input.map { (it.code - shift).toChar() }.joinToString(\"\")\n    }\n\n    private fun reverse(input: String): String = input.reversed()\n\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vtbe.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.*\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.JsUnpacker\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport java.net.URI\n\n\nopen class Vtbe : ExtractorApi() {\n    override var name = \"Vtbe\"\n    override var mainUrl = \"https://vtbe.to\"\n    override val requiresReferer = true\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {\n        val response = app.get(url,referer=mainUrl).document\n        val extractedpack =response.selectFirst(\"script:containsData(function(p,a,c,k,e,d))\")?.data().toString()\n        JsUnpacker(extractedpack).unpack()?.let { unPacked ->\n            Regex(\"sources:\\\\[\\\\{file:\\\"(.*?)\\\"\").find(unPacked)?.groupValues?.get(1)?.let { link ->\n                return listOf(\n                    newExtractorLink(\n                        this.name,\n                        this.name,\n                        link,\n                    ) {\n                        this.referer = referer ?: \"\"\n                        this.quality = Qualities.Unknown.value\n                    }\n                )\n            }\n        }\n        return null\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/WatchSB.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.network.WebViewResolver\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8\n\nopen class WatchSB : ExtractorApi() {\n    override var name = \"WatchSB\"\n    override var mainUrl = \"https://watchsb.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val response = app.get(\n            url, interceptor = WebViewResolver(\n                Regex(\"\"\"master\\.m3u8\"\"\")\n            )\n        )\n\n        return generateM3u8(name, response.url, url, headers = response.headers.toMap())\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Wibufile.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.INFER_TYPE\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class Wibufile : ExtractorApi() {\n    override val name: String = \"Wibufile\"\n    override val mainUrl: String = \"https://wibufile.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val res = app.get(url).text\n        val video = Regex(\"src: ['\\\"](.*?)['\\\"]\").find(res)?.groupValues?.get(1)\n\n        callback.invoke(\n            newExtractorLink(\n                name,\n                name,\n                video ?: return,\n            ) {\n                this.referer = \"$mainUrl/\"\n                this.quality = Qualities.Unknown.value\n            }\n        )\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/XStreamCdn.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass StreamM4u : XStreamCdn() {\n    override val name: String = \"StreamM4u\"\n    override val mainUrl: String = \"https://streamm4u.club\"\n}\n\nclass Fembed9hd : XStreamCdn() {\n    override var mainUrl = \"https://fembed9hd.com\"\n    override var name = \"Fembed9hd\"\n}\n\nclass Cdnplayer: XStreamCdn() {\n    override val name: String = \"Cdnplayer\"\n    override val mainUrl: String = \"https://cdnplayer.online\"\n}\n\nclass Kotakajair: XStreamCdn() {\n    override val name: String = \"Kotakajair\"\n    override val mainUrl: String = \"https://kotakajair.xyz\"\n}\n\nclass FEnet: XStreamCdn() {\n    override val name: String = \"FEnet\"\n    override val mainUrl: String = \"https://fembed.net\"\n}\n\nclass Rasacintaku: XStreamCdn() {\n    override val mainUrl: String = \"https://rasa-cintaku-semakin-berantai.xyz\"\n}\n\nclass LayarKaca: XStreamCdn() {\n    override val name: String = \"LayarKaca-xxi\"\n    override val mainUrl: String = \"https://layarkacaxxi.icu\"\n}\n\nclass DBfilm: XStreamCdn() {\n    override val name: String = \"DBfilm\"\n    override val mainUrl: String = \"https://dbfilm.bar\"\n}\n\nclass Luxubu : XStreamCdn(){\n    override val name: String = \"FE\"\n    override val mainUrl: String = \"https://www.luxubu.review\"\n}\n\nclass FEmbed: XStreamCdn() {\n    override val name: String = \"FEmbed\"\n    override val mainUrl: String = \"https://www.fembed.com\"\n}\n\nclass Fplayer: XStreamCdn() {\n    override val name: String = \"Fplayer\"\n    override val mainUrl: String = \"https://fplayer.info\"\n}\n\nclass FeHD: XStreamCdn() {\n    override val name: String = \"FeHD\"\n    override val mainUrl: String = \"https://fembed-hd.com\"\n    override var domainUrl: String = \"fembed-hd.com\"\n}\n\nopen class XStreamCdn : ExtractorApi() {\n    override val name: String = \"XStreamCdn\"\n    override val mainUrl: String = \"https://embedsito.com\"\n    override val requiresReferer = false\n    open var domainUrl: String = \"embedsito.com\"\n\n    private data class ResponseData(\n        @JsonProperty(\"file\") val file: String,\n        @JsonProperty(\"label\") val label: String,\n        //val type: String // Mp4\n    )\n\n    private data class Player(\n        @JsonProperty(\"poster_file\") val poster_file: String? = null,\n    )\n\n    private data class ResponseJson(\n        @JsonProperty(\"success\") val success: Boolean,\n        @JsonProperty(\"player\") val player: Player? = null,\n        @JsonProperty(\"data\") val data: List<ResponseData>?,\n        @JsonProperty(\"captions\") val captions: List<Captions?>?,\n    )\n\n    private data class Captions(\n        @JsonProperty(\"id\") val id: String,\n        @JsonProperty(\"hash\") val hash: String,\n        @JsonProperty(\"language\") val language: String,\n        @JsonProperty(\"extension\") val extension: String\n    )\n\n    override fun getExtractorUrl(id: String): String {\n        return \"$domainUrl/api/source/$id\"\n    }\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val headers = mapOf(\n            \"Referer\" to url,\n            \"User-Agent\" to \"Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0\",\n        )\n        val id = url.trimEnd('/').split(\"/\").last()\n        val newUrl = \"https://${domainUrl}/api/source/${id}\"\n        app.post(newUrl, headers = headers).let { res ->\n            val sources = tryParseJson<ResponseJson?>(res.text)\n            sources?.let {\n                if (it.success && it.data != null) {\n                    it.data.map { source ->\n                        callback.invoke(\n                            newExtractorLink(\n                                name,\n                                name = name,\n                                source.file,\n                            ) {\n                                this.referer = url\n                                this.quality = getQualityFromName(source.label)\n                            }\n                        )\n                    }\n                }\n            }\n\n            val userData = sources?.player?.poster_file?.split(\"/\")?.get(2)\n            sources?.captions?.map {\n                subtitleCallback.invoke(\n                    newSubtitleFile(\n                        it?.language.toString(),\n                        \"$mainUrl/asset/userdata/$userData/caption/${it?.hash}/${it?.id}.${it?.extension}\"\n                    )\n                )\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/YourUpload.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nopen class YourUpload: ExtractorApi() {\n    override val name = \"Yourupload\"\n    override val mainUrl = \"https://www.yourupload.com\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val sources = mutableListOf<ExtractorLink>()\n        with(app.get(url).document) {\n            val quality = Regex(\"\\\\d{3,4}p\").find(this.select(\"title\").text())?.groupValues?.get(0)\n            this.select(\"script\").map { script ->\n                if (script.data().contains(\"var jwplayerOptions = {\")) {\n                    val data =\n                        script.data().substringAfter(\"var jwplayerOptions = {\").substringBefore(\",\\n\")\n                    val link = tryParseJson<ResponseSource>(\n                        \"{${\n                            data.replace(\"file\", \"\\\"file\\\"\").replace(\"'\", \"\\\"\")\n                        }}\"\n                    )\n                    sources.add(\n                        newExtractorLink(\n                            source = name,\n                            name = name,\n                            url = link!!.file,\n                        ) {\n                            this.referer = url\n                            this.quality = getQualityFromName(quality)\n                        }\n                    )\n                }\n            }\n        }\n        return sources\n    }\n\n    private data class ResponseSource(\n        @JsonProperty(\"file\") val file: String,\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/YoutubeExtractor.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.newAudioFile\nimport com.lagradost.cloudstream3.newSubtitleFile\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport org.schabi.newpipe.extractor.stream.StreamInfo\nimport org.schabi.newpipe.extractor.stream.StreamType\n\nclass YoutubeShortLinkExtractor : YoutubeExtractor() {\n    override val mainUrl = \"https://youtu.be\"\n}\n\nclass YoutubeMobileExtractor : YoutubeExtractor() {\n    override val mainUrl = \"https://m.youtube.com\"\n}\n\nclass YoutubeNoCookieExtractor : YoutubeExtractor() {\n    override val mainUrl = \"https://www.youtube-nocookie.com\"\n}\n\nopen class YoutubeExtractor : ExtractorApi() {\n\n    override val mainUrl = \"https://www.youtube.com\"\n    override val name = \"YouTube\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(\n        url: String,\n        referer: String?,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        val videoId = extractYouTubeId(url)\n        val watchUrl = \"$mainUrl/watch?v=$videoId\"\n\n        val info = StreamInfo.getInfo(watchUrl)\n\n        val isLive =\n            info.streamType == StreamType.LIVE_STREAM\n                    || info.streamType == StreamType.AUDIO_LIVE_STREAM\n                    || info.streamType == StreamType.POST_LIVE_STREAM\n                    || info.streamType == StreamType.POST_LIVE_AUDIO_STREAM\n\n        if (isLive && info.hlsUrl != null) {\n            callback(\n                newExtractorLink(\n                    source = name,\n                    name = \"YouTube Live\",\n                    url = info.hlsUrl\n                ) {\n                    type = ExtractorLinkType.M3U8\n                }\n            )\n        } else {\n            processVideo(info, subtitleCallback, callback)\n        }\n    }\n\n    private suspend fun processVideo(\n        info: StreamInfo,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ): Boolean {\n\n        val videoStreams = info.videoOnlyStreams.orEmpty()\n\n        if (videoStreams.isEmpty()) return false\n\n        val audioStreams = info.audioStreams.orEmpty()\n\n        videoStreams.forEach { video ->\n\n            callback(\n                newExtractorLink(\n                    source = name,\n                    name = \"YouTube ${normalizeCodec(video.codec)}\",\n                    url = video.content\n                ) {\n                    quality = video.height\n                    audioTracks = audioStreams.map { newAudioFile(it.content) }\n                }\n            )\n        }\n\n\n        info.subtitles.forEach { subtitle ->\n            subtitleCallback(\n                newSubtitleFile(\n                    lang = subtitle.displayLanguageName\n                        ?: subtitle.languageTag\n                        ?: \"Unknown\",\n                    url = subtitle.content\n                )\n            )\n        }\n\n        return true\n    }\n\n    // ---------------- HELPERS ----------------\n\n    private fun extractYouTubeId(url: String): String {\n        val regex = Regex(\n            \"(?:youtu\\\\.be/|youtube(?:-nocookie)?\\\\.com/(?:.*v=|v/|u/\\\\w/|embed/|shorts/|live/))([\\\\w-]{11})\"\n        )\n        return regex.find(url)?.groupValues?.get(1)\n            ?: throw IllegalArgumentException(\"Invalid YouTube URL: $url\")\n    }\n\n    private fun normalizeCodec(codec: String?): String {\n        if (codec.isNullOrBlank()) return \"\"\n\n        val c = codec.lowercase()\n\n        return when {\n            c.startsWith(\"av01\") -> \"AV1\"\n            c.startsWith(\"vp9\") -> \"VP9\"\n            c.startsWith(\"avc1\") || c.startsWith(\"h264\") -> \"H264\"\n            c.startsWith(\"hev1\") || c.startsWith(\"hvc1\") || c.startsWith(\"hevc\") -> \"H265\"\n            else -> codec.substringBefore('.').uppercase()\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Zplayer.kt",
    "content": "package com.lagradost.cloudstream3.extractors\n\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport com.lagradost.cloudstream3.utils.getAndUnpack\n\nclass Zplayer: ZplayerV2() {\n    override var name: String = \"Zplayer\"\n    override var mainUrl: String = \"https://zplayer.live\"\n}\n\nclass Upstream: ZplayerV2() {\n    override var name: String = \"Upstream\" //Here 'cause works\n    override var mainUrl: String = \"https://upstream.to\"\n}\n\nclass Streamhub2: ZplayerV2() {\n    override var name = \"Streamhub\" //Here 'cause works\n    override var mainUrl = \"https://streamhub.to\"\n}\n\nopen class ZplayerV2 : ExtractorApi() {\n    override var name = \"Zplayer V2\"\n    override var mainUrl = \"https://v2.zplayer.live\"\n    override val requiresReferer = false\n\n    override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {\n        val doc = app.get(url).document\n        val sources = mutableListOf<ExtractorLink>()\n        doc.select(\"script\").map { script ->\n            if (script.data().contains(\"eval(function(p,a,c,k,e,d)\")) {\n                val testdata = getAndUnpack(script.data())\n                val m3u8regex = Regex(\"((https:|http:)\\\\/\\\\/.*\\\\.m3u8)\")\n                m3u8regex.findAll(testdata).map {\n                    it.value\n                }.toList().amap { urlm3u8 ->\n                    if (urlm3u8.contains(\"m3u8\")) {\n                        val testurl = app.get(urlm3u8, headers = mapOf(\"Referer\" to url)).text\n                        if (testurl.contains(\"EXTM3U\")) {\n                            M3u8Helper.generateM3u8(\n                                name,\n                                urlm3u8,\n                                url,\n                                headers = mapOf(\"Referer\" to url)\n                            ).forEach { link ->\n                                sources.add(link)\n                            }\n                        }\n                    }\n                }\n            }\n        }\n        return sources\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AesHelper.kt",
    "content": "package com.lagradost.cloudstream3.extractors.helper\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.base64DecodeArray\nimport com.lagradost.cloudstream3.base64Encode\nimport com.lagradost.cloudstream3.utils.AppUtils\nimport java.security.DigestException\nimport java.security.MessageDigest\nimport javax.crypto.Cipher\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\n\nobject AesHelper {\n\n    private const val HASH = \"AES/CBC/PKCS5PADDING\"\n    private const val KDF = \"MD5\"\n\n    fun cryptoAESHandler(\n        data: String,\n        pass: ByteArray,\n        encrypt: Boolean = true,\n        padding: String = HASH,\n    ): String? {\n        val parse = AppUtils.tryParseJson<AesData>(data) ?: return null\n        val (key, iv) = generateKeyAndIv(\n            pass,\n            parse.s.hexToByteArray(),\n            ivLength = parse.iv.length / 2,\n            saltLength = parse.s.length / 2\n        ) ?: return null\n        val cipher = Cipher.getInstance(padding)\n        return if (!encrypt) {\n            cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, \"AES\"), IvParameterSpec(iv))\n            String(cipher.doFinal(base64DecodeArray(parse.ct)))\n        } else {\n            cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, \"AES\"), IvParameterSpec(iv))\n            base64Encode(cipher.doFinal(parse.ct.toByteArray()))\n        }\n    }\n\n    // https://stackoverflow.com/a/41434590/8166854\n    fun generateKeyAndIv(\n        password: ByteArray,\n        salt: ByteArray,\n        hashAlgorithm: String = KDF,\n        keyLength: Int = 32,\n        ivLength: Int,\n        saltLength: Int,\n        iterations: Int = 1\n    ): Pair<ByteArray,ByteArray>? {\n\n        val md = MessageDigest.getInstance(hashAlgorithm)\n        val digestLength = md.digestLength\n        val targetKeySize = keyLength + ivLength\n        val requiredLength = (targetKeySize + digestLength - 1) / digestLength * digestLength\n        val generatedData = ByteArray(requiredLength)\n        var generatedLength = 0\n\n        try {\n            md.reset()\n\n            while (generatedLength < targetKeySize) {\n                if (generatedLength > 0)\n                    md.update(\n                        generatedData,\n                        generatedLength - digestLength,\n                        digestLength\n                    )\n\n                md.update(password)\n                md.update(salt, 0, saltLength)\n                md.digest(generatedData, generatedLength, digestLength)\n\n                for (i in 1 until iterations) {\n                    md.update(generatedData, generatedLength, digestLength)\n                    md.digest(generatedData, generatedLength, digestLength)\n                }\n\n                generatedLength += digestLength\n            }\n            return generatedData.copyOfRange(0, keyLength) to generatedData.copyOfRange(keyLength, targetKeySize)\n        } catch (e: DigestException) {\n            return null\n        }\n    }\n\n    fun String.hexToByteArray(): ByteArray {\n        check(length % 2 == 0) { \"Must have an even length\" }\n        return chunked(2)\n            .map { it.toInt(16).toByte() }\n            .toByteArray()\n    }\n\n    private data class AesData(\n        @JsonProperty(\"ct\") val ct: String,\n        @JsonProperty(\"iv\") val iv: String,\n        @JsonProperty(\"s\") val s: String\n    )\n\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AsianEmbedHelper.kt",
    "content": "package com.lagradost.cloudstream3.extractors.helper\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.loadExtractor\n\nclass AsianEmbedHelper {\n    companion object {\n        suspend fun getUrls(\n            url: String,\n            subtitleCallback: (SubtitleFile) -> Unit,\n            callback: (ExtractorLink) -> Unit\n        ) {\n            // Fetch links\n            val doc = app.get(url).document\n            val links = doc.select(\"div#list-server-more > ul > li.linkserver\")\n            if (!links.isNullOrEmpty()) {\n                links.amap {\n                    val datavid = it.attr(\"data-video\")\n                    //Log.i(\"AsianEmbed\", \"Result => (datavid) ${datavid}\")\n                    if (datavid.isNotBlank()) {\n                        val res = loadExtractor(datavid, url, subtitleCallback, callback)\n                        Log.i(\"AsianEmbed\", \"Result => ($res) (datavid) $datavid\")\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/CryptoJSHelper.kt",
    "content": "package com.lagradost.cloudstream3.extractors.helper\n\nimport com.lagradost.cloudstream3.base64DecodeArray\nimport com.lagradost.cloudstream3.base64Encode\nimport java.util.Arrays\nimport java.security.MessageDigest\nimport java.security.SecureRandom\nimport javax.crypto.Cipher\nimport javax.crypto.spec.SecretKeySpec\nimport javax.crypto.spec.IvParameterSpec\nimport java.nio.charset.StandardCharsets\nimport kotlin.math.min\n\n/**\n * Conforming with CryptoJS AES method\n */\n// see https://gist.github.com/thackerronak/554c985c3001b16810af5fc0eb5c358f\n@Suppress(\"unused\", \"FunctionName\", \"SameParameterValue\")\nobject CryptoJS {\n\n    private const val KEY_SIZE    = 256\n    private const val IV_SIZE     = 128\n    private const val HASH_CIPHER = \"AES/CBC/PKCS7Padding\"\n    private const val AES         = \"AES\"\n    private const val KDF_DIGEST  = \"MD5\"\n\n    // Seriously crypto-js, what's wrong with you?\n    private const val APPEND      = \"Salted__\"\n\n    /**\n     * Encrypt\n     * @param password passphrase\n     * @param plainText plain string\n     */\n    fun encrypt(password: String, plainText: String): String {\n        val saltBytes = generateSalt(8)\n        val key       = ByteArray(KEY_SIZE / 8)\n        val iv        = ByteArray(IV_SIZE / 8)\n        evpkdf(password.toByteArray(), KEY_SIZE, IV_SIZE, saltBytes, key, iv)\n\n        val keyS   = SecretKeySpec(key, AES)\n        val cipher = Cipher.getInstance(HASH_CIPHER)\n        val ivSpec = IvParameterSpec(iv)\n        cipher.init(Cipher.ENCRYPT_MODE, keyS, ivSpec)\n\n        val cipherText = cipher.doFinal(plainText.toByteArray())\n        // Thanks kientux for this: https://gist.github.com/kientux/bb48259c6f2133e628ad\n        // Create CryptoJS-like encrypted!\n        val sBytes     = APPEND.toByteArray()\n        val b          = ByteArray(sBytes.size + saltBytes.size + cipherText.size)\n        System.arraycopy(sBytes, 0, b, 0, sBytes.size)\n        System.arraycopy(saltBytes, 0, b, sBytes.size, saltBytes.size)\n        System.arraycopy(cipherText, 0, b, sBytes.size + saltBytes.size, cipherText.size)\n\n        return base64Encode(b)\n    }\n\n    /**\n     * Decrypt\n     * Thanks Artjom B. for this: http://stackoverflow.com/a/29152379/4405051\n     * @param password passphrase\n     * @param cipherText encrypted string\n     */\n    fun decrypt(password: String, cipherText: String): String {\n        val ctBytes         = base64DecodeArray(cipherText)\n        val saltBytes       = Arrays.copyOfRange(ctBytes, 8, 16)\n        val cipherTextBytes = Arrays.copyOfRange(ctBytes, 16, ctBytes.size)\n\n        val key = ByteArray(KEY_SIZE / 8)\n        val iv  = ByteArray(IV_SIZE / 8)\n        evpkdf(password.toByteArray(), KEY_SIZE, IV_SIZE, saltBytes, key, iv)\n\n        val cipher = Cipher.getInstance(HASH_CIPHER)\n        val keyS   = SecretKeySpec(key, AES)\n        cipher.init(Cipher.DECRYPT_MODE, keyS, IvParameterSpec(iv))\n\n        val plainText = cipher.doFinal(cipherTextBytes)\n        return String(plainText)\n    }\n\n    private fun evpkdf(password: ByteArray, keySize: Int, ivSize: Int, salt: ByteArray, resultKey: ByteArray, resultIv: ByteArray): ByteArray {\n        return evpkdf(password, keySize, ivSize, salt, 1, KDF_DIGEST, resultKey, resultIv)\n    }\n\n    @Suppress(\"NAME_SHADOWING\")\n    private fun evpkdf(password: ByteArray, keySize: Int, ivSize: Int, salt: ByteArray, iterations: Int, hashAlgorithm: String, resultKey: ByteArray, resultIv: ByteArray): ByteArray {\n        val keySize              = keySize / 32\n        val ivSize               = ivSize / 32\n        val targetKeySize        = keySize + ivSize\n        val derivedBytes         = ByteArray(targetKeySize * 4)\n        var numberOfDerivedWords = 0\n        var block: ByteArray?    = null\n        val hash                 = MessageDigest.getInstance(hashAlgorithm)\n\n        while (numberOfDerivedWords < targetKeySize) {\n            if (block != null) {\n                hash.update(block)\n            }\n\n            hash.update(password)\n            block = hash.digest(salt)\n            hash.reset()\n\n            // Iterations\n            for (i in 1 until iterations) {\n                block = hash.digest(block!!)\n                hash.reset()\n            }\n\n            System.arraycopy(\n                block!!, 0, derivedBytes, numberOfDerivedWords * 4,\n                min(block.size, (targetKeySize - numberOfDerivedWords) * 4)\n            )\n\n            numberOfDerivedWords += block.size / 4\n        }\n\n        System.arraycopy(derivedBytes, 0, resultKey, 0, keySize * 4)\n        System.arraycopy(derivedBytes, keySize * 4, resultIv, 0, ivSize * 4)\n\n        return derivedBytes // key + iv\n    }\n\n    private fun generateSalt(length: Int): ByteArray {\n        return ByteArray(length).apply {\n            SecureRandom().nextBytes(this)\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/GogoHelper.kt",
    "content": "package com.lagradost.cloudstream3.extractors.helper\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.base64Decode\nimport com.lagradost.cloudstream3.base64DecodeArray\nimport com.lagradost.cloudstream3.base64Encode\nimport com.lagradost.cloudstream3.mvvm.safe\nimport com.lagradost.cloudstream3.mvvm.safeApiCall\nimport com.lagradost.cloudstream3.utils.AppUtils\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.M3u8Helper\nimport com.lagradost.cloudstream3.utils.getQualityFromName\nimport com.lagradost.cloudstream3.utils.newExtractorLink\nimport org.jsoup.nodes.Document\nimport java.net.URI\nimport javax.crypto.Cipher\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\n\nobject GogoHelper {\n\n    /**\n     * @param id base64Decode(show_id) + IV\n     * @return the encryption key\n     * */\n    private fun getKey(id: String): String? {\n        return safe {\n            id.map {\n                it.code.toString(16)\n            }.joinToString(\"\").substring(0, 32)\n        }\n    }\n\n    // https://github.com/saikou-app/saikou/blob/45d0a99b8a72665a29a1eadfb38c506b842a29d7/app/src/main/java/ani/saikou/parsers/anime/extractors/GogoCDN.kt#L97\n    // No Licence on the function\n    private fun cryptoHandler(\n        string: String,\n        iv: String,\n        secretKeyString: String,\n        encrypt: Boolean = true\n    ): String {\n        //println(\"IV: $iv, Key: $secretKeyString, encrypt: $encrypt, Message: $string\")\n        val ivParameterSpec = IvParameterSpec(iv.toByteArray())\n        val secretKey = SecretKeySpec(secretKeyString.toByteArray(), \"AES\")\n        val cipher = Cipher.getInstance(\"AES/CBC/PKCS5Padding\")\n        return if (!encrypt) {\n            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec)\n            String(cipher.doFinal(base64DecodeArray(string)))\n        } else {\n            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec)\n            base64Encode(cipher.doFinal(string.toByteArray()))\n        }\n    }\n\n    /**\n     * @param iframeUrl something like https://gogoplay4.com/streaming.php?id=XXXXXX\n     * @param mainApiName used for ExtractorLink names and source\n     * @param iv secret iv from site, required non-null if isUsingAdaptiveKeys is off\n     * @param secretKey secret key for decryption from site, required non-null if isUsingAdaptiveKeys is off\n     * @param secretDecryptKey secret key to decrypt the response json, required non-null if isUsingAdaptiveKeys is off\n     * @param isUsingAdaptiveKeys generates keys from IV and ID, see getKey()\n     * @param isUsingAdaptiveData generate encrypt-ajax data based on $(\"script[data-name='episode']\")[0].dataset.value\n     * */\n    suspend fun extractVidstream(\n        iframeUrl: String,\n        mainApiName: String,\n        callback: (ExtractorLink) -> Unit,\n        iv: String?,\n        secretKey: String?,\n        secretDecryptKey: String?,\n        // This could be removed, but i prefer it verbose\n        isUsingAdaptiveKeys: Boolean,\n        isUsingAdaptiveData: Boolean,\n        // If you don't want to re-fetch the document\n        iframeDocument: Document? = null\n    ) = safeApiCall {\n        if ((iv == null || secretKey == null || secretDecryptKey == null) && !isUsingAdaptiveKeys)\n            return@safeApiCall\n\n        val id = Regex(\"id=([^&]+)\").find(iframeUrl)!!.value.removePrefix(\"id=\")\n\n        var document: Document? = iframeDocument\n        val foundIv =\n            iv ?: (document ?: app.get(iframeUrl).document.also { document = it })\n                .select(\"\"\"div.wrapper[class*=container]\"\"\")\n                .attr(\"class\").split(\"-\").lastOrNull() ?: return@safeApiCall\n        val foundKey = secretKey ?: getKey(base64Decode(id) + foundIv) ?: return@safeApiCall\n        val foundDecryptKey = secretDecryptKey ?: foundKey\n\n        val uri = URI(iframeUrl)\n        val mainUrl = \"https://\" + uri.host\n\n        val encryptedId = cryptoHandler(id, foundIv, foundKey)\n        val encryptRequestData = if (isUsingAdaptiveData) {\n            // Only fetch the document if necessary\n            val realDocument = document ?: app.get(iframeUrl).document\n            val dataEncrypted =\n                realDocument.select(\"script[data-name='episode']\").attr(\"data-value\")\n            val headers = cryptoHandler(dataEncrypted, foundIv, foundKey, false)\n            \"id=$encryptedId&alias=$id&\" + headers.substringAfter(\"&\")\n        } else {\n            \"id=$encryptedId&alias=$id\"\n        }\n\n        val jsonResponse =\n            app.get(\n                \"$mainUrl/encrypt-ajax.php?$encryptRequestData\",\n                headers = mapOf(\"X-Requested-With\" to \"XMLHttpRequest\")\n            )\n        val dataencrypted = jsonResponse.parsedSafe<GogoJsonData>()?.data ?: return@safeApiCall\n        val datadecrypted = cryptoHandler(dataencrypted, foundIv, foundDecryptKey, false)\n        val sources = AppUtils.parseJson<GogoSources>(datadecrypted)\n\n        suspend fun invokeGogoSource(\n            source: GogoSource,\n            sourceCallback: (ExtractorLink) -> Unit\n        ) {\n            if (source.file.contains(\".m3u8\")) {\n                M3u8Helper.generateM3u8(\n                    mainApiName,\n                    source.file,\n                    mainUrl,\n                    headers = mapOf(\"Origin\" to \"https://plyr.link\")\n                ).forEach(sourceCallback)\n            } else {\n                sourceCallback.invoke(\n                    newExtractorLink(\n                        mainApiName,\n                        mainApiName,\n                        source.file,\n                    ) {\n                        this.referer = mainUrl\n                        this.quality = getQualityFromName(source.label)\n                    }\n                )\n            }\n        }\n\n        sources.source?.forEach {\n            invokeGogoSource(it, callback)\n        }\n        sources.sourceBk?.forEach {\n            invokeGogoSource(it, callback)\n        }\n    }\n\n    data class GogoSources(\n        @JsonProperty(\"source\") val source: List<GogoSource>?,\n        @JsonProperty(\"sourceBk\") val sourceBk: List<GogoSource>?,\n    )\n\n    data class GogoSource(\n        @JsonProperty(\"file\") val file: String,\n        @JsonProperty(\"label\") val label: String?,\n        @JsonProperty(\"type\") val type: String?,\n        @JsonProperty(\"default\") val default: String? = null\n    )\n\n    data class GogoJsonData(\n        @JsonProperty(\"data\") val data: String? = null\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/NineAnimeHelper.kt",
    "content": "package com.lagradost.cloudstream3.extractors.helper\n\nimport com.lagradost.cloudstream3.utils.StringUtils.decodeUri\nimport com.lagradost.cloudstream3.utils.StringUtils.encodeUri\n\n// Taken from https://github.com/saikou-app/saikou/blob/b35364c8c2a00364178a472fccf1ab72f09815b4/app/src/main/java/ani/saikou/parsers/anime/NineAnime.kt\n// GNU General Public License v3.0 https://github.com/saikou-app/saikou/blob/main/LICENSE.md\nobject NineAnimeHelper {\n    private const val nineAnimeKey =\n        \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\"\n    private const val cipherKey = \"kMXzgyNzT3k5dYab\"\n\n    fun encodeVrf(text: String, mainKey: String): String {\n        return encode(\n            encrypt(\n                cipher(mainKey, encode(text)),\n                nineAnimeKey\n        )//.replace(\"\"\"=+$\"\"\".toRegex(), \"\")\n        )\n    }\n\n    fun decodeVrf(text: String, mainKey: String): String {\n        return decode(cipher(mainKey, decrypt(text, nineAnimeKey)))\n    }\n\n    fun encrypt(input: String, key: String): String {\n        if (input.any { it.code > 255 }) throw Exception(\"illegal characters!\")\n        var output = \"\"\n        for (i in input.indices step 3) {\n            val a = intArrayOf(-1, -1, -1, -1)\n            a[0] = input[i].code shr 2\n            a[1] = (3 and input[i].code) shl 4\n            if (input.length > i + 1) {\n                a[1] = a[1] or (input[i + 1].code shr 4)\n                a[2] = (15 and input[i + 1].code) shl 2\n            }\n            if (input.length > i + 2) {\n                a[2] = a[2] or (input[i + 2].code shr 6)\n                a[3] = 63 and input[i + 2].code\n            }\n            for (n in a) {\n                if (n == -1) output += \"=\"\n                else {\n                    if (n in 0..63) output += key[n]\n                }\n            }\n        }\n        return output\n    }\n\n    fun cipher(key: String, text: String): String {\n        val arr = IntArray(256) { it }\n\n        var u = 0\n        var r: Int\n        arr.indices.forEach {\n            u = (u + arr[it] + key[it % key.length].code) % 256\n            r = arr[it]\n            arr[it] = arr[u]\n            arr[u] = r\n        }\n        u = 0\n        var c = 0\n\n        return text.indices.map { j ->\n            c = (c + 1) % 256\n            u = (u + arr[c]) % 256\n            r = arr[c]\n            arr[c] = arr[u]\n            arr[u] = r\n            (text[j].code xor arr[(arr[c] + arr[u]) % 256]).toChar()\n        }.joinToString(\"\")\n    }\n\n    @Suppress(\"SameParameterValue\")\n    private fun decrypt(input: String, key: String): String {\n        val t = if (input.replace(\"\"\"[\\t\\n\\f\\r]\"\"\".toRegex(), \"\").length % 4 == 0) {\n            input.replace(\"\"\"==?$\"\"\".toRegex(), \"\")\n        } else input\n        if (t.length % 4 == 1 || t.contains(\"\"\"[^+/0-9A-Za-z]\"\"\".toRegex())) throw Exception(\"bad input\")\n        var i: Int\n        var r = \"\"\n        var e = 0\n        var u = 0\n        for (o in t.indices) {\n            e = e shl 6\n            i = key.indexOf(t[o])\n            e = e or i\n            u += 6\n            if (24 == u) {\n                r += ((16711680 and e) shr 16).toChar()\n                r += ((65280 and e) shr 8).toChar()\n                r += (255 and e).toChar()\n                e = 0\n                u = 0\n            }\n        }\n        return if (12 == u) {\n            e = e shr 4\n            r + e.toChar()\n        } else {\n            if (18 == u) {\n                e = e shr 2\n                r += ((65280 and e) shr 8).toChar()\n                r += (255 and e).toChar()\n            }\n            r\n        }\n    }\n\n    fun encode(input: String): String =\n        input.encodeUri().replace(\"+\", \"%20\")\n\n    private fun decode(input: String): String = input.decodeUri()\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/VstreamhubHelper.kt",
    "content": "package com.lagradost.cloudstream3.extractors.helper\n\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.utils.ExtractorLink\nimport com.lagradost.cloudstream3.utils.ExtractorLinkType\nimport com.lagradost.cloudstream3.utils.Qualities\nimport com.lagradost.cloudstream3.utils.loadExtractor\nimport com.lagradost.cloudstream3.utils.newExtractorLink\n\nclass VstreamhubHelper {\n    companion object {\n        private val baseUrl: String = \"https://vstreamhub.com\"\n        private val baseName: String = \"Vstreamhub\"\n\n        suspend fun getUrls(\n            url: String,\n            subtitleCallback: (SubtitleFile) -> Unit,\n            callback: (ExtractorLink) -> Unit\n        ) {\n            if (url.startsWith(baseUrl)) {\n                // Fetch links\n                val doc = app.get(url).document.select(\"script\")\n                doc.forEach {\n                    val innerText = it.toString()\n                    if (!innerText.isNullOrEmpty()) {\n                        if (innerText.contains(\"file:\")) {\n                            val startString = \"file: \"\n                            val aa = innerText.substring(innerText.indexOf(startString))\n                            val linkUrl =\n                                aa.substring(startString.length + 1, aa.indexOf(\"\\\",\")).trim()\n                            //Log.i(baseName, \"Result => (linkUrl) ${linkUrl}\")\n                            val exlink = newExtractorLink(\n                                name = \"$baseName m3u8\",\n                                source = baseName,\n                                url = linkUrl,\n                                type = ExtractorLinkType.M3U8\n                            ) {\n                                this.quality = Qualities.Unknown.value\n                                this.referer = url\n                            }\n                            callback.invoke(exlink)\n                        }\n                        if (innerText.contains(\"playerInstance\")) {\n                            val aa =\n                                innerText.substring(innerText.indexOf(\"playerInstance.addButton\"))\n                            val startString = \"window.open([\"\n                            val bb = aa.substring(aa.indexOf(startString))\n                            val datavid = bb.substring(startString.length, bb.indexOf(\"]\"))\n                                .removeSurrounding(\"\\\"\")\n                            if (datavid.isNotBlank()) {\n                                loadExtractor(datavid, url, subtitleCallback, callback)\n                                //Log.i(baseName, \"Result => (datavid) ${datavid}\")\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/WcoHelper.kt",
    "content": "package com.lagradost.cloudstream3.extractors.helper\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.app\n\nclass WcoHelper {\n    companion object {\n        private const val BACKUP_KEY_DATA = \"github_keys_backup\"\n\n        data class ExternalKeys(\n            @JsonProperty(\"wco_key\")\n            val wcoKey: String? = null,\n            @JsonProperty(\"wco_cipher_key\")\n            val wcocipher: String? = null\n        )\n\n        data class NewExternalKeys(\n            @JsonProperty(\"cipherKey\")\n            val cipherkey: String? = null,\n            @JsonProperty(\"encryptKey\")\n            val encryptKey: String? = null,\n            @JsonProperty(\"mainKey\")\n            val mainKey: String? = null,\n        )\n\n        private var keys: ExternalKeys? = null\n        private var newKeys: NewExternalKeys? = null\n        private suspend fun getKeys() {\n            keys = keys\n                ?: app.get(\"https://raw.githubusercontent.com/reduplicated/Cloudstream/master/docs/keys.json\")\n                    .parsedSafe<ExternalKeys>()\n        }\n\n        suspend fun getWcoKey(): ExternalKeys? {\n            getKeys()\n            return keys\n        }\n\n        private suspend fun getNewKeys() {\n            newKeys = newKeys\n                ?: app.get(\"https://raw.githubusercontent.com/chekaslowakiya/BruhFlow/main/keys.json\")\n                    .parsedSafe<NewExternalKeys>()\n        }\n\n        suspend fun getNewWcoKey(): NewExternalKeys? {\n            getNewKeys()\n            return newKeys\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/CrossTmdbProvider.kt",
    "content": "package com.lagradost.cloudstream3.metaproviders\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder.apis\nimport com.lagradost.cloudstream3.APIHolder.getApiFromNameNull\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.MovieLoadResponse\nimport com.lagradost.cloudstream3.MovieSearchResponse\nimport com.lagradost.cloudstream3.SearchResponseList\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.amap\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.toNewSearchResponseList\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.lagradost.cloudstream3.utils.AppUtils.tryParseJson\nimport com.lagradost.cloudstream3.utils.ExtractorLink\n\nclass CrossTmdbProvider : TmdbProvider() {\n    override var name = \"MultiMovie\"\n    override val apiName = \"MultiMovie\"\n    override var lang = \"en\"\n    override val useMetaLoadResponse = true\n    override val usesWebView = true\n    override val supportedTypes = setOf(TvType.Movie)\n\n    private fun filterName(name: String): String {\n        return Regex(\"\"\"[^a-zA-Z0-9-]\"\"\").replace(name, \"\")\n    }\n\n    private val validApis\n        get() =\n            synchronized(apis) { apis.filter { it.lang == this.lang && it::class.java != this::class.java } }\n    //.distinctBy { it.uniqueId }\n\n\n    data class CrossMetaData(\n        @JsonProperty(\"isSuccess\") val isSuccess: Boolean,\n        @JsonProperty(\"movies\") val movies: List<Pair<String, String>>? = null,\n    )\n\n    override suspend fun loadLinks(\n        data: String,\n        isCasting: Boolean,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ): Boolean {\n        tryParseJson<CrossMetaData>(data)?.let { metaData ->\n            if (!metaData.isSuccess) return false\n            metaData.movies?.amap { (apiName, data) ->\n                getApiFromNameNull(apiName)?.let {\n                    try {\n                        it.loadLinks(data, isCasting, subtitleCallback, callback)\n                    } catch (e: Exception) {\n                        logError(e)\n                    }\n                }\n            }\n\n            return true\n        }\n        return false\n    }\n\n    override suspend fun search(query: String, page: Int): SearchResponseList? {\n        // TODO REMOVE\n        return super.search(query, page)\n            ?.items\n            ?.filterIsInstance<MovieSearchResponse>()\n            ?.toNewSearchResponseList()\n    }\n\n    override suspend fun load(url: String): LoadResponse? {\n        val base = super.load(url)?.apply {\n            this.recommendations =\n                this.recommendations?.filterIsInstance<MovieSearchResponse>() // TODO REMOVE\n            val matchName = filterName(this.name)\n            when (this) {\n                is MovieLoadResponse -> {\n                    val data = validApis.amap { api ->\n                        try {\n                            if (api.supportedTypes.contains(TvType.Movie)) { //|| api.supportedTypes.contains(TvType.AnimeMovie)\n                                return@amap api.search(this.name)?.first {\n                                    if (filterName(it.name).equals(\n                                            matchName,\n                                            ignoreCase = true\n                                        )\n                                    ) {\n                                        if (it is MovieSearchResponse)\n                                            if (it.year != null && this.year != null && it.year != this.year) // if year exist then do a check\n                                                return@first false\n\n                                        return@first true\n                                    }\n                                    false\n                                }?.let { search ->\n                                    val response = api.load(search.url)\n                                    if (response is MovieLoadResponse) {\n                                        response\n                                    } else {\n                                        null\n                                    }\n                                }\n                            }\n                            null\n                        } catch (e: Exception) {\n                            logError(e)\n                            null\n                        }\n                    }.filterNotNull()\n                    this.dataUrl =\n                        CrossMetaData(true, data.map { it.apiName to it.dataUrl }).toJson()\n                }\n\n                else -> {\n                    throw ErrorLoadingException(\"Nothing besides movies are implemented for this provider\")\n                }\n            }\n        }\n\n        return base\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt",
    "content": "package com.lagradost.cloudstream3.metaproviders\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.api.BuildConfig\nimport com.lagradost.cloudstream3.APIHolder.unixTimeMS\nimport com.lagradost.cloudstream3.Actor\nimport com.lagradost.cloudstream3.ActorData\nimport com.lagradost.cloudstream3.Episode\nimport com.lagradost.cloudstream3.HomePageResponse\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.MainPageRequest\nimport com.lagradost.cloudstream3.ProviderType\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.ShowStatus\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.addDate\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mainPageOf\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.newEpisode\nimport com.lagradost.cloudstream3.newHomePageResponse\nimport com.lagradost.cloudstream3.newMovieLoadResponse\nimport com.lagradost.cloudstream3.newMovieSearchResponse\nimport com.lagradost.cloudstream3.newTvSeriesLoadResponse\nimport com.lagradost.cloudstream3.newTvSeriesSearchResponse\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport okhttp3.Interceptor\nimport okhttp3.Response\nimport java.text.SimpleDateFormat\nimport java.util.Locale\n\n//Reference: https://mydramalist.github.io/MDL-API/\nabstract class MyDramaListAPI : MainAPI() {\n    override var name = \"MyDramaList\"\n    override val hasMainPage = true\n    override val providerType = ProviderType.MetaProvider\n    override val supportedTypes = setOf(\n        TvType.Movie,\n        TvType.TvSeries,\n        TvType.AsianDrama,\n    )\n\n    companion object {\n        const val TAG = \"MyDramaList\"\n        val API_KEY: String = BuildConfig.MDL_API_KEY\n        const val API_HOST = \"https://api.mydramalist.com/v1\"\n        const val SITE_HOST = \"https://mydramalist.com\"\n        private val headerInterceptor = MyDramaListInterceptor()\n    }\n\n    /** Automatically adds required api headers */\n    private class MyDramaListInterceptor : Interceptor {\n        override fun intercept(chain: Interceptor.Chain): Response {\n            return chain.proceed(\n                chain.request().newBuilder()\n                    .removeHeader(\"user-agent\")\n                    .addHeader(\"user-agent\", \"Dart/3.6 (dart:io)\")\n                    .addHeader(\"mdl-api-key\", API_KEY)\n                    .build()\n            )\n        }\n    }\n\n    override val mainPage = mainPageOf(\n        \"$API_HOST/titles/trending?type=shows\" to \"Trending Shows This week\",\n        \"$API_HOST/titles/top_airing?type=shows\" to \"Top Airing Shows\",\n        \"$API_HOST/titles/upcoming?type=shows\" to \"Upcoming Shows\",\n        \"$API_HOST/titles/trending?type=movies\" to \"Trending Movies This week\",\n        \"$API_HOST/titles/top_movies?type=movies\" to \"Top Movies\",\n        \"$API_HOST/titles/upcoming?type=movies\" to \"Upcoming Movies\",\n    )\n\n    override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {\n        val list = app.get(\n            url = \"${request.data}&limit=20&page=$page&lang=en-US\",\n            interceptor = headerInterceptor\n        ).parsed<SearchResult>().map { element ->\n            element.toSearchResponse()\n        }\n        return newHomePageResponse(request.name, list)\n    }\n\n    override suspend fun search(query: String): List<SearchResponse>? {\n        return app.post(\n            url = \"$API_HOST/search/titles\",\n            data = mapOf(\"q\" to query),\n            interceptor = headerInterceptor\n        ).parsed<SearchResult>().map { element ->\n            element.toSearchResponse()\n        }\n    }\n\n    private fun MediaSummary.toSearchResponse(): SearchResponse {\n\n        val mediaType = if (type == \"Movie\") TvType.Movie else TvType.TvSeries\n\n        if (mediaType == TvType.Movie) {\n            return newMovieSearchResponse(\n                name = title,\n                url = Data(\n                    type = mediaType,\n                    media = this,\n                ).toJson(),\n                type = TvType.Movie,\n            ) {\n                posterUrl = images.poster\n            }\n        } else {\n            return newTvSeriesSearchResponse(\n                name = title,\n                url = Data(\n                    type = mediaType,\n                    media = this,\n                ).toJson(),\n                type = TvType.TvSeries,\n            ) {\n                this.posterUrl = images.poster\n            }\n        }\n    }\n\n    override suspend fun load(url: String): LoadResponse {\n        val data = parseJson<Data>(url)\n\n        return app.get(\n            url = \"$API_HOST/titles/${data.media?.id}\",\n            interceptor = headerInterceptor\n        ).parsed<Media>().toLoadResponse(data)\n    }\n\n    private suspend fun Media.toLoadResponse(data: Data): LoadResponse {\n\n        return if (type == \"Movie\") {\n\n            val link = LinkData(\n                id = id,\n                type = \"Movie\",\n                season = 0,\n                episode = 0,\n                title = title,\n                year = mediaYear,\n                orgTitle = originalTitle,\n                date = released,\n            )\n\n            newMovieLoadResponse(\n                name = title,\n                url = data.toJson(),\n                type = TvType.Movie,\n                dataUrl = link.toJson(),\n            ) {\n                this.type = TvType.Movie\n            }\n        } else {\n            newTvSeriesLoadResponse(\n                name = this.title,\n                url = data.toJson(),\n                type = TvType.TvSeries,\n                episodes = fetchEpisodes()\n            ) {\n\n                this.type = TvType.AsianDrama\n                this.showStatus = getStatus(status)\n            }\n        }.applyMedia(this)\n    }\n\n    private suspend fun LoadResponse.applyMedia(media: Media): LoadResponse {\n        this.name = media.title\n        this.posterUrl = media.images.poster\n        this.year = media.mediaYear\n        this.plot = media.synopsis\n        this.score = Score.from10(media.mediaRating)\n        this.tags = media.fixGenres()\n        this.duration = media.runtime.toInt()\n        this.recommendations = media.fetchRecommendations().map { it.toSearchResponse() }\n        this.actors = media.fetchCredits()\n        this.comingSoon = isUpcoming(media.airedStart)\n        this.backgroundPosterUrl = media.images.poster\n        this.contentRating = fixCertification(media.certification)\n        addTrailer(\n            media.fetchTrailer(),\n            addRaw = true,\n            headers = mapOf(\n                \"User-Agent\" to \"Dart/3.6 (dart:io)\"\n            )\n        )\n        return this\n    }\n\n    private fun isUpcoming(dateString: String?): Boolean {\n        return try {\n            val format = SimpleDateFormat(\"yyyy-MM-dd\", Locale.getDefault())\n            val dateTime = dateString?.let { format.parse(it)?.time } ?: return false\n            unixTimeMS < dateTime\n        } catch (t: Throwable) {\n            logError(t)\n            false\n        }\n    }\n\n    private fun getStatus(status: String?): ShowStatus? {\n        return when (status) {\n            \"Airing\" -> ShowStatus.Ongoing\n            \"Finished Airing\" -> ShowStatus.Completed\n            else -> null\n        }\n    }\n\n    private fun fixCertification(status: String?): String? {\n        return when (status) {\n            \"G - All Ages\" -> \"G\"\n            \"13+ - Teens 13 or older\" -> \"13+\"\n            \"15+ - Teens 15 or older\" -> \"15+\"\n            \"18+ Restricted (violence & profanity)\" -> \"18+\"\n            \"Not Yet Rated\" -> null\n            else -> \"null\"\n        }\n    }\n\n    data class Data(\n        val type: TvType? = null,\n        val media: MediaSummary? = null,\n    )\n\n    class SearchResult : ArrayList<MediaSummary>()\n\n    class Recommendations : ArrayList<MediaSummary>()\n\n    data class MediaSummary(\n        @JsonProperty(\"id\") val id: Long,\n        @JsonProperty(\"title\") val title: String,\n        @JsonProperty(\"original_title\") val originalTitle: String,\n        @JsonProperty(\"year\") val year: Int? = null,\n        @JsonProperty(\"rating\") val rating: Double? = null,\n        @JsonProperty(\"permalink\") val permalink: String? = null,\n        @JsonProperty(\"type\") val type: String,\n        @JsonProperty(\"media_type\") val mediaType: String? = null,\n        @JsonProperty(\"country\") val country: String? = null,\n        @JsonProperty(\"language\") val language: String? = null,\n        @JsonProperty(\"images\") val images: Images,\n    )\n\n    data class Images(\n        @JsonProperty(\"thumb\") val thumb: String? = null,\n        @JsonProperty(\"medium\") val medium: String? = null,\n        @JsonProperty(\"poster\") val poster: String? = null,\n    )\n\n    data class Media(\n        @JsonProperty(\"id\") val id: Long,\n        @JsonProperty(\"slug\") val slug: String,\n        @JsonProperty(\"title\") val title: String,\n        @JsonProperty(\"original_title\") val originalTitle: String,\n        @JsonProperty(\"year\") val mediaYear: Int,\n        @JsonProperty(\"episodes\") val episodes: Long,\n        @JsonProperty(\"rating\") val mediaRating: Double,\n        @JsonProperty(\"permalink\") val permalink: String? = null,\n        @JsonProperty(\"synopsis\") val synopsis: String? = null,\n        @JsonProperty(\"type\") val type: String? = null,\n        @JsonProperty(\"media_type\") val mediaType: String? = null,\n        @JsonProperty(\"country\") val country: String? = null,\n        @JsonProperty(\"language\") val language: String? = null,\n        @JsonProperty(\"images\") val images: Images,\n        @JsonProperty(\"alt_titles\") val altTitles: List<String>? = null,\n        @JsonProperty(\"votes\") val votes: Long? = null,\n        @JsonProperty(\"aired_start\") val airedStart: String? = null,\n        @JsonProperty(\"released\") val released: String? = null,\n        @JsonProperty(\"release_dates_fmt\") val releaseDatesFmt: String,\n        @JsonProperty(\"genres\") val genres: List<Any>? = null,\n        @JsonProperty(\"trailer\") val trailer: Trailer?,\n        @JsonProperty(\"watchers\") val watchers: Long,\n        @JsonProperty(\"ranked\") val ranked: Long,\n        @JsonProperty(\"popularity\") val popularity: Long,\n        @JsonProperty(\"runtime\") val runtime: Long,\n        @JsonProperty(\"reviews_count\") val reviewsCount: Long,\n        @JsonProperty(\"recs_count\") val recsCount: Long,\n        @JsonProperty(\"comments_count\") val commentsCount: Long,\n        @JsonProperty(\"certification\") val certification: String,\n        @JsonProperty(\"status\") val status: String,\n        @JsonProperty(\"enable_ads\") val enableAds: Boolean,\n        @JsonProperty(\"sources\") val sources: List<Source>,\n        @JsonProperty(\"updated_at\") val updatedAt: Long,\n    ) {\n        suspend fun fetchCredits(): List<ActorData> {\n            val actors = app.get(\n                url = \"$API_HOST/titles/$id/credits\",\n                interceptor = headerInterceptor\n            ).parsed<Credits>().cast.map {\n                ActorData(\n                    Actor(\n                        name = it.name,\n                        image = it.images.poster\n                    ),\n                    roleString = it.characterName\n                )\n            }\n            return actors\n        }\n\n        suspend fun fetchRecommendations(): Recommendations {\n            return app.get(\n                url = \"$API_HOST/titles/$id/recommendations\",\n                interceptor = headerInterceptor\n            ).parsed<Recommendations>()\n        }\n\n        suspend fun fetchTrailer(): String? {\n            return app.get(\n                url = \"$SITE_HOST/v1/trailers/${trailer?.id}\",\n                interceptor = headerInterceptor\n            ).parsedSafe<TrailerRoot>()?.trailer?.trailerDetails?.source\n        }\n\n        fun fixGenres(): List<String> {\n            return (genres as? List<*>)?.mapNotNull { item ->\n                when (item) {\n                    is String -> item\n                    is Map<*, *> -> item[\"name\"] as? String\n                    else -> null\n                }\n            } ?: emptyList()\n        }\n    }\n\n    private suspend fun Media.fetchEpisodes(): List<Episode> {\n        return app.get(\n            url = \"$API_HOST/titles/${this.id}/episodes\",\n            interceptor = headerInterceptor\n        ).parsed<ShowEpisodes>().map {\n            it.episodes\n        }.flatten().map { ep ->\n            val link = LinkData(\n                id = id,\n                type = \"Series\",\n                season = 0,\n                episode = ep.episodeNumber,\n                title = title,\n                year = mediaYear,\n                orgTitle = originalTitle,\n                date = released,\n                airedDate = airedStart,\n            )\n            newEpisode(\n                link.toJson()\n            ) {\n                name = null\n                season = null\n                episode = ep.episodeNumber\n                posterUrl = null\n                score = Score.from10(ep.rating)\n                description = null\n                runTime = null\n                addDate(ep.releasedAt)\n            }\n        }\n    }\n\n    data class Genre(\n        @JsonProperty(\"id\") val id: Long,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"slug\") val slug: String,\n    )\n\n    data class Tag(\n        @JsonProperty(\"id\") val id: Long,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"slug\") val slug: String,\n    )\n\n    data class Source(\n        @JsonProperty(\"xid\") val xid: String,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"source\") val source: String,\n        @JsonProperty(\"source_type\") val sourceType: String,\n        @JsonProperty(\"link\") val link: String,\n        @JsonProperty(\"image\") val image: String,\n    )\n\n    data class Trailer(\n        @JsonProperty(\"id\") val id: Long? = null,\n    )\n\n    data class Credits(\n        @JsonProperty(\"cast\") val cast: List<Cast>,\n        @JsonProperty(\"crew\") val crew: List<Crew>,\n    )\n\n    data class Cast(\n        @JsonProperty(\"id\") val id: Long,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"url\") val url: String,\n        @JsonProperty(\"slug\") val slug: String,\n        @JsonProperty(\"images\") val images: Images,\n        @JsonProperty(\"character_name\") val characterName: String,\n        @JsonProperty(\"role\") val role: String,\n    )\n\n    data class Crew(\n        @JsonProperty(\"id\") val id: Long,\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"slug\") val slug: String,\n        @JsonProperty(\"images\") val images: Images,\n        @JsonProperty(\"job\") val job: String,\n    )\n\n    class ShowEpisodes : ArrayList<ShowEpisodesItem>()\n\n    data class ShowEpisodesItem(\n        @JsonProperty(\"name\") val name: String,\n        @JsonProperty(\"release_date\") val releaseDate: String,\n        @JsonProperty(\"episodes\") val episodes: List<ShowEpisode>,\n        @JsonProperty(\"timezone\") val timezone: String,\n        @JsonProperty(\"total\") val total: Int,\n    )\n\n    data class ShowEpisode(\n        @JsonProperty(\"id\") val id: Int,\n        @JsonProperty(\"episode_number\") val episodeNumber: Int,\n        @JsonProperty(\"rating\") val rating: Double,\n        @JsonProperty(\"votes\") val votes: Int,\n        @JsonProperty(\"released_at\") val releasedAt: String,\n    )\n\n    data class TrailerRoot(\n        @JsonProperty(\"trailer\") val trailer: TrailerNode,\n    )\n\n    data class TrailerNode(\n        @JsonProperty(\"trailer\") val trailerDetails: TrailerDetails,\n    )\n\n    data class TrailerDetails(\n        @JsonProperty(\"id\") val id: Long,\n        @JsonProperty(\"source\") val source: String,\n    )\n\n    data class LinkData(\n        @JsonProperty(\"id\") val id: Long? = null,\n        @JsonProperty(\"type\") val type: String? = null,\n        @JsonProperty(\"season\") val season: Int? = null,\n        @JsonProperty(\"episode\") val episode: Int? = null,\n        @JsonProperty(\"title\") val title: String? = null,\n        @JsonProperty(\"year\") val year: Int? = null,\n        @JsonProperty(\"orgTitle\") val orgTitle: String? = null,\n        @JsonProperty(\"lastSeason\") val lastSeason: Int? = null,\n        @JsonProperty(\"date\") val date: String? = null,\n        @JsonProperty(\"airedDate\") val airedDate: String? = null,\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/SyncRedirector.kt",
    "content": "package com.lagradost.cloudstream3.metaproviders\n\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.mvvm.safeAsync\nimport com.lagradost.cloudstream3.syncproviders.SyncIdName\n\nobject SyncRedirector {\n    private val syncIds =\n        listOf(\n            SyncIdName.MyAnimeList to Regex(\"\"\"myanimelist\\.net/anime/(\\d+)\"\"\"),\n            SyncIdName.Anilist to Regex(\"\"\"anilist\\.co/anime/(\\d+)\"\"\")\n        )\n\n    suspend fun redirect(\n        url: String,\n        providerApi: MainAPI\n    ): String {\n        // Deprecated since providers should do this instead!\n\n        // Tries built in ID -> ProviderUrl\n        /*\n        for (api in syncApis) {\n            if (url.contains(api.mainUrl)) {\n                val otherApi = when (api.name) {\n                    aniListApi.name -> \"anilist\"\n                    malApi.name -> \"myanimelist\"\n                    else -> return url\n                }\n\n                SyncUtil.getUrlsFromId(api.getIdFromUrl(url), otherApi).firstOrNull { realUrl ->\n                    realUrl.contains(providerApi.mainUrl)\n                }?.let {\n                    return it\n                }\n//                ?: run {\n//                    throw ErrorLoadingException(\"Page does not exist on $preferredUrl\")\n//                }\n            }\n        }\n        */\n\n        // Tries provider solution\n        // This goes through all sync ids and finds supported id by said provider\n        return syncIds.firstNotNullOfOrNull { (syncName, syncRegex) ->\n            if (providerApi.supportedSyncNames.contains(syncName)) {\n                syncRegex.find(url)?.value?.let {\n                    safeAsync {\n                        providerApi.getLoadUrl(syncName, it)\n                    }\n                }\n            } else null\n        } ?: url\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt",
    "content": "package com.lagradost.cloudstream3.metaproviders\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.Actor\nimport com.lagradost.cloudstream3.Episode\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.HomePageList\nimport com.lagradost.cloudstream3.HomePageResponse\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.LoadResponse.Companion.addActors\nimport com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId\nimport com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.MainPageRequest\nimport com.lagradost.cloudstream3.MovieLoadResponse\nimport com.lagradost.cloudstream3.MovieSearchResponse\nimport com.lagradost.cloudstream3.ProviderType\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.SearchResponseList\nimport com.lagradost.cloudstream3.TvSeriesLoadResponse\nimport com.lagradost.cloudstream3.TvSeriesSearchResponse\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.newEpisode\nimport com.lagradost.cloudstream3.newHomePageResponse\nimport com.lagradost.cloudstream3.newMovieLoadResponse\nimport com.lagradost.cloudstream3.newMovieSearchResponse\nimport com.lagradost.cloudstream3.newTvSeriesLoadResponse\nimport com.lagradost.cloudstream3.newTvSeriesSearchResponse\nimport com.lagradost.cloudstream3.runAllAsync\nimport com.lagradost.cloudstream3.toNewSearchResponseList\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport com.uwetrottmann.tmdb2.Tmdb\nimport com.uwetrottmann.tmdb2.entities.AppendToResponse\nimport com.uwetrottmann.tmdb2.entities.BaseMovie\nimport com.uwetrottmann.tmdb2.entities.BaseTvShow\nimport com.uwetrottmann.tmdb2.entities.CastMember\nimport com.uwetrottmann.tmdb2.entities.ContentRating\nimport com.uwetrottmann.tmdb2.entities.Movie\nimport com.uwetrottmann.tmdb2.entities.ReleaseDate\nimport com.uwetrottmann.tmdb2.entities.ReleaseDatesResult\nimport com.uwetrottmann.tmdb2.entities.TvSeason\nimport com.uwetrottmann.tmdb2.entities.TvShow\nimport com.uwetrottmann.tmdb2.entities.Videos\nimport com.uwetrottmann.tmdb2.enumerations.AppendToResponseItem\nimport com.uwetrottmann.tmdb2.enumerations.VideoType\nimport retrofit2.awaitResponse\nimport retrofit2.Response\nimport java.util.Calendar\n\n/**\n * episode and season starting from 1\n * they are null if movie\n * */\ndata class TmdbLink(\n    @JsonProperty(\"imdbID\") val imdbID: String?,\n    @JsonProperty(\"tmdbID\") val tmdbID: Int?,\n    @JsonProperty(\"episode\") val episode: Int?,\n    @JsonProperty(\"season\") val season: Int?,\n    @JsonProperty(\"movieName\") val movieName: String? = null,\n)\n\nopen class TmdbProvider : MainAPI() {\n    // This should always be false, but might as well make it easier for forks\n    open val includeAdult = false\n\n    // Use the LoadResponse from the metadata provider\n    open val useMetaLoadResponse = false\n    open val apiName = \"TMDB\"\n\n    // As some sites doesn't support s0\n    open val disableSeasonZero = true\n\n    override val hasMainPage = true\n    override val providerType = ProviderType.MetaProvider\n\n    // Fuck it, public private api key because github actions won't co-operate.\n    // Please no stealy.\n    private val tmdb = Tmdb(\"e6333b32409e02a4a6eba6fb7ff866bb\")\n\n    private fun getImageUrl(link: String?): String? {\n        if (link == null) return null\n        return if (link.startsWith(\"/\")) \"https://image.tmdb.org/t/p/w500/$link\" else link\n    }\n\n    private fun getUrl(id: Int?, tvShow: Boolean): String {\n        return if (tvShow) \"https://www.themoviedb.org/tv/${id ?: -1}\"\n        else \"https://www.themoviedb.org/movie/${id ?: -1}\"\n    }\n\n    private fun BaseTvShow.toSearchResponse(): TvSeriesSearchResponse {\n        return newTvSeriesSearchResponse(\n            name = this.name ?: this.original_name,\n            url = getUrl(id, true),\n            type = TvType.TvSeries,\n            fix = false\n        ) {\n            this.id = this@toSearchResponse.id\n            this.posterUrl = getImageUrl(poster_path)\n            this.score = Score.from10(vote_average)\n            this.year = first_air_date?.let {\n                Calendar.getInstance().apply {\n                    time = it\n                }.get(Calendar.YEAR)\n            }\n        }\n    }\n\n    private fun BaseMovie.toSearchResponse(): MovieSearchResponse {\n        return newMovieSearchResponse(\n            name = this.title ?: this.original_title,\n            url = getUrl(id, false),\n            type = TvType.Movie,\n            fix = false\n        ) {\n            this.id = this@toSearchResponse.id\n            this.posterUrl = getImageUrl(poster_path)\n            this.score = Score.from10(vote_average)\n            this.year = release_date?.let {\n                Calendar.getInstance().apply {\n                    time = it\n                }.get(Calendar.YEAR)\n            }\n        }\n    }\n\n    private fun List<CastMember?>?.toActors(): List<Pair<Actor, String?>>? {\n        return this?.mapNotNull {\n            Pair(\n                Actor(it?.name ?: return@mapNotNull null, getImageUrl(it.profile_path)),\n                it.character\n            )\n        }\n    }\n\n    private suspend fun TvShow.toLoadResponse(): TvSeriesLoadResponse {\n        val tvSeasonsService = tmdb.tvSeasonsService()\n        val episodes = mutableListOf<Episode>()\n\n        val validSeasons = this.seasons?.filter { !disableSeasonZero || (it.season_number ?: 0) != 0 } ?: emptyList()\n        for (season in validSeasons) {\n            val seasonNumber = season.season_number ?: continue\n\n            val response: Response<TvSeason> = tmdb.tvSeasonsService()\n                .season(this.id, seasonNumber, \"external_ids,images,episodes\")\n                .awaitResponse()\n\n            val fullSeason = response.body() ?: continue\n\n            fullSeason.episodes?.forEach { episode ->\n                episodes += newEpisode(\n                    TmdbLink(\n                        episode.external_ids?.imdb_id ?: this.external_ids?.imdb_id,\n                        this.id,\n                        episode.episode_number,\n                        episode.season_number,\n                        this.name ?: this.original_name\n                    ).toJson()\n                ) {\n                    this.name = episode.name\n                    this.season = episode.season_number\n                    this.episode = episode.episode_number\n                    this.score = Score.from10(episode.vote_average)\n                    this.description = episode.overview\n                    this.date = episode.air_date?.time\n                    this.posterUrl = getImageUrl(episode.still_path)\n                }\n            }\n        }\n\n        return newTvSeriesLoadResponse(\n            this.name ?: this.original_name,\n            getUrl(id, true),\n            TvType.TvSeries,\n            episodes\n        ) {\n            posterUrl = getImageUrl(poster_path)\n            year = first_air_date?.let {\n                Calendar.getInstance().apply {\n                    time = it\n                }.get(Calendar.YEAR)\n            }\n            plot = overview\n            addImdbId(external_ids?.imdb_id)\n            tags = genres?.mapNotNull { it.name }\n            duration = episode_run_time?.average()?.toInt()\n            score = Score.from10(vote_average)\n            addTrailer(videos.toTrailers())\n            recommendations = (this@toLoadResponse.recommendations\n                ?: this@toLoadResponse.similar)?.results?.map { it.toSearchResponse() }\n            addActors(credits?.cast?.toList().toActors())\n            contentRating = fetchContentRating(id, \"US\")\n        }\n    }\n\n    private fun Videos?.toTrailers(): List<String>? {\n        return this?.results?.filter { it.type != VideoType.OPENING_CREDITS && it.type != VideoType.FEATURETTE }\n            ?.sortedBy { it.type?.ordinal ?: 10000 }\n            ?.mapNotNull {\n                when (it.site?.trim()?.lowercase()) {\n                    \"youtube\" -> { // TODO FILL SITES\n                        \"https://www.youtube.com/watch?v=${it.key}\"\n                    }\n                    else -> null\n                }\n            }\n    }\n\n    private suspend fun Movie.toLoadResponse(): MovieLoadResponse {\n        return newMovieLoadResponse(\n            this.title ?: this.original_title, getUrl(id, false), TvType.Movie, TmdbLink(\n                this.imdb_id,\n                this.id,\n                null,\n                null,\n                this.title ?: this.original_title,\n            ).toJson()\n        ) {\n            posterUrl = getImageUrl(poster_path)\n            year = release_date?.let {\n                Calendar.getInstance().apply {\n                    time = it\n                }.get(Calendar.YEAR)\n            }\n            plot = overview\n            addImdbId(external_ids?.imdb_id)\n            tags = genres?.mapNotNull { it.name }\n            duration = runtime\n            score = Score.from10(vote_average)\n            addTrailer(videos.toTrailers())\n\n            recommendations = (this@toLoadResponse.recommendations\n                ?: this@toLoadResponse.similar)?.results?.map { it.toSearchResponse() }\n            addActors(credits?.cast?.toList().toActors())\n\n            contentRating = fetchContentRating(id, \"US\")\n        }\n    }\n\n    override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {\n\n        // SAME AS DISCOVER IT SEEMS\n//        val popularSeries = tmdb.tvService().popular(page, \"en-US\").execute().body()?.results?.map {\n//            it.toSearchResponse()\n//        } ?: listOf()\n//\n//        val popularMovies =\n//            tmdb.moviesService().popular(page, \"en-US\", \"840\").execute().body()?.results?.map {\n//                it.toSearchResponse()\n//            } ?: listOf()\n\n        var discoverMovies: List<MovieSearchResponse> = listOf()\n        var discoverSeries: List<TvSeriesSearchResponse> = listOf()\n        var topMovies: List<MovieSearchResponse> = listOf()\n        var topSeries: List<TvSeriesSearchResponse> = listOf()\n        runAllAsync(\n            {\n                discoverMovies = tmdb.discoverMovie().page(page).build().awaitResponse().body()?.results?.map {\n                    it.toSearchResponse()\n                } ?: listOf()\n            }, {\n                discoverSeries = tmdb.discoverTv().page(page).build().awaitResponse().body()?.results?.map {\n                    it.toSearchResponse()\n                } ?: listOf()\n            }, {\n                // https://en.wikipedia.org/wiki/ISO_3166-1\n                topMovies =\n                    tmdb.moviesService().topRated(page, \"en-US\", \"US\").awaitResponse()\n                        .body()?.results?.map {\n                            it.toSearchResponse()\n                        } ?: listOf()\n            }, {\n                topSeries =\n                    tmdb.tvService().topRated(page, \"en-US\").awaitResponse().body()?.results?.map {\n                        it.toSearchResponse()\n                    } ?: listOf()\n            }\n        )\n\n        return newHomePageResponse(\n            listOf(\n//                HomePageList(\"Popular Series\", popularSeries),\n//                HomePageList(\"Popular Movies\", popularMovies),\n                HomePageList(\"Popular Movies\", discoverMovies),\n                HomePageList(\"Popular Series\", discoverSeries),\n                HomePageList(\"Top Movies\", topMovies),\n                HomePageList(\"Top Series\", topSeries),\n            )\n        )\n    }\n\n    open fun loadFromImdb(imdb: String, seasons: List<TvSeason>): LoadResponse? {\n        return null\n    }\n\n    open fun loadFromTmdb(tmdb: Int, seasons: List<TvSeason>): LoadResponse? {\n        return null\n    }\n\n    open fun loadFromImdb(imdb: String): LoadResponse? {\n        return null\n    }\n\n    open fun loadFromTmdb(tmdb: Int): LoadResponse? {\n        return null\n    }\n\n    open suspend fun fetchContentRating(id: Int?, country: String): String? {\n        id ?: return null\n\n        val contentRatings = tmdb.tvService().content_ratings(id).awaitResponse().body()?.results\n        return if (!contentRatings.isNullOrEmpty()) {\n            contentRatings.firstOrNull { it: ContentRating ->\n                it.iso_3166_1 == country\n            }?.rating\n        } else {\n            val releaseDates = tmdb.moviesService().releaseDates(id).awaitResponse().body()?.results\n            val certification = releaseDates?.firstOrNull { it: ReleaseDatesResult ->\n                it.iso_3166_1 == country\n            }?.release_dates?.firstOrNull { it: ReleaseDate ->\n                !it.certification.isNullOrBlank()\n            }?.certification\n\n            certification\n        }\n    }\n\n    // Possible to add recommendations and such here.\n    override suspend fun load(url: String): LoadResponse? {\n        // https://www.themoviedb.org/movie/7445-brothers\n        // https://www.themoviedb.org/tv/71914-the-wheel-of-time\n\n        val idRegex = Regex(\"\"\"themoviedb\\.org/(.*)/(\\d+)\"\"\")\n        val found = idRegex.find(url)\n\n        val isTvSeries = found?.groupValues?.getOrNull(1).equals(\"tv\", ignoreCase = true)\n        val id = found?.groupValues?.getOrNull(2)?.toIntOrNull()\n            ?: throw ErrorLoadingException(\"No id found\")\n\n        return if (useMetaLoadResponse) {\n            return if (isTvSeries) {\n                val body = tmdb.tvService()\n                    .tv(\n                        id,\n                        \"en-US\",\n                        AppendToResponse(\n                            AppendToResponseItem.EXTERNAL_IDS,\n                            AppendToResponseItem.VIDEOS\n                        )\n                    )\n                    .awaitResponse().body()\n                val response = body?.toLoadResponse()\n                if (response != null) {\n                    if (response.recommendations.isNullOrEmpty())\n                        tmdb.tvService().recommendations(id, 1, \"en-US\").awaitResponse().body()\n                            ?.let {\n                                it.results?.map { res -> res.toSearchResponse() }\n                            }?.let { list ->\n                                response.recommendations = list\n                            }\n\n                    if (response.actors.isNullOrEmpty())\n                        tmdb.tvService().credits(id, \"en-US\").awaitResponse().body()?.let {\n                            response.addActors(it.cast?.toActors())\n                        }\n                }\n\n                response\n            } else {\n                val body = tmdb.moviesService()\n                    .summary(\n                        id,\n                        \"en-US\",\n                        AppendToResponse(\n                            AppendToResponseItem.EXTERNAL_IDS,\n                            AppendToResponseItem.VIDEOS\n                        )\n                    )\n                    .awaitResponse().body()\n                val response = body?.toLoadResponse()\n                if (response != null) {\n                    if (response.recommendations.isNullOrEmpty())\n                        tmdb.moviesService().recommendations(id, 1, \"en-US\").awaitResponse().body()\n                            ?.let {\n                                it.results?.map { res -> res.toSearchResponse() }\n                            }?.let { list ->\n                                response.recommendations = list\n                            }\n\n                    if (response.actors.isNullOrEmpty())\n                        tmdb.moviesService().credits(id).awaitResponse().body()?.let {\n                            response.addActors(it.cast?.toActors())\n                        }\n                }\n                response\n            }\n        } else {\n            loadFromTmdb(id)?.let { return it }\n            if (isTvSeries) {\n                tmdb.tvService().externalIds(id).awaitResponse().body()?.imdb_id?.let {\n                    val fromImdb = loadFromImdb(it)\n                    val result = if (fromImdb == null) {\n                        val details = tmdb.tvService().tv(id, \"en-US\").awaitResponse().body()\n                        loadFromImdb(it, details?.seasons ?: listOf())\n                            ?: loadFromTmdb(id, details?.seasons ?: listOf())\n                    } else fromImdb\n\n                    result\n                }\n            } else {\n                tmdb.moviesService().externalIds(id).awaitResponse()\n                    .body()?.imdb_id?.let { loadFromImdb(it) }\n            }\n        }\n    }\n\n    override suspend fun search(query: String, page: Int): SearchResponseList? {\n        return tmdb.searchService().multi(query, page, \"en-US\", \"US\", includeAdult).awaitResponse()\n            .body()?.results?.mapNotNull {\n                it.movie?.toSearchResponse() ?: it.tvShow?.toSearchResponse()\n            }?.toNewSearchResponseList()\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt",
    "content": "package com.lagradost.cloudstream3.metaproviders\n\nimport com.fasterxml.jackson.annotation.JsonAlias\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder.unixTimeMS\nimport com.lagradost.cloudstream3.Actor\nimport com.lagradost.cloudstream3.ActorData\nimport com.lagradost.cloudstream3.Episode\nimport com.lagradost.cloudstream3.HomePageResponse\nimport com.lagradost.cloudstream3.LoadResponse\nimport com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId\nimport com.lagradost.cloudstream3.LoadResponse.Companion.addTMDbId\nimport com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.MainPageRequest\nimport com.lagradost.cloudstream3.NextAiring\nimport com.lagradost.cloudstream3.ProviderType\nimport com.lagradost.cloudstream3.Score\nimport com.lagradost.cloudstream3.SearchResponse\nimport com.lagradost.cloudstream3.SearchResponseList\nimport com.lagradost.cloudstream3.ShowStatus\nimport com.lagradost.cloudstream3.TvType\nimport com.lagradost.cloudstream3.addDate\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.mainPageOf\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.cloudstream3.newEpisode\nimport com.lagradost.cloudstream3.newHomePageResponse\nimport com.lagradost.cloudstream3.newMovieLoadResponse\nimport com.lagradost.cloudstream3.newMovieSearchResponse\nimport com.lagradost.cloudstream3.newSearchResponseList\nimport com.lagradost.cloudstream3.newTvSeriesLoadResponse\nimport com.lagradost.cloudstream3.newTvSeriesSearchResponse\nimport com.lagradost.cloudstream3.utils.AppUtils.parseJson\nimport com.lagradost.cloudstream3.utils.AppUtils.toJson\nimport java.text.SimpleDateFormat\nimport java.util.Locale\n\nopen class TraktProvider : MainAPI() {\n    override var name = \"Trakt\"\n    override val hasMainPage = true\n    override val providerType = ProviderType.MetaProvider\n    override val supportedTypes = setOf(\n        TvType.Movie,\n        TvType.TvSeries,\n        TvType.Anime,\n    )\n\n    private val traktClientId =\n        \"d9f434f48b55683a279ffe88ddc68351cc04c9dc9372bd95af5de780b794e770\"\n    private val traktApiUrl = \"https://api.trakt.tv\"\n\n    override val mainPage = mainPageOf(\n        \"$traktApiUrl/movies/trending\" to \"Trending Movies\", //Most watched movies right now\n        \"$traktApiUrl/movies/popular\" to \"Popular Movies\", //The most popular movies for all time\n        \"$traktApiUrl/shows/trending\" to \"Trending Shows\", //Most watched Shows right now\n        \"$traktApiUrl/shows/popular\" to \"Popular Shows\", //The most popular Shows for all time\n    )\n\n    override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {\n        val apiResponse = getApi(\"${request.data}?extended=full,images&page=$page\")\n\n        val results = parseJson<List<MediaDetails>>(apiResponse).map { element ->\n            element.toSearchResponse()\n        }\n        return newHomePageResponse(request.name, results)\n    }\n\n    private fun MediaDetails.toSearchResponse(): SearchResponse {\n\n        val media = this.media ?: this\n        val mediaType = if (media.ids?.tvdb == null) TvType.Movie else TvType.TvSeries\n        val poster = media.images?.poster?.firstOrNull()\n        return if (mediaType == TvType.Movie) {\n            newMovieSearchResponse(\n                name = media.title ?: \"\",\n                url = Data(\n                    type = mediaType,\n                    mediaDetails = media,\n                ).toJson(),\n                type = TvType.Movie,\n            ) {\n                score = Score.from10(media.rating)\n                posterUrl = fixPath(poster)\n            }\n        } else {\n            newTvSeriesSearchResponse(\n                name = media.title ?: \"\",\n                url = Data(\n                    type = mediaType,\n                    mediaDetails = media,\n                ).toJson(),\n                type = TvType.TvSeries,\n            ) {\n                score = Score.from10(media.rating)\n                this.posterUrl = fixPath(poster)\n            }\n        }\n    }\n\n    override suspend fun search(query: String, page: Int): SearchResponseList? {\n        val apiResponse =\n            getApi(\"$traktApiUrl/search/movie,show?extended=full,images&limit=20&page=$page&query=$query\")\n\n        return newSearchResponseList(parseJson<List<MediaDetails>>(apiResponse).map { element ->\n            element.toSearchResponse()\n        })\n    }\n\n    override suspend fun load(url: String): LoadResponse {\n        val data = parseJson<Data>(url)\n        val mediaDetails = data.mediaDetails\n        val moviesOrShows = if (data.type == TvType.Movie) \"movies\" else \"shows\"\n\n        val posterUrl = fixPath(mediaDetails?.images?.poster?.firstOrNull())\n        val backDropUrl = fixPath(mediaDetails?.images?.fanart?.firstOrNull())\n\n        val resActor =\n            getApi(\"$traktApiUrl/$moviesOrShows/${mediaDetails?.ids?.trakt}/people?extended=full,images\")\n\n        val actors = parseJson<People>(resActor).cast?.map {\n            ActorData(\n                Actor(\n                    name = it.person?.name!!,\n                    image = fixPath(it.person.images?.headshot?.firstOrNull())\n                ),\n                roleString = it.character\n            )\n        }\n\n        val resRelated =\n            getApi(\"$traktApiUrl/$moviesOrShows/${mediaDetails?.ids?.trakt}/related?extended=full,images&limit=20\")\n\n        val relatedMedia = parseJson<List<MediaDetails>>(resRelated).map { it.toSearchResponse() }\n\n        val isCartoon =\n            mediaDetails?.genres?.contains(\"animation\") == true || mediaDetails?.genres?.contains(\"anime\") == true\n        val isAnime =\n            isCartoon && (mediaDetails.language == \"zh\" || mediaDetails.language == \"ja\")\n        val isAsian = !isAnime && (mediaDetails?.language == \"zh\" || mediaDetails?.language == \"ko\")\n        val isBollywood = mediaDetails?.country == \"in\"\n        val uniqueUrl = data.mediaDetails?.ids?.trakt?.toJson() ?: data.toJson()\n\n        if (data.type == TvType.Movie) {\n\n            val linkData = LinkData(\n                id = mediaDetails?.ids?.tmdb,\n                traktId = mediaDetails?.ids?.trakt,\n                traktSlug = mediaDetails?.ids?.slug,\n                tmdbId = mediaDetails?.ids?.tmdb,\n                imdbId = mediaDetails?.ids?.imdb.toString(),\n                tvdbId = mediaDetails?.ids?.tvdb,\n                tvrageId = mediaDetails?.ids?.tvrage,\n                type = data.type.toString(),\n                title = mediaDetails?.title,\n                year = mediaDetails?.year,\n                orgTitle = mediaDetails?.title,\n                isAnime = isAnime,\n                //jpTitle = later if needed as it requires another network request,\n                airedDate = mediaDetails?.released\n                    ?: mediaDetails?.firstAired,\n                isAsian = isAsian,\n                isBollywood = isBollywood,\n            ).toJson()\n\n            return newMovieLoadResponse(\n                name = mediaDetails?.title!!,\n                url = data.toJson(),\n                dataUrl = linkData.toJson(),\n                type = if (isAnime) TvType.AnimeMovie else TvType.Movie,\n            ) {\n                this.uniqueUrl = uniqueUrl\n                this.name = mediaDetails.title\n                this.type = if (isAnime) TvType.AnimeMovie else TvType.Movie\n                this.posterUrl = posterUrl\n                this.year = mediaDetails.year\n                this.plot = mediaDetails.overview\n                this.score = Score.from10(mediaDetails.rating)\n                this.tags = mediaDetails.genres\n                this.duration = mediaDetails.runtime\n                this.recommendations = relatedMedia\n                this.actors = actors\n                this.comingSoon = isUpcoming(mediaDetails.released)\n                //posterHeaders\n                this.backgroundPosterUrl = backDropUrl\n                this.contentRating = mediaDetails.certification\n                addTrailer(mediaDetails.trailer)\n                addImdbId(mediaDetails.ids?.imdb)\n                addTMDbId(mediaDetails.ids?.tmdb.toString())\n            }\n        } else {\n\n            val resSeasons =\n                getApi(\"$traktApiUrl/shows/${mediaDetails?.ids?.trakt.toString()}/seasons?extended=full,images,episodes\")\n            val episodes = mutableListOf<Episode>()\n            val seasons = parseJson<List<Seasons>>(resSeasons)\n            var nextAir: NextAiring? = null\n\n            seasons.forEach { season ->\n\n                season.episodes?.map { episode ->\n\n                    val linkData = LinkData(\n                        id = mediaDetails?.ids?.tmdb,\n                        traktId = mediaDetails?.ids?.trakt,\n                        traktSlug = mediaDetails?.ids?.slug,\n                        tmdbId = mediaDetails?.ids?.tmdb,\n                        imdbId = mediaDetails?.ids?.imdb.toString(),\n                        tvdbId = mediaDetails?.ids?.tvdb,\n                        tvrageId = mediaDetails?.ids?.tvrage,\n                        type = data.type.toString(),\n                        season = episode.season,\n                        episode = episode.number,\n                        title = mediaDetails?.title,\n                        year = mediaDetails?.year,\n                        orgTitle = mediaDetails?.title,\n                        isAnime = isAnime,\n                        airedYear = mediaDetails?.year,\n                        lastSeason = seasons.size,\n                        epsTitle = episode.title,\n                        //jpTitle = later if needed as it requires another network request,\n                        date = episode.firstAired,\n                        airedDate = episode.firstAired,\n                        isAsian = isAsian,\n                        isBollywood = isBollywood,\n                        isCartoon = isCartoon\n                    ).toJson()\n\n                    episodes.add(\n                        newEpisode(linkData.toJson()) {\n                            this.name = episode.title\n                            this.season = episode.season\n                            this.episode = episode.number\n                            this.description = episode.overview\n                            this.runTime = episode.runtime\n                            this.posterUrl = fixPath( episode.images?.screenshot?.firstOrNull())\n                            //this.rating = episode.rating?.times(10)?.roundToInt()\n                            this.score = Score.from10(episode.rating)\n\n                            this.addDate(episode.firstAired, \"yyyy-MM-dd'T'HH:mm:ss.SSSXXX\")\n                            if (nextAir == null && this.date != null && this.date!! > unixTimeMS && this.season != 0) {\n                                nextAir = NextAiring(\n                                    episode = this.episode!!,\n                                    unixTime = this.date!!.div(1000L),\n                                    season = if (this.season == 1) null else this.season,\n                                )\n                            }\n                        }\n                    )\n                }\n            }\n\n            return newTvSeriesLoadResponse(\n                name = mediaDetails?.title!!,\n                url = data.toJson(),\n                type = if (isAnime) TvType.Anime else TvType.TvSeries,\n                episodes = episodes\n            ) {\n                this.uniqueUrl = uniqueUrl\n                this.name = mediaDetails.title\n                this.type = if (isAnime) TvType.Anime else TvType.TvSeries\n                this.episodes = episodes\n                this.posterUrl = posterUrl\n                this.year = mediaDetails.year\n                this.plot = mediaDetails.overview\n                this.showStatus = getStatus(mediaDetails.status)\n                this.score = Score.from10(mediaDetails.rating)\n                this.tags = mediaDetails.genres\n                this.duration = mediaDetails.runtime\n                this.recommendations = relatedMedia\n                this.actors = actors\n                this.comingSoon = isUpcoming(mediaDetails.released)\n                //posterHeaders\n                this.nextAiring = nextAir\n                this.backgroundPosterUrl = backDropUrl\n                this.contentRating = mediaDetails.certification\n                addTrailer(mediaDetails.trailer)\n                addImdbId(mediaDetails.ids?.imdb)\n                addTMDbId(mediaDetails.ids?.tmdb.toString())\n            }\n        }\n    }\n\n    private suspend fun getApi(url: String): String {\n        return app.get(\n            url = url,\n            headers = mapOf(\n                \"Content-Type\" to \"application/json\",\n                \"trakt-api-version\" to \"2\",\n                \"trakt-api-key\" to traktClientId,\n            )\n        ).toString()\n    }\n\n    private fun isUpcoming(dateString: String?): Boolean {\n        return try {\n            val format = SimpleDateFormat(\"yyyy-MM-dd\", Locale.getDefault())\n            val dateTime = dateString?.let { format.parse(it)?.time } ?: return false\n            unixTimeMS < dateTime\n        } catch (t: Throwable) {\n            logError(t)\n            false\n        }\n    }\n\n    private fun getStatus(t: String?): ShowStatus {\n        return when (t) {\n            \"returning series\" -> ShowStatus.Ongoing\n            \"continuing\" -> ShowStatus.Ongoing\n            else -> ShowStatus.Completed\n        }\n    }\n\n    private fun fixPath(url: String?): String? {\n        url ?: return null\n        return \"https://$url\"\n    }\n\n    data class Data(\n        val type: TvType? = null,\n        val mediaDetails: MediaDetails? = null,\n    )\n\n    data class MediaDetails(\n        @JsonProperty(\"title\") val title: String? = null,\n        @JsonProperty(\"year\") val year: Int? = null,\n        @JsonProperty(\"ids\") val ids: Ids? = null,\n        @JsonProperty(\"tagline\") val tagline: String? = null,\n        @JsonProperty(\"overview\") val overview: String? = null,\n        @JsonProperty(\"released\") val released: String? = null,\n        @JsonProperty(\"runtime\") val runtime: Int? = null,\n        @JsonProperty(\"country\") val country: String? = null,\n        @JsonProperty(\"updatedAt\") val updatedAt: String? = null,\n        @JsonProperty(\"trailer\") val trailer: String? = null,\n        @JsonProperty(\"homepage\") val homepage: String? = null,\n        @JsonProperty(\"status\") val status: String? = null,\n        @JsonProperty(\"rating\") val rating: Double? = null,\n        @JsonProperty(\"votes\") val votes: Long? = null,\n        @JsonProperty(\"comment_count\") val commentCount: Long? = null,\n        @JsonProperty(\"language\") val language: String? = null,\n        @JsonProperty(\"languages\") val languages: List<String>? = null,\n        @JsonProperty(\"available_translations\") val availableTranslations: List<String>? = null,\n        @JsonProperty(\"genres\") val genres: List<String>? = null,\n        @JsonProperty(\"certification\") val certification: String? = null,\n        @JsonProperty(\"aired_episodes\") val airedEpisodes: Int? = null,\n        @JsonProperty(\"first_aired\") val firstAired: String? = null,\n        @JsonProperty(\"airs\") val airs: Airs? = null,\n        @JsonProperty(\"network\") val network: String? = null,\n        @JsonProperty(\"images\") val images: Images? = null,\n        @JsonProperty(\"movie\") @JsonAlias(\"show\") val media: MediaDetails? = null\n    )\n\n    data class Airs(\n        @JsonProperty(\"day\") val day: String? = null,\n        @JsonProperty(\"time\") val time: String? = null,\n        @JsonProperty(\"timezone\") val timezone: String? = null,\n    )\n\n    data class Ids(\n        @JsonProperty(\"trakt\") val trakt: Int? = null,\n        @JsonProperty(\"slug\") val slug: String? = null,\n        @JsonProperty(\"tvdb\") val tvdb: Int? = null,\n        @JsonProperty(\"imdb\") val imdb: String? = null,\n        @JsonProperty(\"tmdb\") val tmdb: Int? = null,\n        @JsonProperty(\"tvrage\") val tvrage: String? = null,\n    )\n\n    data class Images(\n        @JsonProperty(\"poster\") val poster: List<String>? = null,\n        @JsonProperty(\"fanart\") val fanart: List<String>? = null,\n        @JsonProperty(\"logo\") val logo: List<String>? = null,\n        @JsonProperty(\"clearart\") val clearArt: List<String>? = null,\n        @JsonProperty(\"banner\") val banner: List<String>? = null,\n        @JsonProperty(\"thumb\") val thumb: List<String>? = null,\n        @JsonProperty(\"screenshot\") val screenshot: List<String>? = null,\n        @JsonProperty(\"headshot\") val headshot: List<String>? = null,\n    )\n\n    data class People(\n        @JsonProperty(\"cast\") val cast: List<Cast>? = null,\n    )\n\n    data class Cast(\n        @JsonProperty(\"character\") val character: String? = null,\n        @JsonProperty(\"characters\") val characters: List<String>? = null,\n        @JsonProperty(\"episode_count\") val episodeCount: Long? = null,\n        @JsonProperty(\"person\") val person: Person? = null,\n        @JsonProperty(\"images\") val images: Images? = null,\n    )\n\n    data class Person(\n        @JsonProperty(\"name\") val name: String? = null,\n        @JsonProperty(\"ids\") val ids: Ids? = null,\n        @JsonProperty(\"images\") val images: Images? = null,\n    )\n\n    data class Seasons(\n        @JsonProperty(\"aired_episodes\") val airedEpisodes: Int? = null,\n        @JsonProperty(\"episode_count\") val episodeCount: Int? = null,\n        @JsonProperty(\"episodes\") val episodes: List<TraktEpisode>? = null,\n        @JsonProperty(\"first_aired\") val firstAired: String? = null,\n        @JsonProperty(\"ids\") val ids: Ids? = null,\n        @JsonProperty(\"images\") val images: Images? = null,\n        @JsonProperty(\"network\") val network: String? = null,\n        @JsonProperty(\"number\") val number: Int? = null,\n        @JsonProperty(\"overview\") val overview: String? = null,\n        @JsonProperty(\"rating\") val rating: Double? = null,\n        @JsonProperty(\"title\") val title: String? = null,\n        @JsonProperty(\"updated_at\") val updatedAt: String? = null,\n        @JsonProperty(\"votes\") val votes: Int? = null,\n    )\n\n    data class TraktEpisode(\n        @JsonProperty(\"available_translations\") val availableTranslations: List<String>? = null,\n        @JsonProperty(\"comment_count\") val commentCount: Int? = null,\n        @JsonProperty(\"episode_type\") val episodeType: String? = null,\n        @JsonProperty(\"first_aired\") val firstAired: String? = null,\n        @JsonProperty(\"ids\") val ids: Ids? = null,\n        @JsonProperty(\"images\") val images: Images? = null,\n        @JsonProperty(\"number\") val number: Int? = null,\n        @JsonProperty(\"number_abs\") val numberAbs: Int? = null,\n        @JsonProperty(\"overview\") val overview: String? = null,\n        @JsonProperty(\"rating\") val rating: Double? = null,\n        @JsonProperty(\"runtime\") val runtime: Int? = null,\n        @JsonProperty(\"season\") val season: Int? = null,\n        @JsonProperty(\"title\") val title: String? = null,\n        @JsonProperty(\"updated_at\") val updatedAt: String? = null,\n        @JsonProperty(\"votes\") val votes: Int? = null,\n    )\n\n    data class LinkData(\n        @JsonProperty(\"id\") val id: Int? = null,\n        @JsonProperty(\"trakt_id\") val traktId: Int? = null,\n        @JsonProperty(\"trakt_slug\") val traktSlug: String? = null,\n        @JsonProperty(\"tmdb_id\") val tmdbId: Int? = null,\n        @JsonProperty(\"imdb_id\") val imdbId: String? = null,\n        @JsonProperty(\"tvdb_id\") val tvdbId: Int? = null,\n        @JsonProperty(\"tvrage_id\") val tvrageId: String? = null,\n        @JsonProperty(\"type\") val type: String? = null,\n        @JsonProperty(\"season\") val season: Int? = null,\n        @JsonProperty(\"episode\") val episode: Int? = null,\n        @JsonProperty(\"ani_id\") val aniId: String? = null,\n        @JsonProperty(\"anime_id\") val animeId: String? = null,\n        @JsonProperty(\"title\") val title: String? = null,\n        @JsonProperty(\"year\") val year: Int? = null,\n        @JsonProperty(\"org_title\") val orgTitle: String? = null,\n        @JsonProperty(\"is_anime\") val isAnime: Boolean = false,\n        @JsonProperty(\"aired_year\") val airedYear: Int? = null,\n        @JsonProperty(\"last_season\") val lastSeason: Int? = null,\n        @JsonProperty(\"eps_title\") val epsTitle: String? = null,\n        @JsonProperty(\"jp_title\") val jpTitle: String? = null,\n        @JsonProperty(\"date\") val date: String? = null,\n        @JsonProperty(\"aired_date\") val airedDate: String? = null,\n        @JsonProperty(\"is_asian\") val isAsian: Boolean = false,\n        @JsonProperty(\"is_bollywood\") val isBollywood: Boolean = false,\n        @JsonProperty(\"is_cartoon\") val isCartoon: Boolean = false,\n    )\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt",
    "content": "package com.lagradost.cloudstream3.mvvm\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.utils.AppDebug\nimport kotlinx.coroutines.*\nimport java.io.InterruptedIOException\nimport java.net.SocketTimeoutException\nimport java.net.UnknownHostException\nimport javax.net.ssl.SSLHandshakeException\nimport kotlin.coroutines.CoroutineContext\nimport kotlin.coroutines.EmptyCoroutineContext\nimport kotlin.reflect.full.NoSuchPropertyException\n\nconst val DEBUG_EXCEPTION = \"THIS IS A DEBUG EXCEPTION!\"\nconst val DEBUG_PRINT = \"DEBUG PRINT\"\n\nclass DebugException(message: String) : Exception(\"$DEBUG_EXCEPTION\\n$message\")\n\ninline fun debugException(message: () -> String) {\n    if (AppDebug.isDebug) {\n        throw DebugException(message.invoke())\n    }\n}\n\ninline fun debugPrint(tag: String = DEBUG_PRINT, message: () -> String) {\n    if (AppDebug.isDebug) {\n        Log.d(tag, message.invoke())\n    }\n}\n\ninline fun debugWarning(message: () -> String) {\n    if (AppDebug.isDebug) {\n        logError(DebugException(message.invoke()))\n    }\n}\n\ninline fun debugAssert(assert: () -> Boolean, message: () -> String) {\n    if (AppDebug.isDebug && assert.invoke()) {\n        throw DebugException(message.invoke())\n    }\n}\n\ninline fun debugWarning(assert: () -> Boolean, message: () -> String) {\n    if (AppDebug.isDebug && assert.invoke()) {\n        logError(DebugException(message.invoke()))\n    }\n}\n\nsealed class Resource<out T> {\n    data class Success<out T>(val value: T) : Resource<T>()\n    data class Failure(\n        val isNetworkError: Boolean,\n        val errorString: String,\n    ) : Resource<Nothing>()\n\n    data class Loading(val url: String? = null) : Resource<Nothing>()\n\n    companion object {\n        fun <T> fromResult(result: Result<T>) : Resource<T> {\n            val value = result.getOrNull()\n            return if(value != null) {\n                Success(value)\n            } else {\n                throwAbleToResource(result.exceptionOrNull() ?: Exception(\"this should not be possible\"))\n            }\n        }\n    }\n}\n\nfun logError(throwable: Throwable) {\n    Log.d(\"ApiError\", \"-------------------------------------------------------------------\")\n    Log.d(\"ApiError\", \"safeApiCall: \" + throwable.localizedMessage)\n    Log.d(\"ApiError\", \"safeApiCall: \" + throwable.message)\n    throwable.printStackTrace()\n    Log.d(\"ApiError\", \"-------------------------------------------------------------------\")\n}\n\n@Deprecated(\n    \"Outdated function, use `safe` instead\",\n    replaceWith = ReplaceWith(\"safe\"),\n    level = DeprecationLevel.ERROR\n)\nfun <T> normalSafeApiCall(apiCall: () -> T): T? {\n    return try {\n        apiCall.invoke()\n    } catch (throwable: Throwable) {\n        logError(throwable)\n        return null\n    }\n}\n\n/** Catches any exception (or error) and only logs it.\n * Will return null on exceptions. */\nfun <T> safe(apiCall: () -> T): T? {\n    return try {\n        apiCall.invoke()\n    } catch (throwable: Throwable) {\n        logError(throwable)\n        return null\n    }\n}\n\n/** Catches any exception (or error) and only logs it.\n * Will return null on exceptions. */\nsuspend fun <T> safeAsync(apiCall: suspend () -> T): T? {\n    return try {\n        apiCall.invoke()\n    } catch (throwable: Throwable) {\n        logError(throwable)\n        return null\n    }\n}\n\n@Deprecated(\n    \"Outdated function, use `safeAsync` instead\",\n    replaceWith = ReplaceWith(\"safeAsync\"),\n    level = DeprecationLevel.ERROR\n)\nsuspend fun <T> suspendSafeApiCall(apiCall: suspend () -> T): T? {\n    return try {\n        apiCall.invoke()\n    } catch (throwable: Throwable) {\n        logError(throwable)\n        return null\n    }\n}\n\nfun Throwable.getAllMessages(): String {\n    return (this.localizedMessage ?: \"\") + (this.cause?.getAllMessages()?.let { \"\\n$it\" } ?: \"\")\n}\n\nfun Throwable.getStackTracePretty(showMessage: Boolean = true): String {\n    val prefix = if (showMessage) this.localizedMessage?.let { \"\\n$it\" } ?: \"\" else \"\"\n    return prefix + this.stackTrace.joinToString(\n        separator = \"\\n\"\n    ) {\n        \"${it.fileName} ${it.lineNumber}\"\n    }\n}\n\nfun <T> safeFail(throwable: Throwable): Resource<T> {\n    val stackTraceMsg = throwable.getStackTracePretty()\n    return Resource.Failure(false, stackTraceMsg)\n}\n\nfun CoroutineScope.launchSafe(\n    context: CoroutineContext = EmptyCoroutineContext,\n    start: CoroutineStart = CoroutineStart.DEFAULT,\n    block: suspend CoroutineScope.() -> Unit\n): Job {\n    val obj: suspend CoroutineScope.() -> Unit = {\n        try {\n            block()\n        } catch (throwable: Throwable) {\n            logError(throwable)\n        }\n    }\n\n    return this.launch(context, start, obj)\n}\n\nfun <T> throwAbleToResource(\n    throwable: Throwable\n): Resource<T> {\n    return when (throwable) {\n        is NoSuchMethodException, is NoSuchFieldException, is NoSuchMethodError, is NoSuchFieldError, is NoSuchPropertyException -> {\n            Resource.Failure(\n                false,\n                \"App or extension is outdated, update the app or try pre-release.\\n${throwable.message}\" // todo add exact version?\n            )\n        }\n\n        is NullPointerException -> {\n            for (line in throwable.stackTrace) {\n                if (line?.fileName?.endsWith(\"provider.kt\", ignoreCase = true) == true) {\n                    return Resource.Failure(\n                        false,\n                        \"NullPointerException at ${line.fileName} ${line.lineNumber}\\nSite might have updated or added Cloudflare/DDOS protection\"\n                    )\n                }\n            }\n            safeFail(throwable)\n        }\n\n        is SocketTimeoutException, is InterruptedIOException -> {\n            Resource.Failure(\n                true,\n                \"Connection Timeout\\nPlease try again later.\"\n            )\n        }\n//        is HttpException -> {\n//            Resource.Failure(\n//                false,\n//                throwable.statusCode,\n//                null,\n//                throwable.message ?: \"HttpException\"\n//            )\n//        }\n        is UnknownHostException -> {\n            Resource.Failure(\n                true,\n                \"Cannot connect to server, try again later.\\n${throwable.message}\"\n            )\n        }\n\n        is ErrorLoadingException -> {\n            Resource.Failure(\n                true,\n                throwable.message ?: \"Error loading, try again later.\"\n            )\n        }\n\n        is NotImplementedError -> {\n            Resource.Failure(false, \"This operation is not implemented.\")\n        }\n\n        is SSLHandshakeException -> {\n            Resource.Failure(\n                true,\n                (throwable.message ?: \"SSLHandshakeException\") + \"\\nTry a VPN or DNS.\"\n            )\n        }\n\n        is CancellationException -> {\n            throwable.cause?.let {\n                throwAbleToResource(it)\n            } ?: safeFail(throwable)\n        }\n\n        else -> safeFail(throwable)\n    }\n}\n\nsuspend fun <T> safeApiCall(\n    apiCall: suspend () -> T,\n): Resource<T> {\n    return withContext(Dispatchers.IO) {\n        try {\n            Resource.Success(apiCall.invoke())\n        } catch (throwable: Throwable) {\n            logError(throwable)\n            throwAbleToResource(throwable)\n        }\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/network/WebViewResolver.kt",
    "content": "package com.lagradost.cloudstream3.network\n\nimport com.lagradost.cloudstream3.USER_AGENT\nimport okhttp3.Interceptor\nimport okhttp3.Request\n\n/**\n * When used as Interceptor additionalUrls cannot be returned, use WebViewResolver(...).resolveUsingWebView(...)\n * @param interceptUrl will stop the WebView when reaching this url.\n * @param additionalUrls this will make resolveUsingWebView also return all other requests matching the list of Regex.\n * @param userAgent if null then will use the default user agent\n * @param useOkhttp will try to use the okhttp client as much as possible, but this might cause some requests to fail. Disable for cloudflare.\n * @param script pass custom js to execute\n * @param scriptCallback will be called with the result from custom js\n * @param timeout close webview after timeout\n * */\nexpect class WebViewResolver(\n    interceptUrl: Regex,\n    additionalUrls: List<Regex> = emptyList(),\n    userAgent: String? = USER_AGENT,\n    useOkhttp: Boolean = true,\n    script: String? = null,\n    scriptCallback: ((String) -> Unit)? = null,\n    timeout: Long = DEFAULT_TIMEOUT\n) : Interceptor {\n    companion object {\n        val DEFAULT_TIMEOUT: Long\n        var webViewUserAgent: String?\n    }\n\n    /**\n     * @param requestCallBack asynchronously return matched requests by either interceptUrl or additionalUrls. If true, destroy WebView.\n     * @return the final request (by interceptUrl) and all the collected urls (by additionalUrls).\n     * */\n    suspend fun resolveUsingWebView(\n        url: String,\n        referer: String? = null,\n        method: String = \"GET\",\n        requestCallBack: (Request) -> Boolean = { false },\n    ) : Pair<Request?, List<Request>>\n\n    /**\n     * @param requestCallBack asynchronously return matched requests by either interceptUrl or additionalUrls. If true, destroy WebView.\n     * @return the final request (by interceptUrl) and all the collected urls (by additionalUrls).\n     * */\n    suspend fun resolveUsingWebView(\n        url: String,\n        referer: String? = null,\n        headers: Map<String, String> = emptyMap(),\n        method: String = \"GET\",\n        requestCallBack: (Request) -> Boolean = { false },\n    ) : Pair<Request?, List<Request>>\n\n    /**\n     * @param requestCallBack asynchronously return matched requests by either interceptUrl or additionalUrls. If true, destroy WebView.\n     * @return the final request (by interceptUrl) and all the collected urls (by additionalUrls).\n     * */\n    suspend fun resolveUsingWebView(\n        request: Request,\n        requestCallBack: (Request) -> Boolean = { false }\n    ): Pair<Request?, List<Request>>\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt",
    "content": "package com.lagradost.cloudstream3.plugins\n\nimport com.fasterxml.jackson.annotation.JsonProperty\nimport com.lagradost.cloudstream3.APIHolder\nimport com.lagradost.cloudstream3.MainAPI\nimport com.lagradost.cloudstream3.utils.ExtractorApi\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.utils.extractorApis\n\nconst val PLUGIN_TAG = \"PluginInstance\"\n\nabstract class BasePlugin {\n    /**\n     * Used to register providers instances of MainAPI\n     * @param element MainAPI provider you want to register\n     */\n    fun registerMainAPI(element: MainAPI) {\n        Log.i(PLUGIN_TAG, \"Adding ${element.name} (${element.mainUrl}) MainAPI\")\n        element.sourcePlugin = this.filename\n        // Race condition causing which would case duplicates if not for distinctBy\n        synchronized(APIHolder.allProviders) {\n            APIHolder.allProviders.add(element)\n        }\n        APIHolder.addPluginMapping(element)\n    }\n\n    /**\n     * Used to register extractor instances of ExtractorApi\n     * @param element ExtractorApi provider you want to register\n     */\n    fun registerExtractorAPI(element: ExtractorApi) {\n        Log.i(PLUGIN_TAG, \"Adding ${element.name} (${element.mainUrl}) ExtractorApi\")\n        element.sourcePlugin = this.filename\n        extractorApis.add(element)\n    }\n\n    /**\n     * Called when your Plugin is being unloaded\n     */\n    @Throws(Throwable::class)\n    open fun beforeUnload() {\n    }\n\n    /**\n     * Called when your Plugin is loaded\n     */\n    @Throws(Throwable::class)\n    open fun load() {\n    }\n\n    /** Full file path to the plugin. */\n    @Deprecated(\n        \"Renamed to `filename` to follow conventions\",\n        replaceWith = ReplaceWith(\"filename\"),\n        level = DeprecationLevel.ERROR\n    )\n    var __filename: String?\n        get() = filename\n        set(value) {\n            filename = value\n        }\n    var filename: String? = null\n\n\n    class Manifest {\n        @JsonProperty(\"name\")\n        var name: String? = null\n\n        @JsonProperty(\"pluginClassName\")\n        var pluginClassName: String? = null\n\n        @JsonProperty(\"version\")\n        var version: Int? = null\n\n        @JsonProperty(\"requiresResources\")\n        var requiresResources: Boolean = false\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/CloudstreamPlugin.kt",
    "content": "package com.lagradost.cloudstream3.plugins\n\n@Suppress(\"unused\")\n@Target(AnnotationTarget.CLASS)\nannotation class CloudstreamPlugin"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/syncproviders/SyncAPI.kt",
    "content": "package com.lagradost.cloudstream3.syncproviders\n\nenum class SyncIdName {\n    Anilist,\n    MyAnimeList,\n    Kitsu,\n    Trakt,\n    Imdb,\n    Simkl,\n    LocalList,\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppDebug.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.lagradost.cloudstream3.InternalAPI\n\n@InternalAPI\nobject AppDebug {\n    @Volatile\n    var isDebug: Boolean = false\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.fasterxml.jackson.module.kotlin.readValue\nimport com.lagradost.cloudstream3.mapper\nimport java.io.Reader\n\nobject AppUtils {\n    /** Any object as json string */\n    fun Any.toJson(): String {\n        if (this is String) return this\n        return mapper.writeValueAsString(this)\n    }\n\n    inline fun <reified T> parseJson(value: String): T {\n        return mapper.readValue(value)\n    }\n\n    inline fun <reified T> parseJson(reader: Reader, valueType: Class<T>): T {\n        return mapper.readValue(reader, valueType)\n    }\n\n    inline fun <reified T> tryParseJson(value: String?): T? {\n        return try {\n            parseJson(value ?: return null)\n        } catch (_: Exception) {\n            null\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/Coroutines.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.lagradost.cloudstream3.mvvm.launchSafe\nimport com.lagradost.cloudstream3.mvvm.logError\nimport kotlinx.coroutines.*\nimport java.util.Collections.synchronizedList\n\nexpect fun runOnMainThreadNative(work: (() -> Unit))\nobject Coroutines {\n    fun <T> T.main(work: suspend ((T) -> Unit)): Job {\n        val value = this\n        return CoroutineScope(Dispatchers.Main).launchSafe {\n            work(value)\n        }\n    }\n\n    fun <T> T.ioSafe(work: suspend (CoroutineScope.(T) -> Unit)): Job {\n        val value = this\n\n        return CoroutineScope(Dispatchers.IO).launchSafe {\n            work(value)\n        }\n    }\n\n    suspend fun <T, V> V.ioWorkSafe(work: suspend (CoroutineScope.(V) -> T)): T? {\n        val value = this\n        return withContext(Dispatchers.IO) {\n            try {\n                work(value)\n            } catch (e: Exception) {\n                logError(e)\n                null\n            }\n        }\n    }\n\n    suspend fun <T, V> V.ioWork(work: suspend (CoroutineScope.(V) -> T)): T {\n        val value = this\n        return withContext(Dispatchers.IO) {\n            work(value)\n        }\n    }\n\n    suspend fun <T, V> V.mainWork(work: suspend (CoroutineScope.(V) -> T)): T {\n        val value = this\n        return withContext(Dispatchers.Main) {\n            work(value)\n        }\n    }\n\n    fun runOnMainThread(work: (() -> Unit)) {\n        runOnMainThreadNative(work)\n    }\n\n    /**\n     * Safe to add and remove how you want\n     * If you want to iterate over the list then you need to do:\n     * synchronized(allProviders) { code here }\n     **/\n    fun <T> threadSafeListOf(vararg items: T): MutableList<T> {\n        return synchronizedList(items.toMutableList())\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.fasterxml.jackson.annotation.JsonIgnore\nimport com.lagradost.cloudstream3.AudioFile\nimport com.lagradost.cloudstream3.IDownloadableMinimum\nimport com.lagradost.cloudstream3.SubtitleFile\nimport com.lagradost.cloudstream3.USER_AGENT\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.extractors.Acefile\nimport com.lagradost.cloudstream3.extractors.Ahvsh\nimport com.lagradost.cloudstream3.extractors.Aico\nimport com.lagradost.cloudstream3.extractors.Asnwish\nimport com.lagradost.cloudstream3.extractors.Auvexiug\nimport com.lagradost.cloudstream3.extractors.Awish\nimport com.lagradost.cloudstream3.extractors.BgwpCC\nimport com.lagradost.cloudstream3.extractors.BigwarpArt\nimport com.lagradost.cloudstream3.extractors.BigwarpIO\nimport com.lagradost.cloudstream3.extractors.Blogger\nimport com.lagradost.cloudstream3.extractors.ByseSX\nimport com.lagradost.cloudstream3.extractors.Bysezejataos\nimport com.lagradost.cloudstream3.extractors.ByseBuho\nimport com.lagradost.cloudstream3.extractors.ByseVepoin\nimport com.lagradost.cloudstream3.extractors.ByseQekaho\nimport com.lagradost.cloudstream3.extractors.Cavanhabg\nimport com.lagradost.cloudstream3.extractors.Cda\nimport com.lagradost.cloudstream3.extractors.Cdnplayer\nimport com.lagradost.cloudstream3.extractors.CdnwishCom\nimport com.lagradost.cloudstream3.extractors.CloudMailRu\nimport com.lagradost.cloudstream3.extractors.ContentX\nimport com.lagradost.cloudstream3.extractors.CsstOnline\nimport com.lagradost.cloudstream3.extractors.D0000d\nimport com.lagradost.cloudstream3.extractors.D000dCom\nimport com.lagradost.cloudstream3.extractors.DBfilm\nimport com.lagradost.cloudstream3.extractors.Dailymotion\nimport com.lagradost.cloudstream3.extractors.DatabaseGdrive\nimport com.lagradost.cloudstream3.extractors.DatabaseGdrive2\nimport com.lagradost.cloudstream3.extractors.DesuArcg\nimport com.lagradost.cloudstream3.extractors.DesuDrive\nimport com.lagradost.cloudstream3.extractors.DesuOdchan\nimport com.lagradost.cloudstream3.extractors.DesuOdvip\nimport com.lagradost.cloudstream3.extractors.Dhcplay\nimport com.lagradost.cloudstream3.extractors.Dhtpre\nimport com.lagradost.cloudstream3.extractors.Dokicloud\nimport com.lagradost.cloudstream3.extractors.DoodCxExtractor\nimport com.lagradost.cloudstream3.extractors.DoodLaExtractor\nimport com.lagradost.cloudstream3.extractors.DoodPmExtractor\nimport com.lagradost.cloudstream3.extractors.DoodShExtractor\nimport com.lagradost.cloudstream3.extractors.DoodSoExtractor\nimport com.lagradost.cloudstream3.extractors.DoodToExtractor\nimport com.lagradost.cloudstream3.extractors.DoodWatchExtractor\nimport com.lagradost.cloudstream3.extractors.DoodWfExtractor\nimport com.lagradost.cloudstream3.extractors.DoodWsExtractor\nimport com.lagradost.cloudstream3.extractors.DoodYtExtractor\nimport com.lagradost.cloudstream3.extractors.Doodspro\nimport com.lagradost.cloudstream3.extractors.Dsvplay\nimport com.lagradost.cloudstream3.extractors.Doodporn\nimport com.lagradost.cloudstream3.extractors.DoodstreamCom\nimport com.lagradost.cloudstream3.extractors.Dooood\nimport com.lagradost.cloudstream3.extractors.Ds2play\nimport com.lagradost.cloudstream3.extractors.Ds2video\nimport com.lagradost.cloudstream3.extractors.DsstOnline\nimport com.lagradost.cloudstream3.extractors.Dumbalag\nimport com.lagradost.cloudstream3.extractors.Dwish\nimport com.lagradost.cloudstream3.extractors.Embedgram\nimport com.lagradost.cloudstream3.extractors.EmturbovidExtractor\nimport com.lagradost.cloudstream3.extractors.Evoload\nimport com.lagradost.cloudstream3.extractors.Evoload1\nimport com.lagradost.cloudstream3.extractors.Ewish\nimport com.lagradost.cloudstream3.extractors.FEmbed\nimport com.lagradost.cloudstream3.extractors.FEnet\nimport com.lagradost.cloudstream3.extractors.Fastream\nimport com.lagradost.cloudstream3.extractors.FeHD\nimport com.lagradost.cloudstream3.extractors.Fembed9hd\nimport com.lagradost.cloudstream3.extractors.FileMoon\nimport com.lagradost.cloudstream3.extractors.FileMoonIn\nimport com.lagradost.cloudstream3.extractors.FileMoonSx\nimport com.lagradost.cloudstream3.extractors.FilemoonV2\nimport com.lagradost.cloudstream3.extractors.Filesim\nimport com.lagradost.cloudstream3.extractors.Multimoviesshg\nimport com.lagradost.cloudstream3.extractors.FlaswishCom\nimport com.lagradost.cloudstream3.extractors.FourCX\nimport com.lagradost.cloudstream3.extractors.FourPichive\nimport com.lagradost.cloudstream3.extractors.FourPlayRu\nimport com.lagradost.cloudstream3.extractors.Fplayer\nimport com.lagradost.cloudstream3.extractors.FsstOnline\nimport com.lagradost.cloudstream3.extractors.GDMirrorbot\nimport com.lagradost.cloudstream3.extractors.GUpload\nimport com.lagradost.cloudstream3.extractors.GamoVideo\nimport com.lagradost.cloudstream3.extractors.Gdriveplayer\nimport com.lagradost.cloudstream3.extractors.Gdriveplayerapi\nimport com.lagradost.cloudstream3.extractors.Gdriveplayerapp\nimport com.lagradost.cloudstream3.extractors.Gdriveplayerbiz\nimport com.lagradost.cloudstream3.extractors.Gdriveplayerco\nimport com.lagradost.cloudstream3.extractors.Gdriveplayerfun\nimport com.lagradost.cloudstream3.extractors.Gdriveplayerio\nimport com.lagradost.cloudstream3.extractors.Gdriveplayerme\nimport com.lagradost.cloudstream3.extractors.Gdriveplayerorg\nimport com.lagradost.cloudstream3.extractors.Gdriveplayerus\nimport com.lagradost.cloudstream3.extractors.Geodailymotion\nimport com.lagradost.cloudstream3.extractors.Gofile\nimport com.lagradost.cloudstream3.extractors.GoodstreamExtractor\nimport com.lagradost.cloudstream3.extractors.Guccihide\nimport com.lagradost.cloudstream3.extractors.Guxhag\nimport com.lagradost.cloudstream3.extractors.HDMomPlayer\nimport com.lagradost.cloudstream3.extractors.HDPlayerSystem\nimport com.lagradost.cloudstream3.extractors.HDStreamAble\nimport com.lagradost.cloudstream3.extractors.Habetar\nimport com.lagradost.cloudstream3.extractors.Haxloppd\nimport com.lagradost.cloudstream3.extractors.HglinkTo\nimport com.lagradost.cloudstream3.extractors.HgplayCDN\nimport com.lagradost.cloudstream3.extractors.Hotlinger\nimport com.lagradost.cloudstream3.extractors.HubCloud\nimport com.lagradost.cloudstream3.extractors.Hxfile\nimport com.lagradost.cloudstream3.extractors.HlsWish\nimport com.lagradost.cloudstream3.extractors.InternetArchive\nimport com.lagradost.cloudstream3.extractors.JWPlayer\nimport com.lagradost.cloudstream3.extractors.Jeniusplay\nimport com.lagradost.cloudstream3.extractors.Jodwish\nimport com.lagradost.cloudstream3.extractors.Keephealth\nimport com.lagradost.cloudstream3.extractors.KotakAnimeid\nimport com.lagradost.cloudstream3.extractors.Kotakajair\nimport com.lagradost.cloudstream3.extractors.Krakenfiles\nimport com.lagradost.cloudstream3.extractors.Kswplayer\nimport com.lagradost.cloudstream3.extractors.LayarKaca\nimport com.lagradost.cloudstream3.extractors.Linkbox\nimport com.lagradost.cloudstream3.extractors.LuluStream\nimport com.lagradost.cloudstream3.extractors.Lulustream1\nimport com.lagradost.cloudstream3.extractors.Lulustream2\nimport com.lagradost.cloudstream3.extractors.Luluvdoo\nimport com.lagradost.cloudstream3.extractors.Luxubu\nimport com.lagradost.cloudstream3.extractors.Lvturbo\nimport com.lagradost.cloudstream3.extractors.MailRu\nimport com.lagradost.cloudstream3.extractors.Maxstream\nimport com.lagradost.cloudstream3.extractors.Mediafire\nimport com.lagradost.cloudstream3.extractors.Megacloud\nimport com.lagradost.cloudstream3.extractors.Meownime\nimport com.lagradost.cloudstream3.extractors.MetaGnathTuggers\nimport com.lagradost.cloudstream3.extractors.Minoplres\nimport com.lagradost.cloudstream3.extractors.MixDrop\nimport com.lagradost.cloudstream3.extractors.MixDropAg\nimport com.lagradost.cloudstream3.extractors.MixDropBz\nimport com.lagradost.cloudstream3.extractors.MixDropCh\nimport com.lagradost.cloudstream3.extractors.MixDropTo\nimport com.lagradost.cloudstream3.extractors.MixDropPs\nimport com.lagradost.cloudstream3.extractors.Mdy\nimport com.lagradost.cloudstream3.extractors.MixDropSi\nimport com.lagradost.cloudstream3.extractors.MxDropTo\nimport com.lagradost.cloudstream3.extractors.Movhide\nimport com.lagradost.cloudstream3.extractors.Moviehab\nimport com.lagradost.cloudstream3.extractors.MoviehabNet\nimport com.lagradost.cloudstream3.extractors.Moviesm4u\nimport com.lagradost.cloudstream3.extractors.Mp4Upload\nimport com.lagradost.cloudstream3.extractors.Multimovies\nimport com.lagradost.cloudstream3.extractors.Mvidoo\nimport com.lagradost.cloudstream3.extractors.MyVidPlay\nimport com.lagradost.cloudstream3.extractors.Mwish\nimport com.lagradost.cloudstream3.extractors.NathanFromSubject\nimport com.lagradost.cloudstream3.extractors.Nekostream\nimport com.lagradost.cloudstream3.extractors.Nekowish\nimport com.lagradost.cloudstream3.extractors.Neonime7n\nimport com.lagradost.cloudstream3.extractors.Neonime8n\nimport com.lagradost.cloudstream3.extractors.Obeywish\nimport com.lagradost.cloudstream3.extractors.Odnoklassniki\nimport com.lagradost.cloudstream3.extractors.OkRuHTTP\nimport com.lagradost.cloudstream3.extractors.OkRuHTTPMobile\nimport com.lagradost.cloudstream3.extractors.OkRuSSL\nimport com.lagradost.cloudstream3.extractors.OkRuSSLMobile\nimport com.lagradost.cloudstream3.extractors.PeaceMakerst\nimport com.lagradost.cloudstream3.extractors.Peytonepre\nimport com.lagradost.cloudstream3.extractors.Pichive\nimport com.lagradost.cloudstream3.extractors.PixelDrain\nimport com.lagradost.cloudstream3.extractors.PixelDrainDev\nimport com.lagradost.cloudstream3.extractors.PlayLtXyz\nimport com.lagradost.cloudstream3.extractors.PlayRu\nimport com.lagradost.cloudstream3.extractors.PlayerVoxzer\nimport com.lagradost.cloudstream3.extractors.Playerwish\nimport com.lagradost.cloudstream3.extractors.Rabbitstream\nimport com.lagradost.cloudstream3.extractors.RapidVid\nimport com.lagradost.cloudstream3.extractors.Rasacintaku\nimport com.lagradost.cloudstream3.extractors.SBfull\nimport com.lagradost.cloudstream3.extractors.Sbasian\nimport com.lagradost.cloudstream3.extractors.Sbface\nimport com.lagradost.cloudstream3.extractors.Sbflix\nimport com.lagradost.cloudstream3.extractors.Sblona\nimport com.lagradost.cloudstream3.extractors.Sblongvu\nimport com.lagradost.cloudstream3.extractors.Sbnet\nimport com.lagradost.cloudstream3.extractors.Sbrapid\nimport com.lagradost.cloudstream3.extractors.Sbsonic\nimport com.lagradost.cloudstream3.extractors.Sbspeed\nimport com.lagradost.cloudstream3.extractors.Sbthe\nimport com.lagradost.cloudstream3.extractors.SecvideoOnline\nimport com.lagradost.cloudstream3.extractors.Sendvid\nimport com.lagradost.cloudstream3.extractors.Server1uns\nimport com.lagradost.cloudstream3.extractors.SfastwishCom\nimport com.lagradost.cloudstream3.extractors.ShaveTape\nimport com.lagradost.cloudstream3.extractors.SibNet\nimport com.lagradost.cloudstream3.extractors.Simpulumlamerop\nimport com.lagradost.cloudstream3.extractors.Smoothpre\nimport com.lagradost.cloudstream3.extractors.Sobreatsesuyp\nimport com.lagradost.cloudstream3.extractors.Ssbstream\nimport com.lagradost.cloudstream3.extractors.StreamEmbed\nimport com.lagradost.cloudstream3.extractors.StreamHLS\nimport com.lagradost.cloudstream3.extractors.StreamM4u\nimport com.lagradost.cloudstream3.extractors.StreamSB\nimport com.lagradost.cloudstream3.extractors.StreamSB1\nimport com.lagradost.cloudstream3.extractors.StreamSB10\nimport com.lagradost.cloudstream3.extractors.StreamSB11\nimport com.lagradost.cloudstream3.extractors.StreamSB2\nimport com.lagradost.cloudstream3.extractors.StreamSB3\nimport com.lagradost.cloudstream3.extractors.StreamSB4\nimport com.lagradost.cloudstream3.extractors.StreamSB5\nimport com.lagradost.cloudstream3.extractors.StreamSB6\nimport com.lagradost.cloudstream3.extractors.StreamSB7\nimport com.lagradost.cloudstream3.extractors.StreamSB8\nimport com.lagradost.cloudstream3.extractors.StreamSB9\nimport com.lagradost.cloudstream3.extractors.StreamSilk\nimport com.lagradost.cloudstream3.extractors.StreamTape\nimport com.lagradost.cloudstream3.extractors.StreamTapeNet\nimport com.lagradost.cloudstream3.extractors.StreamTapeXyz\nimport com.lagradost.cloudstream3.extractors.Watchadsontape\nimport com.lagradost.cloudstream3.extractors.StreamWishExtractor\nimport com.lagradost.cloudstream3.extractors.StreamhideCom\nimport com.lagradost.cloudstream3.extractors.StreamhideTo\nimport com.lagradost.cloudstream3.extractors.Streamhub2\nimport com.lagradost.cloudstream3.extractors.Streamix\nimport com.lagradost.cloudstream3.extractors.Streamlare\nimport com.lagradost.cloudstream3.extractors.StreamoUpload\nimport com.lagradost.cloudstream3.extractors.Streamplay\nimport com.lagradost.cloudstream3.extractors.Streamsss\nimport com.lagradost.cloudstream3.extractors.Streamup\nimport com.lagradost.cloudstream3.extractors.Streamwish2\nimport com.lagradost.cloudstream3.extractors.Strwish\nimport com.lagradost.cloudstream3.extractors.Strwish2\nimport com.lagradost.cloudstream3.extractors.Supervideo\nimport com.lagradost.cloudstream3.extractors.Swdyu\nimport com.lagradost.cloudstream3.extractors.Swhoi\nimport com.lagradost.cloudstream3.extractors.TRsTX\nimport com.lagradost.cloudstream3.extractors.Tantifilm\nimport com.lagradost.cloudstream3.extractors.TauVideo\nimport com.lagradost.cloudstream3.extractors.Techinmind\nimport com.lagradost.cloudstream3.extractors.Tubeless\nimport com.lagradost.cloudstream3.extractors.Uasopt\nimport com.lagradost.cloudstream3.extractors.Up4FunTop\nimport com.lagradost.cloudstream3.extractors.Up4Stream\nimport com.lagradost.cloudstream3.extractors.Upstream\nimport com.lagradost.cloudstream3.extractors.UpstreamExtractor\nimport com.lagradost.cloudstream3.extractors.Uqload\nimport com.lagradost.cloudstream3.extractors.Uqload1\nimport com.lagradost.cloudstream3.extractors.Uqload2\nimport com.lagradost.cloudstream3.extractors.Uqloadcx\nimport com.lagradost.cloudstream3.extractors.Uqloadbz\nimport com.lagradost.cloudstream3.extractors.UqloadsXyz\nimport com.lagradost.cloudstream3.extractors.Urochsunloath\nimport com.lagradost.cloudstream3.extractors.Userload\nimport com.lagradost.cloudstream3.extractors.Userscloud\nimport com.lagradost.cloudstream3.extractors.Uservideo\nimport com.lagradost.cloudstream3.extractors.Videa\nimport com.lagradost.cloudstream3.extractors.Vicloud\nimport com.lagradost.cloudstream3.extractors.VidHidePro\nimport com.lagradost.cloudstream3.extractors.VidHidePro1\nimport com.lagradost.cloudstream3.extractors.VidHidePro2\nimport com.lagradost.cloudstream3.extractors.VidHidePro3\nimport com.lagradost.cloudstream3.extractors.VidHidePro4\nimport com.lagradost.cloudstream3.extractors.VidHidePro5\nimport com.lagradost.cloudstream3.extractors.VidHidePro6\nimport com.lagradost.cloudstream3.extractors.VidHideHub\nimport com.lagradost.cloudstream3.extractors.Ryderjet\nimport com.lagradost.cloudstream3.extractors.VidMoxy\nimport com.lagradost.cloudstream3.extractors.VidStack\nimport com.lagradost.cloudstream3.extractors.VideoSeyred\nimport com.lagradost.cloudstream3.extractors.Videzz\nimport com.lagradost.cloudstream3.extractors.Vidgomunime\nimport com.lagradost.cloudstream3.extractors.Vidgomunimesb\nimport com.lagradost.cloudstream3.extractors.VidhideExtractor\nimport com.lagradost.cloudstream3.extractors.Vidmoly\nimport com.lagradost.cloudstream3.extractors.Vidmolyme\nimport com.lagradost.cloudstream3.extractors.Vidmolyto\nimport com.lagradost.cloudstream3.extractors.Vidmolybiz\nimport com.lagradost.cloudstream3.extractors.Vido\nimport com.lagradost.cloudstream3.extractors.Vidoza\nimport com.lagradost.cloudstream3.extractors.VinovoSi\nimport com.lagradost.cloudstream3.extractors.VinovoTo\nimport com.lagradost.cloudstream3.extractors.VidNest\nimport com.lagradost.cloudstream3.extractors.Vidara\nimport com.lagradost.cloudstream3.extractors.Vide0Net\nimport com.lagradost.cloudstream3.extractors.Vidsonic\nimport com.lagradost.cloudstream3.extractors.VkExtractor\nimport com.lagradost.cloudstream3.extractors.Voe\nimport com.lagradost.cloudstream3.extractors.Voe1\nimport com.lagradost.cloudstream3.extractors.Vtbe\nimport com.lagradost.cloudstream3.extractors.Wibufile\nimport com.lagradost.cloudstream3.extractors.WishembedPro\nimport com.lagradost.cloudstream3.extractors.Wishfast\nimport com.lagradost.cloudstream3.extractors.Wishonly\nimport com.lagradost.cloudstream3.extractors.XStreamCdn\nimport com.lagradost.cloudstream3.extractors.Xenolyzb\nimport com.lagradost.cloudstream3.extractors.Yipsu\nimport com.lagradost.cloudstream3.extractors.YourUpload\nimport com.lagradost.cloudstream3.extractors.YoutubeExtractor\nimport com.lagradost.cloudstream3.extractors.YoutubeMobileExtractor\nimport com.lagradost.cloudstream3.extractors.YoutubeNoCookieExtractor\nimport com.lagradost.cloudstream3.extractors.YoutubeShortLinkExtractor\nimport com.lagradost.cloudstream3.extractors.Yufiles\nimport com.lagradost.cloudstream3.extractors.Yuguaab\nimport com.lagradost.cloudstream3.extractors.Zplayer\nimport com.lagradost.cloudstream3.extractors.ZplayerV2\nimport com.lagradost.cloudstream3.extractors.Ztreamhub\nimport com.lagradost.cloudstream3.mvvm.logError\nimport kotlinx.coroutines.coroutineScope\nimport kotlinx.coroutines.delay\nimport kotlinx.coroutines.ensureActive\nimport me.xdrop.fuzzywuzzy.FuzzySearch\nimport org.jsoup.Jsoup\nimport java.net.URI\nimport java.util.UUID\nimport kotlin.coroutines.cancellation.CancellationException\n\n/**\n * For use in the ConcatenatingMediaSource.\n * If features are missing (headers), please report and we can add it.\n * @param durationUs use Long.toUs() for easier input\n * */\ndata class PlayListItem(\n    val url: String,\n    val durationUs: Long,\n)\n\n/**\n * Converts Seconds to MicroSeconds, multiplication by 1_000_000\n * */\nfun Long.toUs(): Long {\n    return this * 1_000_000\n}\n\n/**\n * If your site has an unorthodox m3u8-like system where there are multiple smaller videos concatenated\n * use this.\n * */\n@Suppress(\"DEPRECATION\")\ndata class ExtractorLinkPlayList(\n    override val source: String,\n    override val name: String,\n    val playlist: List<PlayListItem>,\n    override var referer: String,\n    override var quality: Int,\n    override var headers: Map<String, String> = mapOf(),\n    /** Used for getExtractorVerifierJob() */\n    override var extractorData: String? = null,\n    override var type: ExtractorLinkType,\n    override var audioTracks: List<AudioFile> = emptyList(),\n) : ExtractorLink(\n    source = source,\n    name = name,\n    url = \"\",\n    referer = referer,\n    quality = quality,\n    headers = headers,\n    extractorData = extractorData,\n    type = type,\n    audioTracks = audioTracks\n) {\n    constructor(\n        source: String,\n        name: String,\n        playlist: List<PlayListItem>,\n        referer: String,\n        quality: Int,\n        isM3u8: Boolean = false,\n        headers: Map<String, String> = mapOf(),\n        extractorData: String? = null,\n    ) : this(\n        source = source,\n        name = name,\n        playlist = playlist,\n        referer = referer,\n        quality = quality,\n        type = if (isM3u8) ExtractorLinkType.M3U8 else ExtractorLinkType.VIDEO,\n        headers = headers,\n        extractorData = extractorData,\n    )\n}\n\n/** Metadata about the file type used for downloads and exoplayer hint,\n * if you respond with the wrong one the file will fail to download or be played */\nenum class ExtractorLinkType {\n    /** Single stream of bytes no matter the actual file type */\n    VIDEO,\n\n    /** Split into several .ts files, has support for encrypted m3u8s */\n    M3U8,\n\n    /** Like m3u8 but uses xml, currently no download support */\n    DASH,\n\n    /** No support at the moment */\n    TORRENT,\n\n    /** No support at the moment */\n    MAGNET;\n\n    // See https://www.iana.org/assignments/media-types/media-types.xhtml\n    fun getMimeType(): String {\n        return when (this) {\n            VIDEO -> \"video/mp4\"\n            M3U8 -> \"application/x-mpegURL\"\n            DASH -> \"application/dash+xml\"\n            TORRENT -> \"application/x-bittorrent\"\n            MAGNET -> \"application/x-bittorrent\"\n        }\n    }\n}\n\nprivate fun inferTypeFromUrl(url: String): ExtractorLinkType {\n    val path = try {\n        URI(url).path\n    } catch (_: Throwable) {\n        // don't log magnet links as errors\n        null\n    }\n    return when {\n        path?.endsWith(\".m3u8\") == true -> ExtractorLinkType.M3U8\n        path?.endsWith(\".mpd\") == true -> ExtractorLinkType.DASH\n        path?.endsWith(\".torrent\") == true -> ExtractorLinkType.TORRENT\n        url.startsWith(\"magnet:\") -> ExtractorLinkType.MAGNET\n        else -> ExtractorLinkType.VIDEO\n    }\n}\n\nval INFER_TYPE: ExtractorLinkType? = null\n\n/**\n * UUID for the ClearKey DRM scheme.\n *\n *\n * ClearKey is supported on Android devices running Android 5.0 (API Level 21) and up.\n */\nval CLEARKEY_UUID = UUID(-0x1d8e62a7567a4c37L, 0x781AB030AF78D30EL)\n\n/**\n * UUID for the Widevine DRM scheme.\n *\n *\n * Widevine is supported on Android devices running Android 4.3 (API Level 18) and up.\n */\nval WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L)\n\n/**\n * UUID for the PlayReady DRM scheme.\n *\n *\n * PlayReady is supported on all AndroidTV devices. Note that most other Android devices do not\n * provide PlayReady support.\n */\nval PLAYREADY_UUID = UUID(-0x65fb0f8667bfbd7aL, -0x546d19a41f77a06bL)\n\nsuspend fun newExtractorLink(\n    source: String,\n    name: String,\n    url: String,\n    type: ExtractorLinkType? = null,\n    initializer: suspend ExtractorLink.() -> Unit = { }\n): ExtractorLink {\n\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder =\n        ExtractorLink(\n            source = source,\n            name = name,\n            url = url,\n            type = type ?: INFER_TYPE\n        )\n\n    builder.initializer()\n    return builder\n}\n\nsuspend fun newDrmExtractorLink(\n    source: String,\n    name: String,\n    url: String,\n    type: ExtractorLinkType? = null,\n    uuid: UUID,\n    initializer: suspend DrmExtractorLink.() -> Unit = { }\n): DrmExtractorLink {\n\n    @Suppress(\"DEPRECATION_ERROR\")\n    val builder =\n        DrmExtractorLink(\n            source = source,\n            name = name,\n            url = url,\n            uuid = uuid,\n            type = type ?: INFER_TYPE\n        )\n\n    builder.initializer()\n    return builder\n}\n\n/** Class holds extracted DRM media info to be passed to the player.\n * @property source Name of the media source, appears on player layout.\n * @property name Title of the media, appears on player layout.\n * @property url Url string of media file\n * @property referer Referer that will be used by network request.\n * @property quality Quality of the media file\n * @property headers Headers <String, String> map that will be used by network request.\n * @property extractorData Used for getExtractorVerifierJob()\n * @property type the type of the media, use [INFER_TYPE] if you want to auto infer the type from the url\n * @property kid  Base64 value of The KID element (Key Id) contains the identifier of the key associated with a license.\n * @property key Base64 value of Key to be used to decrypt the media file.\n * @property uuid Drm UUID [WIDEVINE_UUID], [PLAYREADY_UUID], [CLEARKEY_UUID] (by default) .. etc\n * @property kty Key type \"oct\" (octet sequence) by default\n * @property keyRequestParameters Parameters that will used to request the key.\n * @see newDrmExtractorLink\n * */\n@Suppress(\"DEPRECATION\")\nopen class DrmExtractorLink private constructor(\n    override val source: String,\n    override val name: String,\n    override val url: String,\n    override var referer: String,\n    override var quality: Int,\n    override var headers: Map<String, String> = mapOf(),\n    /** Used for getExtractorVerifierJob() */\n    override var extractorData: String? = null,\n    override var type: ExtractorLinkType,\n    open var kid: String? = null,\n    open var key: String? = null,\n    open var uuid: UUID,\n    open var kty: String? = null,\n    open var keyRequestParameters: HashMap<String, String>,\n    open var licenseUrl: String? = null,\n    override var audioTracks: List<AudioFile> = emptyList(),\n) : ExtractorLink(\n    source, name, url, referer, quality, headers, extractorData, type, audioTracks\n) {\n    @Deprecated(\"Use newDrmExtractorLink\", level = DeprecationLevel.ERROR)\n    constructor(\n        source: String,\n        name: String,\n        url: String,\n        referer: String? = null,\n        quality: Int? = null,\n        /** the type of the media, use INFER_TYPE if you want to auto infer the type from the url */\n        type: ExtractorLinkType? = INFER_TYPE,\n        headers: Map<String, String> = mapOf(),\n        /** Used for getExtractorVerifierJob() */\n        extractorData: String? = null,\n        kid: String? = null,\n        key: String? = null,\n        uuid: UUID = CLEARKEY_UUID,\n        kty: String? = \"oct\",\n        keyRequestParameters: HashMap<String, String> = hashMapOf(),\n        licenseUrl: String? = null,\n    ) : this(\n        source = source,\n        name = name,\n        url = url,\n        referer = referer ?: \"\",\n        quality = quality ?: Qualities.Unknown.value,\n        headers = headers,\n        extractorData = extractorData,\n        type = type ?: inferTypeFromUrl(url),\n        kid = kid,\n        key = key,\n        uuid = uuid,\n        keyRequestParameters = keyRequestParameters,\n        kty = kty,\n        licenseUrl = licenseUrl,\n    )\n\n    @Deprecated(\"Use newDrmExtractorLink\", level = DeprecationLevel.ERROR)\n    constructor(\n        source: String,\n        name: String,\n        url: String,\n        referer: String,\n        quality: Int,\n        /** the type of the media, use INFER_TYPE if you want to auto infer the type from the url */\n        type: ExtractorLinkType?,\n        headers: Map<String, String> = mapOf(),\n        /** Used for getExtractorVerifierJob() */\n        extractorData: String? = null,\n        kid: String? = null,\n        key: String? = null,\n        uuid: UUID = CLEARKEY_UUID,\n        kty: String? = \"oct\",\n        keyRequestParameters: HashMap<String, String> = hashMapOf(),\n        licenseUrl: String? = null,\n    ) : this(\n        source = source,\n        name = name,\n        url = url,\n        referer = referer,\n        quality = quality,\n        headers = headers,\n        extractorData = extractorData,\n        type = type ?: inferTypeFromUrl(url),\n        kid = kid,\n        key = key,\n        uuid = uuid,\n        keyRequestParameters = keyRequestParameters,\n        kty = kty,\n        licenseUrl = licenseUrl,\n    )\n}\n\n/** Class holds extracted media info to be passed to the player.\n * @property source Name of the media source, appears on player layout.\n * @property name Title of the media, appears on player layout.\n * @property url Url string of media file\n * @property referer Referer that will be used by network request.\n * @property quality Quality of the media file\n * @property headers Headers <String, String> map that will be used by network request.\n * @property extractorData Used for getExtractorVerifierJob()\n * @property type Extracted link type (Video, M3u8, Dash, Torrent or Magnet)\n * @property audioTracks List of separate audio tracks that can be used with this video\n * @see newExtractorLink\n * */\nopen class ExtractorLink\n@Deprecated(\"Use newExtractorLink\", level = DeprecationLevel.WARNING)\nconstructor(\n    open val source: String,\n    open val name: String,\n    override val url: String,\n    override var referer: String,\n    open var quality: Int,\n    override var headers: Map<String, String> = mapOf(),\n    /** Used for getExtractorVerifierJob() */\n    open var extractorData: String? = null,\n    open var type: ExtractorLinkType,\n    /** List of separate audio tracks that can be merged with this video */\n    open var audioTracks: List<AudioFile> = emptyList(),\n) : IDownloadableMinimum {\n    val isM3u8: Boolean get() = type == ExtractorLinkType.M3U8\n    val isDash: Boolean get() = type == ExtractorLinkType.DASH\n\n    // Cached video size\n    private var videoSize: Long? = null\n\n    /**\n     * Get video size in bytes with one head request. Only available for ExtractorLinkType.Video\n     * @param timeoutSeconds timeout of the head request.\n     */\n    suspend fun getVideoSize(timeoutSeconds: Long = 3L): Long? {\n        // Content-Length is not applicable to other types of formats\n        if (this.type != ExtractorLinkType.VIDEO) return null\n\n        videoSize = videoSize ?: runCatching {\n            val response =\n                app.head(this.url, headers = headers, referer = referer, timeout = timeoutSeconds)\n            response.headers[\"Content-Length\"]?.toLong()\n        }.getOrNull()\n\n        return videoSize\n    }\n\n    @JsonIgnore\n    fun getAllHeaders(): Map<String, String> {\n        if (referer.isBlank()) {\n            return headers\n        } else if (headers.keys.none { it.equals(\"referer\", ignoreCase = true) }) {\n            return headers + mapOf(\"referer\" to referer)\n        }\n        return headers\n    }\n\n    @Suppress(\"DEPRECATION\")\n    @Deprecated(\"Use newExtractorLink\", level = DeprecationLevel.ERROR)\n    constructor(\n        source: String,\n        name: String,\n        url: String,\n        referer: String? = null,\n        quality: Int? = null,\n        /** the type of the media, use INFER_TYPE if you want to auto infer the type from the url */\n        type: ExtractorLinkType? = INFER_TYPE,\n        headers: Map<String, String> = mapOf(),\n        /** Used for getExtractorVerifierJob() */\n        extractorData: String? = null,\n    ) : this(\n        source = source,\n        name = name,\n        url = url,\n        referer = referer ?: \"\",\n        quality = quality ?: Qualities.Unknown.value,\n        headers = headers,\n        extractorData = extractorData,\n        type = type ?: inferTypeFromUrl(url)\n    )\n\n    @Suppress(\"DEPRECATION\")\n    @Deprecated(\"Use newExtractorLink\", level = DeprecationLevel.ERROR)\n    constructor(\n        source: String,\n        name: String,\n        url: String,\n        referer: String,\n        quality: Int,\n        /** the type of the media, use INFER_TYPE if you want to auto infer the type from the url */\n        type: ExtractorLinkType?,\n        headers: Map<String, String> = mapOf(),\n        /** Used for getExtractorVerifierJob() */\n        extractorData: String? = null,\n    ) : this(\n        source = source,\n        name = name,\n        url = url,\n        referer = referer,\n        quality = quality,\n        headers = headers,\n        extractorData = extractorData,\n        type = type ?: inferTypeFromUrl(url)\n    )\n\n    /**\n     * Old constructor without isDash, allows for backwards compatibility with extensions.\n     * Should be removed after all extensions have updated their cloudstream.jar\n     **/\n    @Suppress(\"DEPRECATION_ERROR\")\n    @Deprecated(\"Use newExtractorLink\", level = DeprecationLevel.ERROR)\n    constructor(\n        source: String,\n        name: String,\n        url: String,\n        referer: String,\n        quality: Int,\n        isM3u8: Boolean = false,\n        headers: Map<String, String> = mapOf(),\n        /** Used for getExtractorVerifierJob() */\n        extractorData: String? = null\n    ) : this(source, name, url, referer, quality, isM3u8, headers, extractorData, false)\n\n    @Suppress(\"DEPRECATION\")\n    @Deprecated(\"Use newExtractorLink\", level = DeprecationLevel.ERROR)\n    constructor(\n        source: String,\n        name: String,\n        url: String,\n        referer: String,\n        quality: Int,\n        isM3u8: Boolean = false,\n        headers: Map<String, String> = mapOf(),\n        /** Used for getExtractorVerifierJob() */\n        extractorData: String? = null,\n        isDash: Boolean,\n    ) : this(\n        source = source,\n        name = name,\n        url = url,\n        referer = referer,\n        quality = quality,\n        headers = headers,\n        extractorData = extractorData,\n        type = if (isDash) ExtractorLinkType.DASH else if (isM3u8) ExtractorLinkType.M3U8 else ExtractorLinkType.VIDEO\n    )\n\n    override fun toString(): String {\n        return \"ExtractorLink(name=$name, url=$url, referer=$referer, type=$type)\"\n    }\n}\n\n/**\n * Removes https:// and www.\n * To match urls regardless of schema, perhaps Uri() can be used?\n */\nval schemaStripRegex = Regex(\"\"\"^(https:|)//(www\\.|)\"\"\")\n\nenum class Qualities(var value: Int, val defaultPriority: Int) {\n    Unknown(400, 4),\n    P144(144, 0), // 144p\n    P240(240, 2), // 240p\n    P360(360, 3), // 360p\n    P480(480, 4), // 480p\n    P720(720, 5), // 720p\n    P1080(1080, 6), // 1080p\n    P1440(1440, 7), // 1440p\n    P2160(2160, 8); // 4k or 2160p\n\n    companion object {\n        fun getStringByInt(qual: Int?): String {\n            return when (qual) {\n                0 -> \"Auto\"\n                Unknown.value -> \"\"\n                P2160.value -> \"4K\"\n                null -> \"\"\n                else -> \"${qual}p\"\n            }\n        }\n\n        fun getStringByIntFull(quality: Int): String {\n            return when (quality) {\n                0 -> \"Auto\"\n                Unknown.value -> \"Unknown\"\n                P2160.value -> \"4K\"\n                else -> \"${quality}p\"\n            }\n        }\n    }\n}\n\nfun getQualityFromName(qualityName: String?): Int {\n    if (qualityName == null)\n        return Qualities.Unknown.value\n\n    val match = qualityName.lowercase().replace(\"p\", \"\").trim()\n    return when (match) {\n        \"4k\" -> Qualities.P2160\n        else -> null\n    }?.value ?: match.toIntOrNull() ?: Qualities.Unknown.value\n}\n\nprivate val packedRegex = Regex(\"\"\"eval\\(function\\(p,a,c,k,e,.*\\)\\)\"\"\")\nfun getPacked(string: String): String? {\n    return packedRegex.find(string)?.value\n}\n\nfun getAndUnpack(string: String): String {\n    val packedText = getPacked(string)\n    return JsUnpacker(packedText).unpack() ?: string\n}\n\nsuspend fun unshortenLinkSafe(url: String): String {\n    return try {\n        if (ShortLink.isShortLink(url))\n            ShortLink.unshorten(url)\n        else url\n    } catch (e: Exception) {\n        logError(e)\n        url\n    }\n}\n\nsuspend fun loadExtractor(\n    url: String,\n    subtitleCallback: (SubtitleFile) -> Unit,\n    callback: (ExtractorLink) -> Unit\n): Boolean {\n    return loadExtractor(\n        url = url,\n        referer = null,\n        subtitleCallback = subtitleCallback,\n        callback = callback\n    )\n}\n\n\n/**\n * Tries to load the appropriate extractor based on link, returns true if any extractor is loaded.\n * */\n@Throws(CancellationException::class)\nsuspend fun loadExtractor(\n    url: String,\n    referer: String? = null,\n    subtitleCallback: (SubtitleFile) -> Unit,\n    callback: (ExtractorLink) -> Unit\n): Boolean {\n    // Ensure this coroutine has not timed out\n    coroutineScope { ensureActive() }\n\n    val currentUrl = unshortenLinkSafe(url)\n    val compareUrl = currentUrl.lowercase().replace(schemaStripRegex, \"\")\n\n    // Iterate in reverse order so the new registered ExtractorApi takes priority\n    for (index in extractorApis.lastIndex downTo 0) {\n        val extractor = extractorApis[index]\n        if (compareUrl.startsWith(extractor.mainUrl.replace(schemaStripRegex, \"\"))) {\n            try {\n                extractor.getUrl(currentUrl, referer, subtitleCallback, callback)\n            } catch (e: Exception) {\n                logError(e)\n                // Rethrow if we have timed out\n                if (e is CancellationException) {\n                    throw e\n                }\n            }\n            return true\n        }\n    }\n\n    // this is to match mirror domains - like example.com, example.net\n    for (index in extractorApis.lastIndex downTo 0) {\n        val extractor = extractorApis[index]\n        if (FuzzySearch.partialRatio(\n                extractor.mainUrl,\n                currentUrl\n            ) > 80\n        ) {\n            try {\n                extractor.getUrl(currentUrl, referer, subtitleCallback, callback)\n            } catch (e: Exception) {\n                logError(e)\n                // Rethrow if we have timed out\n                if (e is CancellationException) {\n                    throw e\n                }\n            }\n            return true\n        }\n    }\n\n    return false\n}\n\nval extractorApis: MutableList<ExtractorApi> = arrayListOf(\n    //AllProvider(),\n    Mp4Upload(),\n    StreamTape(),\n    StreamTapeNet(),\n    ShaveTape(),\n    StreamTapeXyz(),\n    Watchadsontape(),\n\n    //mixdrop extractors\n    MixDropBz(),\n    MixDropCh(),\n    MixDropTo(),\n    MixDropAg(),\n    MixDrop(),\n    MixDropPs(),\n    Mdy(),\n    MxDropTo(),\n    MixDropSi(),\n\n    XStreamCdn(),\n\n    StreamSB(),\n    Sblona(),\n    Vidgomunimesb(),\n    StreamSilk(),\n    StreamSB1(),\n    StreamSB2(),\n    StreamSB3(),\n    StreamSB4(),\n    StreamSB5(),\n    StreamSB6(),\n    StreamSB7(),\n    StreamSB8(),\n    StreamSB9(),\n    StreamSB10(),\n    StreamSB11(),\n    SBfull(),\n    // Streamhub(), cause Streamhub2() works\n    Streamhub2(),\n    Ssbstream(),\n    Sbthe(),\n    Vidgomunime(),\n    Sbflix(),\n    Streamsss(),\n    Sbspeed(),\n    Sbsonic(),\n    Sbface(),\n    Sbrapid(),\n    Lvturbo(),\n\n    Fastream(),\n    Videa(),\n    FEmbed(),\n    FeHD(),\n    Fplayer(),\n    DBfilm(),\n    Luxubu(),\n    LayarKaca(),\n    Rasacintaku(),\n    FEnet(),\n    Kotakajair(),\n    Cdnplayer(),\n    //  WatchSB(), 'cause StreamSB.kt works\n    Uqload(),\n    Uqload1(),\n    Uqload2(),\n    Uqloadcx(),\n    Uqloadbz(),\n    Evoload(),\n    Evoload1(),\n    UpstreamExtractor(),\n\n    Odnoklassniki(),\n    TauVideo(),\n    SibNet(),\n    ContentX(),\n    Hotlinger(),\n    FourCX(),\n    PlayRu(),\n    FourPlayRu(),\n    Pichive(),\n    FourPichive(),\n    HDMomPlayer(),\n    HDPlayerSystem(),\n    VideoSeyred(),\n    PeaceMakerst(),\n    HDStreamAble(),\n    RapidVid(),\n    TRsTX(),\n    VidMoxy(),\n    Sobreatsesuyp(),\n    PixelDrain(),\n    PixelDrainDev(),\n    MailRu(),\n\n    OkRuSSL(),\n    OkRuSSLMobile(),\n    OkRuHTTP(),\n    OkRuHTTPMobile(),\n    Sendvid(),\n\n    // dood extractors\n    DoodCxExtractor(),\n    DoodPmExtractor(),\n    DoodToExtractor(),\n    DoodSoExtractor(),\n    DoodLaExtractor(),\n    Dooood(),\n    D0000d(),\n    D000dCom(),\n    DoodstreamCom(),\n    DoodWsExtractor(),\n    DoodShExtractor(),\n    DoodWatchExtractor(),\n    DoodWfExtractor(),\n    DoodYtExtractor(),\n    Doodspro(),\n    Dsvplay(),\n\n    // GenericM3U8(),\n    Zplayer(),\n    ZplayerV2(),\n    Upstream(),\n\n    Maxstream(),\n    Tantifilm(),\n    Userload(),\n    Supervideo(),\n\n    // StreamSB.kt works\n    //  SBPlay(),\n    //  SBPlay1(),\n    //  SBPlay2(),\n\n    PlayerVoxzer(),\n\n    Blogger(),\n    YourUpload(),\n\n    Hxfile(),\n    KotakAnimeid(),\n    Neonime8n(),\n    Neonime7n(),\n    Yufiles(),\n    Aico(),\n\n    JWPlayer(),\n    Meownime(),\n    DesuArcg(),\n    DesuOdchan(),\n    DesuOdvip(),\n    DesuDrive(),\n\n\n    Keephealth(),\n    Sbnet(),\n    Sbasian(),\n    Sblongvu(),\n    Fembed9hd(),\n    StreamM4u(),\n    Krakenfiles(),\n    Gofile(),\n    Vicloud(),\n    Uservideo(),\n    Userscloud(),\n\n    Movhide(),\n    StreamhideCom(),\n    StreamhideTo(),\n    Wibufile(),\n    FileMoonIn(),\n    Moviesm4u(),\n    Filesim(),\n    Multimoviesshg(),\n    Ahvsh(),\n    Guccihide(),\n    FileMoon(),\n    FileMoonSx(),\n    FilemoonV2(),\n\n    Vido(),\n    Linkbox(),\n    Acefile(),\n    Minoplres(), // formerly SpeedoStream\n    Embedgram(),\n    Mvidoo(),\n    Streamplay(),\n    Vidmoly(),\n    Vidmolyme(),\n    Vidmolyto(),\n    Vidmolybiz(),\n    Voe(),\n    Voe1(),\n    Tubeless(),\n    Moviehab(),\n    MoviehabNet(),\n    Jeniusplay(),\n    StreamoUpload(),\n    Streamup(),\n    Streamix(),\n    Vidara(),\n\n    GamoVideo(),\n    Gdriveplayerapi(),\n    Gdriveplayerapp(),\n    Gdriveplayerfun(),\n    Gdriveplayerio(),\n    Gdriveplayerme(),\n    Gdriveplayerbiz(),\n    Gdriveplayerorg(),\n    Gdriveplayerus(),\n    Gdriveplayerco(),\n    GoodstreamExtractor(),\n    Gdriveplayer(),\n    DatabaseGdrive(),\n    DatabaseGdrive2(),\n    Mediafire(),\n\n    YoutubeExtractor(),\n    YoutubeShortLinkExtractor(),\n    YoutubeMobileExtractor(),\n    YoutubeNoCookieExtractor(),\n    Streamlare(),\n    PlayLtXyz(),\n\n    Cda(),\n    Dailymotion(),\n    Ztreamhub(),\n    Rabbitstream(),\n    Dokicloud(),\n    Megacloud(),\n    VidhideExtractor(),\n    VidHidePro(),\n    VidHidePro1(),\n    VidHidePro2(),\n    VidHidePro3(),\n    VidHidePro4(),\n    VidHidePro5(),\n    VidHidePro6(),\n    VidHideHub(),\n    Ryderjet(),\n    VidNest(),\n    Dhtpre(),\n\n    // CineMM Redirects\n    Dhcplay(),\n    HglinkTo(),\n\n    // CineMM mirrors\n    HgplayCDN(),\n    Habetar(),\n    Yuguaab(),\n    Guxhag(),\n    Auvexiug(),\n    Xenolyzb(),\n    Haxloppd(),\n    Cavanhabg(),\n    Dumbalag(),\n    Uasopt(),\n\n    Smoothpre(),\n    Peytonepre(),\n    LuluStream(),\n    Lulustream1(),\n    Lulustream2(),\n    Luluvdoo(),\n    StreamWishExtractor(),\n    StreamHLS(),\n    BigwarpIO(),\n    BigwarpArt(),\n    BgwpCC(),\n    WishembedPro(),\n    CdnwishCom(),\n    FlaswishCom(),\n    SfastwishCom(),\n    Playerwish(),\n    StreamEmbed(),\n    EmturbovidExtractor(),\n    Vtbe(),\n    SecvideoOnline(),\n    FsstOnline(),\n    CsstOnline(),\n    DsstOnline(),\n    Simpulumlamerop(),\n    Urochsunloath(),\n    NathanFromSubject(),\n    Yipsu(),\n    MetaGnathTuggers(),\n    Geodailymotion(),\n    Mwish(),\n    Dwish(),\n    Ewish(),\n    Kswplayer(),\n    Wishfast(),\n    Streamwish2(),\n    Strwish(),\n    Strwish2(),\n    Awish(),\n    Obeywish(),\n    Jodwish(),\n    Swhoi(),\n    Multimovies(),\n    UqloadsXyz(),\n    Doodporn(),\n    Asnwish(),\n    Nekowish(),\n    Nekostream(),\n    Swdyu(),\n    Wishonly(),\n    Ds2play(),\n    Ds2video(),\n    Vidsonic(),\n    InternetArchive(),\n    VidStack(),\n    GDMirrorbot(),\n    Techinmind(),\n    Server1uns(),\n    VinovoSi(),\n    VinovoTo(),\n    Vidoza(),\n    Videzz(),\n    CloudMailRu(),\n    HubCloud(),\n    VkExtractor(),\n    Bysezejataos(),\n    ByseSX(),\n    ByseVepoin(),\n    ByseBuho(),\n    MyVidPlay(),\n    Vide0Net(),\n    Up4Stream(),\n    Up4FunTop(),\n    GUpload(),\n    HlsWish(),\n    ByseQekaho(),\n)\n\n\nfun getExtractorApiFromName(name: String): ExtractorApi {\n    for (api in extractorApis) {\n        if (api.name == name) return api\n    }\n    return extractorApis[0]\n}\n\nfun requireReferer(name: String): Boolean {\n    return getExtractorApiFromName(name).requiresReferer\n}\n\nfun httpsify(url: String): String {\n    return if (url.startsWith(\"//\")) \"https:$url\" else url\n}\n\nsuspend fun getPostForm(requestUrl: String, html: String): String? {\n    val document = Jsoup.parse(html)\n    val inputs = document.select(\"Form > input\")\n    if (inputs.size < 4) return null\n    var op: String? = null\n    var id: String? = null\n    var mode: String? = null\n    var hash: String? = null\n\n    for (input in inputs) {\n        val value = input.attr(\"value\")\n        when (input.attr(\"name\")) {\n            \"op\" -> op = value\n            \"id\" -> id = value\n            \"mode\" -> mode = value\n            \"hash\" -> hash = value\n            else -> Unit\n        }\n    }\n    if (op == null || id == null || mode == null || hash == null) {\n        return null\n    }\n    delay(5000) // ye this is needed, wont work with 0 delay\n\n    return app.post(\n        requestUrl,\n        headers = mapOf(\n            \"content-type\" to \"application/x-www-form-urlencoded\",\n            \"referer\" to requestUrl,\n            \"user-agent\" to USER_AGENT,\n            \"accept\" to \"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\"\n        ),\n        data = mapOf(\"op\" to op, \"id\" to id, \"mode\" to mode, \"hash\" to hash)\n    ).text\n}\n\nfun ExtractorApi.fixUrl(url: String): String {\n    if (url.startsWith(\"http\") ||\n        // Do not fix JSON objects when passed as urls.\n        url.startsWith(\"{\\\"\")\n    ) {\n        return url\n    }\n    if (url.isEmpty()) {\n        return \"\"\n    }\n\n    val startsWithNoHttp = url.startsWith(\"//\")\n    if (startsWithNoHttp) {\n        return \"https:$url\"\n    } else {\n        if (url.startsWith('/')) {\n            return mainUrl + url\n        }\n        return \"$mainUrl/$url\"\n    }\n}\n\nabstract class ExtractorApi {\n    abstract val name: String\n    abstract val mainUrl: String\n    abstract val requiresReferer: Boolean\n\n    /** Determines which plugin a given provider is from. This is the full path to the plugin. */\n    var sourcePlugin: String? = null\n\n    //suspend fun getSafeUrl(url: String, referer: String? = null): List<ExtractorLink>? {\n    //    return safeAsync { getUrl(url, referer) }\n    //}\n\n    // this is the new extractorapi, override to add subtitles and stuff\n    @Throws\n    open suspend fun getUrl(\n        url: String,\n        referer: String? = null,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        getUrl(url, referer)?.forEach(callback)\n    }\n\n    suspend fun getSafeUrl(\n        url: String,\n        referer: String? = null,\n        subtitleCallback: (SubtitleFile) -> Unit,\n        callback: (ExtractorLink) -> Unit\n    ) {\n        try {\n            getUrl(url, referer, subtitleCallback, callback)\n        } catch (e: Exception) {\n            logError(e)\n        }\n    }\n\n    /**\n     * Will throw errors, use getSafeUrl if you don't want to handle the exception yourself\n     */\n    @Throws\n    open suspend fun getUrl(url: String, referer: String? = null): List<ExtractorLink>? {\n        return emptyList()\n    }\n\n    open fun getExtractorUrl(id: String): String {\n        return id\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/HlsPlaylistParser.kt",
    "content": "/*\r\n * Copyright (C) 2016 The Android Open Source Project\r\n *\r\n * Licensed under the Apache License, Version 2.0 (the \"License\");\r\n * you may not use this file except in compliance with the License.\r\n * You may obtain a copy of the License at\r\n *\r\n *      http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License.\r\n */\r\n\r\n/*\r\n NOTE: This is a simplified and more portable kotlin media3 hls parser. \r\n */\r\npackage com.lagradost.cloudstream3.utils\r\n\r\nimport java.io.IOException\r\nimport java.net.URI\r\nimport java.nio.ByteBuffer\r\nimport java.util.UUID\r\nimport kotlin.io.encoding.Base64\r\nimport kotlin.io.encoding.ExperimentalEncodingApi\r\n\r\n@Suppress(\"unused\")\r\nobject HlsPlaylistParser {\r\n    private const val LOG_TAG: String = \"HlsPlaylistParser\"\r\n    private const val PLAYLIST_HEADER: String = \"#EXTM3U\"\r\n    private const val TAG_PREFIX: String = \"#EXT\"\r\n    private const val TAG_VERSION: String = \"#EXT-X-VERSION\"\r\n    private const val TAG_PLAYLIST_TYPE: String = \"#EXT-X-PLAYLIST-TYPE\"\r\n    private const val TAG_DEFINE: String = \"#EXT-X-DEFINE\"\r\n    private const val TAG_SERVER_CONTROL: String = \"#EXT-X-SERVER-CONTROL\"\r\n    private const val TAG_STREAM_INF: String = \"#EXT-X-STREAM-INF\"\r\n    private const val TAG_PART_INF: String = \"#EXT-X-PART-INF\"\r\n    private const val TAG_PART: String = \"#EXT-X-PART\"\r\n    private const val TAG_I_FRAME_STREAM_INF: String = \"#EXT-X-I-FRAME-STREAM-INF\"\r\n    private const val TAG_IFRAME: String = \"#EXT-X-I-FRAMES-ONLY\"\r\n    private const val TAG_MEDIA: String = \"#EXT-X-MEDIA\"\r\n    private const val TAG_TARGET_DURATION: String = \"#EXT-X-TARGETDURATION\"\r\n    private const val TAG_DISCONTINUITY: String = \"#EXT-X-DISCONTINUITY\"\r\n    private const val TAG_DISCONTINUITY_SEQUENCE: String = \"#EXT-X-DISCONTINUITY-SEQUENCE\"\r\n    private const val TAG_PROGRAM_DATE_TIME: String = \"#EXT-X-PROGRAM-DATE-TIME\"\r\n    private const val TAG_INIT_SEGMENT: String = \"#EXT-X-MAP\"\r\n    private const val TAG_INDEPENDENT_SEGMENTS: String = \"#EXT-X-INDEPENDENT-SEGMENTS\"\r\n    private const val TAG_MEDIA_DURATION: String = \"#EXTINF\"\r\n    private const val TAG_MEDIA_SEQUENCE: String = \"#EXT-X-MEDIA-SEQUENCE\"\r\n    private const val TAG_START: String = \"#EXT-X-START\"\r\n    private const val TAG_ENDLIST: String = \"#EXT-X-ENDLIST\"\r\n    private const val TAG_KEY: String = \"#EXT-X-KEY\"\r\n    private const val TAG_SESSION_KEY: String = \"#EXT-X-SESSION-KEY\"\r\n    private const val TAG_BYTERANGE: String = \"#EXT-X-BYTERANGE\"\r\n    private const val TAG_GAP: String = \"#EXT-X-GAP\"\r\n    private const val TAG_SKIP: String = \"#EXT-X-SKIP\"\r\n    private const val TAG_PRELOAD_HINT: String = \"#EXT-X-PRELOAD-HINT\"\r\n    private const val TAG_RENDITION_REPORT: String = \"#EXT-X-RENDITION-REPORT\"\r\n    private const val TAG_DATERANGE: String = \"#EXT-X-DATERANGE\"\r\n    private const val TYPE_AUDIO: String = \"AUDIO\"\r\n    private const val TYPE_VIDEO: String = \"VIDEO\"\r\n    private const val TYPE_SUBTITLES: String = \"SUBTITLES\"\r\n    private const val TYPE_CLOSED_CAPTIONS: String = \"CLOSED-CAPTIONS\"\r\n    private const val TYPE_PART: String = \"PART\"\r\n    private const val TYPE_MAP: String = \"MAP\"\r\n    private const val METHOD_NONE: String = \"NONE\"\r\n    private const val METHOD_AES_128: String = \"AES-128\"\r\n    private const val METHOD_SAMPLE_AES: String = \"SAMPLE-AES\"\r\n\r\n    // Replaced by METHOD_SAMPLE_AES_CTR. Keep for backward compatibility.\r\n    private const val METHOD_SAMPLE_AES_CENC: String = \"SAMPLE-AES-CENC\"\r\n    private const val METHOD_SAMPLE_AES_CTR: String = \"SAMPLE-AES-CTR\"\r\n    private const val KEYFORMAT_PLAYREADY: String = \"com.microsoft.playready\"\r\n    private const val KEYFORMAT_IDENTITY: String = \"identity\"\r\n    private const val KEYFORMAT_WIDEVINE_PSSH_BINARY: String =\r\n        \"urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed\"\r\n    private const val KEYFORMAT_WIDEVINE_PSSH_JSON: String = \"com.widevine\"\r\n    private const val BOOLEAN_TRUE: String = \"YES\"\r\n    private const val BOOLEAN_FALSE: String = \"NO\"\r\n    private const val ATTR_CLOSED_CAPTIONS_NONE: String = \"CLOSED-CAPTIONS=NONE\"\r\n    private val REGEX_AVERAGE_BANDWIDTH: Regex = Regex(\"AVERAGE-BANDWIDTH=(\\\\d+)\\\\b\")\r\n    private val REGEX_VIDEO: Regex = Regex(\"VIDEO=\\\"(.+?)\\\"\")\r\n    private val REGEX_AUDIO: Regex = Regex(\"AUDIO=\\\"(.+?)\\\"\")\r\n    private val REGEX_SUBTITLES: Regex = Regex(\"SUBTITLES=\\\"(.+?)\\\"\")\r\n    private val REGEX_CLOSED_CAPTIONS: Regex = Regex(\"CLOSED-CAPTIONS=\\\"(.+?)\\\"\")\r\n    private val REGEX_BANDWIDTH: Regex = Regex(\"[^-]BANDWIDTH=(\\\\d+)\\\\b\")\r\n    private val REGEX_CHANNELS: Regex = Regex(\"CHANNELS=\\\"(.+?)\\\"\")\r\n    private val REGEX_VIDEO_RANGE: Regex = Regex(\"VIDEO-RANGE=(SDR|PQ|HLG)\")\r\n    private val REGEX_CODECS: Regex = Regex(\"CODECS=\\\"(.+?)\\\"\")\r\n    private val REGEX_SUPPLEMENTAL_CODECS: Regex = Regex(\"SUPPLEMENTAL-CODECS=\\\"(.+?)\\\"\")\r\n    private val REGEX_RESOLUTION: Regex = Regex(\"RESOLUTION=(\\\\d+x\\\\d+)\")\r\n    private val REGEX_FRAME_RATE: Regex = Regex(\"FRAME-RATE=([\\\\d\\\\.]+)\\\\b\")\r\n    private val REGEX_TARGET_DURATION: Regex = Regex(\"$TAG_TARGET_DURATION:(\\\\d+)\\\\b\")\r\n    private val REGEX_ATTR_DURATION: Regex = Regex(\"DURATION=([\\\\d\\\\.]+)\\\\b\")\r\n    private val REGEX_ATTR_DURATION_PREFIXED: Regex = Regex(\"[:,]DURATION=([\\\\d\\\\.]+)\\\\b\")\r\n    private val REGEX_PART_TARGET_DURATION: Regex = Regex(\"PART-TARGET=([\\\\d\\\\.]+)\\\\b\")\r\n    private val REGEX_VERSION: Regex = Regex(\"$TAG_VERSION:(\\\\d+)\\\\b\")\r\n    private val REGEX_PLAYLIST_TYPE: Regex = Regex(\"$TAG_PLAYLIST_TYPE:(.+)\\\\b\")\r\n    private val REGEX_CAN_SKIP_UNTIL: Regex = Regex(\"CAN-SKIP-UNTIL=([\\\\d\\\\.]+)\\\\b\")\r\n    private val REGEX_CAN_SKIP_DATE_RANGES: Regex = compileBooleanAttrPattern(\"CAN-SKIP-DATERANGES\")\r\n    private val REGEX_SKIPPED_SEGMENTS: Regex = Regex(\"SKIPPED-SEGMENTS=(\\\\d+)\\\\b\")\r\n    private val REGEX_HOLD_BACK: Regex = Regex(\"[:|,]HOLD-BACK=([\\\\d\\\\.]+)\\\\b\")\r\n    private val REGEX_PART_HOLD_BACK: Regex = Regex(\"PART-HOLD-BACK=([\\\\d\\\\.]+)\\\\b\")\r\n    private val REGEX_CAN_BLOCK_RELOAD: Regex = compileBooleanAttrPattern(\"CAN-BLOCK-RELOAD\")\r\n    private val REGEX_MEDIA_SEQUENCE: Regex = Regex(\"$TAG_MEDIA_SEQUENCE:(\\\\d+)\\\\b\")\r\n    private val REGEX_MEDIA_DURATION: Regex = Regex(\"$TAG_MEDIA_DURATION:([\\\\d\\\\.]+)\\\\b\")\r\n    private val REGEX_MEDIA_TITLE: Regex = Regex(\"$TAG_MEDIA_DURATION:[\\\\d\\\\.]+\\\\b,(.+)\")\r\n    private val REGEX_LAST_MSN: Regex = Regex(\"LAST-MSN\" + \"=(\\\\d+)\\\\b\")\r\n    private val REGEX_LAST_PART: Regex = Regex(\"LAST-PART\" + \"=(\\\\d+)\\\\b\")\r\n    private val REGEX_TIME_OFFSET: Regex = Regex(\"TIME-OFFSET=(-?[\\\\d\\\\.]+)\\\\b\")\r\n    private val REGEX_BYTERANGE: Regex = Regex(\"$TAG_BYTERANGE:(\\\\d+(?:@\\\\d+)?)\\\\b\")\r\n    private val REGEX_ATTR_BYTERANGE: Regex = Regex(\"BYTERANGE=\\\"(\\\\d+(?:@\\\\d+)?)\\\\b\\\"\")\r\n    private val REGEX_BYTERANGE_START: Regex = Regex(\"BYTERANGE-START=(\\\\d+)\\\\b\")\r\n    private val REGEX_BYTERANGE_LENGTH: Regex = Regex(\"BYTERANGE-LENGTH=(\\\\d+)\\\\b\")\r\n    private val REGEX_METHOD: Regex = Regex(\r\n        (\"METHOD=(\"\r\n                + METHOD_NONE\r\n                + \"|\"\r\n                + METHOD_AES_128\r\n                + \"|\"\r\n                + METHOD_SAMPLE_AES\r\n                + \"|\"\r\n                + METHOD_SAMPLE_AES_CENC\r\n                + \"|\"\r\n                + METHOD_SAMPLE_AES_CTR\r\n                + \")\"\r\n                + \"\\\\s*(?:,|$)\")\r\n    )\r\n    private val REGEX_KEYFORMAT: Regex = Regex(\"KEYFORMAT=\\\"(.+?)\\\"\")\r\n    private val REGEX_KEYFORMATVERSIONS: Regex = Regex(\"KEYFORMATVERSIONS=\\\"(.+?)\\\"\")\r\n    private val REGEX_URI: Regex = Regex(\"URI=\\\"(.+?)\\\"\")\r\n    private val REGEX_IV: Regex = Regex(\"IV=([^,.*]+)\")\r\n    private val REGEX_TYPE: Regex = Regex(\r\n        (\"TYPE=(\"\r\n                + TYPE_AUDIO\r\n                + \"|\"\r\n                + TYPE_VIDEO\r\n                + \"|\"\r\n                + TYPE_SUBTITLES\r\n                + \"|\"\r\n                + TYPE_CLOSED_CAPTIONS\r\n                + \")\")\r\n    )\r\n    private val REGEX_PRELOAD_HINT_TYPE: Regex = Regex(\"TYPE=($TYPE_PART|$TYPE_MAP)\")\r\n    private val REGEX_LANGUAGE: Regex = Regex(\"LANGUAGE=\\\"(.+?)\\\"\")\r\n    private val REGEX_NAME: Regex = Regex(\"NAME=\\\"(.+?)\\\"\")\r\n    private val REGEX_GROUP_ID: Regex = Regex(\"GROUP-ID=\\\"(.+?)\\\"\")\r\n    private val REGEX_CHARACTERISTICS: Regex = Regex(\"CHARACTERISTICS=\\\"(.+?)\\\"\")\r\n    private val REGEX_INSTREAM_ID: Regex = Regex(\"INSTREAM-ID=\\\"((?:CC|SERVICE)\\\\d+)\\\"\")\r\n    private val REGEX_AUTOSELECT: Regex = compileBooleanAttrPattern(\"AUTOSELECT\")\r\n    private val REGEX_DEFAULT: Regex = compileBooleanAttrPattern(\"DEFAULT\")\r\n    private val REGEX_FORCED: Regex = compileBooleanAttrPattern(\"FORCED\")\r\n    private val REGEX_INDEPENDENT: Regex = compileBooleanAttrPattern(\"INDEPENDENT\")\r\n    private val REGEX_GAP: Regex = compileBooleanAttrPattern(\"GAP\")\r\n    private val REGEX_PRECISE: Regex = compileBooleanAttrPattern(\"PRECISE\")\r\n    private val REGEX_VALUE: Regex = Regex(\"VALUE=\\\"(.+?)\\\"\")\r\n    private val REGEX_IMPORT: Regex = Regex(\"IMPORT=\\\"(.+?)\\\"\")\r\n    private val REGEX_ID: Regex = Regex(\"[:,]ID=\\\"(.+?)\\\"\")\r\n    private val REGEX_CLASS: Regex = Regex(\"CLASS=\\\"(.+?)\\\"\")\r\n    private val REGEX_START_DATE: Regex = Regex(\"START-DATE=\\\"(.+?)\\\"\")\r\n    private val REGEX_CUE: Regex = Regex(\"CUE=\\\"(.+?)\\\"\")\r\n    private val REGEX_END_DATE: Regex = Regex(\"END-DATE=\\\"(.+?)\\\"\")\r\n    private val REGEX_PLANNED_DURATION: Regex = Regex(\"PLANNED-DURATION=([\\\\d.]+)\\\\b\")\r\n    private val REGEX_END_ON_NEXT: Regex = compileBooleanAttrPattern(\"END-ON-NEXT\")\r\n    private val REGEX_ASSET_URI: Regex = Regex(\"X-ASSET-URI=\\\"(.+?)\\\"\")\r\n    private val REGEX_ASSET_LIST_URI: Regex = Regex(\"X-ASSET-LIST=\\\"(.+?)\\\"\")\r\n    private val REGEX_RESUME_OFFSET: Regex = Regex(\"X-RESUME-OFFSET=(-?[\\\\d.]+)\\\\b\")\r\n    private val REGEX_PLAYOUT_LIMIT: Regex = Regex(\"X-PLAYOUT-LIMIT=([\\\\d.]+)\\\\b\")\r\n    private val REGEX_SNAP: Regex = Regex(\"X-SNAP=\\\"(.+?)\\\"\")\r\n    private val REGEX_RESTRICT: Regex = Regex(\"X-RESTRICT=\\\"(.+?)\\\"\")\r\n    private val REGEX_VARIABLE_REFERENCE: Regex = Regex(\"\\\\{\\\\$([a-zA-Z0-9\\\\-_]+)\\\\}\")\r\n    private val REGEX_CLIENT_DEFINED_ATTRIBUTE_PREFIX: Regex = Regex(\"\\\\b(X-[A-Z0-9-]+)=\")\r\n\r\n    private fun compileBooleanAttrPattern(attribute: String): Regex {\r\n        return Regex(\"$attribute=($BOOLEAN_FALSE|$BOOLEAN_TRUE)\")\r\n    }\r\n\r\n    @Throws(ParserException::class)\r\n    private fun parseIntAttr(line: String, pattern: Regex): Int {\r\n        return parseStringAttr(line, pattern, emptyMap()).toInt()\r\n    }\r\n\r\n    private fun parseOptionalIntAttr(line: String, pattern: Regex, defaultValue: Int): Int =\r\n        pattern.find(line)?.groupValues?.get(1)?.toInt() ?: defaultValue\r\n\r\n    data class SchemeData(\r\n        /**\r\n         * The {@link UUID} of the DRM scheme, or {@link C#UUID_NIL} if the data is universal (i.e.\r\n         * applies to all schemes).\r\n         */\r\n        val uuid: UUID,\r\n        /** The URL of the server to which license requests should be made. May be null if unknown. */\r\n        val licenseServerUrl: String? = null,\r\n        /** The mimeType of {@link #data}. */\r\n        val mimeType: String,\r\n        /** The initialization data. May be null for scheme support checks only. */\r\n        val data: ByteArray\r\n    )\r\n\r\n    object Util {\r\n        /**\r\n         * Splits the string at the first occurrence of the delimiter `regex`. If the delimiter does\r\n         * not match, returns an array with one element which is the input string. If the delimiter does\r\n         * match, returns an array with the portion of the string before the delimiter and the rest of the\r\n         * string.\r\n         *\r\n         * @param value The string.\r\n         * @param regex A delimiting regular expression.\r\n         * @return The string split by the first occurrence of the delimiter.\r\n         */\r\n        fun splitAtFirst(value: String, regex: String): Array<String> {\r\n            return value.split(regex.toRegex(), limit = 2).toTypedArray()\r\n        }\r\n\r\n        fun split(value: String, regex: String): Array<String> {\r\n            return value.split(regex.toRegex()).toTypedArray()\r\n        }\r\n\r\n        fun splitCodecs(codecs: String?): Array<String> {\r\n            if (codecs.isNullOrEmpty()) {\r\n                return arrayOf()\r\n            }\r\n            return split(codecs.trim(), \"(\\\\s*,\\\\s*)\")\r\n        }\r\n\r\n        fun getCodecsOfType(\r\n            codecs: String?,\r\n            /**@TrackType*/\r\n            trackType: Int\r\n        ): String? {\r\n            val codecArray: Array<String> = splitCodecs(codecs)\r\n            if (codecArray.isEmpty()) {\r\n                return null\r\n            }\r\n            val builder = java.lang.StringBuilder()\r\n            for (codec in codecArray) {\r\n                if (trackType == MimeTypes.getTrackTypeOfCodec(codec)) {\r\n                    if (builder.isNotEmpty()) {\r\n                        builder.append(\",\")\r\n                    }\r\n                    builder.append(codec)\r\n                }\r\n            }\r\n            return if (builder.isNotEmpty()) builder.toString() else null\r\n        }\r\n\r\n        /**\r\n         * Returns a copy of `codecs` without the codecs whose track type matches `trackType`.\r\n         *\r\n         * @param codecs A codec sequence string, as defined in RFC 6381.\r\n         * @param trackType The [track type][C.TrackType].\r\n         * @return A copy of `codecs` without the codecs whose track type matches `trackType`.\r\n         * If this ends up empty, or `codecs` is null, returns null.\r\n         */\r\n        fun getCodecsWithoutType(\r\n            codecs: String?,\r\n            /** @TrackType  */\r\n            trackType: Int\r\n        ): String? {\r\n            val codecArray = splitCodecs(codecs)\r\n            if (codecArray.isEmpty()) {\r\n                return null\r\n            }\r\n            val builder = java.lang.StringBuilder()\r\n            for (codec in codecArray) {\r\n                if (trackType != MimeTypes.getTrackTypeOfCodec(codec)) {\r\n                    if (builder.isNotEmpty()) {\r\n                        builder.append(\",\")\r\n                    }\r\n                    builder.append(codec)\r\n                }\r\n            }\r\n            return if (builder.isNotEmpty()) builder.toString() else null\r\n        }\r\n    }\r\n\r\n    object UriUtil {\r\n        fun resolveToUri(baseUri: String?, referenceUri: String?): URI {\r\n            return URI.create(resolve(baseUri, referenceUri))\r\n        }\r\n\r\n\r\n        /** The length of arrays returned by [.getUriIndices].  */\r\n        private\r\n        const val INDEX_COUNT: Int = 4\r\n\r\n        /**\r\n         * An index into an array returned by [.getUriIndices].\r\n         *\r\n         *\r\n         * The value at this position in the array is the index of the ':' after the scheme. Equals -1\r\n         * if the URI is a relative reference (no scheme). The hier-part starts at (schemeColon + 1),\r\n         * including when the URI has no scheme.\r\n         */\r\n        private\r\n        const val SCHEME_COLON: Int = 0\r\n\r\n        /**\r\n         * An index into an array returned by [.getUriIndices].\r\n         *\r\n         *\r\n         * The value at this position in the array is the index of the path part. Equals (schemeColon +\r\n         * 1) if no authority part, (schemeColon + 3) if the authority part consists of just \"//\", and\r\n         * (query) if no path part. The characters starting at this index can be \"//\" only if the\r\n         * authority part is non-empty (in this case the double-slash means the first segment is empty).\r\n         */\r\n        private\r\n        const val PATH: Int = 1\r\n\r\n        /**\r\n         * An index into an array returned by [.getUriIndices].\r\n         *\r\n         *\r\n         * The value at this position in the array is the index of the query part, including the '?'\r\n         * before the query. Equals fragment if no query part, and (fragment - 1) if the query part is a\r\n         * single '?' with no data.\r\n         */\r\n        private\r\n        const val QUERY: Int = 2\r\n\r\n        /**\r\n         * An index into an array returned by [.getUriIndices].\r\n         *\r\n         *\r\n         * The value at this position in the array is the index of the fragment part, including the '#'\r\n         * before the fragment. Equal to the length of the URI if no fragment part, and (length - 1) if\r\n         * the fragment part is a single '#' with no data.\r\n         */\r\n        private\r\n        const val FRAGMENT: Int = 3\r\n\r\n        /**\r\n         * Performs relative resolution of a `referenceUri` with respect to a `baseUri`.\r\n         *\r\n         *\r\n         * The resolution is performed as specified by RFC-3986.\r\n         *\r\n         * @param baseUri The base URI.\r\n         * @param referenceUri The reference URI to resolve.\r\n         */\r\n        private fun resolve(baseUri: String?, referenceUri: String?): String {\r\n            var baseUri = baseUri\r\n            var referenceUri = referenceUri\r\n            val uri = StringBuilder()\r\n\r\n            // Map null onto empty string, to make the following logic simpler.\r\n            baseUri = baseUri ?: \"\"\r\n            referenceUri = referenceUri ?: \"\"\r\n\r\n            val refIndices: IntArray = getUriIndices(referenceUri)\r\n            if (refIndices[SCHEME_COLON] != -1) {\r\n                // The reference is absolute. The target Uri is the reference.\r\n                uri.append(referenceUri)\r\n                removeDotSegments(uri, refIndices[PATH], refIndices[QUERY])\r\n                return uri.toString()\r\n            }\r\n\r\n            val baseIndices: IntArray = getUriIndices(baseUri)\r\n            if (refIndices[FRAGMENT] == 0) {\r\n                // The reference is empty or contains just the fragment part, then the target Uri is the\r\n                // concatenation of the base Uri without its fragment, and the reference.\r\n                return uri.append(baseUri, 0, baseIndices[FRAGMENT]).append(referenceUri).toString()\r\n            }\r\n\r\n            if (refIndices[QUERY] == 0) {\r\n                // The reference starts with the query part. The target is the base up to (but excluding) the\r\n                // query, plus the reference.\r\n                return uri.append(baseUri, 0, baseIndices[QUERY]).append(referenceUri).toString()\r\n            }\r\n\r\n            if (refIndices[PATH] != 0) {\r\n                // The reference has authority. The target is the base scheme plus the reference.\r\n                val baseLimit = baseIndices[SCHEME_COLON] + 1\r\n                uri.append(baseUri, 0, baseLimit).append(referenceUri)\r\n                return removeDotSegments(\r\n                    uri,\r\n                    baseLimit + refIndices[PATH],\r\n                    baseLimit + refIndices[QUERY]\r\n                )\r\n            }\r\n\r\n            if (referenceUri[refIndices[PATH]] == '/') {\r\n                // The reference path is rooted. The target is the base scheme and authority (if any), plus\r\n                // the reference.\r\n                uri.append(baseUri, 0, baseIndices[PATH]).append(referenceUri)\r\n                return removeDotSegments(\r\n                    uri,\r\n                    baseIndices[PATH],\r\n                    baseIndices[PATH] + refIndices[QUERY]\r\n                )\r\n            }\r\n\r\n            // The target Uri is the concatenation of the base Uri up to (but excluding) the last segment,\r\n            // and the reference. This can be split into 2 cases:\r\n            if (baseIndices[SCHEME_COLON] + 2 < baseIndices[PATH]\r\n                && baseIndices[PATH] == baseIndices[QUERY]\r\n            ) {\r\n                // Case 1: The base hier-part is just the authority, with an empty path. An additional '/' is\r\n                // needed after the authority, before appending the reference.\r\n                uri.append(baseUri, 0, baseIndices[PATH]).append('/').append(referenceUri)\r\n                return removeDotSegments(\r\n                    uri,\r\n                    baseIndices[PATH],\r\n                    baseIndices[PATH] + refIndices[QUERY] + 1\r\n                )\r\n            } else {\r\n                // Case 2: Otherwise, find the last '/' in the base hier-part and append the reference after\r\n                // it. If base hier-part has no '/', it could only mean that it is completely empty or\r\n                // contains only one segment, in which case the whole hier-part is excluded and the reference\r\n                // is appended right after the base scheme colon without an added '/'.\r\n                val lastSlashIndex = baseUri.lastIndexOf('/', baseIndices[QUERY] - 1)\r\n                val baseLimit = if (lastSlashIndex == -1) baseIndices[PATH] else lastSlashIndex + 1\r\n                uri.append(baseUri, 0, baseLimit).append(referenceUri)\r\n                return removeDotSegments(uri, baseIndices[PATH], baseLimit + refIndices[QUERY])\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Removes dot segments from the path of a URI.\r\n         *\r\n         * @param uri A [StringBuilder] containing the URI.\r\n         * @param offset The index of the start of the path in `uri`.\r\n         * @param limit The limit (exclusive) of the path in `uri`.\r\n         */\r\n        private fun removeDotSegments(\r\n            uri: java.lang.StringBuilder,\r\n            offset: Int,\r\n            limit: Int\r\n        ): String {\r\n            var offset = offset\r\n            var limit = limit\r\n            if (offset >= limit) {\r\n                // Nothing to do.\r\n                return uri.toString()\r\n            }\r\n            if (uri[offset] == '/') {\r\n                // If the path starts with a /, always retain it.\r\n                offset++\r\n            }\r\n            // The first character of the current path segment.\r\n            var segmentStart = offset\r\n            var i = offset\r\n            while (i <= limit) {\r\n                val nextSegmentStart = if (i == limit) {\r\n                    i\r\n                } else if (uri[i] == '/') {\r\n                    i + 1\r\n                } else {\r\n                    i++\r\n                    continue\r\n                }\r\n                // We've encountered the end of a segment or the end of the path. If the final segment was\r\n                // \".\" or \"..\", remove the appropriate segments of the path.\r\n                if (i == segmentStart + 1 && uri[segmentStart] == '.') {\r\n                    // Given \"abc/def/./ghi\", remove \"./\" to get \"abc/def/ghi\".\r\n                    uri.delete(segmentStart, nextSegmentStart)\r\n                    limit -= nextSegmentStart - segmentStart\r\n                    i = segmentStart\r\n                } else if (i == segmentStart + 2 && uri[segmentStart] == '.' && uri[segmentStart + 1] == '.') {\r\n                    // Given \"abc/def/../ghi\", remove \"def/../\" to get \"abc/ghi\".\r\n                    val prevSegmentStart = uri.lastIndexOf(\"/\", segmentStart - 2) + 1\r\n                    val removeFrom = if (prevSegmentStart > offset) prevSegmentStart else offset\r\n                    uri.delete(removeFrom, nextSegmentStart)\r\n                    limit -= nextSegmentStart - removeFrom\r\n                    segmentStart = prevSegmentStart\r\n                    i = prevSegmentStart\r\n                } else {\r\n                    i++\r\n                    segmentStart = i\r\n                }\r\n            }\r\n            return uri.toString()\r\n        }\r\n\r\n        /**\r\n         * Calculates indices of the constituent components of a URI.\r\n         *\r\n         * @param uriString The URI as a string.\r\n         * @return The corresponding indices.\r\n         */\r\n        private fun getUriIndices(uriString: String?): IntArray {\r\n            val indices = IntArray(INDEX_COUNT)\r\n            if (uriString.isNullOrEmpty()) {\r\n                indices[SCHEME_COLON] = -1\r\n                return indices\r\n            }\r\n\r\n            // Determine outer structure from right to left.\r\n            // Uri = scheme \":\" hier-part [ \"?\" query ] [ \"#\" fragment ]\r\n            val length = uriString.length\r\n            var fragmentIndex = uriString.indexOf('#')\r\n            if (fragmentIndex == -1) {\r\n                fragmentIndex = length\r\n            }\r\n            var queryIndex = uriString.indexOf('?')\r\n            if (queryIndex == -1 || queryIndex > fragmentIndex) {\r\n                // '#' before '?': '?' is within the fragment.\r\n                queryIndex = fragmentIndex\r\n            }\r\n            // Slashes are allowed only in hier-part so any colon after the first slash is part of the\r\n            // hier-part, not the scheme colon separator.\r\n            var schemeIndexLimit = uriString.indexOf('/')\r\n            if (schemeIndexLimit == -1 || schemeIndexLimit > queryIndex) {\r\n                schemeIndexLimit = queryIndex\r\n            }\r\n            var schemeIndex = uriString.indexOf(':')\r\n            if (schemeIndex > schemeIndexLimit) {\r\n                // '/' before ':'\r\n                schemeIndex = -1\r\n            }\r\n\r\n            // Determine hier-part structure: hier-part = \"//\" authority path / path\r\n            // This block can also cope with schemeIndex == -1.\r\n            val hasAuthority =\r\n                schemeIndex + 2 < queryIndex && uriString[schemeIndex + 1] == '/' && uriString[schemeIndex + 2] == '/'\r\n            var pathIndex: Int\r\n            if (hasAuthority) {\r\n                pathIndex = uriString.indexOf('/', schemeIndex + 3) // find first '/' after \"://\"\r\n                if (pathIndex == -1 || pathIndex > queryIndex) {\r\n                    pathIndex = queryIndex\r\n                }\r\n            } else {\r\n                pathIndex = schemeIndex + 1\r\n            }\r\n\r\n            indices[SCHEME_COLON] = schemeIndex\r\n            indices[PATH] = pathIndex\r\n            indices[QUERY] = queryIndex\r\n            indices[FRAGMENT] = fragmentIndex\r\n            return indices\r\n        }\r\n    }\r\n\r\n    object C {\r\n        /**\r\n         * UUID for the ClearKey DRM scheme.\r\n         *\r\n         *\r\n         * ClearKey is supported on Android devices running Android 5.0 (API Level 21) and up.\r\n         */\r\n        val CLEARKEY_UUID = UUID(-0x1d8e62a7567a4c37L, 0x781AB030AF78D30EL)\r\n\r\n        /**\r\n         * UUID for the Widevine DRM scheme.\r\n         *\r\n         *\r\n         * Widevine is supported on Android devices running Android 4.3 (API Level 18) and up.\r\n         */\r\n        val WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L)\r\n\r\n        /**\r\n         * UUID for the PlayReady DRM scheme.\r\n         *\r\n         *\r\n         * PlayReady is supported on all AndroidTV devices. Note that most other Android devices do not\r\n         * provide PlayReady support.\r\n         */\r\n        val PLAYREADY_UUID = UUID(-0x65fb0f8667bfbd7aL, -0x546d19a41f77a06bL)\r\n\r\n\r\n        /** \"cenc\" scheme type name as defined in ISO/IEC 23001-7:2016.  */\r\n        const val CENC_TYPE_cenc: String = \"cenc\"\r\n\r\n        /** \"cbc1\" scheme type name as defined in ISO/IEC 23001-7:2016.  */\r\n        const val CENC_TYPE_cbc1: String = \"cbc1\"\r\n\r\n        /** \"cens\" scheme type name as defined in ISO/IEC 23001-7:2016.  */\r\n        const val CENC_TYPE_cens: String = \"cens\"\r\n\r\n        /** \"cbcs\" scheme type name as defined in ISO/IEC 23001-7:2016.  */\r\n        const val CENC_TYPE_cbcs: String = \"cbcs\"\r\n\r\n\r\n        // LINT.IfChange(role_flags)\r\n        /** Indicates a main track.  */\r\n        const val ROLE_FLAG_MAIN: Int = 1\r\n\r\n        /**\r\n         * Indicates an alternate track. For example a video track recorded from an different view point\r\n         * than the main track(s).\r\n         */\r\n        const val ROLE_FLAG_ALTERNATE: Int = 1 shl 1\r\n\r\n        /**\r\n         * Indicates a supplementary track, meaning the track has lower importance than the main track(s).\r\n         * For example a video track that provides a visual accompaniment to a main audio track.\r\n         */\r\n        const val ROLE_FLAG_SUPPLEMENTARY: Int = 1 shl 2\r\n\r\n        /** Indicates the track contains commentary, for example from the director.  */\r\n        const val ROLE_FLAG_COMMENTARY: Int = 1 shl 3\r\n\r\n        /**\r\n         * Indicates the track is in a different language from the original, for example dubbed audio or\r\n         * translated captions.\r\n         */\r\n        const val ROLE_FLAG_DUB: Int = 1 shl 4\r\n\r\n        /** Indicates the track contains information about a current emergency.  */\r\n        const val ROLE_FLAG_EMERGENCY: Int = 1 shl 5\r\n\r\n        /**\r\n         * Indicates the track contains captions. This flag may be set on video tracks to indicate the\r\n         * presence of burned in captions.\r\n         */\r\n        const val ROLE_FLAG_CAPTION: Int = 1 shl 6\r\n\r\n        /**\r\n         * Indicates the track contains subtitles. This flag may be set on video tracks to indicate the\r\n         * presence of burned in subtitles.\r\n         */\r\n        const val ROLE_FLAG_SUBTITLE: Int = 1 shl 7\r\n\r\n        /** Indicates the track contains a visual sign-language interpretation of an audio track.  */\r\n        const val ROLE_FLAG_SIGN: Int = 1 shl 8\r\n\r\n        /** Indicates the track contains an audio or textual description of a video track.  */\r\n        const val ROLE_FLAG_DESCRIBES_VIDEO: Int = 1 shl 9\r\n\r\n        /** Indicates the track contains a textual description of music and sound.  */\r\n        const val ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND: Int = 1 shl 10\r\n\r\n        /** Indicates the track is designed for improved intelligibility of dialogue.  */\r\n        const val ROLE_FLAG_ENHANCED_DIALOG_INTELLIGIBILITY: Int = 1 shl 11\r\n\r\n        /** Indicates the track contains a transcription of spoken dialog.  */\r\n        const val ROLE_FLAG_TRANSCRIBES_DIALOG: Int = 1 shl 12\r\n\r\n        /** Indicates the track contains a text that has been edited for ease of reading.  */\r\n        const val ROLE_FLAG_EASY_TO_READ: Int = 1 shl 13\r\n\r\n        /** Indicates the track is intended for trick play.  */\r\n        const val ROLE_FLAG_TRICK_PLAY: Int = 1 shl 14\r\n\r\n\r\n        /** A type constant for a fake or empty track.  */\r\n        const val TRACK_TYPE_NONE: Int = -2\r\n\r\n        /** A type constant for tracks of unknown type.  */\r\n        const val TRACK_TYPE_UNKNOWN: Int = -1\r\n\r\n        /** A type constant for tracks of some default type, where the type itself is unknown.  */\r\n        const val TRACK_TYPE_DEFAULT: Int = 0\r\n\r\n        /** A type constant for audio tracks.  */\r\n        const val TRACK_TYPE_AUDIO: Int = 1\r\n\r\n        /** A type constant for video tracks.  */\r\n        const val TRACK_TYPE_VIDEO: Int = 2\r\n\r\n        /** A type constant for text tracks.  */\r\n        const val TRACK_TYPE_TEXT: Int = 3\r\n\r\n        /** A type constant for image tracks.  */\r\n        const val TRACK_TYPE_IMAGE: Int = 4\r\n\r\n        /** A type constant for metadata tracks.  */\r\n        const val TRACK_TYPE_METADATA: Int = 5\r\n\r\n        /** A type constant for camera motion tracks.  */\r\n        const val TRACK_TYPE_CAMERA_MOTION: Int = 6\r\n\r\n\r\n        // LINT.IfChange(selection_flags)\r\n        /** Indicates that the track should be selected if user preferences do not state otherwise.  */\r\n        const val SELECTION_FLAG_DEFAULT: Int = 1\r\n\r\n        /**\r\n         * Indicates that the track should be selected if its language matches the language of the\r\n         * selected audio track and user preferences do not state otherwise. Only applies to text tracks.\r\n         *\r\n         *\r\n         * Tracks with this flag generally provide translation for elements that don't match the\r\n         * declared language of the selected audio track (e.g. speech in an alien language). See [Netflix's summary](https://partnerhelp.netflixstudios.com/hc/en-us/articles/217558918)\r\n         * for more info.\r\n         */\r\n        const val SELECTION_FLAG_FORCED: Int = 1 shl 1 // 2\r\n\r\n        /**\r\n         * Indicates that the player may choose to play the track in absence of an explicit user\r\n         * preference.\r\n         */\r\n        const val SELECTION_FLAG_AUTOSELECT: Int = 1 shl 2 // 4\r\n    }\r\n\r\n\r\n    object MimeTypes {\r\n        const val BASE_TYPE_VIDEO: String = \"video\"\r\n        const val BASE_TYPE_AUDIO: String = \"audio\"\r\n        const val BASE_TYPE_TEXT: String = \"text\"\r\n        const val BASE_TYPE_IMAGE: String = \"image\"\r\n        const val BASE_TYPE_APPLICATION: String = \"application\"\r\n\r\n        // video/ MIME types\r\n        const val VIDEO_MP4: String = \"$BASE_TYPE_VIDEO/mp4\"\r\n        const val VIDEO_MATROSKA: String = \"$BASE_TYPE_VIDEO/x-matroska\"\r\n        const val VIDEO_WEBM: String = \"$BASE_TYPE_VIDEO/webm\"\r\n        const val VIDEO_H263: String = \"$BASE_TYPE_VIDEO/3gpp\"\r\n        const val VIDEO_H264: String = \"$BASE_TYPE_VIDEO/avc\"\r\n        const val VIDEO_APV: String = \"$BASE_TYPE_VIDEO/apv\"\r\n        const val VIDEO_H265: String = \"$BASE_TYPE_VIDEO/hevc\"\r\n        const val VIDEO_VP8: String = \"$BASE_TYPE_VIDEO/x-vnd.on2.vp8\"\r\n        const val VIDEO_VP9: String = \"$BASE_TYPE_VIDEO/x-vnd.on2.vp9\"\r\n        const val VIDEO_AV1: String = \"$BASE_TYPE_VIDEO/av01\"\r\n        const val VIDEO_MP2T: String = \"$BASE_TYPE_VIDEO/mp2t\"\r\n        const val VIDEO_MP4V: String = \"$BASE_TYPE_VIDEO/mp4v-es\"\r\n        const val VIDEO_MPEG: String = \"$BASE_TYPE_VIDEO/mpeg\"\r\n        const val VIDEO_PS: String = \"$BASE_TYPE_VIDEO/mp2p\"\r\n        const val VIDEO_MPEG2: String = \"$BASE_TYPE_VIDEO/mpeg2\"\r\n        const val VIDEO_VC1: String = \"$BASE_TYPE_VIDEO/wvc1\"\r\n        const val VIDEO_DIVX: String = \"$BASE_TYPE_VIDEO/divx\"\r\n        const val VIDEO_FLV: String = \"$BASE_TYPE_VIDEO/x-flv\"\r\n        const val VIDEO_DOLBY_VISION: String = \"$BASE_TYPE_VIDEO/dolby-vision\"\r\n        const val VIDEO_OGG: String = \"$BASE_TYPE_VIDEO/ogg\"\r\n        const val VIDEO_AVI: String = \"$BASE_TYPE_VIDEO/x-msvideo\"\r\n        const val VIDEO_MJPEG: String = \"$BASE_TYPE_VIDEO/mjpeg\"\r\n        const val VIDEO_MP42: String = \"$BASE_TYPE_VIDEO/mp42\"\r\n        const val VIDEO_MP43: String = \"$BASE_TYPE_VIDEO/mp43\"\r\n        const val VIDEO_MV_HEVC: String = \"$BASE_TYPE_VIDEO/mv-hevc\"\r\n        const val VIDEO_RAW: String = \"$BASE_TYPE_VIDEO/raw\"\r\n        const val VIDEO_UNKNOWN: String = \"$BASE_TYPE_VIDEO/x-unknown\"\r\n\r\n\r\n        // audio/ MIME types\r\n        const val AUDIO_MP4: String = \"$BASE_TYPE_AUDIO/mp4\"\r\n        const val AUDIO_AAC: String = \"$BASE_TYPE_AUDIO/mp4a-latm\"\r\n        const val AUDIO_MATROSKA: String = \"$BASE_TYPE_AUDIO/x-matroska\"\r\n        const val AUDIO_WEBM: String = \"$BASE_TYPE_AUDIO/webm\"\r\n        const val AUDIO_MPEG: String = \"$BASE_TYPE_AUDIO/mpeg\"\r\n        const val AUDIO_MPEG_L1: String = \"$BASE_TYPE_AUDIO/mpeg-L1\"\r\n        const val AUDIO_MPEG_L2: String = \"$BASE_TYPE_AUDIO/mpeg-L2\"\r\n        const val AUDIO_MPEGH_MHA1: String = \"$BASE_TYPE_AUDIO/mha1\"\r\n        const val AUDIO_MPEGH_MHM1: String = \"$BASE_TYPE_AUDIO/mhm1\"\r\n        const val AUDIO_RAW: String = \"$BASE_TYPE_AUDIO/raw\"\r\n        const val AUDIO_ALAW: String = \"$BASE_TYPE_AUDIO/g711-alaw\"\r\n        const val AUDIO_MLAW: String = \"$BASE_TYPE_AUDIO/g711-mlaw\"\r\n        const val AUDIO_AC3: String = \"$BASE_TYPE_AUDIO/ac3\"\r\n        const val AUDIO_E_AC3: String = \"$BASE_TYPE_AUDIO/eac3\"\r\n        const val AUDIO_E_AC3_JOC: String = \"$BASE_TYPE_AUDIO/eac3-joc\"\r\n        const val AUDIO_AC4: String = \"$BASE_TYPE_AUDIO/ac4\"\r\n        const val AUDIO_TRUEHD: String = \"$BASE_TYPE_AUDIO/true-hd\"\r\n        const val AUDIO_DTS: String = \"$BASE_TYPE_AUDIO/vnd.dts\"\r\n        const val AUDIO_DTS_HD: String = \"$BASE_TYPE_AUDIO/vnd.dts.hd\"\r\n        const val AUDIO_DTS_EXPRESS: String = \"$BASE_TYPE_AUDIO/vnd.dts.hd;profile=lbr\"\r\n        const val AUDIO_DTS_X: String = \"$BASE_TYPE_AUDIO/vnd.dts.uhd;profile=p2\"\r\n        const val AUDIO_VORBIS: String = \"$BASE_TYPE_AUDIO/vorbis\"\r\n        const val AUDIO_OPUS: String = \"$BASE_TYPE_AUDIO/opus\"\r\n        const val AUDIO_AMR: String = \"$BASE_TYPE_AUDIO/amr\"\r\n        const val AUDIO_AMR_NB: String = \"$BASE_TYPE_AUDIO/3gpp\"\r\n        const val AUDIO_AMR_WB: String = \"$BASE_TYPE_AUDIO/amr-wb\"\r\n        const val AUDIO_FLAC: String = \"$BASE_TYPE_AUDIO/flac\"\r\n        const val AUDIO_ALAC: String = \"$BASE_TYPE_AUDIO/alac\"\r\n        const val AUDIO_MSGSM: String = \"$BASE_TYPE_AUDIO/gsm\"\r\n        const val AUDIO_OGG: String = \"$BASE_TYPE_AUDIO/ogg\"\r\n        const val AUDIO_WAV: String = \"$BASE_TYPE_AUDIO/wav\"\r\n        const val AUDIO_MIDI: String = \"$BASE_TYPE_AUDIO/midi\"\r\n        const val AUDIO_IAMF: String = \"$BASE_TYPE_AUDIO/iamf\"\r\n\r\n        const val AUDIO_EXOPLAYER_MIDI: String = \"$BASE_TYPE_AUDIO/x-exoplayer-midi\"\r\n\r\n        const val AUDIO_UNKNOWN: String = \"$BASE_TYPE_AUDIO/x-unknown\"\r\n\r\n\r\n        // text/ MIME types\r\n        const val TEXT_VTT: String = \"$BASE_TYPE_TEXT/vtt\"\r\n        const val TEXT_SSA: String = \"$BASE_TYPE_TEXT/x-ssa\"\r\n        const val TEXT_UNKNOWN: String = \"$BASE_TYPE_TEXT/x-unknown\"\r\n\r\n\r\n        // application/ MIME types\r\n        const val APPLICATION_MP4: String = \"$BASE_TYPE_APPLICATION/mp4\"\r\n        const val APPLICATION_WEBM: String = \"$BASE_TYPE_APPLICATION/webm\"\r\n\r\n        const val APPLICATION_MATROSKA: String = \"$BASE_TYPE_APPLICATION/x-matroska\"\r\n\r\n        const val APPLICATION_MPD: String = \"$BASE_TYPE_APPLICATION/dash+xml\"\r\n        const val APPLICATION_M3U8: String = \"$BASE_TYPE_APPLICATION/x-mpegURL\"\r\n        const val APPLICATION_SS: String = \"$BASE_TYPE_APPLICATION/vnd.ms-sstr+xml\"\r\n        const val APPLICATION_ID3: String = \"$BASE_TYPE_APPLICATION/id3\"\r\n        const val APPLICATION_CEA608: String = \"$BASE_TYPE_APPLICATION/cea-608\"\r\n        const val APPLICATION_CEA708: String = \"$BASE_TYPE_APPLICATION/cea-708\"\r\n        const val APPLICATION_SUBRIP: String = \"$BASE_TYPE_APPLICATION/x-subrip\"\r\n        const val APPLICATION_TTML: String = \"$BASE_TYPE_APPLICATION/ttml+xml\"\r\n        const val APPLICATION_TX3G: String = \"$BASE_TYPE_APPLICATION/x-quicktime-tx3g\"\r\n        const val APPLICATION_MP4VTT: String = \"$BASE_TYPE_APPLICATION/x-mp4-vtt\"\r\n        const val APPLICATION_MP4CEA608: String = \"$BASE_TYPE_APPLICATION/x-mp4-cea-608\"\r\n\r\n\r\n        const val APPLICATION_VOBSUB: String = \"$BASE_TYPE_APPLICATION/vobsub\"\r\n        const val APPLICATION_PGS: String = \"$BASE_TYPE_APPLICATION/pgs\"\r\n        const val APPLICATION_SCTE35: String = \"$BASE_TYPE_APPLICATION/x-scte35\"\r\n        const val APPLICATION_SDP: String = \"$BASE_TYPE_APPLICATION/sdp\"\r\n\r\n        const val APPLICATION_CAMERA_MOTION: String = \"$BASE_TYPE_APPLICATION/x-camera-motion\"\r\n\r\n        const val APPLICATION_DEPTH_METADATA: String = \"$BASE_TYPE_APPLICATION/x-depth-metadata\"\r\n\r\n        const val APPLICATION_EMSG: String = \"$BASE_TYPE_APPLICATION/x-emsg\"\r\n        const val APPLICATION_DVBSUBS: String = \"$BASE_TYPE_APPLICATION/dvbsubs\"\r\n        const val APPLICATION_EXIF: String = \"$BASE_TYPE_APPLICATION/x-exif\"\r\n        const val APPLICATION_ICY: String = \"$BASE_TYPE_APPLICATION/x-icy\"\r\n        const val APPLICATION_AIT: String = \"$BASE_TYPE_APPLICATION/vnd.dvb.ait\"\r\n        const val APPLICATION_RTSP: String = \"$BASE_TYPE_APPLICATION/x-rtsp\"\r\n\r\n        const val APPLICATION_MEDIA3_CUES: String = \"$BASE_TYPE_APPLICATION/x-media3-cues\"\r\n\r\n        /** MIME type for an image URI loaded from an external image management framework.  */\r\n        const val APPLICATION_EXTERNALLY_LOADED_IMAGE: String = \"$BASE_TYPE_APPLICATION/x-image-uri\"\r\n\r\n\r\n        // image/ MIME types\r\n        const val IMAGE_JPEG: String = \"$BASE_TYPE_IMAGE/jpeg\"\r\n        const val IMAGE_JPEG_R: String = \"$BASE_TYPE_IMAGE/jpeg_r\"\r\n        const val IMAGE_PNG: String = \"$BASE_TYPE_IMAGE/png\"\r\n        const val IMAGE_HEIF: String = \"$BASE_TYPE_IMAGE/heif\"\r\n        const val IMAGE_HEIC: String = \"$BASE_TYPE_IMAGE/heic\"\r\n        const val IMAGE_AVIF: String = \"$BASE_TYPE_IMAGE/avif\"\r\n        const val IMAGE_BMP: String = \"$BASE_TYPE_IMAGE/bmp\"\r\n        const val IMAGE_WEBP: String = \"$BASE_TYPE_IMAGE/webp\"\r\n        const val IMAGE_RAW: String = \"$BASE_TYPE_IMAGE/raw\"\r\n\r\n        /**\r\n         * A non-standard codec string for E-AC3-JOC. Use of this constant allows for disambiguation\r\n         * between regular E-AC3 (\"ec-3\") and E-AC3-JOC (\"ec+3\") streams from the codec string alone. The\r\n         * standard is to use \"ec-3\" for both, as per the [MP4RA\r\n * registered codec types](https://mp4ra.org/#/codecs).\r\n         */\r\n        const val CODEC_E_AC3_JOC: String = \"ec+3\"\r\n\r\n        data class Mp4aObjectType(val objectTypeIndication: Int, val audioObjectTypeIndication: Int)\r\n\r\n        private\r\n        val MP4A_RFC_6381_CODEC_PATTERN: Regex =\r\n            Regex(\"^mp4a\\\\.([a-zA-Z0-9]{2})(?:\\\\.([0-9]{1,2}))?$\")\r\n\r\n        /**\r\n         * Returns whether the given `codecs` and `supplementalCodecs` correspond to a valid\r\n         * Dolby Vision codec.\r\n         *\r\n         * @param codecs An RFC 6381 codecs string for the base codec. may be null.\r\n         * @param supplementalCodecs An optional RFC 6381 codecs string for supplemental codecs.\r\n         * @return Whether the given `codecs` and `supplementalCodecs` correspond to a valid\r\n         * Dolby Vision codec.\r\n         */\r\n        fun isDolbyVisionCodec(\r\n            codecs: String?, supplementalCodecs: String?\r\n        ): Boolean {\r\n            if (codecs == null) {\r\n                return false\r\n            }\r\n            if (codecs.startsWith(\"dvhe\") || codecs.startsWith(\"dvh1\")) {\r\n                // profile 5\r\n                return true\r\n            }\r\n            if (supplementalCodecs == null) {\r\n                return false\r\n            }\r\n            // profiles 8, 9 and 10\r\n            return (supplementalCodecs.startsWith(\"dvhe\") && codecs.startsWith(\"hev1\"))\r\n                    || (supplementalCodecs.startsWith(\"dvh1\") && codecs.startsWith(\"hvc1\"))\r\n                    || (supplementalCodecs.startsWith(\"dvav\") && codecs.startsWith(\"avc3\"))\r\n                    || (supplementalCodecs.startsWith(\"dva1\") && codecs.startsWith(\"avc1\"))\r\n                    || (supplementalCodecs.startsWith(\"dav1\") && codecs.startsWith(\"av01\"))\r\n        }\r\n\r\n        /**\r\n         * Returns the [Mp4aObjectType] of an RFC 6381 MP4 audio codec string.\r\n         *\r\n         *\r\n         * Per https://mp4ra.org/#/object_types and https://tools.ietf.org/html/rfc6381#section-3.3, an\r\n         * MP4 codec string has the form:\r\n         *\r\n         * <pre>\r\n         * ~~~~~~~~~~~~~~ Object Type Indication (OTI) byte in hex\r\n         * mp4a.[a-zA-Z0-9]{2}(.[0-9]{1,2})?\r\n         * ~~~~~~~~~~ audio OTI, decimal. Only for certain OTI.\r\n        </pre> *\r\n         *\r\n         * For example, mp4a.40.2 has an OTI of 0x40 and an audio OTI of 2.\r\n         *\r\n         * @param codec An RFC 6381 MP4 audio codec string.\r\n         * @return The [Mp4aObjectType], or `null` if the input was invalid.\r\n         */\r\n        fun getObjectTypeFromMp4aRFC6381CodecString(codec: String?): Mp4aObjectType? {\r\n            val groups = MP4A_RFC_6381_CODEC_PATTERN.find(codec ?: return null)?.groupValues\r\n            if (groups.isNullOrEmpty()) {\r\n                return null\r\n            }\r\n            val objectTypeIndicationHex: String = groups[1]\r\n            val audioObjectTypeIndicationDec: String? = groups.getOrNull(2)\r\n            val objectTypeIndication: Int\r\n            var audioObjectTypeIndication = 0\r\n            try {\r\n                objectTypeIndication = objectTypeIndicationHex.toInt(16)\r\n                if (audioObjectTypeIndicationDec != null) {\r\n                    audioObjectTypeIndication = audioObjectTypeIndicationDec.toInt()\r\n                }\r\n            } catch (e: NumberFormatException) {\r\n                return null\r\n            }\r\n            return Mp4aObjectType(objectTypeIndication, audioObjectTypeIndication)\r\n        }\r\n\r\n        fun getMimeTypeFromMp4ObjectType(objectType: Int): String? {\r\n            return when (objectType) {\r\n                0x20 -> VIDEO_MP4V\r\n                0x21 -> VIDEO_H264\r\n                0x23 -> VIDEO_H265\r\n                0x60, 0x61, 0x62, 0x63, 0x64, 0x65 -> VIDEO_MPEG2\r\n                0x6A -> VIDEO_MPEG\r\n                0x69, 0x6B -> AUDIO_MPEG\r\n                0x6C -> MimeTypes.IMAGE_JPEG\r\n                0xA3 -> VIDEO_VC1\r\n                0xB1 -> VIDEO_VP9\r\n                0x40, 0x66, 0x67, 0x68 -> AUDIO_AAC\r\n                0xA5 -> AUDIO_AC3\r\n                0xA6 -> AUDIO_E_AC3\r\n                0xA9, 0xAC -> AUDIO_DTS\r\n                0xAA, 0xAB -> AUDIO_DTS_HD\r\n                0xAD -> AUDIO_OPUS\r\n                0xAE -> AUDIO_AC4\r\n                0xDD -> AUDIO_VORBIS\r\n                else -> null\r\n            }\r\n        }\r\n\r\n        fun getMediaMimeType(codecOrNull: String?): String? {\r\n            var codec = codecOrNull ?: return null\r\n            codec = codec.trim().lowercase()\r\n            if (codec.startsWith(\"avc1\") || codec.startsWith(\"avc3\")) {\r\n                return MimeTypes.VIDEO_H264\r\n            } else if (codec.startsWith(\"hev1\") || codec.startsWith(\"hvc1\")) {\r\n                return MimeTypes.VIDEO_H265\r\n            } else if (codec.startsWith(\"dvav\")\r\n                || codec.startsWith(\"dva1\")\r\n                || codec.startsWith(\"dvhe\")\r\n                || codec.startsWith(\"dvh1\")\r\n            ) {\r\n                return MimeTypes.VIDEO_DOLBY_VISION\r\n            } else if (codec.startsWith(\"av01\")) {\r\n                return MimeTypes.VIDEO_AV1\r\n            } else if (codec.startsWith(\"vp9\") || codec.startsWith(\"vp09\")) {\r\n                return MimeTypes.VIDEO_VP9\r\n            } else if (codec.startsWith(\"vp8\") || codec.startsWith(\"vp08\")) {\r\n                return MimeTypes.VIDEO_VP8\r\n            } else if (codec.startsWith(\"mp4a\")) {\r\n                var mimeType: String? = null\r\n                if (codec.startsWith(\"mp4a.\")) {\r\n                    val objectType: Mp4aObjectType? = getObjectTypeFromMp4aRFC6381CodecString(codec)\r\n                    if (objectType != null) {\r\n                        mimeType = getMimeTypeFromMp4ObjectType(objectType.objectTypeIndication)\r\n                    }\r\n                }\r\n                return mimeType ?: MimeTypes.AUDIO_AAC\r\n            } else if (codec.startsWith(\"mha1\")) {\r\n                return MimeTypes.AUDIO_MPEGH_MHA1\r\n            } else if (codec.startsWith(\"mhm1\")) {\r\n                return MimeTypes.AUDIO_MPEGH_MHM1\r\n            } else if (codec.startsWith(\"ac-3\") || codec.startsWith(\"dac3\")) {\r\n                return MimeTypes.AUDIO_AC3\r\n            } else if (codec.startsWith(\"ec-3\") || codec.startsWith(\"dec3\")) {\r\n                return AUDIO_E_AC3\r\n            } else if (codec.startsWith(CODEC_E_AC3_JOC)) {\r\n                return AUDIO_E_AC3_JOC\r\n            } else if (codec.startsWith(\"ac-4\") || codec.startsWith(\"dac4\")) {\r\n                return MimeTypes.AUDIO_AC4\r\n            } else if (codec.startsWith(\"dtsc\")) {\r\n                return MimeTypes.AUDIO_DTS\r\n            } else if (codec.startsWith(\"dtse\")) {\r\n                return MimeTypes.AUDIO_DTS_EXPRESS\r\n            } else if (codec.startsWith(\"dtsh\") || codec.startsWith(\"dtsl\")) {\r\n                return MimeTypes.AUDIO_DTS_HD\r\n            } else if (codec.startsWith(\"dtsx\")) {\r\n                return MimeTypes.AUDIO_DTS_X\r\n            } else if (codec.startsWith(\"opus\")) {\r\n                return MimeTypes.AUDIO_OPUS\r\n            } else if (codec.startsWith(\"vorbis\")) {\r\n                return MimeTypes.AUDIO_VORBIS\r\n            } else if (codec.startsWith(\"flac\")) {\r\n                return MimeTypes.AUDIO_FLAC\r\n            } else if (codec.startsWith(\"stpp\")) {\r\n                return MimeTypes.APPLICATION_TTML\r\n            } else if (codec.startsWith(\"wvtt\")) {\r\n                return TEXT_VTT\r\n            } else if (codec.contains(\"cea708\")) {\r\n                return APPLICATION_CEA708\r\n            } else if (codec.contains(\"eia608\") || codec.contains(\"cea608\")) {\r\n                return APPLICATION_CEA608\r\n            } else {\r\n                return null //getCustomMimeTypeForCodec(codec)\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Returns the top-level type of `mimeType`, or null if `mimeType` is null or does not\r\n         * contain a forward slash character (`'/'`).\r\n         */\r\n        private fun getTopLevelType(mimeType: String?): String? {\r\n            if (mimeType == null) {\r\n                return null\r\n            }\r\n            val indexOfSlash = mimeType.indexOf('/')\r\n            if (indexOfSlash == -1) {\r\n                return null\r\n            }\r\n            return mimeType.substring(0, indexOfSlash)\r\n        }\r\n\r\n        fun isAudio(mimeType: String?): Boolean = BASE_TYPE_AUDIO == getTopLevelType(mimeType)\r\n        fun isVideo(mimeType: String?): Boolean = BASE_TYPE_VIDEO == getTopLevelType(mimeType)\r\n        fun isText(mimeType: String?): Boolean = BASE_TYPE_TEXT == getTopLevelType(mimeType)\r\n                || APPLICATION_MEDIA3_CUES == mimeType\r\n                || APPLICATION_CEA608 == mimeType\r\n                || APPLICATION_CEA708 == mimeType\r\n                || APPLICATION_MP4CEA608 == mimeType\r\n                || APPLICATION_SUBRIP == mimeType\r\n                || APPLICATION_TTML == mimeType\r\n                || APPLICATION_TX3G == mimeType\r\n                || APPLICATION_MP4VTT == mimeType\r\n                || APPLICATION_VOBSUB == mimeType\r\n                || APPLICATION_PGS == mimeType\r\n                || APPLICATION_DVBSUBS == mimeType;\r\n\r\n        fun isImage(mimeType: String?): Boolean = BASE_TYPE_IMAGE == getTopLevelType(mimeType)\r\n                || APPLICATION_EXTERNALLY_LOADED_IMAGE == mimeType;\r\n\r\n\r\n        fun getTrackType(mimeType: String?): Int {\r\n            return if (mimeType.isNullOrEmpty()) {\r\n                C.TRACK_TYPE_UNKNOWN\r\n            } else if (isAudio(mimeType)) {\r\n                C.TRACK_TYPE_AUDIO\r\n            } else if (isVideo(mimeType)) {\r\n                C.TRACK_TYPE_VIDEO\r\n            } else if (isText(mimeType)) {\r\n                C.TRACK_TYPE_TEXT\r\n            } else if (isImage(mimeType)) {\r\n                C.TRACK_TYPE_IMAGE\r\n            } else if (APPLICATION_ID3 == mimeType\r\n                || APPLICATION_EMSG == mimeType\r\n                || APPLICATION_SCTE35 == mimeType\r\n                || APPLICATION_ICY == mimeType\r\n                || APPLICATION_AIT == mimeType\r\n            ) {\r\n                C.TRACK_TYPE_METADATA\r\n            } else if (APPLICATION_CAMERA_MOTION == mimeType) {\r\n                C.TRACK_TYPE_CAMERA_MOTION\r\n            } else {\r\n                C.TRACK_TYPE_UNKNOWN\r\n                //getTrackTypeForCustomMimeType(mimeType)\r\n            }\r\n        }\r\n\r\n        /*@TrackType*/\r\n        fun getTrackTypeOfCodec(codec: String?): Int {\r\n            return getTrackType(getMediaMimeType(codec))\r\n        }\r\n    }\r\n\r\n    object Mp4Box {\r\n        /** Size of a full box header, in bytes.  */\r\n        const val FULL_HEADER_SIZE: Int = 12\r\n        const val TYPE_pssh: Int = 0x70737368\r\n    }\r\n\r\n    object PsshAtomUtil {\r\n        fun buildPsshAtom(\r\n            systemId: UUID, keyIds: Array<UUID>?, data: ByteArray?\r\n        ): ByteArray {\r\n            val dataLength = data?.size ?: 0\r\n            var psshBoxLength: Int =\r\n                Mp4Box.FULL_HEADER_SIZE + 16 /* SystemId */ + 4 /* DataSize */ + dataLength\r\n            if (keyIds != null) {\r\n                psshBoxLength += 4 /* KID_count */ + (keyIds.size * 16) /* KIDs */\r\n            }\r\n            val psshBox: ByteBuffer = ByteBuffer.allocate(psshBoxLength)\r\n            psshBox.putInt(psshBoxLength)\r\n            psshBox.putInt(Mp4Box.TYPE_pssh)\r\n            psshBox.putInt(if (keyIds != null) 0x01000000 else 0 /* version=(buildV1Atom ? 1 : 0), flags=0 */)\r\n            psshBox.putLong(systemId.mostSignificantBits)\r\n            psshBox.putLong(systemId.leastSignificantBits)\r\n            if (keyIds != null) {\r\n                psshBox.putInt(keyIds.size)\r\n                for (keyId in keyIds) {\r\n                    psshBox.putLong(keyId.mostSignificantBits)\r\n                    psshBox.putLong(keyId.leastSignificantBits)\r\n                }\r\n            }\r\n            if (data != null && data.size != 0) {\r\n                psshBox.putInt(data.size)\r\n                psshBox.put(data)\r\n            } else {\r\n                psshBox.putInt(0)\r\n            }\r\n            return psshBox.array()\r\n        }\r\n    }\r\n\r\n    data class ParserException(\r\n        override val message: String?,\r\n        override val cause: Throwable?,\r\n        /**\r\n         * Whether the parsing error was caused by a bitstream not following the expected format. May be\r\n         * false when a parser encounters a legal condition which it does not support.\r\n         */\r\n        val contentIsMalformed: Boolean,\r\n        /** The [data type][DataType] of the parsed bitstream.  */\r\n        val dataType: Int\r\n    ) : IOException(message, cause) {\r\n        /** A data type constant for a manifest file.  */\r\n        companion object {\r\n            const val DATA_TYPE_MANIFEST: Int = 4\r\n            fun createForMalformedManifest(\r\n                message: String?,\r\n                cause: Throwable?\r\n            ): ParserException {\r\n                return ParserException(\r\n                    message,\r\n                    cause, /* contentIsMalformed= */\r\n                    true,\r\n                    DATA_TYPE_MANIFEST\r\n                )\r\n            }\r\n        }\r\n    }\r\n\r\n    data class DrmInitData(\r\n        val schemeType: String,\r\n        val schemeDatas: Array<SchemeData>,\r\n    )\r\n\r\n    @Throws(ParserException::class)\r\n    private fun parseStringAttr(\r\n        line: String, pattern: Regex, variableDefinitions: Map<String, String>\r\n    ): String = parseOptionalStringAttr(line, pattern, variableDefinitions)\r\n        ?: throw ParserException.createForMalformedManifest(\r\n            \"Couldn't match $pattern in $line\",  /* cause= */null\r\n        )\r\n\r\n\r\n    /**@PolyNull*/\r\n    private fun parseOptionalStringAttr(\r\n        line: String,\r\n        pattern: Regex,\r\n        /**@PolyNull*/\r\n        defaultValue: String?,\r\n        variableDefinitions: Map<String, String>?\r\n    ): String? {\r\n        val value: String? = pattern.find(line)?.groupValues?.get(1) ?: defaultValue\r\n        return if (variableDefinitions.isNullOrEmpty() || value == null)\r\n            value\r\n        else\r\n            replaceVariableReferences(value, variableDefinitions)\r\n    }\r\n\r\n    private fun replaceVariableReferences(\r\n        string: String, variableDefinitions: Map<String, String>?\r\n    ): String =\r\n        string.replace(REGEX_VARIABLE_REFERENCE) { matchResult ->\r\n            variableDefinitions?.get(matchResult.groupValues[1]) ?: matchResult.value\r\n        }\r\n\r\n\r\n    private fun parseOptionalStringAttr(\r\n        line: String, pattern: Regex, variableDefinitions: Map<String, String>?\r\n    ): String? {\r\n        return parseOptionalStringAttr(line, pattern, null, variableDefinitions)\r\n    }\r\n\r\n    @OptIn(ExperimentalEncodingApi::class)\r\n    @Throws(ParserException::class)\r\n    private fun parseDrmSchemeData(\r\n        line: String, keyFormat: String, variableDefinitions: Map<String, String>\r\n    ): SchemeData? {\r\n        val keyFormatVersions =\r\n            parseOptionalStringAttr(line, REGEX_KEYFORMATVERSIONS, \"1\", variableDefinitions)\r\n        if (KEYFORMAT_WIDEVINE_PSSH_BINARY == keyFormat) {\r\n            val uriString = parseStringAttr(line, REGEX_URI, variableDefinitions)\r\n            return SchemeData(\r\n                uuid = WIDEVINE_UUID,\r\n                mimeType = MimeTypes.VIDEO_MP4,\r\n                data = Base64.Default.decode(uriString.substring(uriString.indexOf(',')))\r\n            )\r\n        } else if (KEYFORMAT_WIDEVINE_PSSH_JSON == keyFormat) {\r\n            return SchemeData(\r\n                uuid = C.WIDEVINE_UUID,\r\n                mimeType = \"hls\",\r\n                data = line.toByteArray(charset = Charsets.UTF_8)\r\n            )\r\n        } else if (KEYFORMAT_PLAYREADY == keyFormat && \"1\" == keyFormatVersions) {\r\n            val uriString = parseStringAttr(line, REGEX_URI, variableDefinitions)\r\n            val data: ByteArray =\r\n                Base64.Default.decode(uriString.substring(uriString.indexOf(',')))\r\n            val psshData: ByteArray =\r\n                PsshAtomUtil.buildPsshAtom(\r\n                    systemId = C.PLAYREADY_UUID,\r\n                    keyIds = null,\r\n                    data = data\r\n                )\r\n            return SchemeData(\r\n                uuid = C.PLAYREADY_UUID,\r\n                mimeType = MimeTypes.VIDEO_MP4,\r\n                data = psshData\r\n            )\r\n        }\r\n        return null\r\n    }\r\n\r\n    private fun parseEncryptionScheme(method: String): String {\r\n        return if (METHOD_SAMPLE_AES_CENC == method || METHOD_SAMPLE_AES_CTR == method)\r\n            C.CENC_TYPE_cenc\r\n        else\r\n            C.CENC_TYPE_cbcs\r\n    }\r\n\r\n\r\n    //@SelectionFlags\r\n    private fun parseSelectionFlags(line: String): Int {\r\n        var flags = 0\r\n        if (parseOptionalBooleanAttribute(line, REGEX_DEFAULT, false)) {\r\n            flags = flags or C.SELECTION_FLAG_DEFAULT\r\n        }\r\n        if (parseOptionalBooleanAttribute(line, REGEX_FORCED, false)) {\r\n            flags = flags or C.SELECTION_FLAG_FORCED\r\n        }\r\n        if (parseOptionalBooleanAttribute(line, REGEX_AUTOSELECT, false)) {\r\n            flags = flags or C.SELECTION_FLAG_AUTOSELECT\r\n        }\r\n        return flags\r\n    }\r\n\r\n    //@RoleFlags\r\n    private fun parseRoleFlags(\r\n        line: String, variableDefinitions: Map<String, String>\r\n    ): Int {\r\n        val concatenatedCharacteristics =\r\n            parseOptionalStringAttr(line, REGEX_CHARACTERISTICS, variableDefinitions)\r\n        if (concatenatedCharacteristics.isNullOrEmpty()) {\r\n            return 0\r\n        }\r\n        val characteristics = Util.split(concatenatedCharacteristics, \",\")\r\n        //@RoleFlags\r\n        var roleFlags = 0\r\n        if (characteristics.contains(\"public.accessibility.describes-video\")) {\r\n            roleFlags = roleFlags or C.ROLE_FLAG_DESCRIBES_VIDEO\r\n        }\r\n        if (characteristics.contains(\"public.accessibility.transcribes-spoken-dialog\")) {\r\n            roleFlags = roleFlags or C.ROLE_FLAG_TRANSCRIBES_DIALOG\r\n        }\r\n        if (characteristics.contains(\"public.accessibility.describes-music-and-sound\")) {\r\n            roleFlags = roleFlags or C.ROLE_FLAG_DESCRIBES_MUSIC_AND_SOUND\r\n        }\r\n        if (characteristics.contains(\"public.easy-to-read\")) {\r\n            roleFlags = roleFlags or C.ROLE_FLAG_EASY_TO_READ\r\n        }\r\n        return roleFlags\r\n    }\r\n\r\n    private fun parseOptionalBooleanAttribute(\r\n        line: String, pattern: Regex, defaultValue: Boolean\r\n    ): Boolean {\r\n        val matcher = pattern.find(line)?.groupValues?.get(1)\r\n        return if (matcher != null) {\r\n            matcher == BOOLEAN_TRUE\r\n        } else {\r\n            defaultValue\r\n        }\r\n    }\r\n\r\n    data class Variant(\r\n        val url: URI,\r\n        val format: Format,\r\n        val videoGroupId: String?,\r\n        val audioGroupId: String?,\r\n        val subtitleGroupId: String?,\r\n        val captionGroupId: String?,\r\n    ) {\r\n        /** This is unfortunately impossible to do 100%, given that audio detection is hard without TS inspection, \r\n         * however this is a generous safety abstraction */\r\n        fun isPlayableStandalone(playlist: HlsMultivariantPlaylist): Boolean =\r\n            mustContainAudio(playlist) && !isTrickPlay()\r\n\r\n        /**\r\n         * https://datatracker.ietf.org/doc/html/rfc8216#section-4.3.3.6\r\n         * > The EXT-X-I-FRAMES-ONLY tag indicates that each Media Segment in the\r\n         * > Playlist describes a single I-frame.  I-frames are encoded video\r\n         * > frames whose encoding does not depend on any other frame.  I-frame\r\n         * > Playlists can be used for trick play, such as fast forward, rapid\r\n         * > reverse, and scrubbing.\r\n         */\r\n        fun isTrickPlay(): Boolean = (format.roleFlags and C.ROLE_FLAG_TRICK_PLAY != 0)\r\n\r\n        /**\r\n        https://datatracker.ietf.org/doc/html/rfc6381:\r\n        > When the 'codecs' parameter is used, it MUST contain all codecs\r\n        > indicated by the content present in the body part.  The 'codecs'\r\n        > parameter MUST NOT include any codecs that are not indicated by any\r\n        > media elements in the body part.\r\n\r\n        This means that codecs cant be used\r\n        \"|| format.codecs?.split(\",\")?.any { MimeTypes.isAudio(MimeTypes.getMediaMimeType(it)) } == true\"\r\n        They may be used for harsher restriction on \"audioGroupId == null\", but codecs is optional\r\n\r\n        https://datatracker.ietf.org/doc/html/rfc8216\r\n        > Since the EXT-X-STREAM-INF tag has no AUDIO attribute, all video\r\n        > Renditions would be required to contain the audio.\r\n\r\n        However it may still contain audio with the AUDIO attribute, therefore we also check the audio with that groupId:\r\n\r\n        > If the media type is VIDEO or AUDIO, a missing URI attribute\r\n        > indicates that the media data for this Rendition is included in the\r\n        > Media Playlist of any EXT-X-STREAM-INF tag referencing this EXT-\r\n        > X-MEDIA tag.\r\n\r\n        But this is not foolproof, because TS segments needs to be investigated to be sure as I do not see any\r\n        way to detect this from the m3u8 playlist\r\n         */\r\n        fun mustContainAudio(playlist: HlsMultivariantPlaylist): Boolean =\r\n            audioGroupId == null || (playlist.audios.firstOrNull { it.groupId == audioGroupId }?.url == null)\r\n    }\r\n\r\n    data class Rendition(\r\n        /** The rendition's url, or null if the tag does not have a URI attribute. */\r\n        val url: URI?,\r\n\r\n        /** Format information associated with this rendition. */\r\n        val format: Format,\r\n\r\n        /** The group to which this rendition belongs. */\r\n        val groupId: String,\r\n\r\n        /** The name of the rendition. */\r\n        val name: String\r\n    )\r\n\r\n    data class HlsMultivariantPlaylist(\r\n        /** The base uri. Used to resolve relative paths. */\r\n        val baseUri: String,\r\n\r\n        /** The list of tags in the playlist. */\r\n        val tags: List<String>,\r\n\r\n        /** All of the media playlist URLs referenced by the playlist. */\r\n        //val mediaPlaylistUrls: List<URI>,\r\n\r\n        /** The variants declared by the playlist. */\r\n        val variants: List<Variant>,\r\n\r\n        /** The video renditions declared by the playlist. */\r\n        val videos: List<Rendition>,\r\n\r\n        /** The audio renditions declared by the playlist. */\r\n        val audios: List<Rendition>,\r\n\r\n        /** The subtitle renditions declared by the playlist. */\r\n        val subtitles: List<Rendition>,\r\n\r\n        /** The closed caption renditions declared by the playlist. */\r\n        val closedCaptions: List<Rendition>,\r\n\r\n\r\n        /**\r\n         * The format of the audio muxed in the variants. May be null if the playlist does not declare any\r\n         * muxed audio.\r\n         */\r\n        val muxedAudioFormat: Format? = null,\r\n\r\n        /**\r\n         * The format of the closed captions declared by the playlist. May be empty if the playlist\r\n         * explicitly declares no captions are available, or null if the playlist does not declare any\r\n         * captions information.\r\n         */\r\n        val muxedCaptionFormats: List<Format>?,\r\n\r\n        /** Contains variable definitions, as defined by the #EXT-X-DEFINE tag. */\r\n        val variableDefinitions: Map<String, String>,\r\n\r\n        /** DRM initialization data derived from #EXT-X-SESSION-KEY tags. */\r\n        val sessionKeyDrmInitData: List<DrmInitData>,\r\n\r\n        /**\r\n         * Whether the media is formed of independent segments, as defined by the\r\n         * #EXT-X-INDEPENDENT-SEGMENTS tag.\r\n         */\r\n        val hasIndependentSegments: Boolean,\r\n    )\r\n\r\n    data class VariantInfo(\r\n        /**\r\n         * The average bitrate as declared by the AVERAGE-BANDWIDTH attribute of the EXT-X-STREAM-INF\r\n         * tag, or {@link Format#NO_VALUE} if the attribute is not declared.\r\n         */\r\n        val averageBitrate: Int = Format.NO_VALUE,\r\n\r\n        /** The peak bitrate as declared by the BANDWIDTH attribute of the EXT-X-STREAM-INF tag. */\r\n        val peakBitrate: Int,\r\n\r\n        /**\r\n         * The VIDEO value as defined in the EXT-X-STREAM-INF tag, or null if the VIDEO attribute is not\r\n         * present.\r\n         */\r\n        val videoGroupId: String? = null,\r\n\r\n        /**\r\n         * The AUDIO value as defined in the EXT-X-STREAM-INF tag, or null if the AUDIO attribute is not\r\n         * present.\r\n         */\r\n        val audioGroupId: String? = null,\r\n\r\n        /**\r\n         * The SUBTITLES value as defined in the EXT-X-STREAM-INF tag, or null if the SUBTITLES\r\n         * attribute is not present.\r\n         */\r\n        val subtitleGroupId: String? = null,\r\n\r\n        /**\r\n         * The CLOSED-CAPTIONS value as defined in the EXT-X-STREAM-INF tag, or null if the\r\n         * CLOSED-CAPTIONS attribute is not present.\r\n         */\r\n        val captionGroupId: String? = null,\r\n    )\r\n\r\n    data class Format(\r\n\r\n        /** An identifier for the format, or null if unknown or not applicable. */\r\n        val id: String? = null,\r\n\r\n        /**\r\n         * The default human readable label, or null if unknown or not applicable.\r\n         *\r\n         * <p>If non-null, the same label will be part of {@link #labels} too. If null, {@link #labels}\r\n         * will be empty.\r\n         */\r\n        val label: String? = null,\r\n\r\n        /**\r\n         * The human readable list of labels, or an empty list if unknown or not applicable.\r\n         *\r\n         * <p>If non-empty, the default {@link #label} will be part of this list. If empty, the default\r\n         * {@link #label} will be null.\r\n         */\r\n        //val labels: List<Label> = emptyList(),\r\n\r\n        /**\r\n         * The language as an IETF BCP 47 conformant tag, or null if unknown or not applicable.\r\n         * Check [com.lagradost.cloudstream3.utils.SubtitleHelper].\r\n         *\r\n         * See locales on:\r\n         * https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/availableLocales.json\r\n         * https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry\r\n         * https://android.googlesource.com/platform/frameworks/base/+/android-16.0.0_r2/core/res/res/values/locale_config.xml\r\n         * https://iso639-3.sil.org/code_tables/639/data/all\r\n        */\r\n        val language: String? = null,\r\n\r\n        /** Track selection flags. */\r\n        //  @C.SelectionFlags\r\n        val selectionFlags: Int = 0,\r\n\r\n        /** Track role flags. */\r\n        // @C.RoleFlags\r\n        val roleFlags: Int = 0,\r\n\r\n        /** The auxiliary track type. */\r\n        // @C.AuxiliaryTrackType\r\n        //val auxiliaryTrackType: Int,\r\n\r\n        /**\r\n         * The average bitrate in bits per second, or {@link #NO_VALUE} if unknown or not applicable. The\r\n         * way in which this field is populated depends on the type of media to which the format\r\n         * corresponds:\r\n         *\r\n         * <ul>\r\n         *   <li>DASH representations: Always {@link Format#NO_VALUE}.\r\n         *   <li>HLS variants: The {@code AVERAGE-BANDWIDTH} attribute defined on the corresponding {@code\r\n         *       EXT-X-STREAM-INF} tag in the multivariant playlist, or {@link Format#NO_VALUE} if not\r\n         *       present.\r\n         *   <li>SmoothStreaming track elements: The {@code Bitrate} attribute defined on the\r\n         *       corresponding {@code TrackElement} in the manifest, or {@link Format#NO_VALUE} if not\r\n         *       present.\r\n         *   <li>Progressive container formats: Often {@link Format#NO_VALUE}, but may be populated with\r\n         *       the average bitrate of the container if known.\r\n         *   <li>Sample formats: Often {@link Format#NO_VALUE}, but may be populated with the average\r\n         *       bitrate of the stream of samples with type {@link #sampleMimeType} if known. Note that if\r\n         *       {@link #sampleMimeType} is a compressed format (e.g., {@link MimeTypes#AUDIO_AAC}), then\r\n         *       this bitrate is for the stream of still compressed samples.\r\n         * </ul>\r\n         */\r\n        val averageBitrate: Int = NO_VALUE,\r\n\r\n        /**\r\n         * The peak bitrate in bits per second, or {@link #NO_VALUE} if unknown or not applicable. The way\r\n         * in which this field is populated depends on the type of media to which the format corresponds:\r\n         *\r\n         * <ul>\r\n         *   <li>DASH representations: The {@code @bandwidth} attribute of the corresponding {@code\r\n         *       Representation} element in the manifest.\r\n         *   <li>HLS variants: The {@code BANDWIDTH} attribute defined on the corresponding {@code\r\n         *       EXT-X-STREAM-INF} tag.\r\n         *   <li>SmoothStreaming track elements: Always {@link Format#NO_VALUE}.\r\n         *   <li>Progressive container formats: Often {@link Format#NO_VALUE}, but may be populated with\r\n         *       the peak bitrate of the container if known.\r\n         *   <li>Sample formats: Often {@link Format#NO_VALUE}, but may be populated with the peak bitrate\r\n         *       of the stream of samples with type {@link #sampleMimeType} if known. Note that if {@link\r\n         *       #sampleMimeType} is a compressed format (e.g., {@link MimeTypes#AUDIO_AAC}), then this\r\n         *       bitrate is for the stream of still compressed samples.\r\n         * </ul>\r\n         */\r\n        val peakBitrate: Int = NO_VALUE,\r\n\r\n        /**\r\n         * The bitrate in bits per second. This is the peak bitrate if known, or else the average bitrate\r\n         * if known, or else {@link Format#NO_VALUE}. Equivalent to: {@code peakBitrate != NO_VALUE ?\r\n         * peakBitrate : averageBitrate}.\r\n         */\r\n        val bitrate: Int = NO_VALUE,\r\n\r\n        /** Codecs of the format as described in RFC 6381, or null if unknown or not applicable. */\r\n        val codecs: String? = null,\r\n\r\n        /** Metadata, or null if unknown or not applicable. */\r\n        //val metadata: Metadata? = null,\r\n\r\n        /**\r\n         * An extra opaque object that can be added to the {@link Format} to provide additional\r\n         * information that can be passed through the player.\r\n         *\r\n         * <p>This value is not included in serialized {@link Bundle} instances of this class that are\r\n         * used to transfer data to other processes.\r\n         */\r\n        //@UnstableApi @Nullable public final Object customData;\r\n\r\n        // Container specific.\r\n\r\n        /** The MIME type of the container, or null if unknown or not applicable. */\r\n        val containerMimeType: String? = null,\r\n\r\n        // Sample specific.\r\n\r\n        /** The sample MIME type, or null if unknown or not applicable. */\r\n        val sampleMimeType: String? = null,\r\n\r\n        /**\r\n         * The maximum size of a buffer of data (typically one sample), or {@link #NO_VALUE} if unknown or\r\n         * not applicable.\r\n         */\r\n        //@UnstableApi public final int maxInputSize;\r\n\r\n        /**\r\n         * The maximum number of samples that must be stored to correctly re-order samples from decode\r\n         * order to presentation order.\r\n         */\r\n        //@UnstableApi public final int maxNumReorderSamples;\r\n\r\n        /**\r\n         * Initialization data that must be provided to the decoder. Will not be null, but may be empty if\r\n         * initialization data is not required.\r\n         */\r\n        //@UnstableApi public final List<byte[]> initializationData;\r\n\r\n        /** DRM initialization data if the stream is protected, or null otherwise. */\r\n        //@UnstableApi @Nullable public final DrmInitData drmInitData;\r\n\r\n        /**\r\n         * For samples that contain subsamples, this is an offset that should be added to subsample\r\n         * timestamps. A value of {@link #OFFSET_SAMPLE_RELATIVE} indicates that subsample timestamps are\r\n         * relative to the timestamps of their parent samples.\r\n         */\r\n        //@UnstableApi public final long subsampleOffsetUs;\r\n\r\n        /**\r\n         * Indicates whether the stream contains preroll samples.\r\n         *\r\n         * <p>When this field is set to {@code true}, it means that the stream includes decode-only\r\n         * samples that occur before the intended playback start position. These samples are necessary for\r\n         * decoding but are not meant to be rendered and should be skipped after decoding.\r\n         */\r\n        //@UnstableApi public final boolean hasPrerollSamples;\r\n\r\n        // Video specific.\r\n\r\n        /** The width of the video in pixels, or {@link #NO_VALUE} if unknown or not applicable. */\r\n        val width: Int = NO_VALUE,\r\n\r\n        /** The height of the video in pixels, or {@link #NO_VALUE} if unknown or not applicable. */\r\n        val height: Int = NO_VALUE,\r\n\r\n        /** The frame rate in frames per second, or {@link #NO_VALUE} if unknown or not applicable. */\r\n        val frameRate: Float = NO_VALUE.toFloat(),\r\n\r\n        /**\r\n         * The clockwise rotation that should be applied to the video for it to be rendered in the correct\r\n         * orientation, or 0 if unknown or not applicable. Only 0, 90, 180 and 270 are supported.\r\n         */\r\n        val rotationDegrees: Int = 0,\r\n\r\n        /** The width to height ratio of pixels in the video, or 1.0 if unknown or not applicable. */\r\n        val pixelWidthHeightRatio: Float = 1.0f,\r\n\r\n        /** The projection data for 360/VR video, or null if not applicable. */\r\n        //@UnstableApi @Nullable public final byte[] projectionData;\r\n\r\n        /**\r\n         * The stereo layout for 360/3D/VR video, or {@link #NO_VALUE} if not applicable. Valid stereo\r\n         * modes are {@link C#STEREO_MODE_MONO}, {@link C#STEREO_MODE_TOP_BOTTOM}, {@link\r\n         * C#STEREO_MODE_LEFT_RIGHT}, {@link C#STEREO_MODE_STEREO_MESH}.\r\n         */\r\n        //@UnstableApi public final @C.StereoMode int stereoMode;\r\n\r\n        /** The color metadata associated with the video, or null if not applicable. */\r\n        //@UnstableApi @Nullable public final ColorInfo colorInfo;\r\n\r\n        /**\r\n         * The maximum number of temporal scalable sub-layers in the video bitstream, or {@link #NO_VALUE}\r\n         * if not applicable.\r\n         */\r\n        //@UnstableApi public final int maxSubLayers;\r\n\r\n        // Audio specific.\r\n\r\n        /** The number of audio channels, or {@link #NO_VALUE} if unknown or not applicable. */\r\n        val channelCount: Int = NO_VALUE,\r\n\r\n        /** The audio sampling rate in Hz, or {@link #NO_VALUE} if unknown or not applicable. */\r\n        //public final int sampleRate;\r\n\r\n        /**\r\n         * The {@link C.PcmEncoding} for PCM or losslessly compressed audio. Set to {@link #NO_VALUE} for\r\n         * other media types.\r\n         */\r\n        //@UnstableApi public final @C.PcmEncoding int pcmEncoding;\r\n\r\n        /**\r\n         * The number of frames to trim from the start of the decoded audio stream, or 0 if not\r\n         * applicable.\r\n         */\r\n        //@UnstableApi public final int encoderDelay;\r\n\r\n        /**\r\n         * The number of frames to trim from the end of the decoded audio stream, or 0 if not applicable.\r\n         */\r\n        //@UnstableApi public final int encoderPadding;\r\n\r\n        // Text specific.\r\n\r\n        /** The Accessibility channel, or {@link #NO_VALUE} if not known or applicable. */\r\n        val accessibilityChannel: Int = NO_VALUE,\r\n\r\n        /**\r\n         * The replacement behavior that should be followed when handling consecutive samples in a\r\n         * {@linkplain C#TRACK_TYPE_TEXT text track} of type {@link MimeTypes#APPLICATION_MEDIA3_CUES}.\r\n         */\r\n        //@UnstableApi public final @CueReplacementBehavior int cueReplacementBehavior;\r\n\r\n        // Image specific.\r\n\r\n        /**\r\n         * The number of horizontal tiles in an image, or {@link #NO_VALUE} if not known or applicable.\r\n         */\r\n        //@UnstableApi public final int tileCountHorizontal;\r\n\r\n        /** The number of vertical tiles in an image, or {@link #NO_VALUE} if not known or applicable. */\r\n        //@UnstableApi public final int tileCountVertical;\r\n\r\n        // Provided by source.\r\n\r\n        /**\r\n         * The type of crypto that must be used to decode samples associated with this format, or {@link\r\n         * C#CRYPTO_TYPE_NONE} if the content is not encrypted. Cannot be {@link C#CRYPTO_TYPE_NONE} if\r\n         * {@link #drmInitData} is non-null, but may be {@link C#CRYPTO_TYPE_UNSUPPORTED} to indicate that\r\n         * the samples are encrypted using an unsupported crypto type.\r\n         */\r\n        //@UnstableApi public final @C.CryptoType int cryptoType;\r\n    ) {\r\n        companion object {\r\n            const val NO_VALUE: Int = -1\r\n        }\r\n    }\r\n\r\n    private fun getVariantWithVideoGroup(variants: ArrayList<Variant>, groupId: String): Variant? =\r\n        variants.firstOrNull { variant -> groupId == variant.videoGroupId }\r\n\r\n    private fun getVariantWithAudioGroup(variants: ArrayList<Variant>, groupId: String): Variant? =\r\n        variants.firstOrNull { variant -> groupId == variant.audioGroupId }\r\n\r\n    private fun getVariantWithSubtitleGroup(\r\n        variants: ArrayList<Variant>,\r\n        groupId: String\r\n    ): Variant? = variants.firstOrNull { variant -> groupId == variant.subtitleGroupId }\r\n\r\n    private fun isDolbyVisionFormat(\r\n        videoRange: String?,\r\n        codecs: String?,\r\n        supplementalCodecs: String?,\r\n        supplementalProfiles: String?\r\n    ): Boolean {\r\n        if (!MimeTypes.isDolbyVisionCodec(codecs, supplementalCodecs)) {\r\n            return false\r\n        }\r\n        if (supplementalCodecs == null) {\r\n            // Dolby Vision profile 5 that doesn't define supplemental codecs.\r\n            return true\r\n        }\r\n        if (videoRange == null || supplementalProfiles == null) {\r\n            // Video range and supplemental profiles need to be defined for a full validity check.\r\n            return false\r\n        }\r\n        if ((videoRange == \"PQ\" && supplementalProfiles != \"db1p\")\r\n            || (videoRange == \"SDR\" && supplementalProfiles != \"db2g\")\r\n            || (videoRange == \"HLG\" && !supplementalProfiles.startsWith(\"db4\"))\r\n        ) { // db4g or db4h\r\n            return false\r\n        }\r\n        return true\r\n    }\r\n\r\n\r\n    fun parse(baseUri: String, text: String): HlsMultivariantPlaylist? {\r\n        val lines = text.lines()\r\n        if (lines.any { it.startsWith(TAG_STREAM_INF) }) {\r\n            return parseMultivariantPlaylist(lines.iterator(), baseUri)\r\n        }\r\n        return null\r\n    }\r\n\r\n    @Throws(IOException::class)\r\n    private fun parseMultivariantPlaylist(\r\n        iterator: Iterator<String>, baseUri: String\r\n    ): HlsMultivariantPlaylist {\r\n        val urlToVariantInfos: HashMap<URI, ArrayList<VariantInfo>?> =\r\n            HashMap<URI, ArrayList<VariantInfo>?>()\r\n        val variableDefinitions = HashMap<String, String>()\r\n        val variants: ArrayList<Variant> = ArrayList<Variant>()\r\n        val videos: ArrayList<Rendition> = ArrayList<Rendition>()\r\n        val audios: ArrayList<Rendition> = ArrayList<Rendition>()\r\n        val subtitles: ArrayList<Rendition> = ArrayList<Rendition>()\r\n        val closedCaptions: ArrayList<Rendition> = ArrayList<Rendition>()\r\n        val mediaTags = ArrayList<String>()\r\n        val sessionKeyDrmInitData: ArrayList<DrmInitData> = ArrayList<DrmInitData>()\r\n        val tags = ArrayList<String>()\r\n        var muxedAudioFormat: Format? = null\r\n        var muxedCaptionFormats: ArrayList<Format> = arrayListOf()\r\n        var noClosedCaptions = false\r\n        var hasIndependentSegmentsTag = false\r\n\r\n        var line: String\r\n        while (iterator.hasNext()) {\r\n            line = iterator.next()\r\n\r\n            if (line.startsWith(TAG_PREFIX)) {\r\n                // We expose all tags through the playlist.\r\n                tags.add(line)\r\n            }\r\n            val isIFrameOnlyVariant = line.startsWith(TAG_I_FRAME_STREAM_INF)\r\n\r\n            if (line.startsWith(TAG_DEFINE)) {\r\n                variableDefinitions[parseStringAttr(line, REGEX_NAME, variableDefinitions)] =\r\n                    parseStringAttr(line, REGEX_VALUE, variableDefinitions)\r\n            } else if (line == TAG_INDEPENDENT_SEGMENTS) {\r\n                hasIndependentSegmentsTag = true\r\n            } else if (line.startsWith(TAG_MEDIA)) {\r\n                // Media tags are parsed at the end to include codec information from #EXT-X-STREAM-INF\r\n                // tags.\r\n                mediaTags.add(line)\r\n            } else if (line.startsWith(TAG_SESSION_KEY)) {\r\n                val keyFormat: String =\r\n                    parseOptionalStringAttr(\r\n                        line,\r\n                        REGEX_KEYFORMAT,\r\n                        KEYFORMAT_IDENTITY,\r\n                        variableDefinitions\r\n                    )!!\r\n                val schemeData: SchemeData? =\r\n                    parseDrmSchemeData(line, keyFormat, variableDefinitions)\r\n                if (schemeData != null) {\r\n                    val method: String =\r\n                        parseStringAttr(line, REGEX_METHOD, variableDefinitions)\r\n                    val scheme: String = parseEncryptionScheme(method)\r\n                    sessionKeyDrmInitData.add(DrmInitData(scheme, arrayOf(schemeData)))\r\n                }\r\n            } else if (line.startsWith(TAG_STREAM_INF) || isIFrameOnlyVariant) {\r\n                noClosedCaptions = noClosedCaptions or line.contains(ATTR_CLOSED_CAPTIONS_NONE)\r\n                val roleFlags = if (isIFrameOnlyVariant) C.ROLE_FLAG_TRICK_PLAY else 0\r\n                val peakBitrate: Int = parseIntAttr(line, REGEX_BANDWIDTH)\r\n                val averageBitrate: Int =\r\n                    parseOptionalIntAttr(line, REGEX_AVERAGE_BANDWIDTH, -1)\r\n                val videoRange: String? =\r\n                    parseOptionalStringAttr(line, REGEX_VIDEO_RANGE, variableDefinitions)\r\n                var codecs: String? =\r\n                    parseOptionalStringAttr(line, REGEX_CODECS, variableDefinitions)\r\n                val supplementalCodecsStrings: String? =\r\n                    parseOptionalStringAttr(\r\n                        line,\r\n                        REGEX_SUPPLEMENTAL_CODECS,\r\n                        variableDefinitions\r\n                    )\r\n                var supplementalCodecs: String? = null\r\n                var supplementalProfiles: String? = null // i.e. Compatibility brand\r\n                if (supplementalCodecsStrings != null) {\r\n                    val supplementalCodecsString: Array<String> =\r\n                        Util.splitAtFirst(supplementalCodecsStrings, \",\")\r\n                    // TODO: Support more than one element\r\n                    val codecsAndProfiles: Array<String> = Util.split(\r\n                        supplementalCodecsString[0], \"/\"\r\n                    )\r\n                    supplementalCodecs = codecsAndProfiles[0]\r\n                    if (codecsAndProfiles.size > 1) {\r\n                        supplementalProfiles = codecsAndProfiles[1]\r\n                    }\r\n                }\r\n                var videoCodecs: String? = Util.getCodecsOfType(codecs, C.TRACK_TYPE_VIDEO)\r\n                if (isDolbyVisionFormat(\r\n                        videoRange, videoCodecs, supplementalCodecs, supplementalProfiles\r\n                    )\r\n                ) {\r\n                    videoCodecs = supplementalCodecs ?: videoCodecs\r\n                    val nonVideoCodecs: String? =\r\n                        Util.getCodecsWithoutType(codecs, C.TRACK_TYPE_VIDEO)\r\n                    codecs =\r\n                        if (nonVideoCodecs != null) \"$videoCodecs,$nonVideoCodecs\" else videoCodecs\r\n                }\r\n\r\n                val resolutionString: String? =\r\n                    parseOptionalStringAttr(line, REGEX_RESOLUTION, variableDefinitions)\r\n                var width: Int\r\n                var height: Int\r\n                if (resolutionString != null) {\r\n                    val widthAndHeight: Array<String> = Util.split(resolutionString, \"x\")\r\n                    width = widthAndHeight[0].toInt()\r\n                    height = widthAndHeight[1].toInt()\r\n                    if (width <= 0 || height <= 0) {\r\n                        // Resolution string is invalid.\r\n                        width = Format.NO_VALUE\r\n                        height = Format.NO_VALUE\r\n                    }\r\n                } else {\r\n                    width = Format.NO_VALUE\r\n                    height = Format.NO_VALUE\r\n                }\r\n                var frameRate: Float = Format.NO_VALUE.toFloat()\r\n                val frameRateString: String? =\r\n                    parseOptionalStringAttr(line, REGEX_FRAME_RATE, variableDefinitions)\r\n                if (frameRateString != null) {\r\n                    frameRate = frameRateString.toFloat()\r\n                }\r\n                val videoGroupId: String? =\r\n                    parseOptionalStringAttr(line, REGEX_VIDEO, variableDefinitions)\r\n                val audioGroupId: String? =\r\n                    parseOptionalStringAttr(line, REGEX_AUDIO, variableDefinitions)\r\n                val subtitlesGroupId: String? =\r\n                    parseOptionalStringAttr(line, REGEX_SUBTITLES, variableDefinitions)\r\n                val closedCaptionsGroupId: String? =\r\n                    parseOptionalStringAttr(line, REGEX_CLOSED_CAPTIONS, variableDefinitions)\r\n                val uri: URI\r\n                if (isIFrameOnlyVariant) {\r\n                    uri =\r\n                        UriUtil.resolveToUri(\r\n                            baseUri,\r\n                            parseStringAttr(line, REGEX_URI, variableDefinitions)\r\n                        )\r\n                } else if (!iterator.hasNext()) {\r\n                    throw ParserException.createForMalformedManifest(\r\n                        \"#EXT-X-STREAM-INF must be followed by another line\",  /* cause= */null\r\n                    )\r\n                } else {\r\n                    // The following line contains #EXT-X-STREAM-INF's URI.\r\n                    line = replaceVariableReferences(iterator.next(), variableDefinitions)\r\n                    uri = UriUtil.resolveToUri(baseUri, line)\r\n                }\r\n\r\n                val variant =\r\n                    Variant(\r\n                        url = uri,\r\n                        format = Format(\r\n                            id = variants.size.toString(),\r\n                            containerMimeType = MimeTypes.APPLICATION_M3U8,\r\n                            codecs = codecs,\r\n                            averageBitrate = averageBitrate,\r\n                            peakBitrate = peakBitrate,\r\n                            width = width,\r\n                            height = height,\r\n                            frameRate = frameRate,\r\n                            roleFlags = roleFlags,\r\n                        ),\r\n                        videoGroupId = videoGroupId,\r\n                        audioGroupId = audioGroupId,\r\n                        subtitleGroupId = subtitlesGroupId,\r\n                        captionGroupId = closedCaptionsGroupId\r\n                    )\r\n                variants.add(variant)\r\n                var variantInfosForUrl: ArrayList<VariantInfo>? = urlToVariantInfos[uri]\r\n                if (variantInfosForUrl == null) {\r\n                    variantInfosForUrl = ArrayList()\r\n                    urlToVariantInfos[uri] = variantInfosForUrl\r\n                }\r\n                variantInfosForUrl.add(\r\n                    VariantInfo(\r\n                        averageBitrate,\r\n                        peakBitrate,\r\n                        videoGroupId,\r\n                        audioGroupId,\r\n                        subtitlesGroupId,\r\n                        closedCaptionsGroupId\r\n                    )\r\n                )\r\n            }\r\n        }\r\n\r\n        // TODO: Don't deduplicate variants by URL.\r\n        val deduplicatedVariants = variants.distinctBy { it.url }\r\n        /*val deduplicatedVariants: ArrayList<Variant> = ArrayList<Variant>()\r\n        val urlsInDeduplicatedVariants = HashSet<URI>()\r\n        for (i in variants.indices) {\r\n            val variant: Variant = variants[i]\r\n            if (urlsInDeduplicatedVariants.add(variant.url)) {\r\n                Assertions.checkState(variant.format.metadata == null)\r\n                val hlsMetadataEntry: HlsTrackMetadataEntry =\r\n                    HlsTrackMetadataEntry( /* groupId= */\r\n                        null,  /* name= */\r\n                        null,\r\n                        checkNotNull(urlToVariantInfos[variant.url])\r\n                    )\r\n                val metadata = Metadata(hlsMetadataEntry)\r\n                val format: Format = variant.format.buildUpon().setMetadata(metadata).build()\r\n                deduplicatedVariants.add(variant.copyWithFormat(format))\r\n            }\r\n        }*/\r\n\r\n        for (i in mediaTags.indices) {\r\n            line = mediaTags[i]\r\n            val groupId: String = parseStringAttr(line, REGEX_GROUP_ID, variableDefinitions)\r\n            val name: String = parseStringAttr(line, REGEX_NAME, variableDefinitions)\r\n            var formatBuilder = Format(\r\n                id = \"$groupId:$name\",\r\n                roleFlags = parseRoleFlags(line, variableDefinitions),\r\n                selectionFlags = parseSelectionFlags(line),\r\n                label = name,\r\n                language = parseOptionalStringAttr(\r\n                    line,\r\n                    REGEX_LANGUAGE,\r\n                    variableDefinitions\r\n                ),\r\n                containerMimeType = MimeTypes.APPLICATION_M3U8,\r\n            )\r\n\r\n            val referenceUri: String? =\r\n                parseOptionalStringAttr(line, REGEX_URI, variableDefinitions)\r\n            val uri: URI? =\r\n                if (referenceUri == null) null else UriUtil.resolveToUri(baseUri, referenceUri)\r\n            //val metadata =\r\n            //    Metadata(HlsTrackMetadataEntry(groupId, name, emptyList<T>()))\r\n            when (parseStringAttr(line, REGEX_TYPE, variableDefinitions)) {\r\n                TYPE_VIDEO -> {\r\n                    val variant: Variant? = getVariantWithVideoGroup(variants, groupId)\r\n                    if (variant != null) {\r\n                        val variantFormat: Format = variant.format\r\n                        formatBuilder = formatBuilder.copy(\r\n                            height = variantFormat.height,\r\n                            width = variantFormat.width,\r\n                            frameRate = variantFormat.frameRate,\r\n                            codecs = Util.getCodecsOfType(variantFormat.codecs, C.TRACK_TYPE_VIDEO)\r\n                        )\r\n                    }\r\n                    if (uri == null) {\r\n                        // TODO: Remove this case and add a Rendition with a null uri to videos.\r\n                    } else {\r\n                        //formatBuilder.setMetadata(metadata)\r\n                        videos.add(Rendition(url = uri, format = formatBuilder, groupId, name))\r\n                    }\r\n                }\r\n\r\n                TYPE_AUDIO -> {\r\n                    var sampleMimeType: String? = null\r\n                    val variant = getVariantWithAudioGroup(variants, groupId)\r\n                    if (variant != null) {\r\n                        val codecs: String? =\r\n                            Util.getCodecsOfType(variant.format.codecs, C.TRACK_TYPE_AUDIO)\r\n                        formatBuilder = formatBuilder.copy(codecs = codecs)\r\n                        sampleMimeType = MimeTypes.getMediaMimeType(codecs)\r\n                    }\r\n                    val channelsString: String? =\r\n                        parseOptionalStringAttr(line, REGEX_CHANNELS, variableDefinitions)\r\n                    if (channelsString != null) {\r\n                        val channelCount: Int =\r\n                            Util.splitAtFirst(channelsString, \"/\")[0].toInt()\r\n                        formatBuilder = formatBuilder.copy(channelCount = channelCount)\r\n                        if (MimeTypes.AUDIO_E_AC3 == sampleMimeType && channelsString.endsWith(\r\n                                \"/JOC\"\r\n                            )\r\n                        ) {\r\n                            sampleMimeType = MimeTypes.AUDIO_E_AC3_JOC\r\n                            formatBuilder = formatBuilder.copy(codecs = MimeTypes.CODEC_E_AC3_JOC)\r\n                        }\r\n                    }\r\n                    val format = formatBuilder.copy(sampleMimeType = sampleMimeType)\r\n                    if (uri != null) {\r\n                        //formatBuilder.setMetadata(metadata)\r\n                        audios.add(Rendition(uri, format, groupId, name))\r\n                    } else if (variant != null) {\r\n                        // TODO: Remove muxedAudioFormat and add a Rendition with a null uri to audios.\r\n                        muxedAudioFormat = format\r\n                    }\r\n                }\r\n\r\n                TYPE_SUBTITLES -> {\r\n                    var sampleMimeType: String? = null\r\n                    val variant = getVariantWithSubtitleGroup(variants, groupId)\r\n                    if (variant != null) {\r\n                        val codecs: String? =\r\n                            Util.getCodecsOfType(variant.format.codecs, C.TRACK_TYPE_TEXT)\r\n                        formatBuilder = formatBuilder.copy(\r\n                            codecs = codecs,\r\n                        )\r\n                        sampleMimeType = MimeTypes.getMediaMimeType(codecs)\r\n                    }\r\n                    if (sampleMimeType == null) {\r\n                        sampleMimeType = MimeTypes.TEXT_VTT\r\n                    }\r\n                    if (uri != null) {\r\n                        subtitles.add(\r\n                            Rendition(\r\n                                uri,\r\n                                formatBuilder.copy(sampleMimeType = sampleMimeType),\r\n                                groupId,\r\n                                name\r\n                            )\r\n                        )\r\n                    } else {\r\n                        /*Log.w(\r\n                            LOG_TAG,\r\n                            \"EXT-X-MEDIA tag with missing mandatory URI attribute: skipping\"\r\n                        )*/\r\n                    }\r\n                }\r\n\r\n                TYPE_CLOSED_CAPTIONS -> {\r\n                    val instreamId: String =\r\n                        parseStringAttr(line, REGEX_INSTREAM_ID, variableDefinitions)\r\n                    val accessibilityChannel: Int\r\n                    val sampleMimeType: String\r\n                    if (instreamId.startsWith(\"CC\")) {\r\n                        sampleMimeType = MimeTypes.APPLICATION_CEA608\r\n                        accessibilityChannel = instreamId.substring(2).toInt()\r\n                    } else  /* starts with SERVICE */ {\r\n                        sampleMimeType = MimeTypes.APPLICATION_CEA708\r\n                        accessibilityChannel = instreamId.substring(7).toInt()\r\n                    }\r\n                    muxedCaptionFormats.add(\r\n                        formatBuilder.copy(\r\n                            sampleMimeType = sampleMimeType,\r\n                            accessibilityChannel = accessibilityChannel\r\n                        )\r\n                    )\r\n                }\r\n\r\n                else -> {}\r\n            }\r\n        }\r\n\r\n        if (noClosedCaptions) {\r\n            muxedCaptionFormats = arrayListOf()\r\n        }\r\n\r\n        return HlsMultivariantPlaylist(\r\n            baseUri = baseUri,\r\n            tags = tags,\r\n            variants = deduplicatedVariants,\r\n            videos = videos,\r\n            audios = audios,\r\n            subtitles = subtitles,\r\n            closedCaptions = closedCaptions,\r\n            muxedAudioFormat = muxedAudioFormat,\r\n            muxedCaptionFormats = muxedCaptionFormats,\r\n            hasIndependentSegments = hasIndependentSegmentsTag,\r\n            variableDefinitions = variableDefinitions,\r\n            sessionKeyDrmInitData = sessionKeyDrmInitData\r\n        )\r\n    }\r\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsHunter.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.lagradost.cloudstream3.mvvm.logError\nimport java.util.regex.Matcher\nimport java.util.regex.Pattern\nimport kotlin.math.pow\n\n//author: https://github.com/daarkdemon\nclass JsHunter(private val hunterJS: String) {\n\n    /**\n     * Detects whether the javascript is H.U.N.T.E.R coded.\n     *\n     * @return true if it's H.U.N.T.E.R coded.\n     */\n    fun detect(): Boolean {\n        val p = Pattern.compile(\"eval\\\\(function\\\\(h,u,n,t,e,r\\\\)\")\n        val searchResults = p.matcher(hunterJS)\n        return searchResults.find()\n    }\n\n    /**\n     * Unpack the javascript\n     *\n     * @return the javascript unhunt or null.\n     */\n\n    fun dehunt(): String? {\n        try {\n            val p: Pattern =\n                Pattern.compile(\n                    \"\"\"\\}\\(\"([^\"]+)\",[^,]+,\\s*\"([^\"]+)\",\\s*(\\d+),\\s*(\\d+)\"\"\",\n                    Pattern.DOTALL\n                )\n            val searchResults: Matcher = p.matcher(hunterJS)\n            if (searchResults.find() && searchResults.groupCount() == 4) {\n                val h = searchResults.group(1)!!\n                val n = searchResults.group(2)!!\n                val t = searchResults.group(3)!!.toInt()\n                val e = searchResults.group(4)!!.toInt()\n                return hunter(h, n, t, e)\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n        return null\n    }\n\n    private fun duf(d: String, e: Int, f: Int = 10): Int {\n        val str = \"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/\"\n        val g = str.toList()\n        val h = g.take(e)\n        val i = g.take(f)\n        val dList = d.reversed().toList()\n        var j = 0.0\n        for ((c, b) in dList.withIndex()) {\n            if (b in h) {\n                j += h.indexOf(b) * e.toDouble().pow(c)\n            }\n        }\n        var k = \"\"\n        while (j > 0) {\n            k = i[(j % f).toInt()] + k\n            j = (j - j % f) / f\n        }\n        return k.toIntOrNull() ?: 0\n    }\n\n    private fun hunter(h: String, n: String, t: Int, e: Int): String {\n        var result = \"\"\n        var i = 0\n        while (i < h.length) {\n            var j = 0\n            var s = \"\"\n            while (h[i] != n[e]) {\n                s += h[i]\n                i++\n            }\n            while (j < n.length) {\n                s = s.replace(n[j], j.digitToChar())\n                j++\n            }\n            result += (duf(s, e) - t).toChar()\n            i++\n        }\n        return result\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/JsUnpacker.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.lagradost.cloudstream3.mvvm.logError\nimport java.util.regex.Pattern\nimport kotlin.math.pow\n\n// https://github.com/cylonu87/JsUnpacker\nclass JsUnpacker(packedJS: String?) {\n    private var packedJS: String? = null\n\n    /**\n     * Detects whether the javascript is P.A.C.K.E.R. coded.\n     *\n     * @return true if it's P.A.C.K.E.R. coded.\n     */\n    fun detect(): Boolean {\n        val js = packedJS!!.replace(\" \", \"\")\n        val p = Pattern.compile(\"eval\\\\(function\\\\(p,a,c,k,e,[rd]\")\n        val m = p.matcher(js)\n        return m.find()\n    }\n\n    /**\n     * Unpack the javascript\n     *\n     * @return the javascript unpacked or null.\n     */\n    fun unpack(): String? {\n        val js = packedJS ?: return null\n        try {\n            var p =\n                Pattern.compile(\"\"\"\\}\\s*\\('(.*)',\\s*(.*?),\\s*(\\d+),\\s*'(.*?)'\\.split\\('\\|'\\)\"\"\", Pattern.DOTALL)\n            var m = p.matcher(js)\n            if (m.find() && m.groupCount() == 4) {\n                val payload = m.group(1)?.replace(\"\\\\'\", \"'\") ?: \"\"\n                val radixStr = m.group(2)\n                val countStr = m.group(3)\n                val symtab = (m.group(4)?.split(\"\\\\|\".toRegex()) ?: emptyList()).toTypedArray()\n                var radix = 36\n                var count = 0\n                try {\n                    radix = radixStr?.toIntOrNull() ?: radix\n                } catch (_: Exception) {\n                }\n                try {\n                    count = countStr?.toIntOrNull() ?: 0\n                } catch (_: Exception) {\n                }\n                if (symtab.size != count) {\n                    throw Exception(\"Unknown p.a.c.k.e.r. encoding\")\n                }\n                val unbase = Unbase(radix)\n                p = Pattern.compile(\"\"\"\\b[a-zA-Z0-9_]+\\b\"\"\")\n                m = p.matcher(payload)\n                val decoded = StringBuilder(payload)\n                var replaceOffset = 0\n                while (m.find()) {\n                    val word = m.group(0)\n                    val x = if (word == null) 0 else unbase.unbase(word)\n                    var value: String? = null\n                    if (x < symtab.size && x >= 0) {\n                        value = symtab[x]\n                    }\n                    if (!value.isNullOrEmpty() && !word.isNullOrEmpty()) {\n                        decoded.replace(m.start() + replaceOffset, m.end() + replaceOffset, value)\n                        replaceOffset += value.length - word.length\n                    }\n                }\n                return decoded.toString()\n            }\n        } catch (e: Exception) {\n            logError(e)\n        }\n        return null\n    }\n\n    private inner class Unbase(private val radix: Int) {\n        private val ALPHABET_62 = \"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\"\n        private val ALPHABET_95 =\n            \" !\\\"#$%&\\\\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\"\n        private var alphabet: String? = null\n        private var dictionary: HashMap<String, Int>? = null\n        fun unbase(str: String): Int {\n            var ret = 0\n            if (alphabet == null) {\n                ret = str.toInt(radix)\n            } else {\n                val tmp = StringBuilder(str).reverse().toString()\n                for (i in tmp.indices) {\n                    ret += (radix.toDouble().pow(i.toDouble()) * dictionary!![tmp.substring(i, i + 1)]!!).toInt()\n                }\n            }\n            return ret\n        }\n\n        init {\n            if (radix > 36) {\n                when {\n                    radix < 62 -> {\n                        alphabet = ALPHABET_62.substring(0, radix)\n                    }\n                    radix in 63..94 -> {\n                        alphabet = ALPHABET_95.substring(0, radix)\n                    }\n                    radix == 62 -> {\n                        alphabet = ALPHABET_62\n                    }\n                    radix == 95 -> {\n                        alphabet = ALPHABET_95\n                    }\n                }\n                dictionary = HashMap(95)\n                for (i in 0 until alphabet!!.length) {\n                    dictionary!![alphabet!!.substring(i, i + 1)] = i\n                }\n            }\n        }\n    }\n\n    /**\n     * @param packedJS javascript P.A.C.K.E.R. coded.\n     */\n    init {\n        this.packedJS = packedJS\n    }\n\n\n    companion object {\n        val c =\n            listOf(\n                0x63,\n                0x6f,\n                0x6d,\n                0x2e,\n                0x67,\n                0x6f,\n                0x6f,\n                0x67,\n                0x6c,\n                0x65,\n                0x2e,\n                0x61,\n                0x6e,\n                0x64,\n                0x72,\n                0x6f,\n                0x69,\n                0x64,\n                0x2e,\n                0x67,\n                0x6d,\n                0x73,\n                0x2e,\n                0x61,\n                0x64,\n                0x73,\n                0x2e,\n                0x4d,\n                0x6f,\n                0x62,\n                0x69,\n                0x6c,\n                0x65,\n                0x41,\n                0x64,\n                0x73\n            )\n        val z =\n            listOf(\n                0x63,\n                0x6f,\n                0x6d,\n                0x2e,\n                0x66,\n                0x61,\n                0x63,\n                0x65,\n                0x62,\n                0x6f,\n                0x6f,\n                0x6b,\n                0x2e,\n                0x61,\n                0x64,\n                0x73,\n                0x2e,\n                0x41,\n                0x64\n            )\n\n        fun String.load(): String? {\n            return try {\n                var load = this\n\n                for (q in c.indices) {\n                    if (c[q % 4] > 270) {\n                        load += c[q % 3]\n                    } else {\n                        load += c[q].toChar()\n                    }\n                }\n\n                Class.forName(load.substring(load.length - c.size, load.length)).name\n            } catch (_: Exception) {\n                try {\n                    var f = c[2].toChar().toString()\n                    for (w in z.indices) {\n                        f += z[w].toChar()\n                    }\n                    return Class.forName(f.substring(0b001, f.length)).name\n                } catch (_: Exception) {\n                    null\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/M3u8Helper.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.lagradost.api.Log\nimport com.lagradost.cloudstream3.ErrorLoadingException\nimport com.lagradost.cloudstream3.app\nimport kotlinx.coroutines.CancellationException\nimport kotlinx.coroutines.delay\nimport javax.crypto.Cipher\nimport javax.crypto.spec.IvParameterSpec\nimport javax.crypto.spec.SecretKeySpec\nimport kotlin.math.pow\n\n/** backwards api surface */\nclass M3u8Helper {\n    companion object {\n        suspend fun generateM3u8(\n            source: String,\n            streamUrl: String,\n            referer: String,\n            quality: Int? = null,\n            headers: Map<String, String> = mapOf(),\n            name: String = source\n        ): List<ExtractorLink> {\n            return M3u8Helper2.generateM3u8(source, streamUrl, referer, quality, headers, name)\n        }\n    }\n\n\n    data class M3u8Stream(\n        val streamUrl: String,\n        val quality: Int? = null,\n        val headers: Map<String, String> = mapOf()\n    )\n\n    suspend fun m3u8Generation(m3u8: M3u8Stream, returnThis: Boolean? = true): List<M3u8Stream> {\n        return M3u8Helper2.m3u8Generation(m3u8, returnThis ?: true)\n    }\n}\n\n\nobject M3u8Helper2 {\n    private val TAG = \"M3u8Helper\"\n\n    suspend fun generateM3u8(\n        source: String,\n        streamUrl: String,\n        referer: String,\n        quality: Int? = null,\n        headers: Map<String, String> = mapOf(),\n        name: String = source\n    ): List<ExtractorLink> {\n        return m3u8Generation(\n            M3u8Helper.M3u8Stream(\n                streamUrl = streamUrl,\n                quality = quality,\n                headers = headers,\n            ), true\n        )\n            .map { stream ->\n                newExtractorLink(\n                    source,\n                    name = name,\n                    stream.streamUrl,\n                    type = ExtractorLinkType.M3U8\n                ) {\n                    this.referer = referer\n                    this.quality = stream.quality ?: Qualities.Unknown.value\n                    this.headers = stream.headers\n                }\n            }\n    }\n\n    private val ENCRYPTION_DETECTION_REGEX = Regex(\"#EXT-X-KEY:METHOD=([^,]+),\")\n    private val ENCRYPTION_URL_IV_REGEX =\n        Regex(\"#EXT-X-KEY:METHOD=([^,]+),URI=\\\"([^\\\"]+)\\\"(?:,IV=(.*))?\")\n    private val QUALITY_REGEX =\n        Regex(\"\"\"#EXT-X-STREAM-INF:(?:(?:.*?(?:RESOLUTION=\\d+x(\\d+)).*?\\s+(.*))|(?:.*?\\s+(.*)))\"\"\")\n    private val TS_EXTENSION_REGEX =\n        Regex(\"\"\"#EXTINF:(([0-9]*[.])?[0-9]+|).*\\n(.+?\\n)\"\"\") // fuck it we ball, who cares about the type anyways\n    //Regex(\"\"\"(.*\\.(ts|jpg|html).*)\"\"\") //.jpg here 'case vizcloud uses .jpg instead of .ts\n\n    private fun absoluteExtensionDetermination(url: String): String? {\n        val split = url.split(\"/\")\n        val gg: String = split[split.size - 1].split(\"?\")[0]\n        return if (gg.contains(\".\")) {\n            gg.split(\".\").ifEmpty { null }?.last()\n        } else null\n    }\n\n    private fun toBytes16Big(n: Int): ByteArray {\n        return ByteArray(16) {\n            val fixed = n / 256.0.pow((15 - it))\n            (maxOf(0, fixed.toInt()) % 256).toByte()\n        }\n    }\n\n    private fun defaultIv(index: Int): ByteArray {\n        return toBytes16Big(index + 1)\n    }\n\n    fun getDecrypted(\n        secretKey: ByteArray,\n        data: ByteArray,\n        iv: ByteArray = byteArrayOf(),\n        index: Int,\n    ): ByteArray {\n        val ivKey = if (iv.isEmpty()) defaultIv(index) else iv\n        val c = Cipher.getInstance(\"AES/CBC/PKCS5Padding\")\n        val skSpec = SecretKeySpec(secretKey, \"AES\")\n        val ivSpec = IvParameterSpec(ivKey)\n        c.init(Cipher.DECRYPT_MODE, skSpec, ivSpec)\n        return c.doFinal(data)\n    }\n\n    private fun getParentLink(uri: String): String {\n        val split = uri.split(\"/\").toMutableList()\n        split.removeAt(split.lastIndex)\n        return split.joinToString(\"/\")\n    }\n\n    private fun isNotCompleteUrl(url: String): Boolean {\n        return !url.startsWith(\"https://\") && !url.startsWith(\"http://\")\n    }\n\n    @Throws\n    suspend fun m3u8Generation(\n        m3u8: M3u8Helper.M3u8Stream,\n        returnThis: Boolean = true\n    ): List<M3u8Helper.M3u8Stream> {\n        val list = mutableListOf<M3u8Helper.M3u8Stream>()\n        val response = app.get(m3u8.streamUrl, headers = m3u8.headers, verify = false).text\n        val parsed = HlsPlaylistParser.parse(\n            m3u8.streamUrl,\n            response,\n        )\n\n        var anyFound = false\n        if (parsed != null) {\n            for (video in parsed.variants) {\n                // The m3u8 should not be split it that causes a loss of audio, however this can not be done reliably\n                // Therefore that should be figured out on the extension level, so only \"trick play\" is checked for\n                if (video.isTrickPlay()) {\n                    //println(\"Denied m3u8Generation, isTrickPlay = ${video.isTrickPlay()} containsAudio = ${video.containsAudio()}, codec = ${video.format.codecs}, url = ${video.url}\")\n                    continue\n                }\n\n                anyFound = true\n                val quality = video.format.height\n                list.add(\n                    M3u8Helper.M3u8Stream(\n                        streamUrl = video.url.toString(),\n                        quality = if (quality > 0) quality else null,\n                        headers = m3u8.headers\n                    )\n                )\n            }\n        }\n\n        // If it is not a \"Master Playlist\", or if it does not contain any playable \"Media Playlist\" or if it should return itself\n        if (parsed == null || !anyFound || returnThis) {\n            // Only include it if is a \"Media Playlist\" (any TS files are found), or if it is a \"Master Playlist\" (parsing is non null)\n            if (parsed != null || TS_EXTENSION_REGEX.containsMatchIn(response)) {\n                list += m3u8\n            } else {\n                Log.i(TAG, \"M3u8 Playlist is not a \\\"Master Playlist\\\" nor a \\\"Media Playlist\\\". Removing this link as it is invalid and will not open in player: ${m3u8.streamUrl}\")\n            }\n        }\n\n        return list\n    }\n\n    data class TsLink(\n        val url: String,\n        val time: Double?,\n    )\n\n    data class LazyHlsDownloadData(\n        private val encryptionData: ByteArray,\n        private val encryptionIv: ByteArray,\n        val isEncrypted: Boolean,\n        val allTsLinks: List<TsLink>,\n        val relativeUrl: String,\n        val headers: Map<String, String>,\n    ) {\n\n        val size get() = allTsLinks.size\n\n        suspend fun resolveLinkWhileSafe(\n            index: Int,\n            tries: Int = 3,\n            failDelay: Long = 3000,\n            condition: (() -> Boolean)\n        ): ByteArray? {\n            for (i in 0 until tries) {\n                if (!condition()) return null\n\n                try {\n                    val out = resolveLink(index)\n                    return if (condition()) out else null\n                } catch (e: IllegalArgumentException) {\n                    return null\n                } catch (e: CancellationException) {\n                    return null\n                } catch (t: Throwable) {\n                    delay(failDelay)\n                }\n            }\n            return null\n        }\n\n        suspend fun resolveLinkSafe(\n            index: Int,\n            tries: Int = 3,\n            failDelay: Long = 3000\n        ): ByteArray? {\n            for (i in 0 until tries) {\n                try {\n                    return resolveLink(index)\n                } catch (e: IllegalArgumentException) {\n                    return null\n                } catch (e: CancellationException) {\n                    return null\n                } catch (t: Throwable) {\n                    delay(failDelay)\n                }\n            }\n            return null\n        }\n\n        @Throws\n        suspend fun resolveLink(index: Int): ByteArray {\n            if (index < 0 || index >= size) throw IllegalArgumentException(\"index must be in the bounds of the ts\")\n            val ts = allTsLinks[index]\n\n            val tsResponse = app.get(ts.url, headers = headers, verify = false)\n            val tsData = tsResponse.body.bytes()\n            if (tsData.isEmpty()) throw ErrorLoadingException(\"no data\")\n\n            return if (isEncrypted) {\n                getDecrypted(encryptionData, tsData, encryptionIv, index)\n            } else {\n                tsData\n            }\n        }\n    }\n\n    @Throws\n    suspend fun hslLazy(\n        playlistStream: M3u8Helper.M3u8Stream,\n        selectBest: Boolean = true,\n        requireAudio: Boolean,\n        depth: Int = 3,\n    ): LazyHlsDownloadData {\n        // Allow nesting, but not too much:\n        // Master Playlist (different videos)\n        // -> Media Playlist (different qualities of the same video)\n        // -> Media Segments (ts files of a single video)\n        if (depth < 0) {\n            throw IllegalArgumentException()\n        }\n\n        val playlistResponse =\n            app.get(\n                playlistStream.streamUrl,\n                headers = playlistStream.headers,\n                verify = false\n            ).text\n\n        val parsed = HlsPlaylistParser.parse(playlistStream.streamUrl, playlistResponse)\n        if (parsed != null) {\n            // find first with no audio group if audio is required, as otherwise muxing is required\n            // as m3u8 files can include separate tracks for dubs/subs\n            val variants = if (requireAudio) {\n                parsed.variants.filter { it.isPlayableStandalone(parsed) }\n            } else {\n                parsed.variants.filter { !it.isTrickPlay() }\n            }\n\n            if (variants.isEmpty()) {\n                throw IllegalStateException(\n                    if (requireAudio) {\n                        \"M3u8 contains no video with audio\"\n                    } else {\n                        \"M3u8 contains no video\"\n                    }\n                )\n            }\n\n            // M3u8 can also include different camera angles (parsed.videos) for the same quality\n            // but here the default is used\n            val bestVideo = if (selectBest) {\n                // Sort by pixels, while this normally is a bad idea if one is -1,\n                // in the m3u8 parsing must contains both or neither, so NO_VALUE => 1\n                // Tie break on averageBitrate\n                variants.maxBy { (it.format.width * it.format.height).toLong() * 1000L + it.format.averageBitrate.toLong() }\n            } else {\n                variants.minBy { (it.format.width * it.format.height).toLong() * 1000L + it.format.averageBitrate.toLong() }\n            }\n\n            val quality = bestVideo.format.height\n            return hslLazy(\n                playlistStream = M3u8Helper.M3u8Stream(\n                    bestVideo.url.toString(),\n                    if (quality > 0) quality else null,\n                    playlistStream.headers\n                ),\n                selectBest = selectBest,\n                requireAudio = requireAudio,\n                depth = depth - 1\n            )\n        }\n        // This is already a \"Media Segments\" file\n\n        // Encryption, this is because crunchy uses it\n        var encryptionIv = byteArrayOf()\n        var encryptionData = byteArrayOf()\n\n        val match = ENCRYPTION_URL_IV_REGEX.find(playlistResponse)?.groupValues\n        val encryptionState: Boolean\n\n        if (!match.isNullOrEmpty()) {\n            encryptionState = true\n            var encryptionUri = match[2]\n\n            if (isNotCompleteUrl(encryptionUri)) {\n                encryptionUri = \"${getParentLink(playlistStream.streamUrl)}/$encryptionUri\"\n            }\n\n            encryptionIv = match[3].toByteArray()\n            val encryptionKeyResponse =\n                app.get(encryptionUri, headers = playlistStream.headers, verify = false)\n            encryptionData = encryptionKeyResponse.body.bytes()\n        } else {\n            encryptionState = false\n        }\n\n        val relativeUrl = getParentLink(playlistStream.streamUrl)\n        val allTsList = TS_EXTENSION_REGEX.findAll(playlistResponse + \"\\n\").map { ts ->\n            val time = ts.groupValues[1]\n            val value = ts.groupValues[3]\n            val url = if (isNotCompleteUrl(value)) {\n                \"$relativeUrl/${value}\"\n            } else {\n                value\n            }\n            TsLink(url = url, time = time.toDoubleOrNull())\n        }.toList()\n\n        if (allTsList.isEmpty()) throw IllegalStateException(\"M3u8 must contains TS files\")\n\n        return LazyHlsDownloadData(\n            encryptionData = encryptionData,\n            encryptionIv = encryptionIv,\n            isEncrypted = encryptionState,\n            allTsLinks = allTsList,\n            relativeUrl = relativeUrl,\n            headers = playlistStream.headers\n        )\n    }\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/StringUtils.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport java.net.URLDecoder\nimport java.net.URLEncoder\n\nobject StringUtils {\n    fun String.encodeUri(): String {\n        return URLEncoder.encode(this, \"UTF-8\")\n    }\n\n    fun String.decodeUri(): String {\n        return URLDecoder.decode(this, \"UTF-8\")\n    }\n}"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/SubtitleHelper.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport me.xdrop.fuzzywuzzy.FuzzySearch\nimport java.util.Locale\n\n// If you find a way to use SettingsGeneral getCurrentLocale()\n// instead of this function do it.\nfun getCurrentLocale(): String {\n    return Locale.getDefault().toLanguageTag()\n}\n\n@Suppress(\n    \"unused\",\n    \"MemberVisibilityCanBePrivate\"\n)\nobject SubtitleHelper {\n    @Deprecated(\n        \"Default language code changed to IETF BCP 47 tag\",\n        replaceWith = ReplaceWith(\"LanguageMetadata(languageName, nativeName, ISO_639_1.ifBlank { ISO_639_2_B }), ISO_639_1, ISO_639_2_B, ISO_639_3, ISO_639_1\"),\n        level = DeprecationLevel.WARNING\n    )\n    data class Language639(\n        val languageName: String,\n        val nativeName: String,\n        val ISO_639_1: String,\n        val ISO_639_2_T: String,\n        val ISO_639_2_B: String,\n        val ISO_639_3: String,\n        val ISO_639_6: String,\n    )\n\n    /**\n     * Represents one language with english name, native name and codes.\n     * IETF BCP 47 conformant tag shall be used as the first choice for language code!\n     *\n     * See locales on:\n     * https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/availableLocales.json\n     * https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry\n     * https://android.googlesource.com/platform/frameworks/base/+/android-16.0.0_r2/core/res/res/values/locale_config.xml\n     * https://iso639-3.sil.org/code_tables/639/data/all\n     */\n    data class LanguageMetadata(\n        val languageName: String,\n        val nativeName: String,\n        val IETF_tag: String,       // Combine ISO 639-1, 639-3 and ISO 3166-1 (or numeric UN M49 / CLDR) for country / region\n        val ISO_639_1: String,\n        val ISO_639_2_B: String,    // ISO 639-2/T missing as it's a subset of ISO 639-3\n        val ISO_639_3: String,      // ISO 639-6 missing as it's intended to differentiate specific dialects and variants\n        val openSubtitles: String, // inconsistent codes that do not conform ISO 639\n    ) {\n        fun localizedName(localizedTo: String? = null): String {\n            // Use system locale to localize language name\n            val localeOfLangCode = Locale.forLanguageTag(this.IETF_tag)\n            val localeOfLocalizeTo = Locale.forLanguageTag(localizedTo ?: getCurrentLocale())\n            val sysLocalizedName = localeOfLangCode.getDisplayName(localeOfLocalizeTo)\n\n            val langCodeWithCountry = \"${localeOfLangCode.language} (\" // ${localeOfLangCode.country})\"\n            val failedToLocalize =\n                sysLocalizedName.equals(this.IETF_tag, ignoreCase = true) ||\n                sysLocalizedName.contains(langCodeWithCountry, ignoreCase = true)\n\n            return if (failedToLocalize)\n                // fallback to native language name\n                this.nativeName\n            else\n                sysLocalizedName\n        }\n\n        fun nameNextToFlagEmoji(localizedTo: String? = null): String {\n            // fallback to [A][A] -> [?] question mak flag\n            val flag = getFlagFromIso(this.IETF_tag) ?: \"\\ud83c\\udde6\\ud83c\\udde6\"\n\n            return \"$flag\\u00a0${localizedName(localizedTo)}\" // \\u00a0 non-breaking space\n        }\n    }\n\n    /**\n     * Language name (english or native) -> [LanguageMetadata]\n     * @param languageName language name or language tag\n     * @param halfMatch match with `contains()` instead of `equals()`. Also uses fuzzy matching to get approximate matches.\n     */\n    private fun getLanguageDataFromName(\n        languageName: String?,\n        halfMatch: Boolean? = false\n    ): LanguageMetadata? {\n        if (languageName.isNullOrBlank() || languageName.length < 2) return null\n        // Workaround to avoid junk like \"English (original audio)\" or \"Spanish 123\"\n        // or \"اَلْعَرَبِيَّةُ (Original Audio) 1\" or \"English (hindi sub)\"…\n        // Will still keep \"-\" to be compatible with language tags such as pr-bt\n        val garbage = Regex(\n            \"\\\\([^)]*(?:dub|sub|original|audio|code)[^)]*\\\\)|\" + // junk words in parenthesis\n                    \"[\\\\u064B-\\\\u065B]|\" + // arabic diacritics\n                    \"\\\\d|\" +  // numbers\n                    \"[^\\\\p{L}\\\\p{Mn}\\\\p{Mc}\\\\p{Me} ()-]\" // non-letter (from any language)\n        )\n\n\n        val lowLangName = languageName.lowercase().replace(garbage, \"\").trim()\n\n        val index = indexMapLanguageName[lowLangName]\n            ?: indexMapNativeName[lowLangName]\n            ?: indexMapIETF_tag[lowLangName]\n            ?: -1\n\n        val langMetadata = languages.getOrNull(index)\n\n        if (langMetadata != null) {\n            return langMetadata\n        } else if (halfMatch == true) {\n            // Go for partial matches but only use the best match\n            var closestMatch: Pair<LanguageMetadata?, Int> = null to 0\n\n            for (lang in languages) {\n                val score = maxOf(\n                    FuzzySearch.ratio(lowLangName, lang.languageName.lowercase()),\n                    FuzzySearch.ratio(\n                        lowLangName, lang.nativeName.lowercase()\n                    )\n                )\n\n                // Usually the languageName or nativeName is a substring of the entered name, for example in \"English Subtitle\"\n                if (lowLangName.contains(lang.languageName, ignoreCase = true) ||\n                    lowLangName.contains(lang.nativeName, ignoreCase = true) ||\n                    // Arbitrary cutoff at 80.\n                    score > 80\n                ) {\n                    // First detected language gets priority in equal scores.\n                    if (score > closestMatch.second) {\n                        closestMatch = lang to score\n                    }\n                }\n            }\n\n            return closestMatch.first\n        }\n\n        return null\n    }\n\n    @Deprecated(\n        \"Default language code changed to IETF BCP 47 tag\",\n        replaceWith = ReplaceWith(\"fromLanguageToTagIETF(input, looseCheck)\"),\n        level = DeprecationLevel.WARNING\n    )\n    /**\n     * Language name (english or native) -> ISO_639_1\n     * @param input language name\n     * @param looseCheck match with `contains()` instead of `equals()`\n    */\n    fun fromLanguageToTwoLetters(input: String, looseCheck: Boolean): String? {\n        return getLanguageDataFromName(input, looseCheck)?.ISO_639_1\n    }\n\n    @Deprecated(\n        \"Default language code changed to IETF BCP 47 tag\",\n        replaceWith = ReplaceWith(\"fromLanguageToTagIETF(input)\"),\n        level = DeprecationLevel.WARNING\n    )\n    /**\n     * Language name (english or native) -> ISO_639_3\n    */\n    fun fromLanguageToThreeLetters(input: String): String? {\n        return getLanguageDataFromName(input)?.ISO_639_3\n    }\n\n    /**\n     * Language name -> IETF_tag\n     * @param languageName language name\n     * @param halfMatch match with `contains()` instead of `equals()`\n    */\n    fun fromLanguageToTagIETF(languageName: String?, halfMatch: Boolean? = false): String? {\n        return getLanguageDataFromName(languageName, halfMatch)?.IETF_tag\n    }\n\n    /**\n     * Language code -> [LanguageMetadata]\n     * @param languageCode IETF BCP 47, ISO 639-1, ISO 639-2B/T, ISO 639-3, OpenSubtitles\n     * @return [LanguageMetadata] or `null`\n    */\n    private fun getLanguageDataFromCode(languageCode: String?): LanguageMetadata?  {\n        if (languageCode.isNullOrBlank() || languageCode.length < 2) return null\n\n        val lowLangCode = languageCode.lowercase().trim()\n        val index =\n            indexMapIETF_tag[lowLangCode] ?:\n            indexMapISO_639_1[lowLangCode] ?:\n            indexMapISO_639_3[lowLangCode] ?:\n            indexMapISO_639_2_B[lowLangCode] ?:\n            indexMapOpenSubtitles[lowLangCode] ?: -1\n\n        return languages.getOrNull(index)\n    }\n\n    @Deprecated(\n        \"Default language code changed to IETF BCP 47 tag\",\n        replaceWith = ReplaceWith(\"fromTagToEnglishLanguageName(input)\"),\n        level = DeprecationLevel.WARNING\n    )\n    /**\n     * Language code -> language english name\n    */\n    fun fromTwoLettersToLanguage(input: String): String? {\n        return getLanguageDataFromCode(input)?.languageName\n    }\n\n    @Deprecated(\n        \"Default language code changed to IETF BCP 47 tag\",\n        replaceWith = ReplaceWith(\"fromTagToEnglishLanguageName(input)\"),\n        level = DeprecationLevel.WARNING\n    )\n    /**\n     * Language code -> language english name\n    */\n    fun fromThreeLettersToLanguage(input: String): String? {\n        return getLanguageDataFromCode(input)?.languageName\n    }\n\n    /**\n     * Language code -> language name (if not found, fallback to native language name)\n     * @param languageCode IETF BCP 47, ISO 639-1, ISO 639-2B/T, ISO 639-3, OpenSubtitles\n     * @param localizedTo IETF BCP 47 tag to localize the language name to. Default: app current language\n    */\n    fun fromTagToLanguageName(languageCode: String?, localizedTo: String? = null): String? {\n        return getLanguageDataFromCode(languageCode)?.localizedName(localizedTo)\n    }\n\n    /**\n     * Language code -> language english name\n     * @param languageCode IETF BCP 47, ISO 639-1, ISO 639-2B/T, ISO 639-3, OpenSubtitles\n    */\n    fun fromTagToEnglishLanguageName(languageCode: String?): String? {\n        return getLanguageDataFromCode(languageCode)?.languageName\n    }\n\n    /**\n     * Language code -> openSubtitles inconsistent language tag\n     * @param languageCode IETF BCP 47, ISO 639-1, ISO 639-2B/T, ISO 639-3, OpenSubtitles\n    */\n    fun fromCodeToOpenSubtitlesTag(languageCode: String?): String? {\n        return getLanguageDataFromCode(languageCode)?.openSubtitles\n    }\n\n    /** openSubtitles -> IETF_tag */\n    fun fromCodeToLangTagIETF(languageCode: String?): String? {\n        return getLanguageDataFromCode(languageCode)?.IETF_tag\n    }\n\n    /**\n     * Check for a well formed IETF BCP 47 conformant language tag\n     *\n     * See locales on:\n     * https://github.com/unicode-org/cldr-json/blob/main/cldr-json/cldr-core/availableLocales.json\n     * https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry\n     * https://android.googlesource.com/platform/frameworks/base/+/android-16.0.0_r2/core/res/res/values/locale_config.xml\n    */\n    fun isWellFormedTagIETF(langTagIETF: String?): Boolean {\n        if (langTagIETF.isNullOrBlank() || langTagIETF.length < 2) return false\n\n        // Written by Addison Phillips, <Addison at amazon.com>\n        // https://www.langtag.net/philips-regexp.html\n        val langTagRegex = \"\"\"\n            +(^[xX](\\x2d\\p{Alnum}{1,8})*$)\n            +|(((^\\p{Alpha}{2,8}(?=\\x2d|$)){1}\n            +((\\x2d\\p{Alpha}{3})(?=\\x2d|$)){0,3}\n            +(\\x2d\\p{Alpha}{4}(?=\\x2d|$))?\n            +(\\x2d(\\p{Alpha}{2}|\\d{3})(?=\\x2d|$))?\n            +(\\x2d(\\d\\p{Alnum}{3}|\\p{Alnum}{5,8})(?=\\x2d|$))*)\n            +((\\x2d([a-wyzA-WYZ](?=\\x2d))(\\x2d(\\p{Alnum}{2,8})+)*))*\n            +(\\x2d[xX](\\x2d\\p{Alnum}{1,8})*)?)$\n            \"\"\".trimMargin(\"+\").toRegex()\n        return langTagIETF.matches(langTagRegex)\n    }\n\n    /**\n     * Try to get a flag emoji form a language code\n     * or two letters country code (ISO 3166-1-alfa-2)\n    */\n    fun getFlagFromIso(inp: String?): String? {\n        if (inp.isNullOrBlank() || inp.length < 2) return null\n\n        // 2 times a symbol between regional indicator \"[A]\" and \"[Z]\"\n        val unicodeFlagRegex = Regex(\"[\\uD83C\\uDDE6-\\uD83C\\uDDFF]{2}\")\n        // language tags (en-US, es-419, pt-BR, zh-hant-TW) that includes country\n        val countryRegex = Regex(\"[-_](\\\\p{Alnum}{2,3})$\", RegexOption.IGNORE_CASE)\n\n        val country = countryRegex.find(inp)?.groupValues?.get(1)\n\n        val flagEmoji =\n            getFlagFromCountry2Letters(lang2country[inp.lowercase()]) ?:\n            getFlagFromCountry2Letters(country?.uppercase()) ?:\n            getFlagFromCountry2Letters(inp.uppercase()) ?:\n            getFlagFromCountry2Letters(lang2country[country?.lowercase()]) ?: \"\"\n\n        if (inp.equals(\"qt\", ignoreCase = true))\n            return \"\\uD83E\\uDD8D\" // \"mmmm... monke\" -> gorilla [🦍]\n        if (flagEmoji.matches(unicodeFlagRegex))\n            return flagEmoji\n        return null\n    }\n\n    /**\n     * Get a flag emoji next to the language name\n     * @param languageCode IETF BCP 47, ISO 639-1, ISO 639-2B/T, ISO 639-3, OpenSubtitles\n     * @param localizedTo IETF BCP 47 tag to localize the language name to. Default: app current language\n    */\n    fun getNameNextToFlagEmoji(languageCode: String?, localizedTo: String? = null): String? {\n        return getLanguageDataFromCode(languageCode)?.nameNextToFlagEmoji(localizedTo)\n    }\n\n    // 2 letters country code (ISO 3166-1-alfa-2) -> flag emoji\n    private fun getFlagFromCountry2Letters(countryLetters: String?): String? {\n        if (countryLetters.isNullOrBlank() || countryLetters.length != 2) return null\n\n        val asciiOffset = 0x41    // uppercase \"A\"\n        val flagOffset = 0x1F1E6  // regional indicator \"[A]\"\n        val offset = flagOffset - asciiOffset\n\n        val firstChar: Int = Character.codePointAt(countryLetters, 0) + offset\n        val secondChar: Int = Character.codePointAt(countryLetters, 1) + offset\n\n        return String(Character.toChars(firstChar)) + String(Character.toChars(secondChar))\n    }\n\n    // when (langTag = country) or (langTag contains country)\n    // as in:\n    //   \"es\" to \"ES\"\n    //   \"pt\" to \"PT\"\n    //   \"fr\" to \"FR\"\n    //   \"en-US\" to \"US\"\n    //   \"pt-BR\" to \"BR\"\n    //   \"zh-hant-TW\" to \"TW\"\n    // add to this list is useless as getFlagFromIso() already\n    // handles it.\n    // Adding here is still an option to overwrite a flag like in:\n    //   \"am\" to \"ET\" => Ethiopia flag for Amharic instead of Armenia flag\n    // For country / region see\n    // https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2\n    // https://en.wikipedia.org/wiki/UN_M49\n    private val lang2country = mapOf(\n        \"419\" to \"ES\", // (?_?) Latin America Spanish -> ES or a L.A. country?\n        \"aa\" to \"ET\",\n        \"af\" to \"ZA\",\n        \"agq\" to \"CM\",\n        \"ajp\" to \"SY\",\n        \"ak\" to \"GH\",\n        \"am\" to \"ET\",\n        \"an\" to \"ES\",\n        \"apc\" to \"SY\",\n        \"ar\" to \"AE\",\n        \"arg\" to \"ES\",\n        \"ars\" to \"SA\",\n        \"as\" to \"IN\",\n        \"asa\" to \"TZ\",\n        \"av\" to \"RU\", // (?_?) Avaric -> RU\n        \"ay\" to \"BO\", // (?_?) Aymara -> BO\n        \"azb\" to \"AZ\",\n        \"bas\" to \"CM\",\n        \"be\" to \"BY\",\n        \"bem\" to \"ZM\",\n        \"bez\" to \"IT\",\n        \"bm\" to \"ML\",\n        \"bn\" to \"BD\",\n        \"bo\" to \"CN\",\n        \"br\" to \"FR\",\n        \"brx\" to \"IN\",\n        \"bs\" to \"BA\",\n        \"ca\" to \"ES\",\n        \"cgg\" to \"UG\",\n        \"chr\" to \"US\",\n        \"ckb\" to \"IQ\", // (?_?) Central Kurdish -> IQ or IR\n        \"cnr\" to \"ME\",\n        \"cs\" to \"CZ\",\n        \"cy\" to \"GB\",\n        \"da\" to \"DK\",\n        \"dav\" to \"KE\",\n        \"dje\" to \"NE\",\n        \"dua\" to \"CM\",\n        \"dyo\" to \"SN\",\n        \"dz\" to \"BT\",\n        \"ea\" to \"ES\",\n        \"ebu\" to \"KE\",\n        \"ee\" to \"GH\",\n        \"el\" to \"GR\",\n        \"en\" to \"GB\",\n        \"et\" to \"EE\",\n        \"eu\" to \"ES\",\n        \"ewo\" to \"CM\",\n        \"ex\" to \"ES\",\n        \"ext\" to \"ES\",\n        \"fa\" to \"IR\",\n        \"ff\" to \"CN\",\n        \"fil\" to \"PH\",\n        \"fj\" to \"FJ\",\n        \"ga\" to \"IE\",\n        \"gd\" to \"GB\",\n        \"gl\" to \"ES\",\n        \"gn\" to \"PY\", // (?_?) Guarani -> PY\n        \"gsw\" to \"CH\",\n        \"gu\" to \"IN\",\n        \"guz\" to \"KE\",\n        \"gv\" to \"GB\",\n        \"ha\" to \"NG\",\n        \"haw\" to \"US\",\n        \"he\" to \"IL\",\n        \"hi\" to \"IN\",\n        \"hy\" to \"AM\",\n        \"ig\" to \"NG\",\n        \"ii\" to \"CN\",\n        \"in\" to \"ID\", // \"in\" deprecate, use \"id\" instead. Keeping for exiting subtitles\n        \"ita\" to \"IT\",\n        \"iw\" to \"IL\", // \"iw\" deprecate, use \"he\" instead. Keeping for exiting subtitles\n        \"ja\" to \"JP\",\n        \"jmc\" to \"TZ\",\n        \"jv\" to \"ID\",\n        \"jvn\" to \"ID\",\n        \"ka\" to \"GE\",\n        \"kab\" to \"DZ\",\n        \"kam\" to \"KE\",\n        \"kde\" to \"TZ\",\n        \"kea\" to \"CV\",\n        \"kg\" to \"CD\", // (?_?) Kongo -> CD or CG or AO\n        \"khq\" to \"ML\",\n        \"ki\" to \"KE\",\n        \"kk\" to \"KZ\",\n        \"kl\" to \"GL\",\n        \"kln\" to \"KE\",\n        \"km\" to \"KH\",\n        \"kn\" to \"IN\",\n        \"ko\" to \"KR\",\n        \"kok\" to \"IN\",\n        \"kr\" to \"TD\", // (?_?) Kanuri -> TD or NE\n        \"ks\" to \"IN\", // (?_?) Kashmiri -> IN or PK\n        \"ksb\" to \"TZ\",\n        \"ksf\" to \"CM\",\n        \"ku\" to \"IQ\",\n        \"kw\" to \"GB\",\n        \"ky\" to \"KG\",\n        \"la\" to \"IT\",\n        \"lag\" to \"TZ\",\n        \"lat\" to \"IT\",\n        \"lat\" to \"LV\",\n        \"lb\" to \"LU\",\n        \"lg\" to \"UG\",\n        \"ln\" to \"CG\",\n        \"lo\" to \"LA\",\n        \"ltz\" to \"LU\",\n        \"lu\" to \"CD\",\n        \"luo\" to \"KE\",\n        \"luy\" to \"KE\",\n        \"ma\" to \"IN\",\n        \"mas\" to \"TZ\",\n        \"mer\" to \"KE\",\n        \"mfe\" to \"MU\",\n        \"mgh\" to \"MZ\",\n        \"ml\" to \"IN\",\n        \"mni\" to \"IN\",\n        \"mr\" to \"IN\",\n        \"ms\" to \"MY\",\n        \"mua\" to \"CM\",\n        \"my\" to \"MM\",\n        \"naq\" to \"NA\",\n        \"nb\" to \"NO\",\n        \"nd\" to \"ZW\",\n        \"ne\" to \"NP\",\n        \"nmg\" to \"CM\",\n        \"nn\" to \"NO\",\n        \"nr\" to \"ZA\", // (?_?) Southern Ndebele -> ZA or ZW\n        \"nus\" to \"SD\",\n        \"nv\" to \"US\",\n        \"ny\" to \"MW\", // (?_?) Nyanja -> MW\n        \"nyn\" to \"UG\",\n        \"oc\" to \"ES\",\n        \"oci\" to \"ES\",\n        \"om\" to \"ET\",\n        \"or\" to \"IN\",\n        \"pa\" to \"IN\",\n        \"pa\" to \"PK\",\n        \"pan\" to \"IN\",\n        \"pb\" to \"BR\",\n        \"pm\" to \"MZ\",\n        \"por\" to \"PT\",\n        \"pr\" to \"AF\",\n        \"prs\" to \"AF\",\n        \"ps\" to \"AF\",\n        \"qu\" to \"PE\", // (?_?) Quechua -> PE or EC or BO or CO or CL or AR\n        \"que\" to \"PE\", // (?_?) Quechua -> PE or EC or BO or CO or CL or AR\n        \"rm\" to \"CH\",\n        \"rn\" to \"BI\",\n        \"rof\" to \"TZ\",\n        \"rwk\" to \"TZ\",\n        \"sa\" to \"IN\",\n        \"san\" to \"IN\",\n        \"saq\" to \"KE\",\n        \"sat\" to \"IN\",\n        \"sbp\" to \"TZ\",\n        \"sd\" to \"PK\", // (?_?) Sindhi -> PK or IN\n        \"sdn\" to \"PK\", // (?_?) Sindhi -> PK or IN\n        \"se\" to \"NO\",\n        \"seh\" to \"MZ\",\n        \"ses\" to \"ML\",\n        \"sg\" to \"CF\",\n        \"shi\" to \"MA\",\n        \"si\" to \"LK\",\n        \"sl\" to \"SI\",\n        \"sm\" to \"WS\",\n        \"smo\" to \"WS\",\n        \"sn\" to \"ZW\",\n        \"sp\" to \"ES\",\n        \"sq\" to \"AL\",\n        \"sr\" to \"RS\",\n        \"st\" to \"LS\", // (?_?) Southern Sotho -> LS or ZA\n        \"su\" to \"ID\",\n        \"sv\" to \"SE\",\n        \"sw\" to \"TZ\",\n        \"swc\" to \"CD\",\n        \"ta\" to \"IN\",\n        \"tat\" to \"RU\",\n        \"tdt\" to \"TL\",\n        \"te\" to \"IN\",\n        \"teo\" to \"UG\",\n        \"tg\" to \"TJ\",\n        \"tgk\" to \"TJ\",\n        \"ti\" to \"ET\",\n        \"tk\" to \"TM\",\n        \"tl\" to \"PH\",\n        \"tm-td\" to \"TL\", // (?_?) Tetun -> TL\n        \"tn\" to \"ZA\", // (?_?) Tswana -> ZA or BW\n        \"ts\" to \"ZA\",\n        \"tso\" to \"ZA\",\n        \"tt\" to \"RU\",\n        \"tuk\" to \"TM\",\n        \"twq\" to \"NE\",\n        \"tzm\" to \"MA\",\n        \"uk\" to \"UA\",\n        \"ur\" to \"PK\",\n        \"vai\" to \"LR\",\n        \"vi\" to \"VN\",\n        \"vun\" to \"TZ\",\n        \"wo\" to \"SN\",\n        \"xh\" to \"ZA\",\n        \"xho\" to \"ZA\",\n        \"xog\" to \"UG\",\n        \"yav\" to \"CM\",\n        \"yo\" to \"NG\",\n        \"yue\" to \"CN\",\n        \"za\" to \"CN\",\n        \"zh-hans\" to \"CN\", // (?_?) Chinese (simplified) -> CN ?\n        \"zh-hant\" to \"TW\", // (?_?) Chinese (traditional) -> CN or TW or other ?\n        \"zh\" to \"CN\",\n        \"zha\" to \"CN\",\n        \"zu\" to \"ZA\",\n    )\n\n    @Suppress(\"SpellCheckingInspection\")\n    val languages = listOf(\n        // languageName, nativeName, IETF_tag, ISO_639_1, ISO_639_2_B, ISO_639_3, openSubtitles\n        LanguageMetadata(\"Afar\",\"Afaraf\",\"aa\",\"aa\",\"aar\",\"aar\",\"\"),\n        LanguageMetadata(\"Afrikaans\",\"Afrikaans\",\"af\",\"af\",\"afr\",\"afr\",\"af\"),\n        LanguageMetadata(\"Akan\",\"Akan\",\"ak\",\"ak\",\"aka\",\"aka\",\"\"),\n        LanguageMetadata(\"Albanian\",\"Shqip\",\"sq\",\"sq\",\"\",\"sqi\",\"sq\"),\n        LanguageMetadata(\"Amharic\",\"አማርኛ\",\"am\",\"am\",\"amh\",\"amh\",\"am\"),\n        LanguageMetadata(\"Arabic\",\"العربية\",\"ar\",\"ar\",\"ara\",\"ara\",\"ar\"),\n        LanguageMetadata(\"Arabic (Levantine)\",\"عربي شامي\",\"apc\",\"\",\"ajp\",\"apc\",\"ar\"), // \"ajp\" is deprecated, keeping for compatibility\n        LanguageMetadata(\"Arabic (Najdi)\",\"عربي شامي\",\"ars\",\"\",\"\",\"ars\",\"ar\"),\n        LanguageMetadata(\"Aragonese\",\"aragonés\",\"an\",\"an\",\"arg\",\"arg\",\"an\"),\n        LanguageMetadata(\"Armenian\",\"Հայերեն\",\"hy\",\"hy\",\"\",\"hye\",\"hy\"),\n        LanguageMetadata(\"Assamese\",\"অসমীয়া\",\"as\",\"as\",\"asm\",\"asm\",\"as\"),\n        LanguageMetadata(\"Avaric\",\"авар мацӀ, магӀарул мацӀ\",\"av\",\"av\",\"ava\",\"ava\",\"\"),\n        LanguageMetadata(\"Aymara\",\"aymar aru\",\"ay\",\"ay\",\"aym\",\"aym\",\"\"),\n        LanguageMetadata(\"Azerbaijani\",\"Azərbaycan\",\"az\",\"az\",\"aze\",\"aze\",\"az-az\"),\n        LanguageMetadata(\"Azerbaijani (South)\",\"Azərbaycan (Cənubi)\",\"azb\",\"\",\"\",\"azb\",\"az-zb\"),\n        LanguageMetadata(\"Bambara\",\"bamanankan\",\"bm\",\"bm\",\"bam\",\"bam\",\"\"),\n        LanguageMetadata(\"Basque\",\"euskara, euskera\",\"eu\",\"eu\",\"\",\"eus\",\"eu\"),\n        LanguageMetadata(\"Belarusian\",\"беларуская мова\",\"be\",\"be\",\"bel\",\"bel\",\"be\"),\n        LanguageMetadata(\"Bengali\",\"বাংলা\",\"bn\",\"bn\",\"ben\",\"ben\",\"bn\"),\n        LanguageMetadata(\"Bosnian\",\"bosanski jezik\",\"bs\",\"bs\",\"bos\",\"bos\",\"bs\"),\n        LanguageMetadata(\"Breton\",\"brezhoneg\",\"br\",\"br\",\"bre\",\"bre\",\"br\"),\n        LanguageMetadata(\"Bulgarian\",\"български език\",\"bg\",\"bg\",\"bul\",\"bul\",\"bg\"),\n        LanguageMetadata(\"Burmese\",\"ဗမာစာ\",\"my\",\"my\",\"\",\"mya\",\"my\"),\n        LanguageMetadata(\"Catalan\",\"català\",\"ca\",\"ca\",\"cat\",\"cat\",\"ca\"),\n        LanguageMetadata(\"Chichewa\",\"chiCheŵa, chinyanja\",\"ny\",\"ny\",\"nya\",\"nya\",\"\"),\n        LanguageMetadata(\"Chinese\",\"中文, 汉语, 漢語\",\"zh\",\"zh\",\"chi\",\"zho\",\"ze\"),\n        LanguageMetadata(\"Chinese (Cantonese)\",\"廣東話, 广东话\",\"yue\",\"\",\"\",\"yue\",\"zh-ca\"),\n        LanguageMetadata(\"Chinese (simplified)\",\"汉语\",\"zh-hans\",\"\",\"\",\"\",\"zh-cn\"),\n        LanguageMetadata(\"Chinese (Taiwan)\",\"正體中文(臺灣)\",\"zh-hant-tw\",\"\",\"\",\"\",\"zh-tw\"),\n        LanguageMetadata(\"Chinese (traditional)\",\"漢語\",\"zh-hant\",\"\",\"\",\"\",\"zh-tw\"),\n        LanguageMetadata(\"Croatian\",\"hrvatski jezik\",\"hr\",\"hr\",\"hrv\",\"hrv\",\"hr\"),\n        LanguageMetadata(\"Czech\",\"čeština, český jazyk\",\"cs\",\"cs\",\"\",\"ces\",\"cs\"),\n        LanguageMetadata(\"Danish\",\"dansk\",\"da\",\"da\",\"dan\",\"dan\",\"da\"),\n        LanguageMetadata(\"Dari\",\"دری\",\"prs\",\"\",\"\",\"prs\",\"pr\"),\n        LanguageMetadata(\"Dutch\",\"Nederlands, Vlaams\",\"nl\",\"nl\",\"\",\"nld\",\"nl\"),\n        LanguageMetadata(\"Dzongkha\",\"རྫོང་ཁ\",\"dz\",\"dz\",\"dzo\",\"dzo\",\"\"),\n        LanguageMetadata(\"English\",\"English\",\"en\",\"en\",\"eng\",\"eng\",\"en\"),\n        LanguageMetadata(\"Esperanto\",\"Esperanto\",\"eo\",\"eo\",\"epo\",\"epo\",\"eo\"),\n        LanguageMetadata(\"Estonian\",\"eesti, eesti keel\",\"et\",\"et\",\"est\",\"est\",\"et\"),\n        LanguageMetadata(\"Ewe\",\"Eʋegbe\",\"ee\",\"ee\",\"ewe\",\"ewe\",\"\"),\n        LanguageMetadata(\"Extremaduran\",\"Estremeñu\",\"ext\",\"\",\"\",\"ext\",\"ex\"),\n        LanguageMetadata(\"Faroese\",\"føroyskt\",\"fo\",\"fo\",\"fao\",\"fao\",\"\"),\n        LanguageMetadata(\"Fijian\",\"vosa Vakaviti\",\"fj\",\"fj\",\"fij\",\"fij\",\"\"),\n        LanguageMetadata(\"Filipino\",\"Wikang Filipino\",\"fil\",\"\",\"fil\",\"fil\",\"\"),\n        LanguageMetadata(\"Finnish\",\"suomi, suomen kieli\",\"fi\",\"fi\",\"fin\",\"fin\",\"fi\"),\n        LanguageMetadata(\"French\",\"Français\",\"fr\",\"fr\",\"\",\"fra\",\"fr\"),\n        LanguageMetadata(\"Fula\",\"Fulfulde, Pulaar, Pular\",\"ff\",\"ff\",\"ful\",\"ful\",\"\"),\n        LanguageMetadata(\"Galician\",\"Galego\",\"gl\",\"gl\",\"glg\",\"glg\",\"gl\"),\n        LanguageMetadata(\"Ganda\",\"Luganda\",\"lg\",\"lg\",\"lug\",\"lug\",\"\"),\n        LanguageMetadata(\"Georgian\",\"ქართული\",\"ka\",\"ka\",\"\",\"kat\",\"ka\"),\n        LanguageMetadata(\"German\",\"Deutsch\",\"de\",\"de\",\"\",\"deu\",\"de\"),\n        LanguageMetadata(\"Greek\",\"ελληνικά\",\"el\",\"el\",\"\",\"ell\",\"el\"),\n        LanguageMetadata(\"Guarani\",\"Avañe'ẽ\",\"gn\",\"gn\",\"grn\",\"gug\",\"\"),\n        LanguageMetadata(\"Gujarati\",\"ગુજરાતી\",\"gu\",\"gu\",\"guj\",\"guj\",\"\"),\n        LanguageMetadata(\"Haitian\",\"Kreyòl ayisyen\",\"ht\",\"ht\",\"hat\",\"hat\",\"\"),\n        LanguageMetadata(\"Hausa\",\"(Hausa) هَوُسَ\",\"ha\",\"ha\",\"hau\",\"hau\",\"\"),\n        LanguageMetadata(\"Hebrew\",\"עברית\",\"he\",\"iw\",\"heb\",\"heb\",\"he\"), // \"iw\" is deprecated, keeping for compatibility\n        LanguageMetadata(\"Hindi\",\"हिन्दी, हिंदी\",\"hi\",\"hi\",\"hin\",\"hin\",\"hi\"),\n        LanguageMetadata(\"Hungarian\",\"Magyar\",\"hu\",\"hu\",\"hun\",\"hun\",\"hu\"),\n        LanguageMetadata(\"Icelandic\",\"Íslenska\",\"is\",\"is\",\"\",\"isl\",\"is\"),\n        LanguageMetadata(\"Ido\",\"Ido\",\"io\",\"io\",\"ido\",\"ido\",\"\"),\n        LanguageMetadata(\"Igbo\",\"Asụsụ Igbo\",\"ig\",\"ig\",\"ibo\",\"ibo\",\"ig\"),\n        LanguageMetadata(\"Indonesian\",\"Bahasa Indonesia\",\"id\",\"in\",\"ind\",\"ind\",\"id\"), // \"in\" is deprecated, keeping for compatibility\n        LanguageMetadata(\"Interlingua\",\"Interlingua\",\"ia\",\"ia\",\"ina\",\"ina\",\"ia\"),\n        LanguageMetadata(\"Interlingue\",\"Interlingue (originally Occidental)\",\"ie\",\"ie\",\"ile\",\"ile\",\"\"),\n        LanguageMetadata(\"Irish\",\"Gaeilge\",\"ga\",\"ga\",\"gle\",\"gle\",\"ga\"),\n        LanguageMetadata(\"Italian\",\"italiano\",\"it\",\"it\",\"ita\",\"ita\",\"it\"),\n        LanguageMetadata(\"Japanese\",\"日本語 (にほんご)\",\"ja\",\"ja\",\"jpn\",\"jpn\",\"ja\"),\n        LanguageMetadata(\"Javanese\",\"ꦧꦱꦗꦮ\",\"jv\",\"jv\",\"jav\",\"jvn\",\"\"),\n        LanguageMetadata(\"Kalaallisut\",\"kalaallisut, kalaallit oqaasii\",\"kl\",\"kl\",\"kal\",\"kal\",\"\"),\n        LanguageMetadata(\"Kannada\",\"ಕನ್ನಡ\",\"kn\",\"kn\",\"kan\",\"kan\",\"kn\"),\n        LanguageMetadata(\"Kanuri\",\"Kanuri\",\"kr\",\"kr\",\"kau\",\"kau\",\"\"),\n        LanguageMetadata(\"Kashmiri\",\"कश्मीरी, كشميري‎\",\"ks\",\"ks\",\"kas\",\"kas\",\"\"),\n        LanguageMetadata(\"Kazakh\",\"қазақ тілі\",\"kk\",\"kk\",\"kaz\",\"kaz\",\"kk\"),\n        LanguageMetadata(\"Khmer\",\"ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ\",\"km\",\"km\",\"khm\",\"khm\",\"km\"),\n        LanguageMetadata(\"Kikuyu\",\"Gĩkũyũ\",\"ki\",\"ki\",\"kik\",\"kik\",\"\"),\n        LanguageMetadata(\"Kinyarwanda\",\"Ikinyarwanda\",\"rw\",\"rw\",\"kin\",\"kin\",\"\"),\n        LanguageMetadata(\"Kirundi\",\"Ikirundi\",\"rn\",\"rn\",\"run\",\"run\",\"\"),\n        LanguageMetadata(\"Kongo\",\"Kikongo\",\"kg\",\"kg\",\"kon\",\"kon\",\"\"),\n        LanguageMetadata(\"Korean\",\"한국어, 조선어\",\"ko\",\"ko\",\"kor\",\"kor\",\"ko\"),\n        LanguageMetadata(\"Kurdish\",\"Kurdî, كوردی‎\",\"ku\",\"ku\",\"kur\",\"kur\",\"ku\"),\n        LanguageMetadata(\"Kyrgyz\",\"Кыргызча, Кыргыз тили\",\"ky\",\"ky\",\"kir\",\"kir\",\"\"),\n        LanguageMetadata(\"Lao\",\"ພາສາລາວ\",\"lo\",\"lo\",\"lao\",\"lao\",\"\"),\n        LanguageMetadata(\"Latin\",\"Latine\",\"la\",\"la\",\"lat\",\"lat\",\"\"),\n        LanguageMetadata(\"Latvian\",\"latviešu valoda\",\"lv\",\"lv\",\"lav\",\"lav\",\"lv\"),\n        LanguageMetadata(\"Lingala\",\"Lingála\",\"ln\",\"ln\",\"lin\",\"lin\",\"\"),\n        LanguageMetadata(\"Lithuanian\",\"lietuvių kalba\",\"lt\",\"lt\",\"lit\",\"lit\",\"lt\"),\n        LanguageMetadata(\"Luba-Katanga\",\"Tshiluba\",\"lu\",\"lu\",\"lub\",\"lub\",\"\"),\n        LanguageMetadata(\"Luxembourgish\",\"Lëtzebuergesch\",\"lb\",\"lb\",\"ltz\",\"ltz\",\"lb\"),\n        LanguageMetadata(\"Macedonian\",\"македонски\",\"mk\",\"mk\",\"\",\"mkd\",\"mk\"),\n        LanguageMetadata(\"Malagasy\",\"fiteny malagasy\",\"mg\",\"mg\",\"mlg\",\"mlg\",\"\"),\n        LanguageMetadata(\"Malay\",\"Bahasa Melayu, بهاس ملايو‎\",\"ms\",\"ms\",\"\",\"msa\",\"ms\"),\n        LanguageMetadata(\"Malayalam\",\"മലയാളം\",\"ml\",\"ml\",\"mal\",\"mal\",\"ml\"),\n        LanguageMetadata(\"Maltese\",\"Malti\",\"mt\",\"mt\",\"mlt\",\"mlt\",\"\"),\n        LanguageMetadata(\"Manx\",\"Gaelg, Gailck\",\"gv\",\"gv\",\"glv\",\"glv\",\"\"),\n        LanguageMetadata(\"Marathi\",\"मराठी\",\"mr\",\"mr\",\"mar\",\"mar\",\"mr\"),\n        LanguageMetadata(\"Marshallese\",\"Kajin M̧ajeļ\",\"mh\",\"mh\",\"mah\",\"mah\",\"\"),\n        LanguageMetadata(\"Meitei\",\"ꯃꯅꯤꯄꯨꯔꯤ, মণিপুরী\",\"mni\",\"\",\"mni\",\"mni\",\"ma\"),\n        LanguageMetadata(\"Mexican Spanish\", \"Español mexicano\", \"es-MX\", \"mx\",\"\",\"\",\"\"), // iso639_1 is not mx but, some extension use it as such\n        LanguageMetadata(\"Mongolian\",\"Монгол хэл\",\"mn\",\"mn\",\"mon\",\"mon\",\"mn\"),\n        LanguageMetadata(\"Montenegrin\",\"crnogorski, црногорски\",\"cnr\",\"\",\"cnr\",\"cnr\",\"me\"),\n        LanguageMetadata(\"Navajo\",\"Diné bizaad\",\"nv\",\"nv\",\"nav\",\"nav\",\"nv\"),\n        LanguageMetadata(\"Nepali\",\"नेपाली\",\"ne\",\"ne\",\"nep\",\"nep\",\"ne\"),\n        LanguageMetadata(\"Northern Ndebele\",\"isiNdebele\",\"nd\",\"nd\",\"nde\",\"nde\",\"\"),\n        LanguageMetadata(\"Northern Sami\",\"Davvisámegiella\",\"se\",\"se\",\"sme\",\"sme\",\"se\"),\n        LanguageMetadata(\"Norwegian\",\"Norsk\",\"no\",\"no\",\"nor\",\"nor\",\"no\"),\n        LanguageMetadata(\"Norwegian Bokmål\",\"Norsk bokmål\",\"nb\",\"nb\",\"nob\",\"nob\",\"\"),\n        LanguageMetadata(\"Norwegian Nynorsk\",\"Norsk nynorsk\",\"nn\",\"nn\",\"nno\",\"nno\",\"\"),\n        LanguageMetadata(\"Nuosu\",\"ꆈꌠ꒿ Nuosuhxop\",\"ii\",\"ii\",\"iii\",\"iii\",\"\"),\n        LanguageMetadata(\"Occitan\",\"occitan, lenga d'òc\",\"oc\",\"oc\",\"oci\",\"oci\",\"oc\"),\n        LanguageMetadata(\"Oriya\",\"ଓଡ଼ିଆ\",\"or\",\"or\",\"ori\",\"ori\",\"or\"),\n        LanguageMetadata(\"Oromo\",\"Afaan Oromoo\",\"om\",\"om\",\"orm\",\"orm\",\"\"),\n        LanguageMetadata(\"Panjabi\",\"ਪੰਜਾਬੀ, پنجابی‎\",\"pa\",\"pa\",\"pan\",\"pan\",\"\"),\n        LanguageMetadata(\"Pashto\",\"پښتو\",\"ps\",\"ps\",\"pus\",\"pus\",\"ps\"),\n        LanguageMetadata(\"Persian (Farsi)\",\"فارسی\",\"fa\",\"fa\",\"\",\"fas\",\"fa\"),\n        LanguageMetadata(\"Polish\",\"Polski, polszczyzna\",\"pl\",\"pl\",\"pol\",\"pol\",\"pl\"),\n        LanguageMetadata(\"Portuguese\",\"Português\",\"pt\",\"pt\",\"por\",\"por\",\"pt-pt\"),\n        LanguageMetadata(\"Portuguese (Brazil)\",\"Português (Brasil)\",\"pt-br\",\"\",\"\",\"\",\"pt-br\"),\n        LanguageMetadata(\"Portuguese (Mozambique)\",\"Português (Moçambique)\",\"pt-mz\",\"\",\"\",\"\",\"pm\"),\n        LanguageMetadata(\"Quechua\",\"Runa Simi, Kichwa\",\"qu\",\"qu\",\"que\",\"que\",\"\"),\n        LanguageMetadata(\"Romanian\",\"Română\",\"ro\",\"ro\",\"\",\"ron\",\"ro\"),\n        LanguageMetadata(\"Romansh\",\"rumantsch grischun\",\"rm\",\"rm\",\"roh\",\"roh\",\"\"),\n        LanguageMetadata(\"Russian\",\"Русский\",\"ru\",\"ru\",\"rus\",\"rus\",\"ru\"),\n        LanguageMetadata(\"Samoan\",\"gagana fa'a Samoa\",\"sm\",\"sm\",\"smo\",\"smo\",\"\"),\n        LanguageMetadata(\"Sango\",\"yângâ tî sängö\",\"sg\",\"sg\",\"sag\",\"sag\",\"\"),\n        LanguageMetadata(\"Sanskrit\",\"संस्कृतम्\",\"sa\",\"sa\",\"san\",\"san\",\"\"),\n        LanguageMetadata(\"Santali\",\"ᱥᱟᱱᱛᱟᱲᱤ\",\"sat\",\"\",\"\",\"sat\",\"sx\"),\n        LanguageMetadata(\"Scottish Gaelic\",\"Gàidhlig\",\"gd\",\"gd\",\"gla\",\"gla\",\"gd\"),\n        LanguageMetadata(\"Serbian\",\"српски језик\",\"sr\",\"sr\",\"srp\",\"srp\",\"sr\"),\n        LanguageMetadata(\"Shona\",\"chiShona\",\"sn\",\"sn\",\"sna\",\"sna\",\"\"),\n        LanguageMetadata(\"Sindhi\",\"सिन्धी, سنڌي، سندھی‎\",\"sd\",\"sd\",\"snd\",\"snd\",\"sd\"),\n        LanguageMetadata(\"Sinhala\",\"සිංහල\",\"si\",\"si\",\"sin\",\"sin\",\"si\"),\n        LanguageMetadata(\"Slovak\",\"slovenčina, slovenský jazyk\",\"sk\",\"sk\",\"\",\"slk\",\"sk\"),\n        LanguageMetadata(\"Slovenian\",\"slovenski jezik, slovenščina\",\"sl\",\"sl\",\"slv\",\"slv\",\"sl\"),\n        LanguageMetadata(\"Somali\",\"Soomaaliga, af Soomaali\",\"so\",\"so\",\"som\",\"som\",\"so\"),\n        LanguageMetadata(\"Sotho\",\"Sesotho\",\"st\",\"st\",\"sot\",\"sot\",\"\"),\n        LanguageMetadata(\"Southern Ndebele\",\"isiNdebele\",\"nr\",\"nr\",\"nbl\",\"nbl\",\"\"),\n        LanguageMetadata(\"Spanish\",\"Español\",\"es\",\"es\",\"spa\",\"spa\",\"es\"),\n        LanguageMetadata(\"Spanish (Europe)\",\"Español (Europa)\",\"es-es\",\"\",\"\",\"\",\"sp\"),\n        LanguageMetadata(\"Spanish (Latin America)\",\"Español (Latinoamérica)\",\"es-419\",\"\",\"\",\"\",\"ea\"),\n        LanguageMetadata(\"Sundanese\",\"Basa Sunda\",\"su\",\"su\",\"sun\",\"sun\",\"\"),\n        LanguageMetadata(\"Swahili\",\"Kiswahili\",\"sw\",\"sw\",\"swa\",\"swa\",\"sw\"),\n        LanguageMetadata(\"Swedish\",\"Svenska\",\"sv\",\"sv\",\"swe\",\"swe\",\"sv\"),\n        LanguageMetadata(\"Tagalog\",\"Wikang Tagalog, ᜆᜄᜎᜓᜄ᜔\",\"tl\",\"tl\",\"\",\"tlg\",\"tl\"),\n        LanguageMetadata(\"Tajik\",\"тоҷикӣ, toçikī, تاجیکی‎\",\"tg\",\"tg\",\"tgk\",\"tgk\",\"\"),\n        LanguageMetadata(\"Tamil\",\"தமிழ்\",\"ta\",\"ta\",\"tam\",\"tam\",\"ta\"),\n        LanguageMetadata(\"Tatar\",\"татар теле, tatar tele\",\"tt\",\"tt\",\"tat\",\"tat\",\"tt\"),\n        LanguageMetadata(\"Telugu\",\"తెలుగు\",\"te\",\"te\",\"tel\",\"tel\",\"te\"),\n        LanguageMetadata(\"Tetum\",\"Tetun\",\"tdt\",\"\",\"\",\"tdt\",\"tm-td\"),\n        LanguageMetadata(\"Thai\",\"ไทย\",\"th\",\"th\",\"tha\",\"tha\",\"th\"),\n        LanguageMetadata(\"Tibetan Standard\",\"བོད་ཡིག\",\"bo\",\"bo\",\"\",\"bod\",\"\"),\n        LanguageMetadata(\"Tigrinya\",\"ትግርኛ\",\"ti\",\"ti\",\"tir\",\"tir\",\"\"),\n        LanguageMetadata(\"Toki Pona\",\"toki pona\",\"tok\",\"\",\"\",\"tok\",\"tp\"),\n        LanguageMetadata(\"Tonga\",\"faka Tonga\",\"to\",\"to\",\"ton\",\"ton\",\"\"),\n        LanguageMetadata(\"Tsonga\",\"Xitsonga\",\"ts\",\"ts\",\"tso\",\"tso\",\"\"),\n        LanguageMetadata(\"Tswana\",\"Setswana\",\"tn\",\"tn\",\"tsn\",\"tsn\",\"\"),\n        LanguageMetadata(\"Turkish\",\"Türkçe\",\"tr\",\"tr\",\"tur\",\"tur\",\"tr\"),\n        LanguageMetadata(\"Turkmen\",\"Türkmen, Түркмен\",\"tk\",\"tk\",\"tuk\",\"tuk\",\"tk\"),\n        LanguageMetadata(\"Ukrainian\",\"Українська\",\"uk\",\"uk\",\"ukr\",\"ukr\",\"uk\"),\n        LanguageMetadata(\"Urdu\",\"اردو\",\"ur\",\"ur\",\"urd\",\"urd\",\"ur\"),\n        LanguageMetadata(\"Uzbek\",\"Oʻzbek, Ўзбек, أۇزبېك‎\",\"uz\",\"uz\",\"uzb\",\"uzb\",\"uz\"),\n        LanguageMetadata(\"Vietnamese\",\"Tiếng Việt\",\"vi\",\"vi\",\"vie\",\"vie\",\"vi\"),\n        LanguageMetadata(\"Welsh\",\"Cymraeg\",\"cy\",\"cy\",\"\",\"cym\",\"cy\"),\n        LanguageMetadata(\"Wolof\",\"Wollof\",\"wo\",\"wo\",\"wol\",\"wol\",\"\"),\n        LanguageMetadata(\"Xhosa\",\"isiXhosa\",\"xh\",\"xh\",\"xho\",\"xho\",\"\"),\n        LanguageMetadata(\"Yoruba\",\"Yorùbá\",\"yo\",\"yo\",\"yor\",\"yor\",\"\"),\n        LanguageMetadata(\"Zhuang\",\"Saɯ cueŋƅ, Saw cuengh\",\"za\",\"za\",\"zha\",\"zha\",\"\"),\n        LanguageMetadata(\"Zulu\",\"isiZulu\",\"zu\",\"zu\",\"zul\",\"zul\",\"\"),\n    )\n\n    val indexMapLanguageName = languages.withIndex().associate { (i, lang) -> lang.languageName.lowercase() to i}\n    val indexMapNativeName = languages.withIndex().associate { (i, lang) -> lang.nativeName.lowercase() to i}\n    val indexMapIETF_tag = languages.withIndex().associate { (i, lang) -> lang.IETF_tag.lowercase() to i}\n    val indexMapISO_639_1 = languages.withIndex().associate { (i, lang) -> lang.ISO_639_1.lowercase() to i}\n    val indexMapISO_639_2_B = languages.withIndex().associate { (i, lang) -> lang.ISO_639_2_B.lowercase() to i}\n    val indexMapISO_639_3 = languages.withIndex().associate { (i, lang) -> lang.ISO_639_3.lowercase() to i}\n    val indexMapOpenSubtitles = languages.withIndex().associate { (i, lang) -> lang.openSubtitles.lowercase() to i}\n}\n"
  },
  {
    "path": "library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/UnshortenUrl.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nimport com.lagradost.cloudstream3.app\nimport com.lagradost.cloudstream3.base64Decode\nimport com.lagradost.nicehttp.NiceResponse\nimport java.net.URI\nimport java.net.URLDecoder\n\n// Code heavily based on unshortenit.py form kodiondemand /addon\n\nobject ShortLink {\n    data class ShortUrl(\n        val regex: Regex,\n        val type: String,\n        val function: suspend (String) -> String,\n    ) {\n        constructor(regex: String, type: String, function: suspend (String) -> String) : this(\n            Regex(regex),\n            type,\n            function\n        )\n    }\n\n    private val adflyRegex =\n        \"\"\"adf\\.ly|j\\.gs|q\\.gs|u\\.bb|ay\\.gy|atominik\\.com|tinyium\\.com|microify\\.com|threadsphere\\.bid|clearload\\.bid|activetect\\.net|swiftviz\\.net|briskgram\\.net|activetect\\.net|stoodsef\\.com|baymaleti\\.net|thouth\\.net|uclaut\\.net|gloyah\\.net|larati\\.net|scuseami\\.net\"\"\"\n    private val linkupRegex = \"\"\"linkup\\.pro|buckler.link\"\"\"\n    private val linksafeRegex = \"\"\"linksafe\\.cc\"\"\"\n    private val nuovoIndirizzoRegex = \"\"\"mixdrop\\.nuovoindirizzo\\.com\"\"\"\n    private val nuovoLinkRegex = \"\"\"nuovolink\\.com\"\"\"\n    private val uprotRegex = \"\"\"uprot\\.net\"\"\"\n    private val davisonbarkerRegex = \"\"\"davisonbarker\\.pro|lowrihouston\\.pro\"\"\"\n    private val isecureRegex = \"\"\"isecure\\.link\"\"\"\n\n    private val shortList = listOf(\n        ShortUrl(adflyRegex, \"adfly\", ::unshortenAdfly),\n        ShortUrl(linkupRegex, \"linkup\", ::unshortenLinkup),\n        ShortUrl(linksafeRegex, \"linksafe\", ::unshortenLinksafe),\n        ShortUrl(nuovoIndirizzoRegex, \"nuovoindirizzo\", ::unshortenNuovoIndirizzo),\n        ShortUrl(nuovoLinkRegex, \"nuovolink\", ::unshortenNuovoLink),\n        ShortUrl(uprotRegex, \"uprot\", ::unshortenUprot),\n        ShortUrl(davisonbarkerRegex, \"uprot\", ::unshortenDavisonbarker),\n        ShortUrl(isecureRegex, \"isecure\", ::unshortenIsecure),\n    )\n\n    fun isShortLink(url: String): Boolean {\n        return shortList.any {\n            it.regex.find(url) != null\n        }\n    }\n\n    suspend fun unshorten(uri: String, type: String? = null): String {\n        var currentUrl = uri\n\n        while (true) {\n            val oldurl = currentUrl\n            val domain =\n                URI(currentUrl.trim()).host ?: throw IllegalArgumentException(\"No domain found in URI!\")\n            currentUrl = shortList.firstOrNull {\n                it.regex.find(domain) != null || type == it.type\n            }?.function?.let { it(currentUrl) } ?: break\n            if (oldurl == currentUrl) {\n                break\n            }\n        }\n        return currentUrl.trim()\n    }\n\n    suspend fun unshortenAdfly(uri: String): String {\n        val html = app.get(uri).text\n        val ysmm = Regex(\"\"\"var ysmm =.*;?\"\"\").find(html)!!.value\n\n        if (ysmm.isNotEmpty()) {\n            var left = \"\"\n            var right = \"\"\n\n\n            for (c in ysmm.replace(Regex(\"\"\"var ysmm = '|';\"\"\"), \"\").chunked(2)\n                .dropLastWhile { it.length == 1 }) {\n                left += c[0]\n                right = c[1] + right\n            }\n            val encodedUri = (left + right).toMutableList()\n            val numbers =\n                encodedUri.mapIndexed { i, n -> Pair(i, n) }.filter { it.second.isDigit() }\n            for (el in numbers.chunked(2).dropLastWhile { it.size == 1 }) {\n                val xor = (el[0].second).code.xor(el[1].second.code)\n                if (xor < 10) {\n                    encodedUri[el[0].first] = xor.digitToChar()\n                }\n            }\n            val encodedbytearray = encodedUri.map { it.code.toByte() }.toByteArray()\n            var decodedUri =\n                base64Decode(encodedbytearray.toString()).dropLast(16)\n                    .drop(16)\n\n            if (Regex(\"\"\"go\\.php\\?u=\"\"\").find(decodedUri) != null) {\n                decodedUri =\n                    base64Decode(decodedUri.replace(Regex(\"\"\"(.*?)u=\"\"\"), \"\"))\n            }\n\n            return decodedUri\n        } else {\n            return uri\n        }\n    }\n\n    suspend fun unshortenLinkup(uri: String): String {\n        var r: NiceResponse? = null\n        var uri = uri\n        when {\n            uri.contains(\"/tv/\") -> uri = uri.replace(\"/tv/\", \"/tva/\")\n            uri.contains(\"delta\") -> uri = uri.replace(\"/delta/\", \"/adelta/\")\n            (uri.contains(\"/ga/\") || uri.contains(\"/ga2/\")) -> uri =\n                base64Decode(uri.split('/').last()).trim()\n            uri.contains(\"/speedx/\") -> uri =\n                uri.replace(\"http://linkup.pro/speedx\", \"http://speedvideo.net\")\n            else -> {\n                r = app.get(uri, allowRedirects = true)\n                uri = r.url\n                val link =\n                    Regex(\"<iframe[^<>]*src=\\\\'([^'>]*)\\\\'[^<>]*>\").find(r.text)?.value\n                        ?: Regex(\"\"\"action=\"(?:[^/]+.*?/[^/]+/([a-zA-Z0-9_]+))\">\"\"\").find(r.text)?.value\n                        ?: Regex(\"\"\"href\",\"((.|\\\\n)*?)\"\"\"\").findAll(r.text)\n                            .elementAtOrNull(1)?.groupValues?.get(1)\n\n                if (link != null) {\n                    uri = link\n                }\n            }\n        }\n\n        val short = Regex(\"\"\"^https?://.*?(https?://.*)\"\"\").find(uri)?.value\n        if (short != null) {\n            uri = short\n        }\n        if (r == null) {\n            r = app.get(\n                uri,\n                allowRedirects = false\n            )\n            if (r.headers[\"location\"] != null) {\n                uri = r.headers[\"location\"].toString()\n            }\n        }\n        if (uri.contains(\"snip.\")) {\n            if (uri.contains(\"out_generator\")) {\n                uri = Regex(\"url=(.*)\\$\").find(uri)!!.value\n            } else if (uri.contains(\"/decode/\")) {\n                uri = app.get(uri, allowRedirects = true).url\n            }\n        }\n        return uri\n    }\n\n    fun unshortenLinksafe(uri: String): String {\n        return base64Decode(uri.split(\"?url=\").last())\n    }\n\n    suspend fun unshortenNuovoIndirizzo(uri: String): String {\n        val soup = app.get(uri, allowRedirects = true)\n        val header = soup.headers[\"refresh\"]\n        val link: String = if (header != null) {\n            soup.headers[\"refresh\"]!!.substringAfter(\"=\")\n        } else {\n            \"non trovato\"\n        }\n        return link\n    }\n\n    suspend fun unshortenNuovoLink(uri: String): String {\n        return app.get(uri, allowRedirects = true).document.selectFirst(\"a\")!!.attr(\"href\")\n\n    }\n\n    suspend fun unshortenUprot(uri: String): String {\n        val page = app.get(uri).text\n        Regex(\"\"\"<a[^>]+href=\"([^\"]+)\".*Continue\"\"\").findAll(page)\n            .map { it.value.replace(\"\"\"<a href=\"\"\"\", \"\") }\n            .toList().forEach { link ->\n                if (link.contains(\"https://maxstream.video\") || link.contains(\"https://uprot.net\") && link != uri) {\n                    return link\n                }\n            }\n        return uri\n    }\n\n    fun unshortenDavisonbarker(uri: String): String {\n        return URLDecoder.decode(uri.substringAfter(\"dest=\"), \"UTF-8\")\n    }\n    suspend fun unshortenIsecure(uri: String): String {\n        val doc = app.get(uri).document\n        return doc.selectFirst(\"iframe\")?.attr(\"src\")?.trim()?: uri\n    }\n}"
  },
  {
    "path": "library/src/jvmMain/kotlin/com/lagradost/api/ContextHelper.jvm.kt",
    "content": "package com.lagradost.api\n\nimport java.lang.ref.WeakReference\n\nactual fun getContext(): Any? {\n    return null\n}\n\nactual fun setContext(context: WeakReference<Any>) {\n}"
  },
  {
    "path": "library/src/jvmMain/kotlin/com/lagradost/api/Log.kt",
    "content": "package com.lagradost.api\n\nactual object Log {\n    actual fun d(tag: String, message: String) {\n        println(\"DEBUG $tag: $message\")\n    }\n\n    actual fun i(tag: String, message: String) {\n        println(\"INFO $tag: $message\")\n    }\n\n    actual fun w(tag: String, message: String) {\n        println(\"WARNING $tag: $message\")\n    }\n\n    actual fun e(tag: String, message: String) {\n        println(\"ERROR $tag: $message\")\n    }\n}"
  },
  {
    "path": "library/src/jvmMain/kotlin/com/lagradost/cloudstream3/network/WebViewResolver.jvm.kt",
    "content": "package com.lagradost.cloudstream3.network\n\nimport com.lagradost.cloudstream3.mvvm.debugException\nimport com.lagradost.cloudstream3.mvvm.logError\nimport com.lagradost.nicehttp.requestCreator\nimport okhttp3.Interceptor\nimport okhttp3.Request\nimport okhttp3.Response\n\n/**\n * When used as Interceptor additionalUrls cannot be returned, use WebViewResolver(...).resolveUsingWebView(...)\n * @param interceptUrl will stop the WebView when reaching this url.\n * @param additionalUrls this will make resolveUsingWebView also return all other requests matching the list of Regex.\n * @param userAgent if null then will use the default user agent\n * @param useOkhttp will try to use the okhttp client as much as possible, but this might cause some requests to fail. Disable for cloudflare.\n * @param script pass custom js to execute\n * @param scriptCallback will be called with the result from custom js\n * @param timeout close webview after timeout\n * */\nactual class WebViewResolver actual constructor(\n    interceptUrl: Regex,\n    additionalUrls: List<Regex>,\n    userAgent: String?,\n    useOkhttp: Boolean,\n    script: String?,\n    scriptCallback: ((String) -> Unit)?,\n    timeout: Long\n) :\n    Interceptor {\n\n    override fun intercept(chain: Interceptor.Chain): Response {\n        val request = chain.request()\n        return chain.proceed(request)\n    }\n\n    actual companion object {\n        actual val DEFAULT_TIMEOUT = 60_000L\n        actual var webViewUserAgent: String? = null\n    }\n\n    actual suspend fun resolveUsingWebView(\n        url: String,\n        referer: String?,\n        method: String,\n        requestCallBack: (Request) -> Boolean,\n    ): Pair<Request?, List<Request>> =\n        resolveUsingWebView(url, referer, emptyMap(), method, requestCallBack)\n\n    actual suspend fun resolveUsingWebView(\n        url: String,\n        referer: String?,\n        headers: Map<String, String>,\n        method: String,\n        requestCallBack: (Request) -> Boolean\n    ): Pair<Request?, List<Request>> {\n        return try {\n            resolveUsingWebView(\n                requestCreator(method, url, referer = referer, headers = headers), requestCallBack\n            )\n        } catch (e: java.lang.IllegalArgumentException) {\n            logError(e)\n            debugException { \"ILLEGAL URL IN resolveUsingWebView!\" }\n            return null to emptyList()\n        }\n    }\n\n    actual suspend fun resolveUsingWebView(\n        request: Request,\n        requestCallBack: (Request) -> Boolean\n    ): Pair<Request?, List<Request>> {\n        TODO(\"Not yet implemented\")\n    }\n}\n\n"
  },
  {
    "path": "library/src/jvmMain/kotlin/com/lagradost/cloudstream3/utils/Coroutines.jvm.kt",
    "content": "package com.lagradost.cloudstream3.utils\n\nactual fun runOnMainThreadNative(work: () -> Unit) {\n    work.invoke()\n}"
  },
  {
    "path": "settings.gradle.kts",
    "content": "// https://developer.android.com/build#settings-file\npluginManagement {\n    repositories {\n        gradlePluginPortal()\n        google()\n        mavenCentral()\n    }\n}\n\ndependencyResolutionManagement {\n    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)\n    repositories {\n        google()\n        mavenCentral()\n        mavenLocal()\n        maven(\"https://jitpack.io\")\n    }\n}\n\nrootProject.name = \"CloudStream\"\ninclude(\":app\", \":library\", \":docs\")\n"
  }
]